#1875·graphiti

[BUG] [PERF] FalkorDB: edge_fulltext_search in search_ops.py re-matches endpoints, causing a full :Entity scan per hit (latent)

Author: brentkearneyCreated Sep 10, 2026Updated Sep 11, 2026

Problem

FalkorSearchOperations.edge_fulltext_search in graphiti_core/driver/falkordb/operations/search_ops.py still contains the pre-#1711 endpoint re-match:

cypher
CALL db.idx.fulltext.queryRelationships('RELATES_TO', $query)
YIELD relationship AS rel, score
MATCH (n:Entity)-[e:RELATES_TO {uuid: rel.uuid}]->(m:Entity)

#1711 fixed this pattern in graphiti_core/search/search_utils.py only. FalkorDB plans the MATCH as a full :Entity label scan for every row the fulltext index yields, so the copy in search_ops.py retains the O(hits × entities) cost that #1711 removed.

This is latent, not currently live: FalkorDriver sets _search_ops / search_ops but leaves the legacy search_interface unset, and edge_fulltext_search in search_utils.py only delegates when driver.search_interface is truthy. So the fixed path is the one that executes today.

The concern is the migration. spec/driver-operations-redesign.md annotates search_utils.py with "Will gradually migrate to use driver.search_ops". When that lands for edge fulltext search, #1506, #1272 and #1592 all regress in full, silently — the query still returns correct results, so only latency changes.

Impact when the migration completes

Measured on falkordb/falkordb:v4.18.10 with the exact v0.30.2 query strings and index definitions from get_fulltext_indices(FALKORDB), comparing the two shapes on identical graphs:

Graph Fulltext hits search_ops.py shape search_utils.py shape (v0.30.2)
2,500 entities / 4,500 edges 4,500 (broad) timeout, >30 s 5.1 ms
5,000 / 20,000 200 (narrow) 4,524 ms 0.5 ms
5,000 / 20,000 20,000 (broad) timeout, >30 s 22.9 ms
20,000 / 100,000 1,000 (narrow) timeout, >30 s 1.9 ms

GRAPH.PROFILE shows the cause: with the re-match, 200 fulltext hits over 5,000 entities scan 1,000,000 records; the v0.30.2 shape has no scan at all. Note that a narrow query is affected too — cost scales with entity count, not just hit count.

Suggested fix

Apply the #1711 change to search_ops.py, so both copies agree:

cypher
YIELD relationship AS rel, score
WITH rel AS e, score, startNode(rel) AS n, endNode(rel) AS m
WHERE n:Entity AND m:Entity

Related

  • #1711 — the fix, applied to search_utils.py only
  • #1506, #1272, #1592 — the issues #1711 resolved, all of which return if search_ops.py becomes live
  • #1826 — the same class of fix for the episode path in search_ops.py. Worth noting that the live episode_fulltext_search in search_utils.py still uses MATCH (e:Episodic) WHERE e.uuid = episode.uuid with no FalkorDB branch, so the episode path has the O(hits × nodes) shape in both copies.