mirror of
https://github.com/basicmachines-co/basic-memory
synced 2026-06-21 13:47:35 +00:00
fix: Return matched chunk text in search results (#601)
Signed-off-by: phernandez <paul@basicmachines.co> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -424,7 +424,7 @@ class PostgresSearchRepository(SearchRepositoryBase):
|
||||
ORDER BY e.embedding <=> CAST(:query_embedding AS vector)
|
||||
LIMIT :vector_k
|
||||
)
|
||||
SELECT c.entity_id, c.chunk_key, vector_matches.distance AS best_distance
|
||||
SELECT c.entity_id, c.chunk_key, c.chunk_text, vector_matches.distance AS best_distance
|
||||
FROM vector_matches
|
||||
JOIN search_vector_chunks c ON c.id = vector_matches.chunk_id
|
||||
WHERE c.project_id = :project_id
|
||||
|
||||
@@ -38,6 +38,9 @@ class SearchIndexRow:
|
||||
to_id: Optional[int] = None # relations
|
||||
relation_type: Optional[str] = None # relations
|
||||
|
||||
# Matched chunk text from vector search (the actual content that matched the query)
|
||||
matched_chunk_text: Optional[str] = None
|
||||
|
||||
CONTENT_DISPLAY_LIMIT = 250
|
||||
|
||||
@property
|
||||
|
||||
@@ -871,12 +871,14 @@ class SearchRepositoryBase(ABC):
|
||||
|
||||
# Build per-search_index_row similarity scores from chunk-level results.
|
||||
# Each chunk_key encodes the search_index row type and id.
|
||||
# Keep the best similarity per search_index row id.
|
||||
# Keep the best similarity (and its chunk text) per search_index row id.
|
||||
similarity_by_si_id: dict[int, float] = {}
|
||||
best_chunk_by_si_id: dict[int, str] = {}
|
||||
for row in vector_rows:
|
||||
chunk_key = row.get("chunk_key", "")
|
||||
distance = float(row["best_distance"])
|
||||
similarity = self._distance_to_similarity(distance)
|
||||
chunk_text = row.get("chunk_text", "")
|
||||
try:
|
||||
_, si_id = self._parse_chunk_key(chunk_key)
|
||||
except (ValueError, IndexError):
|
||||
@@ -885,6 +887,7 @@ class SearchRepositoryBase(ABC):
|
||||
current = similarity_by_si_id.get(si_id)
|
||||
if current is None or similarity > current:
|
||||
similarity_by_si_id[si_id] = similarity
|
||||
best_chunk_by_si_id[si_id] = chunk_text
|
||||
|
||||
if not similarity_by_si_id:
|
||||
return []
|
||||
@@ -944,7 +947,13 @@ class SearchRepositoryBase(ABC):
|
||||
row = search_index_rows.get(si_id)
|
||||
if row is None:
|
||||
continue
|
||||
ranked_rows.append(replace(row, score=similarity))
|
||||
ranked_rows.append(
|
||||
replace(
|
||||
row,
|
||||
score=similarity,
|
||||
matched_chunk_text=best_chunk_by_si_id.get(si_id),
|
||||
)
|
||||
)
|
||||
|
||||
ranked_rows.sort(key=lambda item: item.score or 0.0, reverse=True)
|
||||
return ranked_rows[offset : offset + limit]
|
||||
|
||||
@@ -453,7 +453,7 @@ class SQLiteSearchRepository(SearchRepositoryBase):
|
||||
" WHERE embedding MATCH :query_embedding "
|
||||
" AND k = :vector_k"
|
||||
") "
|
||||
"SELECT c.entity_id, c.chunk_key, vector_matches.distance AS best_distance "
|
||||
"SELECT c.entity_id, c.chunk_key, c.chunk_text, vector_matches.distance AS best_distance "
|
||||
"FROM vector_matches "
|
||||
"JOIN search_vector_chunks c ON c.id = vector_matches.rowid "
|
||||
"WHERE c.project_id = :project_id "
|
||||
|
||||
Reference in New Issue
Block a user