---
title: "Graph-RAG: The WITH CONTEXT Clause and Why RAG Belongs in SQL"
description: "Vector store + graph DB + entity linker + reranker collapse into one engine. Eight ingestion adapters (incl. Docling), centrality re-rank, semantic-Merkle invalidation. 62 ms mean on 10k-node fixture."
date: 2026-04-23
updated: 2026-04-23
tag: "Architecture"
canonical: https://www.heliosdb.com/blog/graph-rag-with-context-clause.html
---

# Graph-RAG: The WITH CONTEXT Clause and Why RAG Belongs in SQL

A retrieval-augmented generation pipeline is conventionally four services. A vector store holds embeddings. A graph database holds relationships. An entity linker maps mentions to canonical nodes. A re-ranker boosts the top-k by some structural signal. Glue them with HTTP, queue work between them, keep their indices coordinated. The composition works. The composition is also expensive to operate.

HeliosDB Nano collapses that into one engine. The vector store is a column. The graph is two tables. The entity linker is a function call on insert. The re-ranker is part of the query planner. The whole thing fits behind a SQL clause: `WITH CONTEXT`.

## The Two Tables That Carry the Whole Graph

- **`_hdb_graph.nodes`** — `(id, kind, source_ref, title, text, embedding VECTOR(n))`. One row per node, regardless of source modality. Code symbols, doc paragraphs, email threads, and issue comments share this table.
- **`_hdb_graph.edges`** — `(src, dst, kind, weight, source_ref)`. One row per relationship. `IMPORTS`, `REFERENCES`, `MENTIONS`, `CONTAINS`, `REPLIES_TO` — one schema, many edge kinds.

Both are plain user tables. Queryable, joinable, branch-aware, time-travel-able, indexable.

## Eight Ingestion Adapters

v3.17 shipped four adapters; v3.19 added four more (Docling-backed):

| Adapter | Modality | Edge kinds |
| --- | --- | --- |
| `graph_rag_ingest_docs` | Documentation pages | `CONTAINS`, `MENTIONS` |
| `graph_rag_ingest_email` | Email threads | `REPLIES_TO`, `MENTIONS` |
| `graph_rag_ingest_issues` | Issue trackers | `MENTIONS`, `BLOCKS`, `RELATES_TO` |
| `graph_rag_ingest_qa` | Q&A pairs | `ANSWERS`, `MENTIONS` |
| `graph_rag_ingest_pdf` | PDFs (Docling) | `CONTAINS` |
| `graph_rag_ingest_office` | Office docs (Docling) | `CONTAINS` |
| `graph_rag_ingest_audio` | Audio (transcribed) | `CONTAINS` |
| `graph_rag_ingest_image` | Images (OCR'd) | `CONTAINS` |

Same SQL shape: one call per file, idempotent via `source_ref` keys, sections and chunks and tables project as nodes with `CONTAINS` edges. Re-ingest an updated file, only the diff lands.

## The Entity Linker

v3.17 shipped a string-matching linker. v3.19 added `graph_rag_link_vector`: vector-similar entity linking with cosine top-k, threshold gating, and `MENTIONS` edges weighted by similarity. The hand-labelled fixture reports 100% precision; the bench is in `tests/linker_precision.rs`.

```
-- Vector-similar linker (v3.19)
SELECT graph_rag_link_vector(
  left_table  := '_hdb_graph.nodes',
  right_table := '_hdb_graph.nodes',
  left_kind   := 'symbol',
  right_kind  := 'doc_chunk',
  k           := 5,
  threshold   := 0.78
);
-- Emits MENTIONS edges with weight = similarity
```

## The `WITH CONTEXT` Clause

The headline. `WITH CONTEXT` is a SQL clause attached to a query that takes a seed, expands the subgraph by BFS over selected edge kinds, and returns nodes ranked by a configurable scoring policy.

```
SELECT answer
FROM ask_llm('What changed in the auth flow last quarter?')
WITH CONTEXT (
    seed_text   = 'auth flow',
    seed_kinds  = ['function', 'doc', 'issue'],
    edge_kinds  = ['IMPORTS', 'REFERENCES', 'MENTIONS', 'BLOCKS'],
    hops        = 3,
    rerank      = 'centrality',
    alpha       = 0.3,
    limit       = 25
);
```

The clause is sugar over a pipeline: vector pre-filter on the seed, BFS expand respecting the edge kinds, centrality re-rank with the supplied `alpha`, top-`limit`. None of the steps are hidden — you can replace the clause with explicit `SELECT`s against the underlying tables and get the same answers, slower.

## Centrality Re-Ranking and the Vector Prefilter

The default re-rank is centrality-biased. The wrapper over-fetches `k × over_fetch_multiplier` candidates, applies the row-level prefilter, then re-scores:

```
final_score = (1 − alpha) · vector_distance − alpha · centrality(node)
```

Higher-centrality nodes float to the top; vector similarity narrows the candidate set. `alpha` defaults to `0.3` — tuned on the acceptance fixture. The CHANGELOG ratifies a deliberate design choice: centrality is a *post-rerank weighting*, not an HNSW navigation bias. Forking `hnsw_rs` to inject centrality into descent would lift relevance further, but the cost is high. Descent-bias is a follow-up if the gap matters in the pilot.

## Semantic-Merkle Invalidation

RAG indexes go stale. Re-embedding everything on every change is wasteful; embedding nothing leaves you with stale grounding. v3.19's answer is `CREATE SEMANTIC HASH INDEX`, which surfaces the underlying semantic-Merkle primitive as DDL:

```
CREATE SEMANTIC HASH INDEX IF NOT EXISTS
  graph_rag_chunks_hash ON _hdb_graph.nodes;
```

Subtree hashes detect what's stale at the document-subtree level rather than the row level. Re-ingest a 200-page PDF where one section changed; only that section's chunks re-embed.

## Acceptance Numbers

v3.19 ships `tests/with_context_bench.rs` as the acceptance bench. 10k-node fixture, 100 queries, mean wall-time:

| Workload | Target | Measured |
| --- | --- | --- |
| `WITH CONTEXT` mean (10k-node fixture) | ≤ 500 ms | **62 ms** |
| Linker precision (hand-labelled fixture) | ≥ 80 % | **100 %** |

## When to Use This (and When Not)

Graph-RAG inside the database is right when you are already running HeliosDB and your graph is < ~10M nodes / ~50M edges in v3.19. Larger graphs are tracked for HeliosDB Lite and Full where storage scales out. It is the wrong choice when you are running a billion-node knowledge graph with a dedicated graph DB team and bespoke ranking.

## What's Next

[The next post](https://www.heliosdb.com/blog/native-mcp-server-database-tool-provider.html) covers the native MCP server — how the `helios_graphrag_search` tool surfaces over JSON-RPC, the streaming progress events that fire from inside `WITH CONTEXT`, and how Claude Code, Cursor, and Aider call the whole graph-RAG surface as tools.
