qdrant-haystack 10.1.0__tar.gz → 10.2.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-10.1.0 → qdrant_haystack-10.2.0}/CHANGELOG.md +8 -1
  2. {qdrant_haystack-10.1.0 → qdrant_haystack-10.2.0}/PKG-INFO +1 -1
  3. {qdrant_haystack-10.1.0 → qdrant_haystack-10.2.0}/src/haystack_integrations/document_stores/qdrant/document_store.py +18 -6
  4. {qdrant_haystack-10.1.0 → qdrant_haystack-10.2.0}/tests/test_document_store.py +17 -7
  5. {qdrant_haystack-10.1.0 → qdrant_haystack-10.2.0}/tests/test_document_store_async.py +18 -7
  6. {qdrant_haystack-10.1.0 → qdrant_haystack-10.2.0}/.gitignore +0 -0
  7. {qdrant_haystack-10.1.0 → qdrant_haystack-10.2.0}/LICENSE.txt +0 -0
  8. {qdrant_haystack-10.1.0 → qdrant_haystack-10.2.0}/README.md +0 -0
  9. {qdrant_haystack-10.1.0 → qdrant_haystack-10.2.0}/examples/embedding_retrieval.py +0 -0
  10. {qdrant_haystack-10.1.0 → qdrant_haystack-10.2.0}/pydoc/config_docusaurus.yml +0 -0
  11. {qdrant_haystack-10.1.0 → qdrant_haystack-10.2.0}/pyproject.toml +0 -0
  12. {qdrant_haystack-10.1.0 → qdrant_haystack-10.2.0}/src/haystack_integrations/components/retrievers/py.typed +0 -0
  13. {qdrant_haystack-10.1.0 → qdrant_haystack-10.2.0}/src/haystack_integrations/components/retrievers/qdrant/__init__.py +0 -0
  14. {qdrant_haystack-10.1.0 → qdrant_haystack-10.2.0}/src/haystack_integrations/components/retrievers/qdrant/retriever.py +0 -0
  15. {qdrant_haystack-10.1.0 → qdrant_haystack-10.2.0}/src/haystack_integrations/document_stores/py.typed +0 -0
  16. {qdrant_haystack-10.1.0 → qdrant_haystack-10.2.0}/src/haystack_integrations/document_stores/qdrant/__init__.py +0 -0
  17. {qdrant_haystack-10.1.0 → qdrant_haystack-10.2.0}/src/haystack_integrations/document_stores/qdrant/converters.py +0 -0
  18. {qdrant_haystack-10.1.0 → qdrant_haystack-10.2.0}/src/haystack_integrations/document_stores/qdrant/filters.py +0 -0
  19. {qdrant_haystack-10.1.0 → qdrant_haystack-10.2.0}/src/haystack_integrations/document_stores/qdrant/migrate_to_sparse.py +0 -0
  20. {qdrant_haystack-10.1.0 → qdrant_haystack-10.2.0}/tests/__init__.py +0 -0
  21. {qdrant_haystack-10.1.0 → qdrant_haystack-10.2.0}/tests/conftest.py +0 -0
  22. {qdrant_haystack-10.1.0 → qdrant_haystack-10.2.0}/tests/test_converters.py +0 -0
  23. {qdrant_haystack-10.1.0 → qdrant_haystack-10.2.0}/tests/test_dict_converters.py +0 -0
  24. {qdrant_haystack-10.1.0 → qdrant_haystack-10.2.0}/tests/test_embedding_retriever.py +0 -0
  25. {qdrant_haystack-10.1.0 → qdrant_haystack-10.2.0}/tests/test_filters.py +0 -0
  26. {qdrant_haystack-10.1.0 → qdrant_haystack-10.2.0}/tests/test_hybrid_retriever.py +0 -0
  27. {qdrant_haystack-10.1.0 → qdrant_haystack-10.2.0}/tests/test_sparse_embedding_retriever.py +0 -0
@@ -1,11 +1,18 @@
1
1
  # Changelog
2
2
 
