weaviate-haystack 7.2.0__tar.gz → 7.3.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 (31) hide show
  1. {weaviate_haystack-7.2.0 → weaviate_haystack-7.3.0}/CHANGELOG.md +16 -0
  2. {weaviate_haystack-7.2.0 → weaviate_haystack-7.3.0}/PKG-INFO +2 -2
  3. {weaviate_haystack-7.2.0 → weaviate_haystack-7.3.0}/docker-compose.yml +1 -1
  4. {weaviate_haystack-7.2.0 → weaviate_haystack-7.3.0}/pyproject.toml +1 -1
  5. {weaviate_haystack-7.2.0 → weaviate_haystack-7.3.0}/src/haystack_integrations/components/retrievers/weaviate/hybrid_retriever.py +3 -3
  6. {weaviate_haystack-7.2.0 → weaviate_haystack-7.3.0}/src/haystack_integrations/document_stores/weaviate/document_store.py +284 -37
  7. {weaviate_haystack-7.2.0 → weaviate_haystack-7.3.0}/tests/test_document_store_async.py +132 -34
  8. {weaviate_haystack-7.2.0 → weaviate_haystack-7.3.0}/tests/test_hybrid_retriever.py +16 -11
  9. {weaviate_haystack-7.2.0 → weaviate_haystack-7.3.0}/.gitignore +0 -0
  10. {weaviate_haystack-7.2.0 → weaviate_haystack-7.3.0}/LICENSE.txt +0 -0
  11. {weaviate_haystack-7.2.0 → weaviate_haystack-7.3.0}/README.md +0 -0
  12. {weaviate_haystack-7.2.0 → weaviate_haystack-7.3.0}/pydoc/config_docusaurus.yml +0 -0
  13. {weaviate_haystack-7.2.0 → weaviate_haystack-7.3.0}/src/haystack_integrations/components/retrievers/py.typed +0 -0
  14. {weaviate_haystack-7.2.0 → weaviate_haystack-7.3.0}/src/haystack_integrations/components/retrievers/weaviate/__init__.py +0 -0
  15. {weaviate_haystack-7.2.0 → weaviate_haystack-7.3.0}/src/haystack_integrations/components/retrievers/weaviate/bm25_retriever.py +0 -0
  16. {weaviate_haystack-7.2.0 → weaviate_haystack-7.3.0}/src/haystack_integrations/components/retrievers/weaviate/embedding_retriever.py +0 -0
  17. {weaviate_haystack-7.2.0 → weaviate_haystack-7.3.0}/src/haystack_integrations/document_stores/py.typed +0 -0
  18. {weaviate_haystack-7.2.0 → weaviate_haystack-7.3.0}/src/haystack_integrations/document_stores/weaviate/__init__.py +0 -0
  19. {weaviate_haystack-7.2.0 → weaviate_haystack-7.3.0}/src/haystack_integrations/document_stores/weaviate/_filters.py +0 -0
  20. {weaviate_haystack-7.2.0 → weaviate_haystack-7.3.0}/src/haystack_integrations/document_stores/weaviate/auth.py +0 -0
  21. {weaviate_haystack-7.2.0 → weaviate_haystack-7.3.0}/tests/__init__.py +0 -0
  22. {weaviate_haystack-7.2.0 → weaviate_haystack-7.3.0}/tests/conftest.py +0 -0
  23. {weaviate_haystack-7.2.0 → weaviate_haystack-7.3.0}/tests/test_auth.py +0 -0
  24. {weaviate_haystack-7.2.0 → weaviate_haystack-7.3.0}/tests/test_bm25_retriever.py +0 -0
  25. {weaviate_haystack-7.2.0 → weaviate_haystack-7.3.0}/tests/test_bm25_retriever_async.py +0 -0
  26. {weaviate_haystack-7.2.0 → weaviate_haystack-7.3.0}/tests/test_document_store.py +0 -0
  27. {weaviate_haystack-7.2.0 → weaviate_haystack-7.3.0}/tests/test_embedding_retriever.py +0 -0
  28. {weaviate_haystack-7.2.0 → weaviate_haystack-7.3.0}/tests/test_embedding_retriever_async.py +0 -0
  29. {weaviate_haystack-7.2.0 → weaviate_haystack-7.3.0}/tests/test_files/robot1.jpg +0 -0
  30. {weaviate_haystack-7.2.0 → weaviate_haystack-7.3.0}/tests/test_filters.py +0 -0
  31. {weaviate_haystack-7.2.0 → weaviate_haystack-7.3.0}/tests/test_hybrid_retriever_async.py +0 -0
@@ -1,5 +1,21 @@
1
1
  # Changelog
2
2
 
