Skip to content
RAG Explained Better

Parent-Document Retrieval

Retrieve small chunks for precision, return their parent for context: how it fixes the size trade-off.

Parent-document retrieval indexes small child chunks for precise vector search, then returns each hit’s larger parent (a section or the source document) to the generator. LangChain’s ParentDocumentRetriever states the conflict directly: embeddings stay sharp on short units, while generation needs enough surrounding text to keep meaning. The price is more child vectors, a parent docstore, and a query-time lookup. The chunking-side family survey lives on hierarchical chunking for small-to-big; the parent map of retrieval choices is retrieval in RAG.

How does parent-document retrieval work?

Parent-document retrieval builds two linked views at ingest and expands at query time. Documents are split into larger parents and then into smaller children that keep a link back to the parent. Only children are embedded for similarity search. Parents are stored as text for generation. GraphRAG’s parent-child retriever note makes the same point: parent chunks need not be embedded because they are not the similarity key.

Three-step vertical flow. One, split into parents then children. Two, embed and index the children only; parents live in a separate docstore. Three, search children and return parents after de-duplication.
The unit you search and the unit the generator reads are different sizes on purpose.

Published demos disagree on exact sizes, which is expected. The MongoDB Atlas parent-document tutorial splits parents with RecursiveCharacterTextSplitter(chunk_size=2000, chunk_overlap=20) and children with chunk_size=200, chunk_overlap=20, then retrieves k=10 children in the initial search. LanceDB’s Modified RAG walkthrough uses small chunks of 512 and bigger chunks of 2048 characters. DhanushKumar’s February 2025 Medium demo sets child_splitter to 400 characters and stores child vectors in Chroma. Treat those numbers as starting recipes, not laws.

At query time the system embeds the question, finds similar child vectors, then loads each child’s parent for the prompt. GraphRAG’s Cypher sketch aggregates children that share a parent and keeps a max or average score so one parent is not emitted once per child hit. That expand-and-dedupe step is the retrieval mode; without it you only have small-chunk RAG.

What are the two parent return modes?

LangChain’s reference documentation states that “parent document” can mean either the whole raw document a child came from or a larger chunk produced by an optional parent_splitter. That is the first-class fork: same child index, different generation unit.

Returning the full source document maximises context and maximises prompt size. LanceDB’s song-lyrics demo shows why that can break short-context models: matching a line and then stuffing the entire parent song can exceed the window or drown the matched verse. Returning a pre-sized parent chunk (MongoDB’s 2000-character parents, or LanceDB’s bigger-chunk table) keeps section-scale context without shipping the whole file. LanceDB further describes a middle ground: keep small children for matching, but return an intermediate bigger chunk (they illustrate mid-size around half the parent) when the true parent is too large for the generator.

Prefer section-aligned parents on long manuals and policies so the generation unit matches author structure rather than an arbitrary character budget. When the hierarchy is real Markdown or HTML headings, start from structure-aware chunking so parents match sections instead of fixed character windows alone.

What does parent-document retrieval cost?

The costs are structural: more child vectors than parent-only indexing, a parent store beside the vector collection, a query-time expand step, and larger generation prompts. You embed children only; parents are looked up as text. GraphRAG states that parent embedding is unnecessary for the similarity search. MongoDB’s Atlas integration stores parent and child documents in one collection while still indexing embeddings for children only, which keeps lookup local to the database.

Demo stacks often put parents in an InMemoryStore. The Medium demo does; so does the LanceDB notebook. That store evaporates on process restart, so production needs a durable docstore or a database-backed parent layer such as MongoDB’s MongoDBDocStore. Embedding spend tracks the child count and child size, not parent length. Prompt tokens and generation latency track parent size after expand, even when retrieval stayed precise on a 200-character child.

Measure on your corpus

Splitter sizes in MongoDB (2000/200), LanceDB (512/2048), and Medium (400 child) are tutorial defaults. Exact dollar and latency deltas depend on your embedding price, average parent size, and how often multiple children collapse to one parent. Family-level cost framing continues on small-to-big family cost framing.

MongoDB’s search_kwargs = {“k”: 10} default in the Atlas tutorial is another knob: more child hits raise recall and raise the chance several children map to the same parent, which only helps if you dedupe before packing the prompt.

What goes wrong with parent-document retrieval?

