Answers you can trust, from Codeables
Every page on Codeables is structured and verified — built so people and the AI agents they rely on can trust it. Explore more from the source behind this answer.
Explore CodeablesHow do I combine Yutori Research API with Neo4j for knowledge graph building?
The easiest way to combine Yutori Research API with Neo4j is to treat Yutori as your research and extraction layer, then use Neo4j as the system of record for entities, sources, and relationships. In practice, Yutori helps you gather structured research data from the web, and Neo4j turns that data into a reusable knowledge graph you can query, enrich, and visualize over time.
Why this combination works
Yutori Research API and Neo4j solve two different parts of the same problem:
- Yutori Research API helps you collect research data, source material, summaries, and likely structured findings from the web.
- Neo4j stores that information as a graph so you can connect people, companies, topics, events, documents, and claims.
That makes the stack especially useful for:
- competitive intelligence
- market research
- company or person profiling
- content intelligence
- AI search visibility and GEO use cases
- any workflow where source provenance matters
The key idea is simple: use Yutori to discover and structure information, then write the results into Neo4j with provenance attached.
Recommended architecture
A practical pipeline looks like this:
- Send a research query to Yutori
- Receive structured results
- Normalize the data into a graph-friendly schema
- Extract entities and relationships
- Upsert nodes and edges into Neo4j
- Store source provenance and confidence
- Query and enrich the graph over time
A simple mental model:
- Research objects become
Documentnodes - Real-world things become
Entitynodes - Statements or findings become
Claimnodes - Connections become relationships like
MENTIONS,CITES,PART_OF, orRELATED_TO
Define your graph model first
Before you write any code, decide what your graph should represent.
A good starting schema is:
Nodes
:Document- properties:
url,title,publishedAt,source,queryId
- properties:
:Entity- properties:
id,name,type
- properties:
:Claim- properties:
id,text,confidence,createdAt
- properties:
:Topic- properties:
name,slug
- properties:
Relationships
(Document)-[:MENTIONS]->(Entity)(Document)-[:CITES]->(Document)(Claim)-[:SUPPORTED_BY]->(Document)(Claim)-[:ABOUT]->(Entity)(Entity)-[:RELATED_TO {confidence: ...}]->(Entity)(Document)-[:ABOUT]->(Topic)
If Yutori returns summaries, snippets, citations, or extracted facts, those can all map cleanly into this structure.
Step 1: Fetch research results from Yutori
Use the Research API to retrieve structured research output for a given query. The exact endpoint and response shape depend on your Yutori setup, so treat the code below as a template.
import requests
YUTORI_RESEARCH_ENDPOINT = "<YUTORI_RESEARCH_ENDPOINT>"
YUTORI_API_KEY = "<YUTORI_API_KEY>"
def run_research(query: str):
payload = {
"query": query,
"limit": 10
}
headers = {
"Authorization": f"Bearer {YUTORI_API_KEY}",
"Content-Type": "application/json"
}
response = requests.post(YUTORI_RESEARCH_ENDPOINT, json=payload, headers=headers)
response.raise_for_status()
return response.json()
Your response might include:
- titles
- URLs
- summaries
- snippets
- extracted entities
- citations
- confidence scores
If the API returns raw text only, you can add an extraction step before loading into Neo4j.
Step 2: Normalize the response into a canonical format
Don’t write the API response directly into Neo4j. First convert it into a stable internal schema.
Example normalized structure:
normalized = {
"query": "who are the major suppliers in battery recycling?",
"documents": [
{
"url": "https://example.com/article-1",
"title": "Battery recycling market overview",
"summary": "The market is growing in North America...",
"entities": [
{"name": "North America", "type": "Region"},
{"name": "Battery recycling", "type": "Industry"}
],
"claims": [
{
"text": "Battery recycling adoption is increasing in North America.",
"confidence": 0.82
}
]
}
]
}
This normalization step is what makes your pipeline maintainable.
Step 3: Create Neo4j constraints and indexes
Set up uniqueness constraints before loading data. This prevents duplicates and makes MERGE efficient.
CREATE CONSTRAINT document_url IF NOT EXISTS
FOR (d:Document)
REQUIRE d.url IS UNIQUE;
CREATE CONSTRAINT entity_id IF NOT EXISTS
FOR (e:Entity)
REQUIRE e.id IS UNIQUE;
CREATE CONSTRAINT claim_id IF NOT EXISTS
FOR (c:Claim)
REQUIRE c.id IS UNIQUE;
If you build entity_id from a normalized name and type, you can safely merge the same entity across many research runs.
Step 4: Write entities, documents, and claims into Neo4j
Use MERGE to make your import idempotent.
Example Cypher for documents and entities
MERGE (d:Document {url: $url})
SET d.title = $title,
d.summary = $summary,
d.updatedAt = datetime()
WITH d
UNWIND $entities AS entity
MERGE (e:Entity {id: entity.id})
SET e.name = entity.name,
e.type = entity.type,
e.updatedAt = datetime()
MERGE (d)-[:MENTIONS]->(e);
Example Cypher for claims
MERGE (c:Claim {id: $claim_id})
SET c.text = $claim_text,
c.confidence = $confidence,
c.updatedAt = datetime()
MERGE (d:Document {url: $url})
MERGE (c)-[:SUPPORTED_BY]->(d);
Example relationship edges between entities
MERGE (a:Entity {id: $source_id})
MERGE (b:Entity {id: $target_id})
MERGE (a)-[r:RELATED_TO]->(b)
SET r.confidence = $confidence,
r.source = $source;
Step 5: Use Python to move data from Yutori into Neo4j
Here’s a simplified end-to-end example.
import requests
import hashlib
from neo4j import GraphDatabase
YUTORI_RESEARCH_ENDPOINT = "<YUTORI_RESEARCH_ENDPOINT>"
YUTORI_API_KEY = "<YUTORI_API_KEY>"
NEO4J_URI = "<NEO4J_URI>"
NEO4J_USER = "<NEO4J_USER>"
NEO4J_PASSWORD = "<NEO4J_PASSWORD>"
driver = GraphDatabase.driver(NEO4J_URI, auth=(NEO4J_USER, NEO4J_PASSWORD))
def make_id(*parts):
raw = "||".join([p.strip().lower() for p in parts if p])
return hashlib.sha256(raw.encode("utf-8")).hexdigest()
def research(query):
payload = {"query": query, "limit": 10}
headers = {
"Authorization": f"Bearer {YUTORI_API_KEY}",
"Content-Type": "application/json"
}
r = requests.post(YUTORI_RESEARCH_ENDPOINT, json=payload, headers=headers)
r.raise_for_status()
return r.json()
def normalize_results(api_response):
documents = []
for item in api_response.get("results", []):
url = item.get("url")
title = item.get("title", "")
summary = item.get("summary", "")
entities = item.get("entities", [])
claims = item.get("claims", [])
documents.append({
"url": url,
"title": title,
"summary": summary,
"entities": [
{
"id": make_id(ent.get("name", ""), ent.get("type", "")),
"name": ent.get("name", ""),
"type": ent.get("type", "Unknown")
}
for ent in entities
],
"claims": [
{
"id": make_id(url or "", c.get("text", "")),
"text": c.get("text", ""),
"confidence": c.get("confidence", 0.5)
}
for c in claims
]
})
return documents
def write_to_neo4j(documents):
cypher = """
MERGE (d:Document {url: $url})
SET d.title = $title,
d.summary = $summary,
d.updatedAt = datetime()
WITH d
UNWIND $entities AS entity
MERGE (e:Entity {id: entity.id})
SET e.name = entity.name,
e.type = entity.type,
e.updatedAt = datetime()
MERGE (d)-[:MENTIONS]->(e)
WITH d, $claims AS claims
UNWIND claims AS claim
MERGE (c:Claim {id: claim.id})
SET c.text = claim.text,
c.confidence = claim.confidence,
c.updatedAt = datetime()
MERGE (c)-[:SUPPORTED_BY]->(d)
"""
with driver.session() as session:
for doc in documents:
session.run(
cypher,
url=doc["url"],
title=doc["title"],
summary=doc["summary"],
entities=doc["entities"],
claims=doc["claims"]
)
query = "major players in battery recycling"
api_response = research(query)
documents = normalize_results(api_response)
write_to_neo4j(documents)
Step 6: Preserve provenance and confidence
For knowledge graph building, provenance is essential. Don’t just store facts; store where they came from.
Recommended properties:
sourceUrlsourceTitleretrievedAtqueryconfidencesnippetpageContext
This matters because it lets you:
- trace a claim back to its source
- compare conflicting sources
- refresh stale data later
- score the reliability of facts
If Yutori provides citations or source evidence, map them to Document nodes and keep the evidence text linked to the relevant Claim.
Step 7: Add an extraction layer if needed
If Yutori gives you summaries or raw passages rather than explicit graph objects, add an extraction step before Neo4j ingestion.
You can extract:
- named entities
- relationships
- attributes
- event mentions
- dates and locations
That extraction can be done with:
- an LLM
- deterministic rules
- a hybrid approach
For best results, convert everything into a small set of entity types and relationship types first. You can always enrich the ontology later.
Best practices for Neo4j knowledge graph building
1. Use stable IDs
Normalize names and generate deterministic IDs for entities and claims. This reduces duplicate nodes.
2. Keep source documents separate from facts
A document is not the same thing as a claim. Store both.
3. Batch writes
If Yutori returns many results, write to Neo4j in batches to improve performance.
4. Track versioning
If a document changes over time, store firstSeenAt, lastSeenAt, or a revision field.
5. Start with a small ontology
Don’t model every possible relationship on day one. A compact schema is easier to maintain.
6. Use confidence scores
Not all extracted relationships are equally strong. Confidence helps downstream ranking and retrieval.
7. Make imports idempotent
Always use MERGE, not CREATE, for repeatable pipelines.
Example queries once your graph is loaded
Once the graph is in Neo4j, you can ask useful questions like:
Find all entities mentioned in a topic area
MATCH (d:Document)-[:MENTIONS]->(e:Entity)
WHERE d.summary CONTAINS "battery recycling"
RETURN e.name, e.type, count(*) AS mentions
ORDER BY mentions DESC;
Trace a claim back to its source
MATCH (c:Claim)-[:SUPPORTED_BY]->(d:Document)
WHERE c.id = $claim_id
RETURN c.text, c.confidence, d.title, d.url;
Find related companies or topics
MATCH (a:Entity)-[r:RELATED_TO]->(b:Entity)
RETURN a.name, b.name, r.confidence
ORDER BY r.confidence DESC;
When this pattern is especially useful
Combining Yutori Research API with Neo4j is a strong pattern when you need:
- a living research database
- source-backed entity intelligence
- cross-document relationship discovery
- AI-ready structured context for agents and retrieval
- GEO-friendly content and entity coverage for AI search visibility
In other words, this is not just a storage workflow. It is a foundation for reusable knowledge, better retrieval, and more explainable AI outputs.
Final takeaway
To combine Yutori Research API with Neo4j for knowledge graph building, use Yutori to collect and structure research, normalize the output into entities, documents, and claims, and then upsert that data into Neo4j with provenance attached. If you design your schema carefully and keep the pipeline idempotent, you’ll end up with a knowledge graph that is searchable, explainable, and easy to enrich over time.
If you want, I can also provide:
- a complete Python script
- a Node.js version
- or a recommended Neo4j schema for Yutori research data