3
+ ## [integrations/weaviate-v7.2.0] - 2026-03-06
4
+
5
+ ### 🐛 Bug Fixes
6
+
7
+ - Remove unnecessary connection test and add `close`/`close_async` methods to `WeaviateDocumentStore` (#2891)
8
+
9
+ ### 📚 Documentation
10
+
11
+ - Simplify pydoc configs (#2855)
12
+
13
+ ### 🧪 Testing
14
+
15
+ - Replacing each `DocumentStore` specific tests and used the generalised ones from `haystack.testing.document_store` (#2812)
16
+ - Fix Weaviate tests to include grpc_config (#2871)
17
+
18
+
3
19
  ## [integrations/weaviate-v7.1.0] - 2026-01-29
4
20
 
5
21
  ### 🚀 Features
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: weaviate-haystack
3
- Version: 7.2.0
3
+ Version: 7.3.0
4
4
  Summary: An integration of Weaviate vector database 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/weaviate/README.md
@@ -20,7 +20,7 @@ Classifier: Programming Language :: Python :: Implementation :: PyPy
20
20
  Requires-Python: >=3.10
21
21
  Requires-Dist: haystack-ai>=2.24.0
22
22
  Requires-Dist: python-dateutil
23
- Requires-Dist: weaviate-client>=4.9
23
+ Requires-Dist: weaviate-client>=4.20
24
24
  Description-Content-Type: text/markdown
25
25
 
26
26
  # weaviate-haystack
@@ -7,7 +7,7 @@ services:
7
7
  - '8080'
8
8
  - --scheme
9
9
  - http
10
- image: semitechnologies/weaviate:1.30.17
10
+ image: semitechnologies/weaviate:1.36.2
11
11
  ports:
12
12
  - 8080:8080
13
13
  - 50051:50051
@@ -24,7 +24,7 @@ classifiers = [
24
24
  ]
25
25
  dependencies = [
26
26
  "haystack-ai>=2.24.0",
27
- "weaviate-client>=4.9",
27
+ "weaviate-client>=4.20",
28
28
  "python-dateutil",
29
29
  ]
30
30
 
@@ -23,7 +23,7 @@ class WeaviateHybridRetriever:
23
23
  document_store: WeaviateDocumentStore,
24
24
  filters: dict[str, Any] | None = None,
25
25
  top_k: int = 10,
26
- alpha: float | None = None,
26
+ alpha: float = 0.7,
27
27
  max_vector_distance: float | None = None,
28
28
  filter_policy: str | FilterPolicy = FilterPolicy.REPLACE,
29
29
  ):
@@ -46,7 +46,7 @@ class WeaviateHybridRetriever:
46
46
  - `alpha = 1.0`: only vector similarity scoring is used.
47
47
  - Values in between blend the two; higher values favor the vector score, lower values favor BM25.
48
48
 
49
- If `None`, the Weaviate server default is used.
49
+ By default, 0.7 is used which is the Weaviate server default.
50
50
 
51
51
  See the official Weaviate docs on Hybrid Search parameters for more details:
52
52
  - [Hybrid search parameters](https://weaviate.io/developers/weaviate/search/hybrid#parameters)
@@ -66,7 +66,7 @@ class WeaviateHybridRetriever:
66
66
  Policy to determine how filters are applied.
67
67
  """
68
68
 
69
- if alpha is not None and not 0.0 <= alpha <= 1.0:
69
+ if not 0.0 <= alpha <= 1.0:
70
70
  msg = f"alpha ({alpha}) must be in the range [0.0, 1.0]"
71
71
  raise ValueError(msg)
72
72
 
@@ -6,7 +6,7 @@ import base64
6
6
  import datetime
7
7
  import json
8
8
  from dataclasses import asdict
9
- from typing import Any
9
+ from typing import Any, NoReturn
10
10
 
11
11
  from haystack import logging
12
12
  from haystack.core.serialization import default_from_dict, default_to_dict
@@ -22,9 +22,13 @@ from weaviate.collections.classes.aggregate import (
22
22
  _MetricsInteger,
23
23
  _MetricsNumber,
24
24
  )
25
- from weaviate.collections.classes.data import DataObject
25
+ from weaviate.collections.classes.batch import ErrorObject
26
+ from weaviate.collections.classes.internal import Object
27
+ from weaviate.collections.collection import Collection, CollectionAsync
28
+ from weaviate.collections.iterator import _ObjectAIterator, _ObjectIterator
26
29
  from weaviate.config import AdditionalConfig
27
30
  from weaviate.embedded import EmbeddedOptions
31
+ from weaviate.types import VECTORS
28
32
  from weaviate.util import generate_uuid5
29
33
 
30
34
  from ._filters import convert_filters, validate_filters
@@ -105,7 +109,7 @@ class WeaviateDocumentStore:
105
109
  additional_config: AdditionalConfig | None = None,
106
110
  grpc_port: int = 50051,
107
111
  grpc_secure: bool = False,
108
- ):
112
+ ) -> None:
109
113
  """
110
114
  Create a new instance of WeaviateDocumentStore and connects to the Weaviate instance.
111
115
 
@@ -267,7 +271,7 @@ class WeaviateDocumentStore:
267
271
  return self._async_client
268
272
 
269
273
  @property
270
- def collection(self):
274
+ def collection(self) -> Collection[dict[str, Any], None]:
271
275
  if self._collection:
272
276
  return self._collection
273
277
 
@@ -276,7 +280,7 @@ class WeaviateDocumentStore:
276
280
  return self._collection
277
281
 
278
282
  @property
279
- async def async_collection(self):
283
+ async def async_collection(self) -> CollectionAsync[dict[str, Any], None]:
280
284
  if self._async_collection:
281
285
  return self._async_collection
282
286
 
@@ -352,6 +356,14 @@ class WeaviateDocumentStore:
352
356
  total = self.collection.aggregate.over_all(total_count=True).total_count
353
357
  return total if total else 0
354
358
 
359
+ async def count_documents_async(self) -> int:
360
+ """
361
+ Asynchronously returns the number of documents present in the DocumentStore.
362
+ """
363
+ collection = await self.async_collection
364
+ total = (await collection.aggregate.over_all(total_count=True)).total_count
365
+ return total if total else 0
366
+
355
367
  def count_documents_by_filter(self, filters: dict[str, Any]) -> int:
356
368
  """
357
369
  Returns the number of documents that match the provided filters.
@@ -755,7 +767,7 @@ class WeaviateDocumentStore:
755
767
  return data
756
768
 
757
769
  @staticmethod
758
- def _to_document(data: DataObject[dict[str, Any], None]) -> Document:
770
+ def _to_document(data: Object[dict[str, Any], None]) -> Document:
759
771
  """
760
772
  Converts a data object read from Weaviate into a Document.
761
773
  """
@@ -793,7 +805,7 @@ class WeaviateDocumentStore:
793
805
 
794
806
  return Document.from_dict(document_data)
795
807
 
796
- def _query(self) -> list[DataObject[dict[str, Any], None]]:
808
+ def _query(self) -> _ObjectIterator[dict[str, Any], None]:
797
809
  properties = [p.name for p in self.collection.config.get().properties]
798
810
  try:
799
811
  result = self.collection.iterator(include_vector=True, return_properties=properties)
@@ -802,7 +814,17 @@ class WeaviateDocumentStore:
802
814
  raise DocumentStoreError(msg) from e
803
815
  return result
804
816
 
805
- def _query_with_filters(self, filters: dict[str, Any]) -> list[DataObject[dict[str, Any], None]]:
817
+ async def _query_async(self) -> _ObjectAIterator[dict[str, Any], None]:
818
+ collection = await self.async_collection
819
+ properties = [p.name for p in (await collection.config.get()).properties]
820
+ try:
821
+ result = collection.iterator(include_vector=True, return_properties=properties)
822
+ except weaviate.exceptions.WeaviateQueryError as e:
823
+ msg = f"Failed to query documents in Weaviate. Error: {e.message}"
824
+ raise DocumentStoreError(msg) from e
825
+ return result
826
+
827
+ def _query_with_filters(self, filters: dict[str, Any]) -> list[Object[dict[str, Any], None]]:
806
828
  properties = [p.name for p in self.collection.config.get().properties]
807
829
  # When querying with filters we need to paginate using limit and offset as using
808
830
  # a cursor with after is not possible. See the official docs:
@@ -833,6 +855,38 @@ class WeaviateDocumentStore:
833
855
  offset += DEFAULT_QUERY_LIMIT
834
856
  return result
835
857
 
858
+ async def _query_with_filters_async(self, filters: dict[str, Any]) -> list[Object[dict[str, Any], None]]:
859
+ collection = await self.async_collection
860
+ properties = [p.name for p in (await collection.config.get()).properties]
861
+ # When querying with filters we need to paginate using limit and offset as using
862
+ # a cursor with after is not possible. See the official docs:
863
+ # https://weaviate.io/developers/weaviate/api/graphql/additional-operators#cursor-with-after
864
+ #
865
+ # Nonetheless there's also another issue, paginating with limit and offset is not efficient
866
+ # and it's still restricted by the QUERY_MAXIMUM_RESULTS environment variable.
867
+ # If the sum of limit and offset is greater than QUERY_MAXIMUM_RESULTS an error is raised.
868
+ # See the official docs for more:
869
+ # https://weaviate.io/developers/weaviate/api/graphql/additional-operators#performance-considerations
870
+ offset = 0
871
+ partial_result = None
872
+ result = []
873
+ # Keep querying until we get all documents matching the filters
874
+ while partial_result is None or len(partial_result.objects) == DEFAULT_QUERY_LIMIT:
875
+ try:
876
+ partial_result = await collection.query.fetch_objects(
877
+ filters=convert_filters(filters),
878
+ include_vector=True,
879
+ limit=DEFAULT_QUERY_LIMIT,
880
+ offset=offset,
881
+ return_properties=properties,
882
+ )
883
+ except weaviate.exceptions.WeaviateQueryError as e:
884
+ msg = f"Failed to query documents in Weaviate. Error: {e.message}"
885
+ raise DocumentStoreError(msg) from e
886
+ result.extend(partial_result.objects)
887
+ offset += DEFAULT_QUERY_LIMIT
888
+ return result
889
+
836
890
  def filter_documents(self, filters: dict[str, Any] | None = None) -> list[Document]:
837
891
  """
838
892
  Returns the documents that match the filters provided.
@@ -852,9 +906,48 @@ class WeaviateDocumentStore:
852
906
  result = []
853
907
  if filters:
854
908
  result = self._query_with_filters(filters)
855
- else:
856
- result = self._query()
857
- return [WeaviateDocumentStore._to_document(doc) for doc in result]
909
+ return [WeaviateDocumentStore._to_document(doc) for doc in result]
910
+ result_iter = self._query()
911
+ return [WeaviateDocumentStore._to_document(doc) for doc in result_iter]
912
+
913
+ async def filter_documents_async(self, filters: dict[str, Any] | None = None) -> list[Document]:
914
+ """
915
+ Asynchronously returns the documents that match the filters provided.
916
+
917
+ For a detailed specification of the filters, refer to the
918
+ DocumentStore.filter_documents() protocol documentation.
919
+
920
+ Note: The ``contains`` filter operator is case-sensitive (substring
921
+ matching). For case-insensitive matching, normalize the value before
922
+ building the filter.
923
+
924
+ :param filters: The filters to apply to the document list.
925
+ :returns: A list of Documents that match the given filters.
926
+ """
927
+ validate_filters(filters)
928
+
929
+ result = []
930
+ if filters:
931
+ result = await self._query_with_filters_async(filters)
932
+ return [WeaviateDocumentStore._to_document(doc) for doc in result]
933
+ result_iter = await self._query_async()
934
+ return [WeaviateDocumentStore._to_document(doc) async for doc in result_iter]
935
+
936
+ @staticmethod
937
+ def _handle_failed_objects(failed_objects: list[ErrorObject]) -> NoReturn:
938
+ # We fall back to use the UUID if the _original_id is not present, this is just to be
939
+ mapped_objects = {}
940
+ for obj in failed_objects:
941
+ properties = obj.object_.properties or {}
942
+ # We get the object uuid just in case the _original_id is not present.
943
+ # That's extremely unlikely to happen but let's stay on the safe side.
944
+ id_ = properties.get("_original_id", obj.object_.uuid)
945
+ mapped_objects[id_] = obj.message
946
+
947
+ msg = "\n".join(
948
+ [f"Failed to write object with id '{id_}'. Error: '{message}'" for id_, message in mapped_objects.items()]
949
+ )
950
+ raise DocumentStoreError(msg)
858
951
 
859
952
  def _batch_write(self, documents: list[Document]) -> int:
860
953
  """
@@ -876,22 +969,35 @@ class WeaviateDocumentStore:
876
969
  vector=doc.embedding,
877
970
  )
878
971
  if failed_objects := self.client.batch.failed_objects:
879
- # We fall back to use the UUID if the _original_id is not present, this is just to be
880
- mapped_objects = {}
881
- for obj in failed_objects:
882
- properties = obj.object_.properties or {}
883
- # We get the object uuid just in case the _original_id is not present.
884
- # That's extremely unlikely to happen but let's stay on the safe side.
885
- id_ = properties.get("_original_id", obj.object_.uuid)
886
- mapped_objects[id_] = obj.message
887
-
888
- msg = "\n".join(
889
- [
890
- f"Failed to write object with id '{id_}'. Error: '{message}'"
891
- for id_, message in mapped_objects.items()
892
- ]
893
- )
894
- raise DocumentStoreError(msg)
972
+ self._handle_failed_objects(failed_objects)
973
+
974
+ # If the document already exists we get no status message back from Weaviate.
975
+ # So we assume that all Documents were written.
976
+ return len(documents)
977
+
978
+ async def _batch_write_async(self, documents: list[Document]) -> int:
979
+ """
980
+ Asynchronously writes document to Weaviate in batches.
981
+ Documents with the same id will be overwritten.
982
+ Raises in case of errors.
983
+ """
984
+ client = await self.async_client
985
+
986
+ async with client.batch.stream() as batch:
987
+ for doc in documents:
988
+ if not isinstance(doc, Document):
989
+ msg = f"Expected a Document, got '{type(doc)}' instead."
990
+ raise ValueError(msg)
991
+
992
+ await batch.add_object(
993
+ properties=WeaviateDocumentStore._to_data_object(doc),
994
+ collection=(await self.async_collection).name,
995
+ uuid=generate_uuid5(doc.id),
996
+ vector=doc.embedding,
997
+ )
998
+
999
+ if failed_objects := client.batch.failed_objects:
1000
+ self._handle_failed_objects(failed_objects)
895
1001
 
896
1002
  # If the document already exists we get no status message back from Weaviate.
897
1003
  # So we assume that all Documents were written.
@@ -931,6 +1037,43 @@ class WeaviateDocumentStore:
931
1037
  raise DuplicateDocumentError(msg)
932
1038
  return written
933
1039
 
1040
+ async def _write_async(self, documents: list[Document], policy: DuplicatePolicy) -> int:
1041
+ """
1042
+ Asynchronously writes documents to Weaviate using the specified policy.
1043
+ This doesn't use the batch API, so it's slower than _batch_write.
1044
+ If policy is set to SKIP it will skip any document that already exists.
1045
+ If policy is set to FAIL it will raise an exception if any of the documents already exists.
1046
+ """
1047
+ collection = await self.async_collection
1048
+
1049
+ duplicate_errors_ids = []
1050
+ for doc in documents:
1051
+ if not isinstance(doc, Document):
1052
+ msg = f"Expected a Document, got '{type(doc)}' instead."
1053
+ raise ValueError(msg)
1054
+
1055
+ if policy == DuplicatePolicy.SKIP and await (await self.async_collection).data.exists(
1056
+ uuid=generate_uuid5(doc.id)
1057
+ ):
1058
+ # This Document already exists, continue
1059
+ continue
1060
+
1061
+ try:
1062
+ await collection.data.insert(
1063
+ uuid=generate_uuid5(doc.id),
1064
+ properties=WeaviateDocumentStore._to_data_object(doc),
1065
+ vector=doc.embedding,
1066
+ )
1067
+
1068
+ except weaviate.exceptions.UnexpectedStatusCodeError:
1069
+ if policy == DuplicatePolicy.FAIL:
1070
+ duplicate_errors_ids.append(doc.id)
1071
+
1072
+ if duplicate_errors_ids:
1073
+ msg = f"IDs '{', '.join(duplicate_errors_ids)}' already exist in the document store."
1074
+ raise DuplicateDocumentError(msg)
1075
+ return len(documents)
1076
+
934
1077
  def write_documents(self, documents: list[Document], policy: DuplicatePolicy = DuplicatePolicy.NONE) -> int:
935
1078
  """
936
1079
  Writes documents to Weaviate using the specified policy.
@@ -939,12 +1082,59 @@ class WeaviateDocumentStore:
939
1082
  We can't use the batch API for other policies as it doesn't return any information whether the document
940
1083
  already exists or not. That prevents us from returning errors when using the FAIL policy or skipping a
941
1084
  Document when using the SKIP policy.
1085
+
1086
+ :param documents:
1087
+ A list of documents to write into the document store.
1088
+ :param policy:
1089
+ DuplicatePolicy to apply when a document with the same ID already exists in the document store.
1090
+
1091
+ :raises ValueError:
1092
+ When input is not valid.
1093
+ :raises DuplicateDocumentError:
1094
+ When duplicate documents are found and using a FAIL policy.
1095
+ :raises DocumentStoreError:
1096
+ When documents have failed to be batch written.
1097
+
1098
+ :returns:
1099
+ The number of documents written.
942
1100
  """
943
1101
  if policy in [DuplicatePolicy.NONE, DuplicatePolicy.OVERWRITE]:
944
1102
  return self._batch_write(documents)
945
1103
 
946
1104
  return self._write(documents, policy)
947
1105
 
1106
+ async def write_documents_async(
1107
+ self, documents: list[Document], policy: DuplicatePolicy = DuplicatePolicy.NONE
1108
+ ) -> int:
1109
+ """
1110
+ Asynchronously writes documents to Weaviate using the specified policy.
1111
+ We recommend using a OVERWRITE policy as it's faster than other policies for Weaviate since it uses
1112
+ the batch API.
1113
+ We can't use the batch API for other policies as it doesn't return any information whether the document
1114
+ already exists or not. That prevents us from returning errors when using the FAIL policy or skipping a
1115
+ Document when using the SKIP policy.
1116
+
1117
+
1118
+ :param documents:
1119
+ A list of documents to write into the document store.
1120
+ :param policy:
1121
+ DuplicatePolicy to apply when a document with the same ID already exists in the document store.
1122
+
1123
+ :raises ValueError:
1124
+ When input is not valid.
1125
+ :raises DuplicateDocumentError:
1126
+ When duplicate documents are found and using a FAIL policy.
1127
+ :raises DocumentStoreError:
1128
+ When documents have failed to be batch written.
1129
+
1130
+ :returns:
1131
+ The number of documents written.
1132
+ """
1133
+ if policy in [DuplicatePolicy.NONE, DuplicatePolicy.OVERWRITE]:
1134
+ return await self._batch_write_async(documents)
1135
+
1136
+ return await self._write_async(documents, policy)
1137
+
948
1138
  def delete_documents(self, document_ids: list[str]) -> None:
949
1139
  """
950
1140
  Deletes all documents with matching document_ids from the DocumentStore.
@@ -954,6 +1144,16 @@ class WeaviateDocumentStore:
954
1144
  weaviate_ids = [generate_uuid5(doc_id) for doc_id in document_ids]
955
1145
  self.collection.data.delete_many(where=weaviate.classes.query.Filter.by_id().contains_any(weaviate_ids))
956
1146
 
1147
+ async def delete_documents_async(self, document_ids: list[str]) -> None:
1148
+ """
1149
+ Asynchronously deletes all documents with matching document_ids from the DocumentStore.
1150
+
1151
+ :param document_ids: The object_ids to delete.
1152
+ """
1153
+ weaviate_ids = [generate_uuid5(doc_id) for doc_id in document_ids]
1154
+ collection = await self.async_collection
1155
+ await collection.data.delete_many(where=weaviate.classes.query.Filter.by_id().contains_any(weaviate_ids))
1156
+
957
1157
  def delete_all_documents(self, *, recreate_index: bool = False, batch_size: int = 1000) -> None:
958
1158
  """
959
1159
  Deletes all documents in a collection.
@@ -1003,6 +1203,57 @@ class WeaviateDocumentStore:
1003
1203
  "Make sure to specify a deletion `batch_size` which is less than `QUERY_MAXIMUM_RESULTS`.",
1004
1204
  )
1005
1205
 
1206
+ async def delete_all_documents_async(self, *, recreate_index: bool = False, batch_size: int = 1000) -> None:
1207
+ """
1208
+ Asynchronously deletes all documents in a collection.
1209
+
1210
+ If recreate_index is False, it keeps the collection but deletes documents iteratively.
1211
+ If recreate_index is True, the collection is dropped and faithfully recreated.
1212
+ This is recommended for performance reasons.
1213
+
1214
+ :param recreate_index: Use drop and recreate strategy. (recommended for performance)
1215
+ :param batch_size: Only relevant if recreate_index is false. Defines the deletion batch size.
1216
+ Note that this parameter needs to be less or equal to the set `QUERY_MAXIMUM_RESULTS` variable
1217
+ set for the weaviate deployment (default is 10000).
1218
+ Reference: https://docs.weaviate.io/weaviate/manage-objects/delete#delete-all-objects
1219
+ """
1220
+ client = await self.async_client
1221
+
1222
+ if recreate_index:
1223
+ # get current up-to-date config from server, so we can recreate the collection faithfully
1224
+ cfg = (await client.collections.get(self._collection_settings["class"]).config.get()).to_dict()
1225
+ class_name = cfg.get("class", self._collection_settings["class"])
1226
+
1227
+ await client.collections.delete(class_name)
1228
+ await client.collections.create_from_dict(cfg)
1229
+
1230
+ self._collection_settings = cfg
1231
+ self._async_collection = client.collections.get(class_name)
1232
+ return
1233
+
1234
+ uuids = []
1235
+ batch_size = max(1, int(batch_size))
1236
+
1237
+ collection = await self.async_collection
1238
+ async for obj in collection.iterator(return_properties=[], include_vector=False):
1239
+ uuids.append(obj.uuid)
1240
+ if len(uuids) >= batch_size:
1241
+ res = await collection.data.delete_many(where=weaviate.classes.query.Filter.by_id().contains_any(uuids))
1242
+ if res.successful < len(uuids):
1243
+ logger.warning(
1244
+ "Not all documents in the batch have been deleted. "
1245
+ "Make sure to specify a deletion `batch_size` which is less than `QUERY_MAXIMUM_RESULTS`.",
1246
+ )
1247
+ uuids.clear()
1248
+
1249
+ if uuids:
1250
+ res = await collection.data.delete_many(where=weaviate.classes.query.Filter.by_id().contains_any(uuids))
1251
+ if res.successful < len(uuids):
1252
+ logger.warning(
1253
+ "Not all documents have been deleted. "
1254
+ "Make sure to specify a deletion `batch_size` which is less than `QUERY_MAXIMUM_RESULTS`.",
1255
+ )
1256
+
1006
1257
  def delete_by_filter(self, filters: dict[str, Any]) -> int:
1007
1258
  """
1008
1259
  Deletes all documents that match the provided filters.
@@ -1095,11 +1346,9 @@ class WeaviateDocumentStore:
1095
1346
 
1096
1347
  # Update the object, preserving the vector
1097
1348
  # Get the vector from the object to preserve it during replace
1098
- vector = None
1099
- if isinstance(obj.vector, list):
1349
+ vector: VECTORS | None = None
1350
+ if isinstance(obj.vector, (list, dict)):
1100
1351
  vector = obj.vector
1101
- elif isinstance(obj.vector, dict):
1102
- vector = obj.vector.get("default")
1103
1352
 
1104
1353
  self.collection.data.replace(
1105
1354
  uuid=obj.uuid,
@@ -1191,11 +1440,9 @@ class WeaviateDocumentStore:
1191
1440
 
1192
1441
  # Update the object, preserving the vector
1193
1442
  # Get the vector from the object to preserve it during replace
1194
- vector = None
1195
- if isinstance(obj.vector, list):
1443
+ vector: VECTORS | None = None
1444
+ if isinstance(obj.vector, (list, dict)):
1196
1445
  vector = obj.vector
1197
- elif isinstance(obj.vector, dict):
1198
- vector = obj.vector.get("default")
1199
1446
 
1200
1447
  await collection.data.replace(
1201
1448
  uuid=obj.uuid,
@@ -1322,7 +1569,7 @@ class WeaviateDocumentStore:
1322
1569
  query_embedding: list[float],
1323
1570
  filters: dict[str, Any] | None = None,
1324
1571
  top_k: int | None = None,
1325
- alpha: float | None = None,
1572
+ alpha: float = 0.7,
1326
1573
  max_vector_distance: float | None = None,
1327
1574
  ) -> list[Document]:
1328
1575
  properties = [p.name for p in self.collection.config.get().properties]
@@ -1347,7 +1594,7 @@ class WeaviateDocumentStore:
1347
1594
  query_embedding: list[float],
1348
1595
  filters: dict[str, Any] | None = None,
1349
1596
  top_k: int | None = None,
1350
- alpha: float | None = None,
1597
+ alpha: float = 0.7,
1351
1598
  max_vector_distance: float | None = None,
1352
1599
  ) -> list[Document]:
1353
1600
  collection = await self.async_collection
@@ -2,11 +2,15 @@
2
2
  #
3
3
  # SPDX-License-Identifier: Apache-2.0
4
4
 
5
+ import logging
5
6
  from collections.abc import AsyncGenerator
7
+ from pathlib import Path
6
8
 
7
9
  import pytest
8
10
  import pytest_asyncio
11
+ from haystack.dataclasses.byte_stream import ByteStream
9
12
  from haystack.dataclasses.document import Document
13
+ from haystack.document_stores.errors import DocumentStoreError
10
14
 
11
15
  from haystack_integrations.document_stores.weaviate import WeaviateDocumentStore
12
16
  from haystack_integrations.document_stores.weaviate.document_store import DOCUMENT_COLLECTION_PROPERTIES
@@ -31,8 +35,7 @@ class TestWeaviateDocumentStoreAsync:
31
35
  collection_settings=collection_settings,
32
36
  )
33
37
  yield store
34
- store.client.collections.delete(collection_settings["class"])
35
- store.close()
38
+ await (await store.async_client).collections.delete(collection_settings["class"])
36
39
  await store.close_async()
37
40
 
38
41
  @pytest.mark.asyncio
@@ -50,20 +53,68 @@ class TestWeaviateDocumentStoreAsync:
50
53
  assert await document_store.async_client is not None
51
54
  assert await document_store.async_collection is not None
52
55
 
53
- document_store.write_documents(
54
- [
55
- Document(content="Haskell is a functional programming language"),
56
- Document(content="Lisp is a functional programming language"),
57
- Document(content="Python is an object oriented programming language"),
58
- ]
56
+ assert await document_store.count_documents_async() == 0
57
+
58
+ @pytest.mark.asyncio
59
+ async def test_filter_documents_with_blob_data_async(
60
+ self, document_store: WeaviateDocumentStore, test_files_path: Path
61
+ ) -> None:
62
+ image = ByteStream.from_file_path(test_files_path / "robot1.jpg", mime_type="image/jpeg")
63
+ doc = Document(content="test doc", blob=image)
64
+ assert await document_store.write_documents_async([doc]) == 1
65
+
66
+ docs = await document_store.filter_documents_async()
67
+
68
+ assert len(docs) == 1
69
+ assert docs[0].blob == image
70
+
71
+ @pytest.mark.asyncio
72
+ async def test_filter_documents_below_default_limit_async(self, document_store: WeaviateDocumentStore) -> None:
73
+ docs = []
74
+ for index in range(9998):
75
+ docs.append(Document(content="This is some content", meta={"index": index}))
76
+ await document_store.write_documents_async(docs)
77
+ result = await document_store.filter_documents_async(
78
+ {"field": "content", "operator": "==", "value": "This is some content"}
59
79
  )
60
- filters = {"field": "content", "operator": "==", "value": "Haskell"}
61
80
 
62
- assert await document_store.count_documents_by_filter_async(filters) == 1
81
+ assert len(result) == 9998
82
+
83
+ @pytest.mark.asyncio
84
+ async def test_filter_documents_over_default_limit(self, document_store: WeaviateDocumentStore) -> None:
85
+ docs = []
86
+ for index in range(10000):
87
+ docs.append(Document(content="This is some content", meta={"index": index}))
88
+ await document_store.write_documents_async(docs)
89
+ with pytest.raises(DocumentStoreError):
90
+ await document_store.filter_documents_async(
91
+ {"field": "content", "operator": "==", "value": "This is some content"}
92
+ )
93
+
94
+ @pytest.mark.asyncio
95
+ async def test_write_documents_async(self, document_store: WeaviateDocumentStore) -> None:
96
+ """
97
+ Test write_documents() with default policy overwrites existing documents.
98
+ """
99
+ doc = Document(content="test doc")
100
+ assert await document_store.write_documents_async([doc]) == 1
101
+ assert await document_store.count_documents_async() == 1
102
+
103
+ doc.content = "test doc 2"
104
+ assert await document_store.write_documents_async([doc]) == 1
105
+ assert await document_store.count_documents_async() == 1
106
+
107
+ @pytest.mark.asyncio
108
+ async def test_write_documents_with_blob_data_async(
109
+ self, document_store: WeaviateDocumentStore, test_files_path: Path
110
+ ) -> None:
111
+ image = ByteStream.from_file_path(test_files_path / "robot1.jpg", mime_type="image/jpeg")
112
+ doc = Document(content="test doc", blob=image)
113
+ assert await document_store.write_documents_async([doc]) == 1
63
114
 
64
115
  @pytest.mark.asyncio
65
116
  async def test_bm25_retrieval_async(self, document_store):
66
- document_store.write_documents(
117
+ await document_store.write_documents_async(
67
118
  [
68
119
  Document(content="Haskell is a functional programming language"),
69
120
  Document(content="Lisp is a functional programming language"),
@@ -80,7 +131,7 @@ class TestWeaviateDocumentStoreAsync:
80
131
 
81
132
  @pytest.mark.asyncio
82
133
  async def test_bm25_retrieval_async_with_filters(self, document_store):
83
- document_store.write_documents(
134
+ await document_store.write_documents_async(
84
135
  [
85
136
  Document(content="Haskell is a functional programming language"),
86
137
  Document(content="Lisp is a functional programming language"),
@@ -96,7 +147,7 @@ class TestWeaviateDocumentStoreAsync:
96
147
 
97
148
  @pytest.mark.asyncio
98
149
  async def test_embedding_retrieval_async(self, document_store):
99
- document_store.write_documents(
150
+ await document_store.write_documents_async(
100
151
  [
101
152
  Document(content="The document", embedding=[1.0, 1.0, 1.0, 1.0]),
102
153
  Document(content="Another document", embedding=[0.8, 0.8, 0.8, 1.0]),
@@ -112,7 +163,7 @@ class TestWeaviateDocumentStoreAsync:
112
163
 
113
164
  @pytest.mark.asyncio
114
165
  async def test_embedding_retrieval_async_with_filters(self, document_store):
115
- document_store.write_documents(
166
+ await document_store.write_documents_async(
116
167
  [
117
168
  Document(content="The document I want", embedding=[1.0, 1.0, 1.0, 1.0]),
118
169
  Document(content="Another document", embedding=[0.8, 0.8, 0.8, 1.0]),
@@ -134,7 +185,7 @@ class TestWeaviateDocumentStoreAsync:
134
185
 
135
186
  @pytest.mark.asyncio
136
187
  async def test_hybrid_retrieval_async(self, document_store):
137
- document_store.write_documents(
188
+ await document_store.write_documents_async(
138
189
  [
139
190
  Document(content="Haskell is a functional programming language", embedding=[1.0, 0.8, 0.2, 0.1]),
140
191
  Document(content="Lisp is a functional programming language", embedding=[0.9, 0.7, 0.3, 0.2]),
@@ -154,7 +205,7 @@ class TestWeaviateDocumentStoreAsync:
154
205
 
155
206
  @pytest.mark.asyncio
156
207
  async def test_hybrid_retrieval_async_with_filters(self, document_store):
157
- document_store.write_documents(
208
+ await document_store.write_documents_async(
158
209
  [
159
210
  Document(content="Haskell is a functional programming language", embedding=[1.0, 0.8, 0.2, 0.1]),
160
211
  Document(content="Lisp is a functional programming language", embedding=[0.9, 0.7, 0.3, 0.2]),
@@ -173,7 +224,7 @@ class TestWeaviateDocumentStoreAsync:
173
224
 
174
225
  @pytest.mark.asyncio
175
226
  async def test_hybrid_retrieval_async_with_alpha(self, document_store):
176
- document_store.write_documents(
227
+ await document_store.write_documents_async(
177
228
  [
178
229
  Document(content="Haskell is a functional programming language", embedding=[1.0, 0.8, 0.2, 0.1]),
179
230
  Document(content="Python is an object oriented language", embedding=[0.1, 0.2, 0.8, 0.9]),
@@ -205,7 +256,7 @@ class TestWeaviateDocumentStoreAsync:
205
256
  Document(content="Doc 2", meta={"category": "TypeB"}),
206
257
  Document(content="Doc 3", meta={"category": "TypeA"}),
207
258
  ]
208
- document_store.write_documents(docs)
259
+ await document_store.write_documents_async(docs)
209
260
 
210
261
  # delete documents with category="TypeA"
211
262
  deleted_count = await document_store.delete_by_filter_async(
@@ -215,7 +266,7 @@ class TestWeaviateDocumentStoreAsync:
215
266
  assert document_store.count_documents() == 1
216
267
 
217
268
  # verify only category TypeB remains
218
- remaining_docs = document_store.filter_documents()
269
+ remaining_docs = await document_store.filter_documents_async()
219
270
  assert len(remaining_docs) == 1
220
271
  assert remaining_docs[0].meta["category"] == "TypeB"
221
272
 
@@ -226,7 +277,7 @@ class TestWeaviateDocumentStoreAsync:
226
277
  Document(content="Doc 2", meta={"category": "TypeB", "status": "draft"}),
227
278
  Document(content="Doc 3", meta={"category": "TypeA", "status": "draft"}),
228
279
  ]
229
- document_store.write_documents(docs)
280
+ await document_store.write_documents_async(docs)
230
281
  assert document_store.count_documents() == 3
231
282
 
232
283
  # update status for category="TypeA" documents
@@ -236,7 +287,7 @@ class TestWeaviateDocumentStoreAsync:
236
287
  assert updated_count == 2
237
288
 
238
289
  # Verify the updates
239
- published_docs = document_store.filter_documents(
290
+ published_docs = await document_store.filter_documents_async(
240
291
  filters={"field": "meta.status", "operator": "==", "value": "published"}
241
292
  )
242
293
  assert len(published_docs) == 2
@@ -257,7 +308,7 @@ class TestWeaviateDocumentStoreAsync:
257
308
  meta={"index": index, "status": "draft", "category": "test"},
258
309
  )
259
310
  )
260
- document_store.write_documents(docs)
311
+ await document_store.write_documents_async(docs)
261
312
 
262
313
  # update all documents should trigger pagination (3 pages)
263
314
  updated_count = await document_store.update_by_filter_async(
@@ -266,7 +317,7 @@ class TestWeaviateDocumentStoreAsync:
266
317
  )
267
318
  assert updated_count == 250
268
319
 
269
- published_docs = document_store.filter_documents(
320
+ published_docs = await document_store.filter_documents_async(
270
321
  filters={"field": "status", "operator": "==", "value": "published"}
271
322
  )
272
323
  assert len(published_docs) == 250
@@ -276,6 +327,17 @@ class TestWeaviateDocumentStoreAsync:
276
327
  assert "index" in doc.meta
277
328
  assert 0 <= doc.meta["index"] < 250
278
329
 
330
+ @pytest.mark.asyncio
331
+ async def test_count_documents_async(self, document_store: WeaviateDocumentStore) -> None:
332
+ docs = [
333
+ Document(content="Doc 1", meta={"category": "TypeA"}),
334
+ Document(content="Doc 2", meta={"category": "TypeB"}),
335
+ Document(content="Doc 3", meta={"category": "TypeA"}),
336
+ Document(content="Doc 4", meta={"category": "TypeA"}),
337
+ ]
338
+ await document_store.write_documents_async(docs)
339
+ assert await document_store.count_documents_async() == 4
340
+
279
341
  @pytest.mark.asyncio
280
342
  async def test_count_documents_by_filter_async(self, document_store):
281
343
  docs = [
@@ -284,8 +346,8 @@ class TestWeaviateDocumentStoreAsync:
284
346
  Document(content="Doc 3", meta={"category": "TypeA"}),
285
347
  Document(content="Doc 4", meta={"category": "TypeA"}),
286
348
  ]
287
- document_store.write_documents(docs)
288
- assert document_store.count_documents() == 4
349
+ await document_store.write_documents_async(docs)
350
+ assert await document_store.count_documents_async() == 4
289
351
 
290
352
  count = await document_store.count_documents_by_filter_async(
291
353
  filters={"field": "meta.category", "operator": "==", "value": "TypeA"}
@@ -325,7 +387,7 @@ class TestWeaviateDocumentStoreAsync:
325
387
  Document(content="Doc 3", meta={"number": 20}),
326
388
  Document(content="Doc 4", meta={"number": 15}),
327
389
  ]
328
- document_store.write_documents(docs)
390
+ await document_store.write_documents_async(docs)
329
391
 
330
392
  result = await document_store.get_metadata_field_min_max_async("number")
331
393
  assert result["min"] == 5
@@ -337,7 +399,7 @@ class TestWeaviateDocumentStoreAsync:
337
399
  Document(content="Doc 1", meta={"number": 100}),
338
400
  Document(content="Doc 2", meta={"number": 200}),
339
401
  ]
340
- document_store.write_documents(docs)
402
+ await document_store.write_documents_async(docs)
341
403
 
342
404
  result = await document_store.get_metadata_field_min_max_async("meta.number")
343
405
  assert result["min"] == 100
@@ -362,7 +424,7 @@ class TestWeaviateDocumentStoreAsync:
362
424
  Document(content="Doc 4", meta={"category": "TypeC", "status": "published"}),
363
425
  Document(content="Doc 5", meta={"category": "TypeA", "status": "archived"}),
364
426
  ]
365
- document_store.write_documents(docs)
427
+ await document_store.write_documents_async(docs)
366
428
 
367
429
  result = await document_store.count_unique_metadata_by_filter_async(
368
430
  filters={"field": "meta.category", "operator": "==", "value": "TypeA"}, metadata_fields=["status"]
@@ -388,7 +450,7 @@ class TestWeaviateDocumentStoreAsync:
388
450
  Document(content="Doc 1", meta={"category": "TypeA"}),
389
451
  Document(content="Doc 2", meta={"category": "TypeB"}),
390
452
  ]
391
- document_store.write_documents(docs)
453
+ await document_store.write_documents_async(docs)
392
454
 
393
455
  result = await document_store.count_unique_metadata_by_filter_async(
394
456
  filters={"field": "meta.category", "operator": "in", "value": ["TypeA", "TypeB"]},
@@ -401,7 +463,7 @@ class TestWeaviateDocumentStoreAsync:
401
463
  docs = [
402
464
  Document(content="Doc 1", meta={"category": "TypeA"}),
403
465
  ]
404
- document_store.write_documents(docs)
466
+ await document_store.write_documents_async(docs)
405
467
 
406
468
  result = await document_store.count_unique_metadata_by_filter_async(
407
469
  filters={"field": "meta.category", "operator": "==", "value": "NonExistent"},
@@ -426,7 +488,7 @@ class TestWeaviateDocumentStoreAsync:
426
488
  Document(content="Doc 4", meta={"category": "TypeC"}),
427
489
  Document(content="Doc 5", meta={"category": "TypeB"}),
428
490
  ]
429
- document_store.write_documents(docs)
491
+ await document_store.write_documents_async(docs)
430
492
 
431
493
  values, total_count = await document_store.get_metadata_field_unique_values_async("category")
432
494
  assert total_count == 3
@@ -438,7 +500,7 @@ class TestWeaviateDocumentStoreAsync:
438
500
  Document(content="Doc 1", meta={"category": "TypeA"}),
439
501
  Document(content="Doc 2", meta={"category": "TypeB"}),
440
502
  ]
441
- document_store.write_documents(docs)
503
+ await document_store.write_documents_async(docs)
442
504
 
443
505
  values, total_count = await document_store.get_metadata_field_unique_values_async("meta.category")
444
506
  assert total_count == 2
@@ -452,7 +514,7 @@ class TestWeaviateDocumentStoreAsync:
452
514
  Document(content="Python is great", meta={"category": "TypeC"}),
453
515
  Document(content="JavaScript tutorial", meta={"category": "TypeD"}),
454
516
  ]
455
- document_store.write_documents(docs)
517
+ await document_store.write_documents_async(docs)
456
518
 
457
519
  values, total_count = await document_store.get_metadata_field_unique_values_async(
458
520
  "category", search_term="Python"
@@ -469,7 +531,7 @@ class TestWeaviateDocumentStoreAsync:
469
531
  Document(content="Doc 4", meta={"category": "TypeD"}),
470
532
  Document(content="Doc 5", meta={"category": "TypeE"}),
471
533
  ]
472
- document_store.write_documents(docs)
534
+ await document_store.write_documents_async(docs)
473
535
 
474
536
  values, total_count = await document_store.get_metadata_field_unique_values_async("category", from_=0, size=2)
475
537
  assert total_count == 5
@@ -491,3 +553,39 @@ class TestWeaviateDocumentStoreAsync:
491
553
  values, total_count = await document_store.get_metadata_field_unique_values_async("category")
492
554
  assert total_count == 0
493
555
  assert values == []
556
+
557
+ @pytest.mark.asyncio
558
+ async def test_delete_all_documents_recreate_async(self, document_store: WeaviateDocumentStore) -> None:
559
+ docs = [Document(content="test doc 1"), Document(content="test doc 2")]
560
+ assert await document_store.write_documents_async(docs) == 2
561
+ assert await document_store.count_documents_async() == 2
562
+
563
+ cls = document_store._collection_settings["class"]
564
+ collection = (await document_store.async_client).collections.get(cls)
565
+ previous_config = (await collection.config.get()).to_dict()
566
+
567
+ await document_store.delete_all_documents_async(recreate_index=True)
568
+ assert await document_store.count_documents_async() == 0
569
+
570
+ new_config = (await (await document_store.async_client).collections.get(cls).config.get()).to_dict()
571
+ assert previous_config == new_config
572
+
573
+ @pytest.mark.asyncio
574
+ async def test_delete_all_documents_batch_size_async(self, document_store: WeaviateDocumentStore) -> None:
575
+ docs = [Document(content=str(i)) for i in range(0, 5)]
576
+ assert await document_store.write_documents_async(docs) == 5
577
+ await document_store.delete_all_documents_async(batch_size=2)
578
+ assert await document_store.count_documents_async() == 0
579
+
580
+ @pytest.mark.asyncio
581
+ async def test_delete_all_documents_excessive_batch_size_async(
582
+ self, document_store: WeaviateDocumentStore, caplog: pytest.LogCaptureFixture
583
+ ) -> None:
584
+ """Test that the deletion is not complete if the batch size exceeds the QUERY_MAXIMUM_RESULTS."""
585
+ # assume QUERY_MAXIMUM_RESULTS == 10000 with standard deployment
586
+ docs = [Document(content=str(i)) for i in range(0, 10005)]
587
+ assert await document_store.write_documents_async(docs) == 10005
588
+ with caplog.at_level(logging.WARNING):
589
+ await document_store.delete_all_documents_async(batch_size=20000)
590
+ assert await document_store.count_documents_async() == 5
591
+ assert "Not all documents have been deleted." in caplog.text
@@ -17,7 +17,7 @@ def test_init_default():
17
17
  assert retriever._document_store == mock_document_store
18
18
  assert retriever._filters == {}
19
19
  assert retriever._top_k == 10
20
- assert retriever._alpha is None
20
+ assert retriever._alpha == 0.7
21
21
  assert retriever._max_vector_distance is None
22
22
  assert retriever._filter_policy == FilterPolicy.REPLACE
23
23
 
@@ -56,7 +56,7 @@ def test_to_dict(_mock_weaviate):
56
56
  "init_parameters": {
57
57
  "filters": {},
58
58
  "top_k": 10,
59
- "alpha": None,
59
+ "alpha": 0.7,
60
60
  "max_vector_distance": None,
61
61
  "filter_policy": "replace",
62
62
  "document_store": {
@@ -112,7 +112,7 @@ def test_from_dict(_mock_weaviate):
112
112
  "init_parameters": {
113
113
  "filters": {},
114
114
  "top_k": 10,
115
- "alpha": None,
115
+ "alpha": 0.7,
116
116
  "max_vector_distance": None,
117
117
  "filter_policy": "replace",
118
118
  "document_store": {
@@ -142,7 +142,7 @@ def test_from_dict(_mock_weaviate):
142
142
  assert retriever._document_store
143
143
  assert retriever._filters == {}
144
144
  assert retriever._top_k == 10
145
- assert retriever._alpha is None
145
+ assert retriever._alpha == 0.7
146
146
  assert retriever._max_vector_distance is None
147
147
 
148
148
 
@@ -200,7 +200,12 @@ def test_run_basic():
200
200
  assert "documents" in result
201
201
  assert len(result["documents"]) == 1
202
202
  mock_document_store._hybrid_retrieval.assert_called_once_with(
203
- query="test query", query_embedding=[0.1, 0.2, 0.3], filters={}, top_k=10, alpha=None, max_vector_distance=None
203
+ query="test query",
204
+ query_embedding=[0.1, 0.2, 0.3],
205
+ filters={},
206
+ top_k=10,
207
+ alpha=0.7,
208
+ max_vector_distance=None,
204
209
  )
205
210
 
206
211
 
@@ -217,7 +222,7 @@ def test_run_with_runtime_filters():
217
222
  query_embedding=[0.1, 0.2, 0.3],
218
223
  filters={"runtime": "filter"},
219
224
  top_k=10,
220
- alpha=None,
225
+ alpha=0.7,
221
226
  max_vector_distance=None,
222
227
  )
223
228
 
@@ -259,7 +264,7 @@ def test_run_empty_query():
259
264
  assert "documents" in result
260
265
  assert len(result["documents"]) == 0
261
266
  mock_document_store._hybrid_retrieval.assert_called_once_with(
262
- query="", query_embedding=[0.1, 0.2, 0.3], filters={}, top_k=10, alpha=None, max_vector_distance=None
267
+ query="", query_embedding=[0.1, 0.2, 0.3], filters={}, top_k=10, alpha=0.7, max_vector_distance=None
263
268
  )
264
269
 
265
270
 
@@ -288,7 +293,7 @@ def test_from_dict_no_filter_policy(_mock_weaviate):
288
293
  "init_parameters": {
289
294
  "filters": {},
290
295
  "top_k": 10,
291
- "alpha": None,
296
+ "alpha": 0.7,
292
297
  "max_vector_distance": None,
293
298
  # filter_policy intentionally omitted
294
299
  "document_store": {
@@ -318,7 +323,7 @@ def test_from_dict_no_filter_policy(_mock_weaviate):
318
323
  assert retriever._document_store
319
324
  assert retriever._filters == {}
320
325
  assert retriever._top_k == 10
321
- assert retriever._alpha is None
326
+ assert retriever._alpha == 0.7
322
327
  assert retriever._max_vector_distance is None
323
328
  assert retriever._filter_policy == FilterPolicy.REPLACE
324
329
 
@@ -381,7 +386,7 @@ def test_run_with_max_vector_distance_zero_runtime():
381
386
  query_embedding=[0.1, 0.2],
382
387
  filters={},
383
388
  top_k=10,
384
- alpha=None,
389
+ alpha=0.7,
385
390
  max_vector_distance=0.0,
386
391
  )
387
392
 
@@ -402,7 +407,7 @@ def test_run_with_max_vector_distance_zero_init_and_none_runtime():
402
407
  query_embedding=[0.1, 0.2],
403
408
  filters={},
404
409
  top_k=10,
405
- alpha=None,
410
+ alpha=0.7,
406
411
  max_vector_distance=0.0,
407
412
  )
408
413