Skip to content

feat: Graph Search Fusion with RRF re-ranking#30

Open
RaviTharuma wants to merge 2 commits intoAVIDS2:mainfrom
RaviTharuma:feature/memorix-awr-graph-search-fusion
Open

feat: Graph Search Fusion with RRF re-ranking#30
RaviTharuma wants to merge 2 commits intoAVIDS2:mainfrom
RaviTharuma:feature/memorix-awr-graph-search-fusion

Conversation

@RaviTharuma
Copy link
Copy Markdown
Contributor

Summary

Adds knowledge graph traversal as a 3rd retrieval source alongside BM25 and vector search. When graph data exists, entity names from search results seed a BFS traversal (1-2 hops), and all sources are merged via Reciprocal Rank Fusion (k=60).

Changes

File Change
src/search/rrf.ts New RRF implementation — multi-source rank fusion with configurable k parameter
src/memory/graph.ts graphSearch() BFS traversal + getEntitiesForNames() helper
src/store/orama-store.ts Graph fusion gate in searchObservations() — activates only when graph has entities
src/server.ts Wire setGraphManager() into store initialization (2 call sites)

How it works

  1. BM25 and vector search run as before
  2. Entity names are extracted from result metadata (entityName field)
  3. If a graphManager is set and contains entities, BFS traverses 1-2 hops from matched entities
  4. Graph results are converted to observation IDs via entity-to-observation mapping
  5. All three result sets are fused via RRF (1/(k + rank) scoring)
  6. Final results are sorted by fused score and returned

Gate conditions (zero breaking changes)

Graph fusion only activates when:

  • graphManager is set on the store (via setGraphManager())
  • Graph has at least 1 entity
  • Search results contain entity names

Otherwise falls back to existing BM25+vector behavior — fully backward compatible.

Tests

  • 18/18 graph-search-fusion integration tests ✅
  • 23/23 RRF unit tests ✅
  • All existing tests unaffected (95 pass in tests/search/, 5 pre-existing vi.resetModules failures unrelated)

Design decisions

  • RRF over linear combination: RRF is parameter-free (no weight tuning) and handles heterogeneous score distributions well
  • k=60: Standard default from the original RRF paper (Cormack et al. 2009)
  • BFS depth 1-2: Keeps traversal fast while capturing meaningful relationships
  • Gate pattern: Graph fusion is additive — never degrades existing search quality

@chatgpt-codex-connector
Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

Copy link
Copy Markdown
Owner

AVIDS2 commented Mar 29, 2026

Thanks for opening this — the graph + RRF direction is interesting, and I do think graph-aware retrieval is something Memorix should likely explore.

That said, I don’t want to merge this PR as-is right now for two concrete reasons:

  1. The branch is not clean yet. It still includes commits that correspond to changes already merged through Fix API embedding fallback order and cache isolation #26 and Handle embedding fallback dimension drift #29, so this needs to be rebased / trimmed down to the graph-fusion change set itself.
  2. We’re about to start the 1.0.6 memory work around provenance, layered retrieval, and source-aware weighting. I don’t want to lock in a flat BM25 + vector + graph fusion path before that layering work lands, because graph retrieval may belong in routing, working-context enrichment, or evidence expansion depending on the final shape.

So my current maintainer take is: good direction, but not ready to merge in the current form. If you want to keep pushing it, the first step would be rebasing it to a graph-only diff on top of current main.

@RaviTharuma RaviTharuma force-pushed the feature/memorix-awr-graph-search-fusion branch from 09e13e9 to ac76c57 Compare March 29, 2026 22:15
@RaviTharuma
Copy link
Copy Markdown
Contributor Author

Rebased to graph-only diff on current main. Dropped the already-merged #26 and #29 commits.

Branch now contains 1 commit:

  • feat: graph search fusion with RRF re-ranking

Files changed (graph-only):

  • src/memory/graph.ts — graph traversal for entity-relation expansion
  • src/search/rrf.ts — Reciprocal Rank Fusion with configurable weights
  • src/store/orama-store.ts — integration of graph expansion into search pipeline
  • src/server.ts — MCP tool registration for graph-enhanced search
  • tests/search/graph-search-fusion.test.ts + tests/search/rrf.test.ts — 41 tests, all passing