3
- ## [unreleased]
3
+ ## [integrations/qdrant-v9.6.0] - 2026-02-02
4
+
5
+ ### 🚀 Features
6
+
7
+ - Adding count with filtering operations to`QdrantDocumentStore` (#2803)
4
8
 
5
9
  ### 🧹 Chores
6
10
 
7
11
  - Make fmt command more forgiving (#2671)
8
12
  - [**breaking**] Qdrant - drop Python 3.9 and use X|Y typing (#2726)
13
+ - Disabling progress bar in `QdrantDocumentStore` tests (#2797)
14
+
15
+ ### 🌀 Miscellaneous
9
16
 
10
17
 
11
18
  ## [integrations/qdrant-v9.5.0] - 2026-01-07
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: qdrant-haystack
3
- Version: 10.1.0
3
+ Version: 10.2.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
@@ -517,7 +517,7 @@ class QdrantDocumentStore:
517
517
  "Called QdrantDocumentStore.delete_documents_async() on a non-existing ID",
518
518
  )
519
519
 
520
- def delete_by_filter(self, filters: dict[str, Any]) -> None:
520
+ def delete_by_filter(self, filters: dict[str, Any]) -> int:
521
521
  """
522
522
  Deletes all documents that match the provided filters.
523
523
 
@@ -533,20 +533,26 @@ class QdrantDocumentStore:
533
533
  try:
534
534
  qdrant_filter = convert_filters_to_qdrant(filters)
535
535
  if qdrant_filter is None:
536
- return
536
+ return 0
537
+
538
+ count_response = self._client.count(
539
+ collection_name=self.index,
540
+ count_filter=qdrant_filter,
541
+ )
542
+ deleted_count = count_response.count
537
543
 
538
- # perform deletion using FilterSelector
539
544
  self._client.delete(
540
545
  collection_name=self.index,
541
546
  points_selector=rest.FilterSelector(filter=qdrant_filter),
542
547
  wait=self.wait_result_from_api,
543
548
  )
549
+ return deleted_count
544
550
 
545
551
  except Exception as e:
546
552
  msg = f"Failed to delete documents by filter from Qdrant: {e!s}"
547
553
  raise QdrantStoreError(msg) from e
548
554
 
549
- async def delete_by_filter_async(self, filters: dict[str, Any]) -> None:
555
+ async def delete_by_filter_async(self, filters: dict[str, Any]) -> int:
550
556
  """
551
557
  Asynchronously deletes all documents that match the provided filters.
552
558
 
@@ -562,14 +568,20 @@ class QdrantDocumentStore:
562
568
  try:
563
569
  qdrant_filter = convert_filters_to_qdrant(filters)
564
570
  if qdrant_filter is None:
565
- return
571
+ return 0
572
+
573
+ count_response = await self._async_client.count(
574
+ collection_name=self.index,
575
+ count_filter=qdrant_filter,
576
+ )
577
+ deleted_count = count_response.count
566
578
 
567
- # perform deletion using FilterSelector
568
579
  await self._async_client.delete(
569
580
  collection_name=self.index,
570
581
  points_selector=rest.FilterSelector(filter=qdrant_filter),
571
582
  wait=self.wait_result_from_api,
572
583
  )
584
+ return deleted_count
573
585
 
574
586
  except Exception as e:
575
587
  msg = f"Failed to delete documents by filter from Qdrant: {e!s}"
@@ -348,7 +348,11 @@ class TestQdrantDocumentStore(CountDocumentsTest, WriteDocumentsTest, DeleteDocu
348
348
  ]
349
349
  document_store.write_documents(docs)
350
350
  assert document_store.count_documents() == 3
351
- document_store.delete_by_filter(filters={"field": "meta.category", "operator": "==", "value": "A"})
351
+
352
+ deleted_count = document_store.delete_by_filter(
353
+ filters={"field": "meta.category", "operator": "==", "value": "A"}
354
+ )
355
+ assert deleted_count == 2
352
356
 
353
357
  # Verify only category B remains
354
358
  remaining_docs = document_store.filter_documents()
@@ -356,7 +360,8 @@ class TestQdrantDocumentStore(CountDocumentsTest, WriteDocumentsTest, DeleteDocu
356
360
  assert remaining_docs[0].meta["category"] == "B"
357
361
 
358
362
  # Delete remaining document by year
359
- document_store.delete_by_filter(filters={"field": "meta.year", "operator": "==", "value": 2023})
363
+ deleted_count = document_store.delete_by_filter(filters={"field": "meta.year", "operator": "==", "value": 2023})
364
+ assert deleted_count == 1
360
365
  assert document_store.count_documents() == 0
361
366
 
362
367
  def test_delete_by_filter_no_matches(self, document_store: QdrantDocumentStore):
@@ -368,7 +373,10 @@ class TestQdrantDocumentStore(CountDocumentsTest, WriteDocumentsTest, DeleteDocu
368
373
  assert document_store.count_documents() == 2
369
374
 
370
375
  # try to delete documents with category="C" (no matches)
371
- document_store.delete_by_filter(filters={"field": "meta.category", "operator": "==", "value": "C"})
376
+ deleted_count = document_store.delete_by_filter(
377
+ filters={"field": "meta.category", "operator": "==", "value": "C"}
378
+ )
379
+ assert deleted_count == 0
372
380
  assert document_store.count_documents() == 2
373
381
 
374
382
  def test_delete_by_filter_advanced_filters(self, document_store: QdrantDocumentStore):
@@ -380,8 +388,8 @@ class TestQdrantDocumentStore(CountDocumentsTest, WriteDocumentsTest, DeleteDocu
380
388
  document_store.write_documents(docs)
381
389
  assert document_store.count_documents() == 3
382
390
 
383
- # AND condition
384
- document_store.delete_by_filter(
391
+ # AND condition (matches only Doc 1)
392
+ deleted_count = document_store.delete_by_filter(
385
393
  filters={
386
394
  "operator": "AND",
387
395
  "conditions": [
@@ -390,10 +398,11 @@ class TestQdrantDocumentStore(CountDocumentsTest, WriteDocumentsTest, DeleteDocu
390
398
  ],
391
399
  }
392
400
  )
401
+ assert deleted_count == 1
393
402
  assert document_store.count_documents() == 2
394
403
 
395
- # OR condition
396
- document_store.delete_by_filter(
404
+ # OR condition (matches Doc 2 and Doc 3)
405
+ deleted_count = document_store.delete_by_filter(
397
406
  filters={
398
407
  "operator": "OR",
399
408
  "conditions": [
@@ -402,6 +411,7 @@ class TestQdrantDocumentStore(CountDocumentsTest, WriteDocumentsTest, DeleteDocu
402
411
  ],
403
412
  }
404
413
  )
414
+ assert deleted_count == 2
405
415
  assert document_store.count_documents() == 0
406
416
 
407
417
  def test_update_by_filter(self, document_store: QdrantDocumentStore):
@@ -275,7 +275,10 @@ class TestQdrantDocumentStore:
275
275
  assert await document_store.count_documents_async() == 3
276
276
 
277
277
  # Delete documents with category="A"
278
- await document_store.delete_by_filter_async(filters={"field": "meta.category", "operator": "==", "value": "A"})
278
+ deleted_count = await document_store.delete_by_filter_async(
279
+ filters={"field": "meta.category", "operator": "==", "value": "A"}
280
+ )
281
+ assert deleted_count == 2
279
282
  assert await document_store.count_documents_async() == 1
280
283
 
281
284
  # Verify only category B remains
@@ -286,7 +289,10 @@ class TestQdrantDocumentStore:
286
289
  assert remaining_docs[0].meta["category"] == "B"
287
290
 
288
291
  # Delete remaining document by year
289
- await document_store.delete_by_filter_async(filters={"field": "meta.year", "operator": "==", "value": 2023})
292
+ deleted_count = await document_store.delete_by_filter_async(
293
+ filters={"field": "meta.year", "operator": "==", "value": 2023}
294
+ )
295
+ assert deleted_count == 1
290
296
  assert await document_store.count_documents_async() == 0
291
297
 
292
298
  @pytest.mark.asyncio
@@ -299,7 +305,10 @@ class TestQdrantDocumentStore:
299
305
  assert await document_store.count_documents_async() == 2
300
306
 
301
307
  # Try to delete documents with category="C" (no matches)
302
- await document_store.delete_by_filter_async(filters={"field": "meta.category", "operator": "==", "value": "C"})
308
+ deleted_count = await document_store.delete_by_filter_async(
309
+ filters={"field": "meta.category", "operator": "==", "value": "C"}
310
+ )
311
+ assert deleted_count == 0
303
312
  assert await document_store.count_documents_async() == 2
304
313
 
305
314
  @pytest.mark.asyncio
@@ -312,8 +321,8 @@ class TestQdrantDocumentStore:
312
321
  await document_store.write_documents_async(docs)
313
322
  assert await document_store.count_documents_async() == 3
314
323
 
315
- # AND condition
316
- await document_store.delete_by_filter_async(
324
+ # AND condition (matches only Doc 1)
325
+ deleted_count = await document_store.delete_by_filter_async(
317
326
  filters={
318
327
  "operator": "AND",
319
328
  "conditions": [
@@ -322,10 +331,11 @@ class TestQdrantDocumentStore:
322
331
  ],
323
332
  }
324
333
  )
334
+ assert deleted_count == 1
325
335
  assert await document_store.count_documents_async() == 2
326
336
 
327
- # OR condition
328
- await document_store.delete_by_filter_async(
337
+ # OR condition (matches Doc 2 and Doc 3)
338
+ deleted_count = await document_store.delete_by_filter_async(
329
339
  filters={
330
340
  "operator": "OR",
331
341
  "conditions": [
@@ -334,6 +344,7 @@ class TestQdrantDocumentStore:
334
344
  ],
335
345
  }
336
346
  )
347
+ assert deleted_count == 2
337
348
  assert await document_store.count_documents_async() == 0
338
349
 
339
350
  @pytest.mark.asyncio