qdrant-haystack 10.6.0__tar.gz → 11.0.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.6.0 → qdrant_haystack-11.0.0}/CHANGELOG.md +40 -19
  2. {qdrant_haystack-10.6.0 → qdrant_haystack-11.0.0}/PKG-INFO +1 -1
  3. {qdrant_haystack-10.6.0 → qdrant_haystack-11.0.0}/src/haystack_integrations/document_stores/qdrant/document_store.py +101 -90
  4. {qdrant_haystack-10.6.0 → qdrant_haystack-11.0.0}/tests/test_document_store.py +14 -9
  5. {qdrant_haystack-10.6.0 → qdrant_haystack-11.0.0}/tests/test_document_store_async.py +14 -9
  6. {qdrant_haystack-10.6.0 → qdrant_haystack-11.0.0}/.gitignore +0 -0
  7. {qdrant_haystack-10.6.0 → qdrant_haystack-11.0.0}/LICENSE.txt +0 -0
  8. {qdrant_haystack-10.6.0 → qdrant_haystack-11.0.0}/README.md +0 -0
  9. {qdrant_haystack-10.6.0 → qdrant_haystack-11.0.0}/examples/embedding_retrieval.py +0 -0
  10. {qdrant_haystack-10.6.0 → qdrant_haystack-11.0.0}/pydoc/config_docusaurus.yml +0 -0
  11. {qdrant_haystack-10.6.0 → qdrant_haystack-11.0.0}/pyproject.toml +0 -0
  12. {qdrant_haystack-10.6.0 → qdrant_haystack-11.0.0}/src/haystack_integrations/components/retrievers/py.typed +0 -0
  13. {qdrant_haystack-10.6.0 → qdrant_haystack-11.0.0}/src/haystack_integrations/components/retrievers/qdrant/__init__.py +0 -0
  14. {qdrant_haystack-10.6.0 → qdrant_haystack-11.0.0}/src/haystack_integrations/components/retrievers/qdrant/retriever.py +0 -0
  15. {qdrant_haystack-10.6.0 → qdrant_haystack-11.0.0}/src/haystack_integrations/document_stores/py.typed +0 -0
  16. {qdrant_haystack-10.6.0 → qdrant_haystack-11.0.0}/src/haystack_integrations/document_stores/qdrant/__init__.py +0 -0
  17. {qdrant_haystack-10.6.0 → qdrant_haystack-11.0.0}/src/haystack_integrations/document_stores/qdrant/converters.py +0 -0
  18. {qdrant_haystack-10.6.0 → qdrant_haystack-11.0.0}/src/haystack_integrations/document_stores/qdrant/filters.py +0 -0
  19. {qdrant_haystack-10.6.0 → qdrant_haystack-11.0.0}/src/haystack_integrations/document_stores/qdrant/migrate_to_sparse.py +0 -0
  20. {qdrant_haystack-10.6.0 → qdrant_haystack-11.0.0}/tests/__init__.py +0 -0
  21. {qdrant_haystack-10.6.0 → qdrant_haystack-11.0.0}/tests/conftest.py +0 -0
  22. {qdrant_haystack-10.6.0 → qdrant_haystack-11.0.0}/tests/test_converters.py +0 -0
  23. {qdrant_haystack-10.6.0 → qdrant_haystack-11.0.0}/tests/test_dict_converters.py +0 -0
  24. {qdrant_haystack-10.6.0 → qdrant_haystack-11.0.0}/tests/test_embedding_retriever.py +0 -0
  25. {qdrant_haystack-10.6.0 → qdrant_haystack-11.0.0}/tests/test_filters.py +0 -0
  26. {qdrant_haystack-10.6.0 → qdrant_haystack-11.0.0}/tests/test_hybrid_retriever.py +0 -0
  27. {qdrant_haystack-10.6.0 → qdrant_haystack-11.0.0}/tests/test_sparse_embedding_retriever.py +0 -0
@@ -1,5 +1,13 @@
1
1
  # Changelog
2
2
 