Most failures are bookkeeping, not a broken idea. Missing child-to-parent links leave you with plain small-chunk retrieval and no expand step. Skipping de-duplication returns the same parent once per child hit and wastes the context window; GraphRAG’s parent aggregation exists to prevent that. Oversized parents recreate the dilution small-to-big was meant to escape, which is why LanceDB adds the bigger-chunk middle path when full parents are too large for the model.

Index drift is the quieter failure. When a document changes you must re-chunk children, re-embed them, and update the parent store together, or a stale parent id returns the wrong section. Persisting only the vector collection while leaving parents in an in-memory store loses the expand map on restart. Cross-parent answers remain possible: if the true span crosses two sections, returning each child’s single parent can still leave a chunk-boundary SPLIT.

Those five modes decide whether the pattern is misconfigured or genuinely the wrong tool for the query mix. A sixth operational failure is quieter: treating child k as if it were parent k. With MongoDB’s tutorial default of ten child hits, three children from one section and seven from another may collapse to two unique parents after dedupe, which is a different packing problem than ten independent passages.

When should you use parent-document retrieval?

Use parent-document retrieval when answers need surrounding context that a precise child hit does not carry. Medium’s Parent Document Retriever framing is the balance case: you want detailed matching on small chunks and still need the larger parent for coherence. LanceDB’s sequel-song example is the continuity case: a short query line should pull style and story from the same parent work, not a mixture of unrelated chunks from other songs.

Skip the pattern for short self-contained FAQs and product cards where the small chunk already is the whole context, and for strict token or latency budgets where parent expansion dominates the SLA. Prefer cheaper chunk overlap first when answers only straddle a seam by a few sentences; escalate when SPLIT survives that band, as the chunk-boundary failure page decides.

Prove the choice on the same queries with and without parent expansion. Compare child-only prompts against parent-expanded prompts on faithfulness and completeness rather than adopting the pattern by name. Also compare full-document parents against section-sized parents on the same child index so the return-mode fork is measured, not assumed from the framework default.

How is parent-document different from sentence-window and auto-merging?

All three are small-to-big. They differ in how the big unit is defined and when it is assembled. Parent-document retrieval fixes parent and child boundaries at index time and returns the pre-defined parent of each child hit (LangChain ParentDocumentRetriever). Sentence-window retrieval embeds sentences and expands each hit by a neighbour window at query time; the window size is a runtime knob. Mode depth continues on sentence-window retrieval.

Auto-merging retrieval builds a multi-level tree and merges sibling leaves upward when enough of them hit. Mode depth continues on auto-merging retrieval. GraphRAG also notes sibling and hierarchical lexical-graph variants where extra context comes from neighbours or a depth of structure rather than a single parent fetch.

The chunking-side survey of the family, including when overlap is enough, lives on parent and hierarchical chunking patterns.

How do you implement parent-document retrieval?

The ParentDocumentRetriever API needs a vector store for children, a docstore for parents, a child_splitter, and optionally a parent_splitter (langchain-classic reference, v1.4.0 as captured September 2026). MongoDB Atlas ships MongoDBAtlasParentDocumentRetriever that creates a child vector search handle and a parent docstore in one collection. LanceDB demos wire child vectors into a LanceDB table and parents into an in-memory or durable store.

Child vectors can live in stores such as Weaviate, Qdrant, Pinecone, Chroma, MongoDB Atlas, and LanceDB; parents need a durable key-value or document store in production. Persist the parent store. Pin splitter sizes and k, measure unique parents after dedupe, and put the runnable end-to-end walkthrough on building the pipeline. Family cost framing returns to the hierarchical chunking survey; the retrieval cluster returns to retrieval methods in RAG.

Start without a mid-size bigger-chunk table; add LanceDB-style intermediate parents only when full parents overflow the generator while child-only answers stay thin. Keep Weaviate as the default child vector collection in worked examples on this site when a dual-store pattern is shown, with parents in a durable docstore beside it.

Parent-document retrieval searches children and generates from parents so embeddings stay sharp while the prompt keeps section context. The two return modes are whole-document versus pre-sized parent chunks; MongoDB publishes a 2000/200 splitter pair with k=10 child search; LanceDB shows when a mid-size bigger chunk beats a whole-document parent. Deduplicate parents, persist the docstore, and route family survey depth to hierarchical chunking and windowed expand depth to sentence-window retrieval.