qdrant-haystack 10.6.0__tar.gz → 11.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {qdrant_haystack-10.6.0 → qdrant_haystack-11.1.0}/CHANGELOG.md +51 -19
- {qdrant_haystack-10.6.0 → qdrant_haystack-11.1.0}/PKG-INFO +1 -1
- {qdrant_haystack-10.6.0 → qdrant_haystack-11.1.0}/src/haystack_integrations/components/retrievers/qdrant/retriever.py +30 -27
- {qdrant_haystack-10.6.0 → qdrant_haystack-11.1.0}/src/haystack_integrations/document_stores/qdrant/document_store.py +109 -96
- {qdrant_haystack-10.6.0 → qdrant_haystack-11.1.0}/tests/test_document_store.py +14 -9
- {qdrant_haystack-10.6.0 → qdrant_haystack-11.1.0}/tests/test_document_store_async.py +14 -9
- {qdrant_haystack-10.6.0 → qdrant_haystack-11.1.0}/tests/test_embedding_retriever.py +31 -0
- {qdrant_haystack-10.6.0 → qdrant_haystack-11.1.0}/tests/test_hybrid_retriever.py +33 -0
- {qdrant_haystack-10.6.0 → qdrant_haystack-11.1.0}/tests/test_sparse_embedding_retriever.py +33 -0
- {qdrant_haystack-10.6.0 → qdrant_haystack-11.1.0}/.gitignore +0 -0
- {qdrant_haystack-10.6.0 → qdrant_haystack-11.1.0}/LICENSE.txt +0 -0
- {qdrant_haystack-10.6.0 → qdrant_haystack-11.1.0}/README.md +0 -0
- {qdrant_haystack-10.6.0 → qdrant_haystack-11.1.0}/examples/embedding_retrieval.py +0 -0
- {qdrant_haystack-10.6.0 → qdrant_haystack-11.1.0}/pydoc/config_docusaurus.yml +0 -0
- {qdrant_haystack-10.6.0 → qdrant_haystack-11.1.0}/pyproject.toml +0 -0
- {qdrant_haystack-10.6.0 → qdrant_haystack-11.1.0}/src/haystack_integrations/components/retrievers/py.typed +0 -0
- {qdrant_haystack-10.6.0 → qdrant_haystack-11.1.0}/src/haystack_integrations/components/retrievers/qdrant/__init__.py +0 -0
- {qdrant_haystack-10.6.0 → qdrant_haystack-11.1.0}/src/haystack_integrations/document_stores/py.typed +0 -0
- {qdrant_haystack-10.6.0 → qdrant_haystack-11.1.0}/src/haystack_integrations/document_stores/qdrant/__init__.py +0 -0
- {qdrant_haystack-10.6.0 → qdrant_haystack-11.1.0}/src/haystack_integrations/document_stores/qdrant/converters.py +0 -0
- {qdrant_haystack-10.6.0 → qdrant_haystack-11.1.0}/src/haystack_integrations/document_stores/qdrant/filters.py +0 -0
- {qdrant_haystack-10.6.0 → qdrant_haystack-11.1.0}/src/haystack_integrations/document_stores/qdrant/migrate_to_sparse.py +0 -0
- {qdrant_haystack-10.6.0 → qdrant_haystack-11.1.0}/tests/__init__.py +0 -0
- {qdrant_haystack-10.6.0 → qdrant_haystack-11.1.0}/tests/conftest.py +0 -0
- {qdrant_haystack-10.6.0 → qdrant_haystack-11.1.0}/tests/test_converters.py +0 -0
- {qdrant_haystack-10.6.0 → qdrant_haystack-11.1.0}/tests/test_dict_converters.py +0 -0
- {qdrant_haystack-10.6.0 → qdrant_haystack-11.1.0}/tests/test_filters.py +0 -0
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [integrations/qdrant-v11.0.0] - 2026-09-25
|
|
4
|
+
|
|
5
|
+
### 🚜 Refactor
|
|
6
|
+
|
|
7
|
+
- [**breaking**] Qdrant - propagate errors on backend failures instead of empty responses (#3997)
|
|
8
|
+
|
|
9
|
+
### ⚙️ CI
|
|
10
|
+
|
|
11
|
+
- Improve changelog generation; fix existing changelogs (#3883)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
## [integrations/qdrant-v10.6.0] - 2026-09-01
|
|
15
|
+
|
|
16
|
+
### 🐛 Bug Fixes
|
|
17
|
+
|
|
18
|
+
- Standardize license files (#3771)
|
|
19
|
+
- `QdrantDocumentStore` removing duplicated tests already covered by haystack Mixin tests + fixing dedup + adding missing Async test (#3785)
|
|
20
|
+
|
|
21
|
+
|
|
3
22
|
## [integrations/qdrant-v10.5.0] - 2026-08-03
|
|
4
23
|
|
|
5
24
|
### 🚀 Features
|
|
@@ -79,7 +98,7 @@
|
|
|
79
98
|
|
|
80
99
|
- Feat: `QdrantDocumentStore` return number deleted docs on `delete_by_filter` (#2807)
|
|
81
100
|
|
|
82
|
-
## [integrations/qdrant-
|
|
101
|
+
## [integrations/qdrant-v10.1.0] - 2026-02-02
|
|
83
102
|
|
|
84
103
|
### 🚀 Features
|
|
85
104
|
|
|
@@ -87,11 +106,15 @@
|
|
|
87
106
|
|
|
88
107
|
### 🧹 Chores
|
|
89
108
|
|
|
90
|
-
- Make fmt command more forgiving (#2671)
|
|
91
|
-
- [**breaking**] Qdrant - drop Python 3.9 and use X|Y typing (#2726)
|
|
92
109
|
- Disabling progress bar in `QdrantDocumentStore` tests (#2797)
|
|
93
110
|
|
|
94
|
-
|
|
111
|
+
|
|
112
|
+
## [integrations/qdrant-v10.0.0] - 2026-01-13
|
|
113
|
+
|
|
114
|
+
### 🧹 Chores
|
|
115
|
+
|
|
116
|
+
- Make fmt command more forgiving (#2671)
|
|
117
|
+
- [**breaking**] Qdrant - drop Python 3.9 and use X|Y typing (#2726)
|
|
95
118
|
|
|
96
119
|
|
|
97
120
|
## [integrations/qdrant-v9.5.0] - 2026-01-07
|
|
@@ -151,6 +174,8 @@
|
|
|
151
174
|
- Align core-integrations Hatch scripts (#1898)
|
|
152
175
|
- Update md files for new hatch scripts (#1911)
|
|
153
176
|
|
|
177
|
+
## [integrations/qdrant-v9.1.3] - 2025-05-28
|
|
178
|
+
|
|
154
179
|
### 🌀 Miscellaneous
|
|
155
180
|
|
|
156
181
|
- Add pins for Qdrant (#1853)
|
|
@@ -374,6 +399,18 @@
|
|
|
374
399
|
- *(Qdrant)* Allow payload indexing + on disk vectors (#553)
|
|
375
400
|
- Qdrant datetime filtering support (#570)
|
|
376
401
|
|
|
402
|
+
### 📚 Documentation
|
|
403
|
+
|
|
404
|
+
- Disable-class-def (#556)
|
|
405
|
+
|
|
406
|
+
### 🌀 Miscellaneous
|
|
407
|
+
|
|
408
|
+
- Make tests show coverage (#566)
|
|
409
|
+
- Remove references to Python 3.7 (#601)
|
|
410
|
+
- Make Document Stores initially skip `SparseEmbedding` (#606)
|
|
411
|
+
|
|
412
|
+
## [integrations/qdrant-v3.1.0] - 2024-03-06
|
|
413
|
+
|
|
377
414
|
### 🐛 Bug Fixes
|
|
378
415
|
|
|
379
416
|
- Fix: fix linter errors (#282)
|
|
@@ -388,18 +425,11 @@
|
|
|
388
425
|
|
|
389
426
|
- Update category slug (#442)
|
|
390
427
|
- Small consistency improvements (#536)
|
|
391
|
-
- Disable-class-def (#556)
|
|
392
428
|
|
|
393
429
|
### ⚙️ CI
|
|
394
430
|
|
|
395
431
|
- Generate API docs for Qdrant (#361)
|
|
396
432
|
|
|
397
|
-
### 🌀 Miscellaneous
|
|
398
|
-
|
|
399
|
-
- Make tests show coverage (#566)
|
|
400
|
-
- Remove references to Python 3.7 (#601)
|
|
401
|
-
- Make Document Stores initially skip `SparseEmbedding` (#606)
|
|
402
|
-
|
|
403
433
|
## [integrations/qdrant-v3.0.0] - 2024-01-22
|
|
404
434
|
|
|
405
435
|
### 🌀 Miscellaneous
|
|
@@ -408,20 +438,22 @@
|
|
|
408
438
|
|
|
409
439
|
## [integrations/qdrant-v2.0.1] - 2024-01-18
|
|
410
440
|
|
|
411
|
-
### 🚀 Features
|
|
412
|
-
|
|
413
|
-
- Add Qdrant integration (#98)
|
|
414
|
-
|
|
415
441
|
### 🐛 Bug Fixes
|
|
416
442
|
|
|
417
443
|
- Fix import paths for beta5 (#237)
|
|
418
444
|
|
|
419
|
-
### 🚜 Refactor
|
|
420
|
-
|
|
421
|
-
- Use `hatch_vcs` to manage integrations versioning (#103)
|
|
422
|
-
|
|
423
445
|
### 🌀 Miscellaneous
|
|
424
446
|
|
|
425
447
|
- Renamed QdrntRetriever to QdrntEmbeddingRetriever (#174)
|
|
426
448
|
|
|
449
|
+
## [integrations/qdrant-v2.0.0] - 2023-12-18
|
|
450
|
+
|
|
451
|
+
### 🚀 Features
|
|
452
|
+
|
|
453
|
+
- Add Qdrant integration (#98)
|
|
454
|
+
|
|
455
|
+
### 🚜 Refactor
|
|
456
|
+
|
|
457
|
+
- Use `hatch_vcs` to manage integrations versioning (#103)
|
|
458
|
+
|
|
427
459
|
<!-- generated by git-cliff -->
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: qdrant-haystack
|
|
3
|
-
Version:
|
|
3
|
+
Version: 11.1.0
|
|
4
4
|
Summary: An integration of Qdrant ANN vector database backend with Haystack
|
|
5
5
|
Project-URL: Source, https://github.com/deepset-ai/haystack-core-integrations
|
|
6
6
|
Project-URL: Documentation, https://github.com/deepset-ai/haystack-core-integrations/blob/main/integrations/qdrant/README.md
|
|
@@ -188,9 +188,9 @@ class QdrantEmbeddingRetriever:
|
|
|
188
188
|
query_embedding=query_embedding,
|
|
189
189
|
filters=filters,
|
|
190
190
|
top_k=top_k or self._top_k,
|
|
191
|
-
scale_score=scale_score
|
|
192
|
-
return_embedding=return_embedding
|
|
193
|
-
score_threshold=score_threshold
|
|
191
|
+
scale_score=scale_score if scale_score is not None else self._scale_score,
|
|
192
|
+
return_embedding=return_embedding if return_embedding is not None else self._return_embedding,
|
|
193
|
+
score_threshold=score_threshold if score_threshold is not None else self._score_threshold,
|
|
194
194
|
group_by=group_by or self._group_by,
|
|
195
195
|
group_size=group_size or self._group_size,
|
|
196
196
|
)
|
|
@@ -243,9 +243,9 @@ class QdrantEmbeddingRetriever:
|
|
|
243
243
|
query_embedding=query_embedding,
|
|
244
244
|
filters=filters,
|
|
245
245
|
top_k=top_k or self._top_k,
|
|
246
|
-
scale_score=scale_score
|
|
247
|
-
return_embedding=return_embedding
|
|
248
|
-
score_threshold=score_threshold
|
|
246
|
+
scale_score=scale_score if scale_score is not None else self._scale_score,
|
|
247
|
+
return_embedding=return_embedding if return_embedding is not None else self._return_embedding,
|
|
248
|
+
score_threshold=score_threshold if score_threshold is not None else self._score_threshold,
|
|
249
249
|
group_by=group_by or self._group_by,
|
|
250
250
|
group_size=group_size or self._group_size,
|
|
251
251
|
)
|
|
@@ -433,9 +433,9 @@ class QdrantSparseEmbeddingRetriever:
|
|
|
433
433
|
query_sparse_embedding=query_sparse_embedding,
|
|
434
434
|
filters=filters,
|
|
435
435
|
top_k=top_k or self._top_k,
|
|
436
|
-
scale_score=scale_score
|
|
437
|
-
return_embedding=return_embedding
|
|
438
|
-
score_threshold=score_threshold
|
|
436
|
+
scale_score=scale_score if scale_score is not None else self._scale_score,
|
|
437
|
+
return_embedding=return_embedding if return_embedding is not None else self._return_embedding,
|
|
438
|
+
score_threshold=score_threshold if score_threshold is not None else self._score_threshold,
|
|
439
439
|
group_by=group_by or self._group_by,
|
|
440
440
|
group_size=group_size or self._group_size,
|
|
441
441
|
)
|
|
@@ -493,9 +493,9 @@ class QdrantSparseEmbeddingRetriever:
|
|
|
493
493
|
query_sparse_embedding=query_sparse_embedding,
|
|
494
494
|
filters=filters,
|
|
495
495
|
top_k=top_k or self._top_k,
|
|
496
|
-
scale_score=scale_score
|
|
497
|
-
return_embedding=return_embedding
|
|
498
|
-
score_threshold=score_threshold
|
|
496
|
+
scale_score=scale_score if scale_score is not None else self._scale_score,
|
|
497
|
+
return_embedding=return_embedding if return_embedding is not None else self._return_embedding,
|
|
498
|
+
score_threshold=score_threshold if score_threshold is not None else self._score_threshold,
|
|
499
499
|
group_by=group_by or self._group_by,
|
|
500
500
|
group_size=group_size or self._group_size,
|
|
501
501
|
)
|
|
@@ -560,9 +560,10 @@ class QdrantHybridRetriever:
|
|
|
560
560
|
:param return_embedding: Whether to return the embeddings of the retrieved Documents.
|
|
561
561
|
:param filter_policy: Policy to determine how filters are applied.
|
|
562
562
|
:param score_threshold: A minimal score threshold for the result.
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
563
|
+
The threshold is applied to the fused Reciprocal Rank Fusion (RRF) scores, so only documents with a
|
|
564
|
+
higher fused score are returned. RRF scores are not comparable to dense or sparse similarity scores,
|
|
565
|
+
so thresholds tuned for those retrievers don't carry over. With `group_by`, groups with no surviving
|
|
566
|
+
hits are dropped.
|
|
566
567
|
:param group_by: Payload field to group by, must be a string or number field. If the field contains more than 1
|
|
567
568
|
value, all values will be used for grouping. One point can be in multiple groups.
|
|
568
569
|
:param group_size: Maximum amount of points to return per group. Default is 3.
|
|
@@ -659,7 +660,7 @@ class QdrantHybridRetriever:
|
|
|
659
660
|
rrf_weights: list[float] | None = None,
|
|
660
661
|
) -> dict[str, list[Document]]:
|
|
661
662
|
"""
|
|
662
|
-
Run the
|
|
663
|
+
Run the Hybrid Retriever on the given input data.
|
|
663
664
|
|
|
664
665
|
:param query_embedding: Dense embedding of the query.
|
|
665
666
|
:param query_sparse_embedding: Sparse embedding of the query.
|
|
@@ -670,9 +671,10 @@ class QdrantHybridRetriever:
|
|
|
670
671
|
groups to return.
|
|
671
672
|
:param return_embedding: Whether to return the embedding of the retrieved Documents.
|
|
672
673
|
:param score_threshold: A minimal score threshold for the result.
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
674
|
+
The threshold is applied to the fused Reciprocal Rank Fusion (RRF) scores, so only documents with a
|
|
675
|
+
higher fused score are returned. RRF scores are not comparable to dense or sparse similarity scores,
|
|
676
|
+
so thresholds tuned for those retrievers don't carry over. With `group_by`, groups with no surviving
|
|
677
|
+
hits are dropped.
|
|
676
678
|
:param group_by: Payload field to group by, must be a string or number field. If the field contains more than 1
|
|
677
679
|
value, all values will be used for grouping. One point can be in multiple groups.
|
|
678
680
|
:param group_size: Maximum amount of points to return per group. Default is 3.
|
|
@@ -704,8 +706,8 @@ class QdrantHybridRetriever:
|
|
|
704
706
|
query_sparse_embedding=query_sparse_embedding,
|
|
705
707
|
filters=filters,
|
|
706
708
|
top_k=top_k or self._top_k,
|
|
707
|
-
return_embedding=return_embedding
|
|
708
|
-
score_threshold=score_threshold
|
|
709
|
+
return_embedding=return_embedding if return_embedding is not None else self._return_embedding,
|
|
710
|
+
score_threshold=score_threshold if score_threshold is not None else self._score_threshold,
|
|
709
711
|
group_by=group_by or self._group_by,
|
|
710
712
|
group_size=group_size or self._group_size,
|
|
711
713
|
rrf_k=rrf_k if rrf_k is not None else self._rrf_k,
|
|
@@ -729,7 +731,7 @@ class QdrantHybridRetriever:
|
|
|
729
731
|
rrf_weights: list[float] | None = None,
|
|
730
732
|
) -> dict[str, list[Document]]:
|
|
731
733
|
"""
|
|
732
|
-
Asynchronously run the
|
|
734
|
+
Asynchronously run the Hybrid Retriever on the given input data.
|
|
733
735
|
|
|
734
736
|
:param query_embedding: Dense embedding of the query.
|
|
735
737
|
:param query_sparse_embedding: Sparse embedding of the query.
|
|
@@ -740,9 +742,10 @@ class QdrantHybridRetriever:
|
|
|
740
742
|
groups to return.
|
|
741
743
|
:param return_embedding: Whether to return the embedding of the retrieved Documents.
|
|
742
744
|
:param score_threshold: A minimal score threshold for the result.
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
745
|
+
The threshold is applied to the fused Reciprocal Rank Fusion (RRF) scores, so only documents with a
|
|
746
|
+
higher fused score are returned. RRF scores are not comparable to dense or sparse similarity scores,
|
|
747
|
+
so thresholds tuned for those retrievers don't carry over. With `group_by`, groups with no surviving
|
|
748
|
+
hits are dropped.
|
|
746
749
|
:param group_by: Payload field to group by, must be a string or number field. If the field contains more than 1
|
|
747
750
|
value, all values will be used for grouping. One point can be in multiple groups.
|
|
748
751
|
:param group_size: Maximum amount of points to return per group. Default is 3.
|
|
@@ -774,8 +777,8 @@ class QdrantHybridRetriever:
|
|
|
774
777
|
query_sparse_embedding=query_sparse_embedding,
|
|
775
778
|
filters=filters,
|
|
776
779
|
top_k=top_k or self._top_k,
|
|
777
|
-
return_embedding=return_embedding
|
|
778
|
-
score_threshold=score_threshold
|
|
780
|
+
return_embedding=return_embedding if return_embedding is not None else self._return_embedding,
|
|
781
|
+
score_threshold=score_threshold if score_threshold is not None else self._score_threshold,
|
|
779
782
|
group_by=group_by or self._group_by,
|
|
780
783
|
group_size=group_size or self._group_size,
|
|
781
784
|
rrf_k=rrf_k if rrf_k is not None else self._rrf_k,
|
|
@@ -15,7 +15,6 @@ from haystack.utils import Secret, deserialize_secrets_inplace
|
|
|
15
15
|
from haystack.utils.misc import _normalize_metadata_field_name
|
|
16
16
|
from numpy import exp
|
|
17
17
|
from qdrant_client.http import models as rest
|
|
18
|
-
from qdrant_client.http.exceptions import UnexpectedResponse
|
|
19
18
|
from tqdm import tqdm
|
|
20
19
|
|
|
21
20
|
from .converters import (
|
|
@@ -338,6 +337,9 @@ class QdrantDocumentStore:
|
|
|
338
337
|
def count_documents(self) -> int:
|
|
339
338
|
"""
|
|
340
339
|
Returns the number of documents present in the Document Store.
|
|
340
|
+
|
|
341
|
+
:returns: The number of documents in the collection.
|
|
342
|
+
:raises QdrantStoreError: Counting documents fails.
|
|
341
343
|
"""
|
|
342
344
|
self._initialize_client()
|
|
343
345
|
assert self._client is not None
|
|
@@ -346,15 +348,16 @@ class QdrantDocumentStore:
|
|
|
346
348
|
collection_name=self.index,
|
|
347
349
|
)
|
|
348
350
|
return response.count
|
|
349
|
-
except
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
# we need to catch both.
|
|
353
|
-
return 0
|
|
351
|
+
except Exception as e:
|
|
352
|
+
msg = f"Error when calling QdrantDocumentStore.count_documents(): {e}"
|
|
353
|
+
raise QdrantStoreError(msg) from e
|
|
354
354
|
|
|
355
355
|
async def count_documents_async(self) -> int:
|
|
356
356
|
"""
|
|
357
|
-
Asynchronously returns the number of documents present in the document
|
|
357
|
+
Asynchronously returns the number of documents present in the document store.
|
|
358
|
+
|
|
359
|
+
:returns: The number of documents in the collection.
|
|
360
|
+
:raises QdrantStoreError: Counting documents fails.
|
|
358
361
|
"""
|
|
359
362
|
await self._initialize_async_client()
|
|
360
363
|
assert self._async_client is not None
|
|
@@ -363,11 +366,9 @@ class QdrantDocumentStore:
|
|
|
363
366
|
collection_name=self.index,
|
|
364
367
|
)
|
|
365
368
|
return response.count
|
|
366
|
-
except
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
# we need to catch both.
|
|
370
|
-
return 0
|
|
369
|
+
except Exception as e:
|
|
370
|
+
msg = f"Error when calling QdrantDocumentStore.count_documents_async(): {e}"
|
|
371
|
+
raise QdrantStoreError(msg) from e
|
|
371
372
|
|
|
372
373
|
def filter_documents(
|
|
373
374
|
self,
|
|
@@ -921,38 +922,39 @@ class QdrantDocumentStore:
|
|
|
921
922
|
Deletes all documents from the document store.
|
|
922
923
|
|
|
923
924
|
:param recreate_index: Whether to recreate the index after deleting all documents.
|
|
925
|
+
:raises QdrantStoreError: Deleting documents or recreating the collection fails.
|
|
924
926
|
"""
|
|
925
927
|
|
|
926
928
|
self._initialize_client()
|
|
927
929
|
assert self._client is not None
|
|
928
930
|
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
931
|
+
try:
|
|
932
|
+
if recreate_index:
|
|
933
|
+
# get current collection config as json
|
|
934
|
+
collection_info = self._client.get_collection(collection_name=self.index)
|
|
935
|
+
info_json = collection_info.model_dump()
|
|
933
936
|
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
+
# deal with the Optional use_sparse_embeddings
|
|
938
|
+
sparse_vectors = info_json["config"]["params"]["sparse_vectors"]
|
|
939
|
+
use_sparse_embeddings = True if sparse_vectors else False
|
|
937
940
|
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
+
# deal with the Optional sparse_idf
|
|
942
|
+
hnsw_config = info_json["config"]["params"]["vectors"].get("config", {}).get("hnsw_config", None)
|
|
943
|
+
sparse_idf = True if use_sparse_embeddings and hnsw_config else False
|
|
941
944
|
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
945
|
+
# recreate collection
|
|
946
|
+
self._set_up_collection(
|
|
947
|
+
collection_name=self.index,
|
|
948
|
+
embedding_dim=info_json["config"]["params"]["vectors"]["size"],
|
|
949
|
+
recreate_collection=True,
|
|
950
|
+
similarity=info_json["config"]["params"]["vectors"]["distance"].lower(),
|
|
951
|
+
use_sparse_embeddings=use_sparse_embeddings,
|
|
952
|
+
sparse_idf=sparse_idf,
|
|
953
|
+
on_disk=info_json["config"]["hnsw_config"]["on_disk"],
|
|
954
|
+
payload_fields_to_index=info_json["payload_schema"],
|
|
955
|
+
)
|
|
953
956
|
|
|
954
|
-
|
|
955
|
-
try:
|
|
957
|
+
else:
|
|
956
958
|
self._client.delete(
|
|
957
959
|
collection_name=self.index,
|
|
958
960
|
points_selector=rest.FilterSelector(
|
|
@@ -962,48 +964,48 @@ class QdrantDocumentStore:
|
|
|
962
964
|
),
|
|
963
965
|
wait=self.wait_result_from_api,
|
|
964
966
|
)
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
)
|
|
967
|
+
except Exception as e:
|
|
968
|
+
msg = f"Error when calling QdrantDocumentStore.delete_all_documents(): {e}"
|
|
969
|
+
raise QdrantStoreError(msg) from e
|
|
969
970
|
|
|
970
971
|
async def delete_all_documents_async(self, recreate_index: bool = False) -> None:
|
|
971
972
|
"""
|
|
972
973
|
Asynchronously deletes all documents from the document store.
|
|
973
974
|
|
|
974
975
|
:param recreate_index: Whether to recreate the index after deleting all documents.
|
|
976
|
+
:raises QdrantStoreError: Deleting documents or recreating the collection fails.
|
|
975
977
|
"""
|
|
976
978
|
|
|
977
979
|
await self._initialize_async_client()
|
|
978
980
|
assert self._async_client is not None
|
|
979
981
|
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
982
|
+
try:
|
|
983
|
+
if recreate_index:
|
|
984
|
+
# get current collection config as json
|
|
985
|
+
collection_info = await self._async_client.get_collection(collection_name=self.index)
|
|
986
|
+
info_json = collection_info.model_dump()
|
|
984
987
|
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
+
# deal with the Optional use_sparse_embeddings
|
|
989
|
+
sparse_vectors = info_json["config"]["params"]["sparse_vectors"]
|
|
990
|
+
use_sparse_embeddings = True if sparse_vectors else False
|
|
988
991
|
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
+
# deal with the Optional sparse_idf
|
|
993
|
+
hnsw_config = info_json["config"]["params"]["vectors"].get("config", {}).get("hnsw_config", None)
|
|
994
|
+
sparse_idf = True if use_sparse_embeddings and hnsw_config else False
|
|
992
995
|
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
996
|
+
# recreate collection
|
|
997
|
+
await self._set_up_collection_async(
|
|
998
|
+
collection_name=self.index,
|
|
999
|
+
embedding_dim=info_json["config"]["params"]["vectors"]["size"],
|
|
1000
|
+
recreate_collection=True,
|
|
1001
|
+
similarity=info_json["config"]["params"]["vectors"]["distance"].lower(),
|
|
1002
|
+
use_sparse_embeddings=use_sparse_embeddings,
|
|
1003
|
+
sparse_idf=sparse_idf,
|
|
1004
|
+
on_disk=info_json["config"]["hnsw_config"]["on_disk"],
|
|
1005
|
+
payload_fields_to_index=info_json["payload_schema"],
|
|
1006
|
+
)
|
|
1004
1007
|
|
|
1005
|
-
|
|
1006
|
-
try:
|
|
1008
|
+
else:
|
|
1007
1009
|
await self._async_client.delete(
|
|
1008
1010
|
collection_name=self.index,
|
|
1009
1011
|
points_selector=rest.FilterSelector(
|
|
@@ -1013,10 +1015,9 @@ class QdrantDocumentStore:
|
|
|
1013
1015
|
),
|
|
1014
1016
|
wait=self.wait_result_from_api,
|
|
1015
1017
|
)
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
)
|
|
1018
|
+
except Exception as e:
|
|
1019
|
+
msg = f"Error when calling QdrantDocumentStore.delete_all_documents_async(): {e}"
|
|
1020
|
+
raise QdrantStoreError(msg) from e
|
|
1020
1021
|
|
|
1021
1022
|
def count_documents_by_filter(self, filters: dict[str, Any]) -> int:
|
|
1022
1023
|
"""
|
|
@@ -1026,6 +1027,7 @@ class QdrantDocumentStore:
|
|
|
1026
1027
|
For filter syntax, see [Haystack metadata filtering](https://docs.haystack.deepset.ai/docs/metadata-filtering)
|
|
1027
1028
|
|
|
1028
1029
|
:returns: The number of documents that match the filters.
|
|
1030
|
+
:raises QdrantStoreError: Counting documents matching the filters fails.
|
|
1029
1031
|
"""
|
|
1030
1032
|
self._initialize_client()
|
|
1031
1033
|
assert self._client is not None
|
|
@@ -1037,9 +1039,9 @@ class QdrantDocumentStore:
|
|
|
1037
1039
|
count_filter=qdrant_filter,
|
|
1038
1040
|
)
|
|
1039
1041
|
return response.count
|
|
1040
|
-
except
|
|
1041
|
-
|
|
1042
|
-
|
|
1042
|
+
except Exception as e:
|
|
1043
|
+
msg = f"Error when calling QdrantDocumentStore.count_documents_by_filter(): {e}"
|
|
1044
|
+
raise QdrantStoreError(msg) from e
|
|
1043
1045
|
|
|
1044
1046
|
async def count_documents_by_filter_async(self, filters: dict[str, Any]) -> int:
|
|
1045
1047
|
"""
|
|
@@ -1050,6 +1052,7 @@ class QdrantDocumentStore:
|
|
|
1050
1052
|
|
|
1051
1053
|
:returns:
|
|
1052
1054
|
The number of documents that match the filters.
|
|
1055
|
+
:raises QdrantStoreError: Counting documents matching the filters fails.
|
|
1053
1056
|
"""
|
|
1054
1057
|
await self._initialize_async_client()
|
|
1055
1058
|
assert self._async_client is not None
|
|
@@ -1061,9 +1064,9 @@ class QdrantDocumentStore:
|
|
|
1061
1064
|
count_filter=qdrant_filter,
|
|
1062
1065
|
)
|
|
1063
1066
|
return response.count
|
|
1064
|
-
except
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
+
except Exception as e:
|
|
1068
|
+
msg = f"Error when calling QdrantDocumentStore.count_documents_by_filter_async(): {e}"
|
|
1069
|
+
raise QdrantStoreError(msg) from e
|
|
1067
1070
|
|
|
1068
1071
|
def get_metadata_fields_info(self) -> dict[str, dict[str, str]]:
|
|
1069
1072
|
"""
|
|
@@ -1078,6 +1081,7 @@ class QdrantDocumentStore:
|
|
|
1078
1081
|
```python
|
|
1079
1082
|
{"category": {"type": "keyword"}, "priority": {"type": "long"}}
|
|
1080
1083
|
```
|
|
1084
|
+
:raises QdrantStoreError: Retrieving or processing metadata field information fails.
|
|
1081
1085
|
"""
|
|
1082
1086
|
self._initialize_client()
|
|
1083
1087
|
assert self._client is not None
|
|
@@ -1103,9 +1107,9 @@ class QdrantDocumentStore:
|
|
|
1103
1107
|
break
|
|
1104
1108
|
|
|
1105
1109
|
return fields_info
|
|
1106
|
-
except
|
|
1107
|
-
|
|
1108
|
-
|
|
1110
|
+
except Exception as e:
|
|
1111
|
+
msg = f"Error when calling QdrantDocumentStore.get_metadata_fields_info(): {e}"
|
|
1112
|
+
raise QdrantStoreError(msg) from e
|
|
1109
1113
|
|
|
1110
1114
|
async def get_metadata_fields_info_async(self) -> dict[str, dict[str, str]]:
|
|
1111
1115
|
"""
|
|
@@ -1120,6 +1124,7 @@ class QdrantDocumentStore:
|
|
|
1120
1124
|
```python
|
|
1121
1125
|
{"category": {"type": "keyword"}, "priority": {"type": "long"}}
|
|
1122
1126
|
```
|
|
1127
|
+
:raises QdrantStoreError: Retrieving or processing metadata field information fails.
|
|
1123
1128
|
"""
|
|
1124
1129
|
await self._initialize_async_client()
|
|
1125
1130
|
assert self._async_client is not None
|
|
@@ -1145,9 +1150,9 @@ class QdrantDocumentStore:
|
|
|
1145
1150
|
break
|
|
1146
1151
|
|
|
1147
1152
|
return fields_info
|
|
1148
|
-
except
|
|
1149
|
-
|
|
1150
|
-
|
|
1153
|
+
except Exception as e:
|
|
1154
|
+
msg = f"Error when calling QdrantDocumentStore.get_metadata_fields_info_async(): {e}"
|
|
1155
|
+
raise QdrantStoreError(msg) from e
|
|
1151
1156
|
|
|
1152
1157
|
def get_metadata_field_min_max(self, metadata_field: str) -> dict[str, Any]:
|
|
1153
1158
|
"""
|
|
@@ -1158,6 +1163,7 @@ class QdrantDocumentStore:
|
|
|
1158
1163
|
:returns: A dictionary with the keys "min" and "max", where each value is the minimum or maximum value of the
|
|
1159
1164
|
metadata field across all documents. Returns ``{"min": None, "max": None}`` if no documents have
|
|
1160
1165
|
the field.
|
|
1166
|
+
:raises QdrantStoreError: Retrieving or computing the metadata bounds fails.
|
|
1161
1167
|
"""
|
|
1162
1168
|
self._initialize_client()
|
|
1163
1169
|
assert self._client is not None
|
|
@@ -1183,8 +1189,8 @@ class QdrantDocumentStore:
|
|
|
1183
1189
|
|
|
1184
1190
|
return {"min": min_value, "max": max_value}
|
|
1185
1191
|
except Exception as e:
|
|
1186
|
-
|
|
1187
|
-
|
|
1192
|
+
msg = f"Error when calling QdrantDocumentStore.get_metadata_field_min_max(): {e}"
|
|
1193
|
+
raise QdrantStoreError(msg) from e
|
|
1188
1194
|
|
|
1189
1195
|
async def get_metadata_field_min_max_async(self, metadata_field: str) -> dict[str, Any]:
|
|
1190
1196
|
"""
|
|
@@ -1195,6 +1201,7 @@ class QdrantDocumentStore:
|
|
|
1195
1201
|
:returns: A dictionary with the keys "min" and "max", where each value is the minimum or maximum value of the
|
|
1196
1202
|
metadata field across all documents. Returns ``{"min": None, "max": None}`` if no documents have
|
|
1197
1203
|
the field.
|
|
1204
|
+
:raises QdrantStoreError: Retrieving or computing the metadata bounds fails.
|
|
1198
1205
|
"""
|
|
1199
1206
|
await self._initialize_async_client()
|
|
1200
1207
|
assert self._async_client is not None
|
|
@@ -1220,8 +1227,8 @@ class QdrantDocumentStore:
|
|
|
1220
1227
|
|
|
1221
1228
|
return {"min": min_value, "max": max_value}
|
|
1222
1229
|
except Exception as e:
|
|
1223
|
-
|
|
1224
|
-
|
|
1230
|
+
msg = f"Error when calling QdrantDocumentStore.get_metadata_field_min_max_async(): {e}"
|
|
1231
|
+
raise QdrantStoreError(msg) from e
|
|
1225
1232
|
|
|
1226
1233
|
def count_unique_metadata_by_filter(self, filters: dict[str, Any], metadata_fields: list[str]) -> dict[str, int]:
|
|
1227
1234
|
"""
|
|
@@ -1233,6 +1240,7 @@ class QdrantDocumentStore:
|
|
|
1233
1240
|
|
|
1234
1241
|
:returns: A dictionary mapping each metadata field name to the count of its unique values among the filtered
|
|
1235
1242
|
documents.
|
|
1243
|
+
:raises QdrantStoreError: Retrieving or counting unique metadata values fails.
|
|
1236
1244
|
"""
|
|
1237
1245
|
self._initialize_client()
|
|
1238
1246
|
assert self._client is not None
|
|
@@ -1257,8 +1265,8 @@ class QdrantDocumentStore:
|
|
|
1257
1265
|
|
|
1258
1266
|
return {field: len(unique_values_by_field[field]) for field in metadata_fields}
|
|
1259
1267
|
except Exception as e:
|
|
1260
|
-
|
|
1261
|
-
|
|
1268
|
+
msg = f"Error when calling QdrantDocumentStore.count_unique_metadata_by_filter(): {e}"
|
|
1269
|
+
raise QdrantStoreError(msg) from e
|
|
1262
1270
|
|
|
1263
1271
|
async def count_unique_metadata_by_filter_async(
|
|
1264
1272
|
self, filters: dict[str, Any], metadata_fields: list[str]
|
|
@@ -1274,6 +1282,7 @@ class QdrantDocumentStore:
|
|
|
1274
1282
|
|
|
1275
1283
|
:returns: A dictionary mapping each metadata field name to the count of its unique values among the filtered
|
|
1276
1284
|
documents.
|
|
1285
|
+
:raises QdrantStoreError: Retrieving or counting unique metadata values fails.
|
|
1277
1286
|
"""
|
|
1278
1287
|
await self._initialize_async_client()
|
|
1279
1288
|
assert self._async_client is not None
|
|
@@ -1298,8 +1307,8 @@ class QdrantDocumentStore:
|
|
|
1298
1307
|
|
|
1299
1308
|
return {field: len(unique_values_by_field[field]) for field in metadata_fields}
|
|
1300
1309
|
except Exception as e:
|
|
1301
|
-
|
|
1302
|
-
|
|
1310
|
+
msg = f"Error when calling QdrantDocumentStore.count_unique_metadata_by_filter_async(): {e}"
|
|
1311
|
+
raise QdrantStoreError(msg) from e
|
|
1303
1312
|
|
|
1304
1313
|
def get_metadata_field_unique_values(
|
|
1305
1314
|
self,
|
|
@@ -1325,6 +1334,7 @@ class QdrantDocumentStore:
|
|
|
1325
1334
|
For filter syntax, see [Haystack metadata filtering](https://docs.haystack.deepset.ai/docs/metadata-filtering)
|
|
1326
1335
|
|
|
1327
1336
|
:returns: A tuple containing (list of unique values, total count of unique matching values).
|
|
1337
|
+
:raises QdrantStoreError: Retrieving or processing unique metadata values fails.
|
|
1328
1338
|
"""
|
|
1329
1339
|
self._initialize_client()
|
|
1330
1340
|
assert self._client is not None
|
|
@@ -1353,8 +1363,8 @@ class QdrantDocumentStore:
|
|
|
1353
1363
|
total_count = len(unique_values)
|
|
1354
1364
|
return unique_values[from_ : from_ + size], total_count
|
|
1355
1365
|
except Exception as e:
|
|
1356
|
-
|
|
1357
|
-
|
|
1366
|
+
msg = f"Error when calling QdrantDocumentStore.get_metadata_field_unique_values(): {e}"
|
|
1367
|
+
raise QdrantStoreError(msg) from e
|
|
1358
1368
|
|
|
1359
1369
|
async def get_metadata_field_unique_values_async(
|
|
1360
1370
|
self,
|
|
@@ -1380,6 +1390,7 @@ class QdrantDocumentStore:
|
|
|
1380
1390
|
For filter syntax, see [Haystack metadata filtering](https://docs.haystack.deepset.ai/docs/metadata-filtering)
|
|
1381
1391
|
|
|
1382
1392
|
:returns: A tuple containing (list of unique values, total count of unique matching values).
|
|
1393
|
+
:raises QdrantStoreError: Retrieving or processing unique metadata values fails.
|
|
1383
1394
|
"""
|
|
1384
1395
|
await self._initialize_async_client()
|
|
1385
1396
|
assert self._async_client is not None
|
|
@@ -1408,8 +1419,8 @@ class QdrantDocumentStore:
|
|
|
1408
1419
|
total_count = len(unique_values)
|
|
1409
1420
|
return unique_values[from_ : from_ + size], total_count
|
|
1410
1421
|
except Exception as e:
|
|
1411
|
-
|
|
1412
|
-
|
|
1422
|
+
msg = f"Error when calling QdrantDocumentStore.get_metadata_field_unique_values_async(): {e}"
|
|
1423
|
+
raise QdrantStoreError(msg) from e
|
|
1413
1424
|
|
|
1414
1425
|
@classmethod
|
|
1415
1426
|
def from_dict(cls, data: dict[str, Any]) -> "QdrantDocumentStore":
|
|
@@ -1746,9 +1757,10 @@ class QdrantDocumentStore:
|
|
|
1746
1757
|
groups to return.
|
|
1747
1758
|
:param return_embedding: Whether to return the embeddings of the retrieved documents.
|
|
1748
1759
|
:param score_threshold: A minimal score threshold for the result.
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1760
|
+
The threshold is applied to the fused Reciprocal Rank Fusion (RRF) scores, so only documents with a
|
|
1761
|
+
higher fused score are returned. RRF scores are not comparable to dense or sparse similarity scores,
|
|
1762
|
+
so thresholds tuned for those retrievers don't carry over. With `group_by`, groups with no surviving
|
|
1763
|
+
hits are dropped.
|
|
1752
1764
|
:param group_by: Payload field to group by, must be a string or number field. If the field contains more than 1
|
|
1753
1765
|
value, all values will be used for grouping. One point can be in multiple groups.
|
|
1754
1766
|
:param group_size: Maximum amount of points to return per group. Default is 3.
|
|
@@ -2009,9 +2021,10 @@ class QdrantDocumentStore:
|
|
|
2009
2021
|
groups to return.
|
|
2010
2022
|
:param return_embedding: Whether to return the embeddings of the retrieved documents.
|
|
2011
2023
|
:param score_threshold: A minimal score threshold for the result.
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2024
|
+
The threshold is applied to the fused Reciprocal Rank Fusion (RRF) scores, so only documents with a
|
|
2025
|
+
higher fused score are returned. RRF scores are not comparable to dense or sparse similarity scores,
|
|
2026
|
+
so thresholds tuned for those retrievers don't carry over. With `group_by`, groups with no surviving
|
|
2027
|
+
hits are dropped.
|
|
2015
2028
|
:param group_by: Payload field to group by, must be a string or number field. If the field contains more than 1
|
|
2016
2029
|
value, all values will be used for grouping. One point can be in multiple groups.
|
|
2017
2030
|
:param group_size: Maximum amount of points to return per group. Default is 3.
|
|
@@ -377,17 +377,19 @@ class TestQdrantDocumentStoreUnit:
|
|
|
377
377
|
document_store._query_by_sparse(query_sparse_embedding=sparse_embedding)
|
|
378
378
|
|
|
379
379
|
@pytest.mark.parametrize(
|
|
380
|
-
("method_name", "args"
|
|
380
|
+
("method_name", "args"),
|
|
381
381
|
[
|
|
382
|
-
("count_documents", ()
|
|
383
|
-
("
|
|
384
|
-
("
|
|
385
|
-
("
|
|
386
|
-
("
|
|
387
|
-
("
|
|
382
|
+
("count_documents", ()),
|
|
383
|
+
("delete_all_documents", (False,)),
|
|
384
|
+
("delete_all_documents", (True,)),
|
|
385
|
+
("count_documents_by_filter", ({},)),
|
|
386
|
+
("get_metadata_fields_info", ()),
|
|
387
|
+
("get_metadata_field_min_max", ("score",)),
|
|
388
|
+
("count_unique_metadata_by_filter", ({}, ["category"])),
|
|
389
|
+
("get_metadata_field_unique_values", ("category",)),
|
|
388
390
|
],
|
|
389
391
|
)
|
|
390
|
-
def
|
|
392
|
+
def test_operations_raise_on_client_errors(self, method_name, args):
|
|
391
393
|
document_store = QdrantDocumentStore(location=":memory:")
|
|
392
394
|
document_store._initialize_client()
|
|
393
395
|
err = ValueError("boom")
|
|
@@ -395,8 +397,11 @@ class TestQdrantDocumentStoreUnit:
|
|
|
395
397
|
patch.object(document_store._client, "count", side_effect=err),
|
|
396
398
|
patch.object(document_store._client, "scroll", side_effect=err),
|
|
397
399
|
patch.object(document_store._client, "get_collection", side_effect=err),
|
|
400
|
+
patch.object(document_store._client, "delete", side_effect=err),
|
|
398
401
|
):
|
|
399
|
-
|
|
402
|
+
with pytest.raises(QdrantStoreError) as exc_info:
|
|
403
|
+
getattr(document_store, method_name)(*args)
|
|
404
|
+
assert exc_info.value.__cause__ is err
|
|
400
405
|
|
|
401
406
|
def test_close(self):
|
|
402
407
|
document_store = QdrantDocumentStore(location=":memory:")
|
|
@@ -141,17 +141,19 @@ class TestQdrantDocumentStoreAsyncUnit:
|
|
|
141
141
|
await document_store.delete_documents_async(["doc-1"])
|
|
142
142
|
|
|
143
143
|
@pytest.mark.parametrize(
|
|
144
|
-
("method_name", "args"
|
|
144
|
+
("method_name", "args"),
|
|
145
145
|
[
|
|
146
|
-
("count_documents_async", ()
|
|
147
|
-
("
|
|
148
|
-
("
|
|
149
|
-
("
|
|
150
|
-
("
|
|
151
|
-
("
|
|
146
|
+
("count_documents_async", ()),
|
|
147
|
+
("delete_all_documents_async", (False,)),
|
|
148
|
+
("delete_all_documents_async", (True,)),
|
|
149
|
+
("count_documents_by_filter_async", ({},)),
|
|
150
|
+
("get_metadata_fields_info_async", ()),
|
|
151
|
+
("get_metadata_field_min_max_async", ("score",)),
|
|
152
|
+
("count_unique_metadata_by_filter_async", ({}, ["category"])),
|
|
153
|
+
("get_metadata_field_unique_values_async", ("category",)),
|
|
152
154
|
],
|
|
153
155
|
)
|
|
154
|
-
async def
|
|
156
|
+
async def test_operations_async_raise_on_client_errors(self, method_name, args):
|
|
155
157
|
document_store = QdrantDocumentStore(location=":memory:")
|
|
156
158
|
await document_store._initialize_async_client()
|
|
157
159
|
err = ValueError("boom")
|
|
@@ -159,8 +161,11 @@ class TestQdrantDocumentStoreAsyncUnit:
|
|
|
159
161
|
patch.object(document_store._async_client, "count", side_effect=err),
|
|
160
162
|
patch.object(document_store._async_client, "scroll", side_effect=err),
|
|
161
163
|
patch.object(document_store._async_client, "get_collection", side_effect=err),
|
|
164
|
+
patch.object(document_store._async_client, "delete", side_effect=err),
|
|
162
165
|
):
|
|
163
|
-
|
|
166
|
+
with pytest.raises(QdrantStoreError) as exc_info:
|
|
167
|
+
await getattr(document_store, method_name)(*args)
|
|
168
|
+
assert exc_info.value.__cause__ is err
|
|
164
169
|
|
|
165
170
|
async def test_close_async(self):
|
|
166
171
|
document_store = QdrantDocumentStore(location=":memory:")
|
|
@@ -200,6 +200,37 @@ class TestQdrantRetriever:
|
|
|
200
200
|
mock_store._query_by_embedding_async.assert_awaited_once()
|
|
201
201
|
assert res["documents"][0].content == "doc"
|
|
202
202
|
|
|
203
|
+
def test_run_falsy_runtime_values_override_init(self):
|
|
204
|
+
mock_store = Mock(spec=QdrantDocumentStore)
|
|
205
|
+
mock_store._query_by_embedding.return_value = []
|
|
206
|
+
|
|
207
|
+
retriever = QdrantEmbeddingRetriever(
|
|
208
|
+
document_store=mock_store, scale_score=True, return_embedding=True, score_threshold=0.5
|
|
209
|
+
)
|
|
210
|
+
retriever.run(query_embedding=[0.5, 0.7], scale_score=False, return_embedding=False, score_threshold=0.0)
|
|
211
|
+
|
|
212
|
+
call_kwargs = mock_store._query_by_embedding.call_args.kwargs
|
|
213
|
+
assert call_kwargs["scale_score"] is False
|
|
214
|
+
assert call_kwargs["return_embedding"] is False
|
|
215
|
+
assert call_kwargs["score_threshold"] == 0.0
|
|
216
|
+
|
|
217
|
+
@pytest.mark.asyncio
|
|
218
|
+
async def test_run_async_falsy_runtime_values_override_init(self):
|
|
219
|
+
mock_store = Mock(spec=QdrantDocumentStore)
|
|
220
|
+
mock_store._query_by_embedding_async = AsyncMock(return_value=[])
|
|
221
|
+
|
|
222
|
+
retriever = QdrantEmbeddingRetriever(
|
|
223
|
+
document_store=mock_store, scale_score=True, return_embedding=True, score_threshold=0.5
|
|
224
|
+
)
|
|
225
|
+
await retriever.run_async(
|
|
226
|
+
query_embedding=[0.5, 0.7], scale_score=False, return_embedding=False, score_threshold=0.0
|
|
227
|
+
)
|
|
228
|
+
|
|
229
|
+
call_kwargs = mock_store._query_by_embedding_async.call_args.kwargs
|
|
230
|
+
assert call_kwargs["scale_score"] is False
|
|
231
|
+
assert call_kwargs["return_embedding"] is False
|
|
232
|
+
assert call_kwargs["score_threshold"] == 0.0
|
|
233
|
+
|
|
203
234
|
def test_run_raises_when_merge_with_native_init_filter(self):
|
|
204
235
|
document_store = QdrantDocumentStore(location=":memory:", index="test")
|
|
205
236
|
retriever = QdrantEmbeddingRetriever(
|
|
@@ -229,6 +229,39 @@ class TestQdrantHybridRetriever:
|
|
|
229
229
|
assert call_args[1]["rrf_k"] == 100
|
|
230
230
|
assert call_args[1]["rrf_weights"] == [3.0, 1.0]
|
|
231
231
|
|
|
232
|
+
def test_run_falsy_runtime_values_override_init(self):
|
|
233
|
+
mock_store = Mock(spec=QdrantDocumentStore)
|
|
234
|
+
mock_store._query_hybrid.return_value = []
|
|
235
|
+
|
|
236
|
+
retriever = QdrantHybridRetriever(document_store=mock_store, return_embedding=True, score_threshold=0.5)
|
|
237
|
+
retriever.run(
|
|
238
|
+
query_embedding=[0.5, 0.7],
|
|
239
|
+
query_sparse_embedding=SparseEmbedding(indices=[0, 5], values=[0.1, 0.7]),
|
|
240
|
+
return_embedding=False,
|
|
241
|
+
score_threshold=0.0,
|
|
242
|
+
)
|
|
243
|
+
|
|
244
|
+
call_args = mock_store._query_hybrid.call_args
|
|
245
|
+
assert call_args[1]["return_embedding"] is False
|
|
246
|
+
assert call_args[1]["score_threshold"] == 0.0
|
|
247
|
+
|
|
248
|
+
@pytest.mark.asyncio
|
|
249
|
+
async def test_run_async_falsy_runtime_values_override_init(self):
|
|
250
|
+
mock_store = Mock(spec=QdrantDocumentStore)
|
|
251
|
+
mock_store._query_hybrid_async = AsyncMock(return_value=[])
|
|
252
|
+
|
|
253
|
+
retriever = QdrantHybridRetriever(document_store=mock_store, return_embedding=True, score_threshold=0.5)
|
|
254
|
+
await retriever.run_async(
|
|
255
|
+
query_embedding=[0.5, 0.7],
|
|
256
|
+
query_sparse_embedding=SparseEmbedding(indices=[0, 5], values=[0.1, 0.7]),
|
|
257
|
+
return_embedding=False,
|
|
258
|
+
score_threshold=0.0,
|
|
259
|
+
)
|
|
260
|
+
|
|
261
|
+
call_args = mock_store._query_hybrid_async.call_args
|
|
262
|
+
assert call_args[1]["return_embedding"] is False
|
|
263
|
+
assert call_args[1]["score_threshold"] == 0.0
|
|
264
|
+
|
|
232
265
|
def test_run_with_group_by(self):
|
|
233
266
|
mock_store = Mock(spec=QdrantDocumentStore)
|
|
234
267
|
sparse_embedding = SparseEmbedding(indices=[0, 1, 2, 3], values=[0.1, 0.8, 0.05, 0.33])
|
|
@@ -199,6 +199,39 @@ class TestQdrantSparseEmbeddingRetriever:
|
|
|
199
199
|
mock_store._query_by_sparse_async.assert_awaited_once()
|
|
200
200
|
assert res["documents"][0].content == "doc"
|
|
201
201
|
|
|
202
|
+
def test_run_falsy_runtime_values_override_init(self):
|
|
203
|
+
mock_store = Mock(spec=QdrantDocumentStore)
|
|
204
|
+
mock_store._query_by_sparse.return_value = []
|
|
205
|
+
sparse = SparseEmbedding(indices=[0, 5], values=[0.1, 0.7])
|
|
206
|
+
|
|
207
|
+
retriever = QdrantSparseEmbeddingRetriever(
|
|
208
|
+
document_store=mock_store, scale_score=True, return_embedding=True, score_threshold=0.5
|
|
209
|
+
)
|
|
210
|
+
retriever.run(query_sparse_embedding=sparse, scale_score=False, return_embedding=False, score_threshold=0.0)
|
|
211
|
+
|
|
212
|
+
call_kwargs = mock_store._query_by_sparse.call_args.kwargs
|
|
213
|
+
assert call_kwargs["scale_score"] is False
|
|
214
|
+
assert call_kwargs["return_embedding"] is False
|
|
215
|
+
assert call_kwargs["score_threshold"] == 0.0
|
|
216
|
+
|
|
217
|
+
@pytest.mark.asyncio
|
|
218
|
+
async def test_run_async_falsy_runtime_values_override_init(self):
|
|
219
|
+
mock_store = Mock(spec=QdrantDocumentStore)
|
|
220
|
+
mock_store._query_by_sparse_async = AsyncMock(return_value=[])
|
|
221
|
+
sparse = SparseEmbedding(indices=[0, 5], values=[0.1, 0.7])
|
|
222
|
+
|
|
223
|
+
retriever = QdrantSparseEmbeddingRetriever(
|
|
224
|
+
document_store=mock_store, scale_score=True, return_embedding=True, score_threshold=0.5
|
|
225
|
+
)
|
|
226
|
+
await retriever.run_async(
|
|
227
|
+
query_sparse_embedding=sparse, scale_score=False, return_embedding=False, score_threshold=0.0
|
|
228
|
+
)
|
|
229
|
+
|
|
230
|
+
call_kwargs = mock_store._query_by_sparse_async.call_args.kwargs
|
|
231
|
+
assert call_kwargs["scale_score"] is False
|
|
232
|
+
assert call_kwargs["return_embedding"] is False
|
|
233
|
+
assert call_kwargs["score_threshold"] == 0.0
|
|
234
|
+
|
|
202
235
|
def test_run_raises_when_merge_with_native_filter(self):
|
|
203
236
|
document_store = QdrantDocumentStore(location=":memory:", index="test")
|
|
204
237
|
retriever = QdrantSparseEmbeddingRetriever(
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{qdrant_haystack-10.6.0 → qdrant_haystack-11.1.0}/src/haystack_integrations/document_stores/py.typed
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|