fix: avoid qdrant lexical full scan on empty text hits
This commit is contained in:
parent
6aa8e93bc9
commit
30b82ba95f
|
|
@ -1027,18 +1027,20 @@ class QdrantCollection(BaseCollection):
|
|||
q_filter = None if _requires_local_filter(where) else _qdrant_filter(where)
|
||||
rows = []
|
||||
text_filter = _text_any_filter(query)
|
||||
text_filter_success = False
|
||||
if text_filter:
|
||||
try:
|
||||
rows = self._scroll_all(
|
||||
qdrant_filter=_combine_filters(q_filter, text_filter),
|
||||
with_vector=False,
|
||||
)
|
||||
text_filter_success = True
|
||||
except BackendError:
|
||||
logger.debug(
|
||||
"Qdrant text filter failed; falling back to lexical scan", exc_info=True
|
||||
)
|
||||
rows = []
|
||||
if not rows:
|
||||
if not text_filter_success:
|
||||
rows = self._scroll_all(qdrant_filter=q_filter, with_vector=False)
|
||||
rows = [row for row in rows if _matches_where(row["metadata"], where)]
|
||||
scores = _bm25_scores(query, [row["document"] for row in rows])
|
||||
|
|
|
|||
|
|
@ -78,6 +78,7 @@ class _FakeQdrantClient:
|
|||
def __init__(self, _config):
|
||||
self.collections = {}
|
||||
self.query_calls = []
|
||||
self.scroll_calls = []
|
||||
self.created_indexes = []
|
||||
_FakeQdrantClient.instances.append(self)
|
||||
|
||||
|
|
@ -143,6 +144,7 @@ class _FakeQdrantClient:
|
|||
offset=None,
|
||||
with_vector=False,
|
||||
):
|
||||
self.scroll_calls.append(qdrant_filter)
|
||||
points = list(self.collections.get(collection, {"points": {}})["points"].values())
|
||||
points = [point for point in points if _fake_match_filter(point, qdrant_filter)]
|
||||
start = int(offset or 0)
|
||||
|
|
@ -312,6 +314,24 @@ def test_qdrant_complex_filters_use_exact_local_fallback(tmp_path, fake_qdrant):
|
|||
assert fake_client.query_calls == []
|
||||
|
||||
|
||||
def test_qdrant_lexical_empty_text_filter_does_not_full_scan(tmp_path, fake_qdrant):
|
||||
_backend, col = _collection(tmp_path)
|
||||
col.upsert(
|
||||
ids=["a", "b"],
|
||||
documents=["alpha backend note", "beta frontend note"],
|
||||
metadatas=[{"wing": "project"}, {"wing": "project"}],
|
||||
embeddings=[[1, 0], [0, 1]],
|
||||
)
|
||||
fake_client = fake_qdrant.instances[0]
|
||||
fake_client.scroll_calls.clear()
|
||||
|
||||
hits = col.lexical_search(query="missingterm", n_results=2).hits
|
||||
|
||||
assert hits == []
|
||||
assert len(fake_client.scroll_calls) == 1
|
||||
assert "text_any" in str(fake_client.scroll_calls[0])
|
||||
|
||||
|
||||
def test_qdrant_dimension_mismatch(tmp_path, fake_qdrant):
|
||||
_backend, col = _collection(tmp_path)
|
||||
col.upsert(ids=["a"], documents=["one"], metadatas=[{}], embeddings=[[1, 0]])
|
||||
|
|
|
|||
Loading…
Reference in New Issue