Skip to content

Commit 81633f9

Browse files
committed
fix(langchain): use "id" key in keyword_search() output, matching similarity_search()
Both search methods now return dicts with "id" as the node identifier key. Docstring updated to document the cross-method consistency guarantee.
1 parent 8169085 commit 81633f9

2 files changed

Lines changed: 14 additions & 9 deletions

File tree

langchain-coordinode/langchain_coordinode/graph.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -273,9 +273,10 @@ def keyword_search(
273273
"""Find nodes matching a full-text BM25 query.
274274
275275
Wraps ``CoordinodeClient.text_search()``. The returned list contains
276-
one dict per result with the keys ``node_id`` (integer internal ID),
277-
``score`` (BM25 relevance score, higher = more relevant), and
278-
``snippet`` (HTML-highlighted excerpt, may be empty).
276+
one dict per result with the keys ``id`` (integer internal node ID,
277+
matches the key used by :meth:`similarity_search`), ``score`` (BM25
278+
relevance score, higher = more relevant), and ``snippet``
279+
(HTML-highlighted excerpt, may be empty).
279280
280281
A full-text index must exist on *label* before calling this method.
281282
Create one via the Cypher DDL statement::
@@ -313,7 +314,9 @@ def keyword_search(
313314
fuzzy=fuzzy,
314315
language=language,
315316
)
316-
return [{"node_id": r.node_id, "score": r.score, "snippet": r.snippet} for r in results]
317+
# Use "id" (not "node_id") for consistency with similarity_search() return
318+
# format, so callers can write generic code over both methods.
319+
return [{"id": r.node_id, "score": r.score, "snippet": r.snippet} for r in results]
317320

318321
def similarity_search(
319322
self,

tests/unit/test_langchain_graph.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,8 @@ def text_search(
5050
return self._results
5151

5252
def close(self) -> None:
53-
pass
53+
# No-op: keeps interface parity with real CoordinodeClient.
54+
return None
5455

5556

5657
class _ClientWithoutTextSearch:
@@ -60,15 +61,16 @@ def cypher(self, query: str, params: dict | None = None) -> list[dict]:
6061
return []
6162

6263
def close(self) -> None:
63-
pass
64+
# No-op: keeps interface parity with real CoordinodeClient.
65+
return None
6466

6567

6668
# ── Tests: keyword_search ─────────────────────────────────────────────────────
6769

6870

6971
class TestKeywordSearch:
7072
def test_returns_list_of_dicts(self) -> None:
71-
"""keyword_search returns list[dict] with node_id/score/snippet keys."""
73+
"""keyword_search returns list[dict] with id/score/snippet keys."""
7274
results = [
7375
_FakeTextResult(node_id=1, score=0.95, snippet="<b>machine</b> learning"),
7476
_FakeTextResult(node_id=2, score=0.72, snippet=""),
@@ -79,8 +81,8 @@ def test_returns_list_of_dicts(self) -> None:
7981
out = graph.keyword_search("machine learning", k=5, label="Article")
8082

8183
assert len(out) == 2
82-
assert out[0] == {"node_id": 1, "score": 0.95, "snippet": "<b>machine</b> learning"}
83-
assert out[1] == {"node_id": 2, "score": 0.72, "snippet": ""}
84+
assert out[0] == {"id": 1, "score": 0.95, "snippet": "<b>machine</b> learning"}
85+
assert out[1] == {"id": 2, "score": 0.72, "snippet": ""}
8486

8587
def test_passes_params_to_client(self) -> None:
8688
"""keyword_search forwards label, query, k, fuzzy, language to client.text_search."""

0 commit comments

Comments
 (0)