Skip to content

fix(search): consume bfs relationship hits directly in edge_bfs_search#1653

Open
kramerica-inc-dev wants to merge 1 commit into
getzep:mainfrom
kramerica-inc-dev:fix/edge-bfs-rematch-scan
Open

fix(search): consume bfs relationship hits directly in edge_bfs_search#1653
kramerica-inc-dev wants to merge 1 commit into
getzep:mainfrom
kramerica-inc-dev:fix/edge-bfs-rematch-scan

Conversation

@kramerica-inc-dev

Copy link
Copy Markdown

fix(search): consume bfs relationship hits directly in edge_bfs_search

Summary

Completes #1500 on the path that executes today. #1500 rewrites the edge fulltext and BFS queries to consume the relationships the index/path already returned (startNode/endNode) instead of re-matching every hit by uuid against the whole graph — but its BFS hunk only lands in graphiti_core/driver/falkordb/operations/search_ops.py. That module is not reached at runtime: driver.search_interface is declared (graphiti_core/driver/driver.py) and never assigned anywhere in graphiti_core, so edge_bfs_search always falls through to the generic query in graphiti_core/search/search_utils.py. This PR applies the exact same transform there:

             UNWIND relationships(path) AS rel
-            MATCH (n:Entity)-[e:RELATES_TO {uuid: rel.uuid}]-(m:Entity)
+            WITH rel AS e, startNode(rel) AS n, endNode(rel) AS m
+            WHERE type(e) = 'RELATES_TO'
+            WITH e, n, m

Notes on the transform:

Type of Change

  • Bug fix
  • New feature
  • Performance improvement
  • Documentation/Tests

Objective

The re-MATCH forces an O(matches × graph) label scan per BFS hit instead of consuming the relationship the path traversal already produced. On our production FalkorDB graph (~2.6k Entity nodes), removing this same antipattern on the fulltext path took dense-document episode processing from 15–25 min down to 1–4 min; GRAPH.PROFILE of the rewritten query resolves 572 hits in <2 ms with no scan operator (measured 2026-07-14). The BFS variant fixed here is the same shape, made worse by the undirected match doubling every row.

Testing

  • Unit tests added/updated
  • Integration tests added/updated
  • All existing tests pass

Added tests/utils/search/test_edge_bfs_query_shape.py, a DB-free query-shape regression test mirroring the RecordingExecutor approach of #1500's tests/test_falkordb_search_ops.py: a recording driver captures the emitted Cypher. Asserts: no uuid: rel.uuid re-MATCH in the BFS query; startNode/endNode consumption present; explicit type(e) = 'RELATES_TO' guard present; e/n/m bindings still reach filters and RETURN; and the fulltext query is not rewritten by this change (formulated so it stays green after #1500 merges).

DISABLE_FALKORDB=1 DISABLE_KUZU=1 DISABLE_NEPTUNE=1 python -m pytest \
  tests/utils/search/test_edge_bfs_query_shape.py \
  tests/utils/search/test_search_security.py -q -m "not integration"
12 passed, 1 warning in 0.09s

Breaking Changes

  • This PR contains breaking changes

No. Query results are identical except that the duplicated/swapped-orientation rows produced by the old undirected re-MATCH are gone; each edge is now returned once, in its stored direction.

Checklist

  • Code follows project style guidelines (make lint passes — ruff format --check + ruff check clean on changed files)
  • Self-review completed
  • Documentation updated where necessary (n/a)
  • No secrets or sensitive information committed

Related Issues

Refs #1272, #1500 (completes it on the live generic path). Related to #789 and PR #1436 (resolves the duplicate/swapped-edge symptom for edge_bfs_search; get_embeddings_for_edges from #789 remains).

Completes getzep#1500 on the generic edge_bfs_search path in search_utils.py,
which is what executes today for FalkorDB and Neo4j: driver.search_interface
is never assigned, so the driver-level operations modules getzep#1500 patches are
not reached at runtime.

Mirrors the exact transform getzep#1500 applies to the FalkorDB driver copy of
this query: replace the per-row re-MATCH by uuid
(MATCH (n:Entity)-[e:RELATES_TO {uuid: rel.uuid}]-(m:Entity)) with a direct
WITH over the relationship already produced by UNWIND relationships(path),
deriving endpoints via startNode/endNode. The explicit
type(e) = 'RELATES_TO' guard is required because the BFS pattern traverses
RELATES_TO|MENTIONS and the old re-MATCH filtered MENTIONS out implicitly.

As a side effect this also removes the duplicated/swapped source-target rows
on this path (the old undirected re-MATCH matched each edge twice; see getzep#789
and PR getzep#1436): startNode/endNode yields one row per relationship in its
original orientation. getzep#789 also flags get_embeddings_for_edges, which is out
of scope here.

Refs getzep#1272, getzep#1500. Related to getzep#789, getzep#1436.
@zep-cla-assistant

Copy link
Copy Markdown
Contributor


Thank you for your submission, we really appreciate it. Like many open-source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution. For privacy information, see our Privacy Notice. You can sign the CLA by just posting a Pull Request Comment same as the below format.


I have read the CLA Document and I hereby sign the CLA behalf on myself, e-mail: example@example.com

or

I have read the CLA Document and I hereby sign the CLA behalf of my company, e-mail: example@example.com

Signature is valid for 6 months.


This bot will be retriggered when the Contributor License Agreement comment has been provided. Posted by the CLA Assistant Lite bot.

@Naseem77

Copy link
Copy Markdown
Contributor

@kramerica-inc-dev Verified live on FalkorDB: identical BFS results, MENTIONS edges still filtered by the type guard, and the O(matches x graph) re-MATCH is gone from the emitted query. This completes #1500 on the path that actually runs.

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