No commits from other PRs remain. Clean diff against main.

Understood re: 1.0.6 layered retrieval architecture — happy to adapt the fusion approach once the retrieval architecture is locked. This rebase gives you a clean branch to evaluate whenever you're ready.

@AVIDS2
Copy link
Copy Markdown
Owner

AVIDS2 commented Mar 30, 2026

Interesting direction. I like the idea of graph-assisted retrieval, but I can't take this one as-is yet.

Immediate blocker: the PR is still red on typecheck, specifically in src/search/rrf.ts where the merged list can contain null before filtering and the type predicate doesn't match the current IndexEntry shape. So the branch is not mergeable in its current state.

Separately from the red CI, this is also touching a part of the search stack that we are about to restructure in 1.0.6 around provenance and layered retrieval. Once the type errors are fixed I'd like to take another look at how graph fusion should fit relative to L1 routing vs L2/L3 enrichment, rather than locking in a flat fusion path too early.

@RaviTharuma
Copy link
Copy Markdown
Contributor Author

Understood on both points.

On the typecheck failure: I'll fix src/search/rrf.ts so the merged list is typed correctly before filtering — the type predicate needs to match the current IndexEntry shape rather than assuming nullability that the merge step can introduce.

On the 1.0.6 restructure: that context is useful. Once the type errors are resolved, happy to discuss how graph fusion should slot in relative to the L1/L2/L3 layering rather than the current flat-fusion approach. I don't want to lock in a shape that conflicts with where provenance-aware retrieval is heading. Let me know if there's a design doc or draft for the 1.0.6 search changes I should read before the next revision.

Add knowledge graph traversal as a 3rd retrieval source alongside BM25
and vector search. When graph data exists, entity names from search
results seed a BFS traversal (1-2 hops), and all sources are merged
via Reciprocal Rank Fusion (k=60).

Changes:
- src/search/rrf.ts: New RRF implementation with multi-source fusion
- src/memory/graph.ts: graphSearch() BFS + getEntitiesForNames()
- src/store/orama-store.ts: Graph fusion gate in searchObservations()
- src/server.ts: Wire setGraphManager() into store initialization

Tests: 18/18 integration tests, 23/23 RRF unit tests pass.
Gate conditions: graph fusion activates only when graphManager is set
and has entities. Falls back gracefully to BM25+vector otherwise.

Closes: memorix-awr
The map+filter chain produced objects with score: number (non-optional)
but the type predicate 'e is IndexEntry' required IndexEntry assignability,
which failed because IndexEntry.score is number | undefined.

Replaced with a simple for-loop that pushes directly into IndexEntry[],
eliminating the null intermediate and the predicate mismatch entirely.
@RaviTharuma RaviTharuma force-pushed the feature/memorix-awr-graph-search-fusion branch from d963901 to 853dde5 Compare April 8, 2026 17:41
@RaviTharuma
Copy link
Copy Markdown
Contributor Author

Rebased on main. Resolved two merge conflicts:

  1. src/server.ts: merged expanded imports from HEAD with our setGraphManager import
  2. src/store/orama-store.ts: kept both upstream's knowledge-layer boost and our graph search fusion (RRF) in sequence, added missing fields to satisfy upstream's narrowed type

Also fixed a TypeScript type predicate error in mergeWithRRF — added missing fields (sourceDetail, valueCategory, entityName, documentType, knowledgeLayer) to match upstream's expanded type.

Typecheck clean, 136 search tests pass. Ready for re-review.

Copy link
Copy Markdown
Owner

@AVIDS2 AVIDS2 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The branch is cleaner than before and I appreciate the rebase work, but I still don’t want to merge this in the current shape. After the layered retrieval / provenance work that has now landed, graph retrieval needs to slot into that model deliberately; this PR still hard-wires graph expansion as a flat RRF fusion path inside the Orama search pipeline. That is a bigger architectural mismatch now than it was when this first opened. If you want to keep pushing it, the next revision should be reworked against the current layered retrieval direction instead of trying to merge graph as a third flat source directly inside searchObservations().

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants