The Big Picture
- Lexical layer — Document and Chunk nodes with provenance edges (the text you ingested)
- Knowledge layer — Entity nodes with relationship edges (the structured knowledge extracted from that text)
MENTIONED_IN edges, which link entities to the chunks where they were found.
Node Labels
Document
Purpose: Represents a source document that was ingested.
Created in: Step 3 (Lexical Graph) of the ingestion pipeline.
Chunk
Purpose: A text fragment from a document. Chunks are the atomic unit of retrieval — when the system finds relevant information, it returns chunks.
Created in: Step 3 (Lexical Graph). Embedding added in Step 9.
Entity Nodes (Person, Organization, etc.)
Purpose: Extracted knowledge entities. Each entity node has two labels: its domain type (e.g.,Person) and __Entity__ (a secondary label shared by all extracted entities).
Created in: Step 7 (Write).
__Entity__ label is automatically added. Embedding is written during finalize().
An entity stays the same size however often it is mentioned. Which chunks mention it, where, and what each says it is are on its MENTIONED_IN edges, one per chunk; the node holds no chunk list. Its descriptions are bounded twice: a write adds at most up to 20 on the node (past that, a mention’s description is kept on its edge only; a write never cuts what a node already holds), and finalize(), after dedup, tries to replace the descriptions of every entity holding more than 5 with one LLM summary of them, marked description_summarised. A summary that fails leaves them as they are, listed in FinalizeResult.description_summary_failures, and the next finalize() tries again.
What a deleted or updated document said is taken off. Before delete_document() or update() removes a document’s chunks, it records what their mention edges said, with the rest of its crash-safe cleanup state; the cleanup then drops exactly that text from the entities’ descriptions, keeping anything a remaining chunk still says, and fills the places this frees on a full node (20) from what the remaining chunks say. No LLM call. If something else writes an entity’s description meanwhile, the entity is read again; one that keeps changing is logged and left, since the delete or update has already taken effect. A summarised entity cannot have text taken out of its summary: when the removed text is no longer said by any remaining edge and every remaining edge records what its chunk said (has said_version; a table row’s edge, which never says anything, does not count), it is rebuilt from them (and summarised again by the next finalize()); otherwise its summary is kept, and the removed text beside it is still dropped.
Graphs written by an earlier version keep their entities’ source_chunk_ids lists and descriptions. MENTIONED_IN edges are what the SDK reads for provenance; the update and delete paths still trim the old lists. Their mention edges carry no said_version — and keep none when a later write adds a description to one — so text a document ingested by an earlier version wrote cannot be taken off on its delete: it is kept, as before this version, and a summarised entity with such an edge is never rebuilt from its edges.
Default entity types (11): Person, Organization, Technology, Product, Location, Date, Event, Concept, Law, Dataset, Method
Entities below the NER confidence threshold get the special label Unknown.
SDK system nodes
Besides your data, the graph holds a small, fixed set of the SDK’s own nodes under two labels:__GraphRAGConfig__ (the embedding model and vector size the graph was written with) and __GraphRAGProcessing__ (dedup work in progress — the run lock, the entities whose dedup check is owed, and an interrupted run’s merge plan; a finished run leaves only what is still owed). They have no edges and no vector, so no traversal or search reaches them, and get_statistics() does not count them. No dedup marker or bookkeeping is written on your entities — only their name vectors, and what a merge folds into the survivor. See Storage.
Edge Types
PART_OF (Document -> Chunk)
Purpose: Provenance — tracks which document a chunk came from.NEXT_CHUNK (Chunk -> Chunk)
Purpose: Sequential ordering — preserves the reading order of chunks within a document. Used to fetch neighboring chunks for context expansion. No additional properties.MENTIONED_IN (Entity -> Chunk)
Purpose: Co-occurrence — links entities to the chunks where they were extracted. This is a critical edge for retrieval: when you find an entity, you can traverse to its source chunks.
Deduplicated by
(entity_id, chunk_id). Written once and deleted with its chunk, so what a deleted document said can be taken off its entities’ descriptions.
RELATES (Entity -> Entity)
Purpose: All extracted relationships between entities. This is the only relationship type used for knowledge edges.Why a Single RELATES Edge Type?
You might expect separate edge types likeWORKS_AT, LOCATED_IN, and MARRIED_TO. Instead, all relationships use the single RELATES type with the original type stored in the rel_type property. Here’s why:
-
Index efficiency. Each edge type in FalkorDB needs its own vector index. With potentially hundreds of LLM-generated relationship types, you’d need hundreds of indexes. One
RELATEStype means one vector index that covers all relationships. - Consistent retrieval. The retrieval system searches all relationships at once via the RELATES edge vector index. Having a single type means one query covers everything.
-
No information loss. The original type is preserved in
rel_typeand appears in thefactstring, so you can still filter by type in custom Cypher queries:
Indexes
The SDK creates 5 standard indexes duringfinalize() (or ensure_indices()). All are idempotent — safe to create repeatedly.
Vector Indexes (3)
Syntax:
Fulltext Indexes (2)
Syntax:
__Entity__ statements build a single index over name and description. They are separate statements so that an existing index on one field cannot stop the other from being added.
The Provenance Chain
The graph structure ensures complete traceability from any answer back to its source:Defining Your Own Schema
AGraphSchema tells the extraction pipeline which entity and relationship types to look for, and the pruning step uses it to filter non-conforming data.
Basic Schema
Schema with Patterns
Patterns define which source-target pairs are valid for each relationship type. They are specified directly onRelationType:
patterns list is allowed between any entity types.
Open Schema Mode
If you create an empty schema (GraphSchema()), the pipeline operates in open schema mode:
- The LLM extracts any entities and relationships it finds
- The pruning step is skipped entirely
- The 11 default entity types are used for NER