Skip to content

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

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

feat: Graph Search Fusion with RRF re-ranking#30
RaviTharuma wants to merge 1 commit 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.

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
@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.

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