qdrant-haystack 11.0.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.
Files changed (27) hide show
  1. {qdrant_haystack-11.0.0 → qdrant_haystack-11.1.0}/CHANGELOG.md +11 -0
  2. {qdrant_haystack-11.0.0 → qdrant_haystack-11.1.0}/PKG-INFO +1 -1
  3. {qdrant_haystack-11.0.0 → qdrant_haystack-11.1.0}/src/haystack_integrations/components/retrievers/qdrant/retriever.py +30 -27
  4. {qdrant_haystack-11.0.0 → qdrant_haystack-11.1.0}/src/haystack_integrations/document_stores/qdrant/document_store.py +8 -6
  5. {qdrant_haystack-11.0.0 → qdrant_haystack-11.1.0}/tests/test_embedding_retriever.py +31 -0
  6. {qdrant_haystack-11.0.0 → qdrant_haystack-11.1.0}/tests/test_hybrid_retriever.py +33 -0
  7. {qdrant_haystack-11.0.0 → qdrant_haystack-11.1.0}/tests/test_sparse_embedding_retriever.py +33 -0
  8. {qdrant_haystack-11.0.0 → qdrant_haystack-11.1.0}/.gitignore +0 -0
  9. {qdrant_haystack-11.0.0 → qdrant_haystack-11.1.0}/LICENSE.txt +0 -0
  10. {qdrant_haystack-11.0.0 → qdrant_haystack-11.1.0}/README.md +0 -0
  11. {qdrant_haystack-11.0.0 → qdrant_haystack-11.1.0}/examples/embedding_retrieval.py +0 -0
  12. {qdrant_haystack-11.0.0 → qdrant_haystack-11.1.0}/pydoc/config_docusaurus.yml +0 -0
  13. {qdrant_haystack-11.0.0 → qdrant_haystack-11.1.0}/pyproject.toml +0 -0
  14. {qdrant_haystack-11.0.0 → qdrant_haystack-11.1.0}/src/haystack_integrations/components/retrievers/py.typed +0 -0
  15. {qdrant_haystack-11.0.0 → qdrant_haystack-11.1.0}/src/haystack_integrations/components/retrievers/qdrant/__init__.py +0 -0
  16. {qdrant_haystack-11.0.0 → qdrant_haystack-11.1.0}/src/haystack_integrations/document_stores/py.typed +0 -0
  17. {qdrant_haystack-11.0.0 → qdrant_haystack-11.1.0}/src/haystack_integrations/document_stores/qdrant/__init__.py +0 -0
  18. {qdrant_haystack-11.0.0 → qdrant_haystack-11.1.0}/src/haystack_integrations/document_stores/qdrant/converters.py +0 -0
  19. {qdrant_haystack-11.0.0 → qdrant_haystack-11.1.0}/src/haystack_integrations/document_stores/qdrant/filters.py +0 -0
  20. {qdrant_haystack-11.0.0 → qdrant_haystack-11.1.0}/src/haystack_integrations/document_stores/qdrant/migrate_to_sparse.py +0 -0
  21. {qdrant_haystack-11.0.0 → qdrant_haystack-11.1.0}/tests/__init__.py +0 -0
  22. {qdrant_haystack-11.0.0 → qdrant_haystack-11.1.0}/tests/conftest.py +0 -0
  23. {qdrant_haystack-11.0.0 → qdrant_haystack-11.1.0}/tests/test_converters.py +0 -0
  24. {qdrant_haystack-11.0.0 → qdrant_haystack-11.1.0}/tests/test_dict_converters.py +0 -0
  25. {qdrant_haystack-11.0.0 → qdrant_haystack-11.1.0}/tests/test_document_store.py +0 -0
  26. {qdrant_haystack-11.0.0 → qdrant_haystack-11.1.0}/tests/test_document_store_async.py +0 -0
  27. {qdrant_haystack-11.0.0 → qdrant_haystack-11.1.0}/tests/test_filters.py +0 -0
@@ -1,5 +1,16 @@
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
+
3
14
  ## [integrations/qdrant-v10.6.0] - 2026-09-01
4
15
 
5
16
  ### 🐛 Bug Fixes
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: qdrant-haystack
3
- Version: 11.0.0
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 or self._scale_score,
192
- return_embedding=return_embedding or self._return_embedding,
193
- score_threshold=score_threshold or self._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 or self._scale_score,
247
- return_embedding=return_embedding or self._return_embedding,
248
- score_threshold=score_threshold or self._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 or self._scale_score,
437
- return_embedding=return_embedding or self._return_embedding,
438
- score_threshold=score_threshold or self._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 or self._scale_score,
497
- return_embedding=return_embedding or self._return_embedding,
498
- score_threshold=score_threshold or self._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
- Score of the returned result might be higher or smaller than the threshold
564
- depending on the Distance function used.
565
- E.g. for cosine similarity only higher scores will be returned.
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 Sparse Embedding Retriever on the given input data.
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
- Score of the returned result might be higher or smaller than the threshold
674
- depending on the Distance function used.
675
- E.g. for cosine similarity only higher scores will be returned.
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 or self._return_embedding,
708
- score_threshold=score_threshold or self._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 Sparse Embedding Retriever on the given input data.
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
- Score of the returned result might be higher or smaller than the threshold
744
- depending on the Distance function used.
745
- E.g. for cosine similarity only higher scores will be returned.
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 or self._return_embedding,
778
- score_threshold=score_threshold or self._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,
@@ -1757,9 +1757,10 @@ class QdrantDocumentStore:
1757
1757
  groups to return.
1758
1758
  :param return_embedding: Whether to return the embeddings of the retrieved documents.
1759
1759
  :param score_threshold: A minimal score threshold for the result.
1760
- Score of the returned result might be higher or smaller than the threshold
1761
- depending on the Distance function used.
1762
- E.g. for cosine similarity only higher scores will be returned.
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.
1763
1764
  :param group_by: Payload field to group by, must be a string or number field. If the field contains more than 1
1764
1765
  value, all values will be used for grouping. One point can be in multiple groups.
1765
1766
  :param group_size: Maximum amount of points to return per group. Default is 3.
@@ -2020,9 +2021,10 @@ class QdrantDocumentStore:
2020
2021
  groups to return.
2021
2022
  :param return_embedding: Whether to return the embeddings of the retrieved documents.
2022
2023
  :param score_threshold: A minimal score threshold for the result.
2023
- Score of the returned result might be higher or smaller than the threshold
2024
- depending on the Distance function used.
2025
- E.g. for cosine similarity only higher scores will be returned.
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.
2026
2028
  :param group_by: Payload field to group by, must be a string or number field. If the field contains more than 1
2027
2029
  value, all values will be used for grouping. One point can be in multiple groups.
2028
2030
  :param group_size: Maximum amount of points to return per group. Default is 3.
@@ -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(