3
+ ## [integrations/qdrant-v10.6.0] - 2026-09-01
4
+
5
+ ### 🐛 Bug Fixes
6
+
7
+ - Standardize license files (#3771)
8
+ - `QdrantDocumentStore` removing duplicated tests already covered by haystack Mixin tests + fixing dedup + adding missing Async test (#3785)
9
+
10
+
3
11
  ## [integrations/qdrant-v10.5.0] - 2026-08-03
4
12
 
5
13
  ### 🚀 Features
@@ -79,7 +87,7 @@
79
87
 
80
88
  - Feat: `QdrantDocumentStore` return number deleted docs on `delete_by_filter` (#2807)
81
89
 
82
- ## [integrations/qdrant-v9.6.0] - 2026-02-02
90
+ ## [integrations/qdrant-v10.1.0] - 2026-02-02
83
91
 
84
92
  ### 🚀 Features
85
93
 
@@ -87,11 +95,15 @@
87
95
 
88
96
  ### 🧹 Chores
89
97
 
90
- - Make fmt command more forgiving (#2671)
91
- - [**breaking**] Qdrant - drop Python 3.9 and use X|Y typing (#2726)
92
98
  - Disabling progress bar in `QdrantDocumentStore` tests (#2797)
93
99
 
94
- ### 🌀 Miscellaneous
100
+
101
+ ## [integrations/qdrant-v10.0.0] - 2026-01-13
102
+
103
+ ### 🧹 Chores
104
+
105
+ - Make fmt command more forgiving (#2671)
106
+ - [**breaking**] Qdrant - drop Python 3.9 and use X|Y typing (#2726)
95
107
 
96
108
 
97
109
  ## [integrations/qdrant-v9.5.0] - 2026-01-07
@@ -151,6 +163,8 @@
151
163
  - Align core-integrations Hatch scripts (#1898)
152
164
  - Update md files for new hatch scripts (#1911)
153
165
 
166
+ ## [integrations/qdrant-v9.1.3] - 2025-05-28
167
+
154
168
  ### 🌀 Miscellaneous
155
169
 
156
170
  - Add pins for Qdrant (#1853)
@@ -374,6 +388,18 @@
374
388
  - *(Qdrant)* Allow payload indexing + on disk vectors (#553)
375
389
  - Qdrant datetime filtering support (#570)
376
390
 
391
+ ### 📚 Documentation
392
+
393
+ - Disable-class-def (#556)
394
+
395
+ ### 🌀 Miscellaneous
396
+
397
+ - Make tests show coverage (#566)
398
+ - Remove references to Python 3.7 (#601)
399
+ - Make Document Stores initially skip `SparseEmbedding` (#606)
400
+
401
+ ## [integrations/qdrant-v3.1.0] - 2024-03-06
402
+
377
403
  ### 🐛 Bug Fixes
378
404
 
379
405
  - Fix: fix linter errors (#282)
@@ -388,18 +414,11 @@
388
414
 
389
415
  - Update category slug (#442)
390
416
  - Small consistency improvements (#536)
391
- - Disable-class-def (#556)
392
417
 
393
418
  ### ⚙️ CI
394
419
 
395
420
  - Generate API docs for Qdrant (#361)
396
421
 
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
422
  ## [integrations/qdrant-v3.0.0] - 2024-01-22
404
423
 
405
424
  ### 🌀 Miscellaneous
@@ -408,20 +427,22 @@
408
427
 
409
428
  ## [integrations/qdrant-v2.0.1] - 2024-01-18
410
429
 
411
- ### 🚀 Features
412
-
413
- - Add Qdrant integration (#98)
414
-
415
430
  ### 🐛 Bug Fixes
416
431
 
417
432
  - Fix import paths for beta5 (#237)
418
433
 
419
- ### 🚜 Refactor
420
-
421
- - Use `hatch_vcs` to manage integrations versioning (#103)
422
-
423
434
  ### 🌀 Miscellaneous
424
435
 
425
436
  - Renamed QdrntRetriever to QdrntEmbeddingRetriever (#174)
426
437
 
438
+ ## [integrations/qdrant-v2.0.0] - 2023-12-18
439
+
440
+ ### 🚀 Features
441
+
442
+ - Add Qdrant integration (#98)
443
+
444
+ ### 🚜 Refactor
445
+
446
+ - Use `hatch_vcs` to manage integrations versioning (#103)
447
+
427
448
  <!-- generated by git-cliff -->
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: qdrant-haystack
3
- Version: 10.6.0
3
+ Version: 11.0.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
@@ -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 (UnexpectedResponse, ValueError):
350
- # Qdrant local raises ValueError if the collection is not found, but
351
- # with the remote server UnexpectedResponse is raised. Until that's unified,
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 dtore.
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 (UnexpectedResponse, ValueError):
367
- # Qdrant local raises ValueError if the collection is not found, but
368
- # with the remote server UnexpectedResponse is raised. Until that's unified,
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
- if recreate_index:
930
- # get current collection config as json
931
- collection_info = self._client.get_collection(collection_name=self.index)
932
- info_json = collection_info.model_dump()
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
- # deal with the Optional use_sparse_embeddings
935
- sparse_vectors = info_json["config"]["params"]["sparse_vectors"]
936
- use_sparse_embeddings = True if sparse_vectors else False
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
- # deal with the Optional sparse_idf
939
- hnsw_config = info_json["config"]["params"]["vectors"].get("config", {}).get("hnsw_config", None)
940
- sparse_idf = True if use_sparse_embeddings and hnsw_config else False
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
- # recreate collection
943
- self._set_up_collection(
944
- collection_name=self.index,
945
- embedding_dim=info_json["config"]["params"]["vectors"]["size"],
946
- recreate_collection=True,
947
- similarity=info_json["config"]["params"]["vectors"]["distance"].lower(),
948
- use_sparse_embeddings=use_sparse_embeddings,
949
- sparse_idf=sparse_idf,
950
- on_disk=info_json["config"]["hnsw_config"]["on_disk"],
951
- payload_fields_to_index=info_json["payload_schema"],
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
- else:
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
- except Exception as e:
966
- logger.warning(
967
- f"Error {e} when calling QdrantDocumentStore.delete_all_documents()",
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
- if recreate_index:
981
- # get current collection config as json
982
- collection_info = await self._async_client.get_collection(collection_name=self.index)
983
- info_json = collection_info.model_dump()
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
- # deal with the Optional use_sparse_embeddings
986
- sparse_vectors = info_json["config"]["params"]["sparse_vectors"]
987
- use_sparse_embeddings = True if sparse_vectors else False
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
- # deal with the Optional sparse_idf
990
- hnsw_config = info_json["config"]["params"]["vectors"].get("config", {}).get("hnsw_config", None)
991
- sparse_idf = True if use_sparse_embeddings and hnsw_config else False
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
- # recreate collection
994
- await self._set_up_collection_async(
995
- collection_name=self.index,
996
- embedding_dim=info_json["config"]["params"]["vectors"]["size"],
997
- recreate_collection=True,
998
- similarity=info_json["config"]["params"]["vectors"]["distance"].lower(),
999
- use_sparse_embeddings=use_sparse_embeddings,
1000
- sparse_idf=sparse_idf,
1001
- on_disk=info_json["config"]["hnsw_config"]["on_disk"],
1002
- payload_fields_to_index=info_json["payload_schema"],
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
- else:
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
- except Exception as e:
1017
- logger.warning(
1018
- f"Error {e} when calling QdrantDocumentStore.delete_all_documents_async()",
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 (UnexpectedResponse, ValueError) as e:
1041
- logger.warning(f"Error {e} when calling QdrantDocumentStore.count_documents_by_filter()")
1042
- return 0
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 (UnexpectedResponse, ValueError) as e:
1065
- logger.warning(f"Error {e} when calling QdrantDocumentStore.count_documents_by_filter_async()")
1066
- return 0
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 (UnexpectedResponse, ValueError) as e:
1107
- logger.warning(f"Error {e} when calling QdrantDocumentStore.get_metadata_fields_info()")
1108
- return {}
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 (UnexpectedResponse, ValueError) as e:
1149
- logger.warning(f"Error {e} when calling QdrantDocumentStore.get_metadata_fields_info_async()")
1150
- return {}
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
- logger.warning(f"Error {e} when calling QdrantDocumentStore.get_metadata_field_min_max()")
1187
- return {}
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
- logger.warning(f"Error {e} when calling QdrantDocumentStore.get_metadata_field_min_max_async()")
1224
- return {}
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
- logger.warning(f"Error {e} when calling QdrantDocumentStore.count_unique_metadata_by_filter()")
1261
- return dict.fromkeys(metadata_fields, 0)
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
- logger.warning(f"Error {e} when calling QdrantDocumentStore.count_unique_metadata_by_filter_async()")
1302
- return dict.fromkeys(metadata_fields, 0)
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
- logger.warning(f"Error {e} when calling QdrantDocumentStore.get_metadata_field_unique_values()")
1357
- return [], 0
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
- logger.warning(f"Error {e} when calling QdrantDocumentStore.get_metadata_field_unique_values_async()")
1412
- return [], 0
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":
@@ -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", "expected"),
380
+ ("method_name", "args"),
381
381
  [
382
- ("count_documents", (), 0),
383
- ("count_documents_by_filter", ({},), 0),
384
- ("get_metadata_fields_info", (), {}),
385
- ("get_metadata_field_min_max", ("score",), {}),
386
- ("count_unique_metadata_by_filter", ({}, ["category"]), {"category": 0}),
387
- ("get_metadata_field_unique_values", ("category",), ([], 0)),
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 test_metadata_methods_swallow_client_errors(self, method_name, args, expected):
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
- assert getattr(document_store, method_name)(*args) == expected
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", "expected"),
144
+ ("method_name", "args"),
145
145
  [
146
- ("count_documents_async", (), 0),
147
- ("count_documents_by_filter_async", ({},), 0),
148
- ("get_metadata_fields_info_async", (), {}),
149
- ("get_metadata_field_min_max_async", ("score",), {}),
150
- ("count_unique_metadata_by_filter_async", ({}, ["category"]), {"category": 0}),
151
- ("get_metadata_field_unique_values_async", ("category",), ([], 0)),
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 test_metadata_methods_async_absorb_client_errors(self, method_name, args, expected):
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
- assert await getattr(document_store, method_name)(*args) == expected
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:")