qdrant-haystack 10.1.0__tar.gz → 10.2.1__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.1.0 → qdrant_haystack-10.2.1}/CHANGELOG.md +14 -1
- {qdrant_haystack-10.1.0 → qdrant_haystack-10.2.1}/PKG-INFO +1 -1
- {qdrant_haystack-10.1.0 → qdrant_haystack-10.2.1}/src/haystack_integrations/document_stores/qdrant/document_store.py +26 -8
- {qdrant_haystack-10.1.0 → qdrant_haystack-10.2.1}/tests/test_document_store.py +17 -7
- {qdrant_haystack-10.1.0 → qdrant_haystack-10.2.1}/tests/test_document_store_async.py +18 -7
- {qdrant_haystack-10.1.0 → qdrant_haystack-10.2.1}/.gitignore +0 -0
- {qdrant_haystack-10.1.0 → qdrant_haystack-10.2.1}/LICENSE.txt +0 -0
- {qdrant_haystack-10.1.0 → qdrant_haystack-10.2.1}/README.md +0 -0
- {qdrant_haystack-10.1.0 → qdrant_haystack-10.2.1}/examples/embedding_retrieval.py +0 -0
- {qdrant_haystack-10.1.0 → qdrant_haystack-10.2.1}/pydoc/config_docusaurus.yml +0 -0
- {qdrant_haystack-10.1.0 → qdrant_haystack-10.2.1}/pyproject.toml +0 -0
- {qdrant_haystack-10.1.0 → qdrant_haystack-10.2.1}/src/haystack_integrations/components/retrievers/py.typed +0 -0
- {qdrant_haystack-10.1.0 → qdrant_haystack-10.2.1}/src/haystack_integrations/components/retrievers/qdrant/__init__.py +0 -0
- {qdrant_haystack-10.1.0 → qdrant_haystack-10.2.1}/src/haystack_integrations/components/retrievers/qdrant/retriever.py +0 -0
- {qdrant_haystack-10.1.0 → qdrant_haystack-10.2.1}/src/haystack_integrations/document_stores/py.typed +0 -0
- {qdrant_haystack-10.1.0 → qdrant_haystack-10.2.1}/src/haystack_integrations/document_stores/qdrant/__init__.py +0 -0
- {qdrant_haystack-10.1.0 → qdrant_haystack-10.2.1}/src/haystack_integrations/document_stores/qdrant/converters.py +0 -0
- {qdrant_haystack-10.1.0 → qdrant_haystack-10.2.1}/src/haystack_integrations/document_stores/qdrant/filters.py +0 -0
- {qdrant_haystack-10.1.0 → qdrant_haystack-10.2.1}/src/haystack_integrations/document_stores/qdrant/migrate_to_sparse.py +0 -0
- {qdrant_haystack-10.1.0 → qdrant_haystack-10.2.1}/tests/__init__.py +0 -0
- {qdrant_haystack-10.1.0 → qdrant_haystack-10.2.1}/tests/conftest.py +0 -0
- {qdrant_haystack-10.1.0 → qdrant_haystack-10.2.1}/tests/test_converters.py +0 -0
- {qdrant_haystack-10.1.0 → qdrant_haystack-10.2.1}/tests/test_dict_converters.py +0 -0
- {qdrant_haystack-10.1.0 → qdrant_haystack-10.2.1}/tests/test_embedding_retriever.py +0 -0
- {qdrant_haystack-10.1.0 → qdrant_haystack-10.2.1}/tests/test_filters.py +0 -0
- {qdrant_haystack-10.1.0 → qdrant_haystack-10.2.1}/tests/test_hybrid_retriever.py +0 -0
- {qdrant_haystack-10.1.0 → qdrant_haystack-10.2.1}/tests/test_sparse_embedding_retriever.py +0 -0
|
@@ -1,11 +1,24 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
## [
|
|
3
|
+
## [integrations/qdrant-v10.2.0] - 2026-02-02
|
|
4
|
+
|
|
5
|
+
### 🌀 Miscellaneous
|
|
6
|
+
|
|
7
|
+
- Feat: `QdrantDocumentStore` return number deleted docs on `delete_by_filter` (#2807)
|
|
8
|
+
|
|
9
|
+
## [integrations/qdrant-v9.6.0] - 2026-02-02
|
|
10
|
+
|
|
11
|
+
### 🚀 Features
|
|
12
|
+
|
|
13
|
+
- Adding count with filtering operations to`QdrantDocumentStore` (#2803)
|
|
4
14
|
|
|
5
15
|
### 🧹 Chores
|
|
6
16
|
|
|
7
17
|
- Make fmt command more forgiving (#2671)
|
|
8
18
|
- [**breaking**] Qdrant - drop Python 3.9 and use X|Y typing (#2726)
|
|
19
|
+
- Disabling progress bar in `QdrantDocumentStore` tests (#2797)
|
|
20
|
+
|
|
21
|
+
### 🌀 Miscellaneous
|
|
9
22
|
|
|
10
23
|
|
|
11
24
|
## [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
|
|
3
|
+
Version: 10.2.1
|
|
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]) ->
|
|
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]) ->
|
|
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}"
|
|
@@ -971,7 +983,10 @@ class QdrantDocumentStore:
|
|
|
971
983
|
Returns the information about the fields from the collection.
|
|
972
984
|
|
|
973
985
|
:returns:
|
|
974
|
-
A dictionary mapping field names to their types
|
|
986
|
+
A dictionary mapping field names to their types e.g.:
|
|
987
|
+
```python
|
|
988
|
+
{"field_name": "integer"}
|
|
989
|
+
```
|
|
975
990
|
"""
|
|
976
991
|
self._initialize_client()
|
|
977
992
|
assert self._client is not None
|
|
@@ -989,7 +1004,10 @@ class QdrantDocumentStore:
|
|
|
989
1004
|
Asynchronously returns the information about the fields from the collection.
|
|
990
1005
|
|
|
991
1006
|
:returns:
|
|
992
|
-
A dictionary mapping field names to their types
|
|
1007
|
+
A dictionary mapping field names to their types e.g.:
|
|
1008
|
+
```python
|
|
1009
|
+
{"field_name": "integer"}
|
|
1010
|
+
```
|
|
993
1011
|
"""
|
|
994
1012
|
await self._initialize_async_client()
|
|
995
1013
|
assert self._async_client is not None
|
|
@@ -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
|
-
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
|
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
|
{qdrant_haystack-10.1.0 → qdrant_haystack-10.2.1}/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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|