liveBook · Manning

Hybrid search

As explained in Essential GraphRAG

Hybrid search is an information-retrieval technique that combines multiple retrieval methods, such as vector similarity search and full-text search.

Hybrid search combines vector similarity search with full-text search to retrieve both semantically related passages and passages containing precise keywords. It improves a basic RAG retriever when either method alone misses useful context. section 2.3 section 2.5

A practical hybrid-search pipeline follows these steps:

  • Run a vector-index query with the question embedding and a full-text query with the original question. section 2.3.2
  • Normalize each result set by dividing scores by that search’s highest score, making the scores comparable. section 2.3.2
  • Union the results, deduplicate nodes, retain each node’s maximum score, sort descending, and return the top k records. section 2.3.2
  • Feed the retrieved passages to the generator, then evaluate quality, accuracy, and performance rather than assuming combined retrieval is sufficient. section 2.4

Neo4j retrieval for an Einstein question

A Neo4j query searches the pdf vector index and ftPdfChunk full-text index with k = 4, normalizes both score streams, merges matching nodes, and returns passages. For a question about Einstein’s upbringing, inventions, and patents, the combined results include a passage about his manufacturer father, machines, instruments, and laboratory work, followed by another Einstein passage. section 2.3.2

Listing 2.13 Performing hybrid search in Neo4j
hybrid_query = '''
CALL {
    // vector index
    CALL db.index.vector.queryNodes('pdf', $k, $question_embedding)
 YIELD node, score
    WITH collect({node:node, score:score}) AS nodes, max(score) AS max
    UNWIND nodes AS n
    // Normalize scores
    RETURN n.node AS node, (n.score / max) AS score
    UNION
    // keyword index
    CALL db.index.fulltext.queryNodes('ftPdfChunk', $question, {limit: $k})
    YIELD node, score
    WITH collect({node:node, score:score}) AS nodes, max(score) AS max
    UNWIND nodes AS n
    // Normalize scores
    RETURN n.node AS node, (n.score / max) AS score
}
// deduplicate nodes
WITH node, max(score) AS score ORDER BY score DESC LIMIT $k
RETURN node, score
'''

Inspect the complete Cypher implementation for querying both indexes, normalizing scores, deduplicating nodes, ordering matches, and limiting the final result set. section 2.3.2

How Essential GraphRAG covers it

How deep it goes
Implements normalized score merging, deduplication, and top-k selection, but stops short of resolving limitations from unstructured data.
Examples
Demonstrates Neo4j Cypher queries and retrieved passages about Einstein’s upbringing, inventions, patents, and laboratory work.
What it assumes
Assumes familiarity with RAG, embeddings, vector similarity search, and retriever-generator roles before adding full-text retrieval.
What you can do after
Build it in Neo4j by querying vector and full-text indexes, combining normalized results, and returning top-k passages.
How it connects
Connects vector similarity search, full-text search, embeddings, retrievers, generators, and RAG applications.

Also explained in

Compare how 8 books explain hybrid search →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Essential GraphRAG. The section links point to the parts of the book it draws on.