chroma-haystack 4.3.2__tar.gz → 4.4.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.
- {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/CHANGELOG.md +7 -0
- {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/PKG-INFO +1 -1
- {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/src/haystack_integrations/components/retrievers/chroma/retriever.py +12 -0
- {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/src/haystack_integrations/document_stores/chroma/document_store.py +32 -24
- {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/tests/test_document_store.py +85 -6
- {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/tests/test_document_store_async.py +34 -0
- {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/tests/test_retriever.py +18 -0
- {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/.gitignore +0 -0
- {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/LICENSE +0 -0
- {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/README.md +0 -0
- {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/example/data/usr_01.txt +0 -0
- {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/example/data/usr_02.txt +0 -0
- {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/example/data/usr_03.txt +0 -0
- {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/example/data/usr_04.txt +0 -0
- {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/example/data/usr_05.txt +0 -0
- {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/example/data/usr_06.txt +0 -0
- {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/example/data/usr_07.txt +0 -0
- {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/example/data/usr_08.txt +0 -0
- {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/example/data/usr_09.txt +0 -0
- {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/example/data/usr_10.txt +0 -0
- {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/example/data/usr_11.txt +0 -0
- {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/example/data/usr_12.txt +0 -0
- {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/example/data/usr_20.txt +0 -0
- {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/example/data/usr_21.txt +0 -0
- {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/example/data/usr_22.txt +0 -0
- {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/example/data/usr_23.txt +0 -0
- {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/example/data/usr_24.txt +0 -0
- {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/example/data/usr_25.txt +0 -0
- {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/example/data/usr_26.txt +0 -0
- {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/example/data/usr_27.txt +0 -0
- {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/example/data/usr_28.txt +0 -0
- {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/example/data/usr_29.txt +0 -0
- {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/example/data/usr_30.txt +0 -0
- {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/example/data/usr_31.txt +0 -0
- {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/example/data/usr_32.txt +0 -0
- {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/example/data/usr_40.txt +0 -0
- {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/example/data/usr_41.txt +0 -0
- {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/example/data/usr_42.txt +0 -0
- {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/example/data/usr_43.txt +0 -0
- {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/example/data/usr_44.txt +0 -0
- {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/example/data/usr_45.txt +0 -0
- {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/example/data/usr_46.txt +0 -0
- {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/example/data/usr_50.txt +0 -0
- {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/example/data/usr_51.txt +0 -0
- {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/example/data/usr_52.txt +0 -0
- {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/example/data/usr_90.txt +0 -0
- {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/example/example.py +0 -0
- {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/pydoc/config_docusaurus.yml +0 -0
- {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/pyproject.toml +0 -0
- {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/src/haystack_integrations/components/retrievers/chroma/__init__.py +0 -0
- {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/src/haystack_integrations/components/retrievers/py.typed +0 -0
- {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/src/haystack_integrations/document_stores/chroma/__init__.py +0 -0
- {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/src/haystack_integrations/document_stores/chroma/errors.py +0 -0
- {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/src/haystack_integrations/document_stores/chroma/filters.py +0 -0
- {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/src/haystack_integrations/document_stores/chroma/utils.py +0 -0
- {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/src/haystack_integrations/document_stores/py.typed +0 -0
- {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/tests/__init__.py +0 -0
- {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/tests/conftest.py +0 -0
- {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/tests/test_filters.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: chroma-haystack
|
|
3
|
-
Version: 4.
|
|
3
|
+
Version: 4.4.0
|
|
4
4
|
Project-URL: Documentation, https://github.com/deepset-ai/haystack-core-integrations/tree/main/integrations/chroma#readme
|
|
5
5
|
Project-URL: Issues, https://github.com/deepset-ai/haystack-core-integrations/issues
|
|
6
6
|
Project-URL: Source, https://github.com/deepset-ai/haystack-core-integrations/tree/main/integrations/chroma
|
|
@@ -119,6 +119,12 @@ class ChromaQueryTextRetriever:
|
|
|
119
119
|
top_k = top_k or self.top_k
|
|
120
120
|
return {"documents": (await self.document_store.search_async([query], top_k, filters))[0]}
|
|
121
121
|
|
|
122
|
+
def close(self) -> None:
|
|
123
|
+
"""
|
|
124
|
+
Release the synchronous resources of the underlying Document Store.
|
|
125
|
+
"""
|
|
126
|
+
self.document_store.close()
|
|
127
|
+
|
|
122
128
|
@classmethod
|
|
123
129
|
def from_dict(cls, data: dict[str, Any]) -> "ChromaQueryTextRetriever":
|
|
124
130
|
"""
|
|
@@ -238,6 +244,12 @@ class ChromaEmbeddingRetriever:
|
|
|
238
244
|
query_embeddings = [query_embedding]
|
|
239
245
|
return {"documents": (await self.document_store.search_embeddings_async(query_embeddings, top_k, filters))[0]}
|
|
240
246
|
|
|
247
|
+
def close(self) -> None:
|
|
248
|
+
"""
|
|
249
|
+
Release the synchronous resources of the underlying Document Store.
|
|
250
|
+
"""
|
|
251
|
+
self.document_store.close()
|
|
252
|
+
|
|
241
253
|
@classmethod
|
|
242
254
|
def from_dict(cls, data: dict[str, Any]) -> "ChromaEmbeddingRetriever":
|
|
243
255
|
"""
|
|
@@ -3,9 +3,11 @@
|
|
|
3
3
|
# SPDX-License-Identifier: Apache-2.0
|
|
4
4
|
|
|
5
5
|
from collections.abc import Sequence
|
|
6
|
+
from contextlib import suppress
|
|
6
7
|
from typing import Any, Literal, cast
|
|
7
8
|
|
|
8
9
|
import chromadb
|
|
10
|
+
from chromadb.api import ClientAPI
|
|
9
11
|
from chromadb.api.models.AsyncCollection import AsyncCollection
|
|
10
12
|
from chromadb.api.types import GetResult, Metadata, OneOrMany, QueryResult
|
|
11
13
|
from chromadb.config import Settings
|
|
@@ -101,6 +103,7 @@ class ChromaDocumentStore:
|
|
|
101
103
|
self._host = host
|
|
102
104
|
self._port = port
|
|
103
105
|
|
|
106
|
+
self._client: ClientAPI | None = None
|
|
104
107
|
self._collection: chromadb.Collection | None = None
|
|
105
108
|
self._async_collection: AsyncCollection | None = None
|
|
106
109
|
|
|
@@ -138,7 +141,7 @@ class ChromaDocumentStore:
|
|
|
138
141
|
# Local persistent storage
|
|
139
142
|
client = chromadb.PersistentClient(path=self._persist_path, **client_kwargs)
|
|
140
143
|
|
|
141
|
-
self._client = client
|
|
144
|
+
self._client = client
|
|
142
145
|
|
|
143
146
|
# Build the collection metadata locally so `self._metadata` stays exactly as the user passed it.
|
|
144
147
|
# This keeps `to_dict()` deterministic and avoids mutating a user-supplied dict in place.
|
|
@@ -213,6 +216,15 @@ class ChromaDocumentStore:
|
|
|
213
216
|
embedding_function=self._embedding_func,
|
|
214
217
|
)
|
|
215
218
|
|
|
219
|
+
def close(self) -> None:
|
|
220
|
+
"""Release the associated synchronous resources."""
|
|
221
|
+
if self._client is not None:
|
|
222
|
+
with suppress(Exception):
|
|
223
|
+
# `close` is not declared on the `ClientAPI` interface, but the concrete Chroma clients implement it
|
|
224
|
+
self._client.close() # type: ignore[attr-defined]
|
|
225
|
+
self._client = None
|
|
226
|
+
self._collection = None
|
|
227
|
+
|
|
216
228
|
@staticmethod
|
|
217
229
|
def _prepare_get_kwargs(filters: dict[str, Any] | None = None) -> dict[str, Any]:
|
|
218
230
|
"""
|
|
@@ -356,7 +368,8 @@ class ChromaDocumentStore:
|
|
|
356
368
|
|
|
357
369
|
:param result: The full GetResult from a Chroma collection get operation.
|
|
358
370
|
:param field_name: The metadata field name to collect unique values for.
|
|
359
|
-
:param search_term: Optional search term to filter
|
|
371
|
+
:param search_term: Optional search term to filter by, matched as a case-insensitive
|
|
372
|
+
substring against the value of `field_name`.
|
|
360
373
|
:param from_: The offset to start returning values from.
|
|
361
374
|
:param size: The maximum number of unique values to return.
|
|
362
375
|
:returns: A tuple of the paginated unique values list and the total count.
|
|
@@ -367,13 +380,15 @@ class ChromaDocumentStore:
|
|
|
367
380
|
return [], 0
|
|
368
381
|
|
|
369
382
|
if search_term:
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
383
|
+
search_term_lower = search_term.lower()
|
|
384
|
+
metadatas = [
|
|
385
|
+
meta
|
|
386
|
+
for meta in metadatas
|
|
387
|
+
if meta
|
|
388
|
+
and field_name in meta
|
|
389
|
+
and meta.get(field_name) is not None
|
|
390
|
+
and search_term_lower in str(meta.get(field_name)).lower()
|
|
375
391
|
]
|
|
376
|
-
metadatas = filtered_metadatas
|
|
377
392
|
|
|
378
393
|
if not metadatas:
|
|
379
394
|
return [], 0
|
|
@@ -901,6 +916,7 @@ class ChromaDocumentStore:
|
|
|
901
916
|
"""
|
|
902
917
|
self._ensure_initialized() # _ensure_initialized ensures _client is not None and a collection exists
|
|
903
918
|
assert self._collection is not None
|
|
919
|
+
assert self._client is not None
|
|
904
920
|
|
|
905
921
|
try:
|
|
906
922
|
if recreate_index:
|
|
@@ -1294,12 +1310,12 @@ class ChromaDocumentStore:
|
|
|
1294
1310
|
size: int = 10,
|
|
1295
1311
|
) -> tuple[list[str], int]:
|
|
1296
1312
|
"""
|
|
1297
|
-
Return unique metadata field values, optionally filtered by a
|
|
1313
|
+
Return unique metadata field values, optionally filtered by a search term, with pagination.
|
|
1298
1314
|
|
|
1299
1315
|
:param metadata_field: The metadata field to get unique values for.
|
|
1300
1316
|
Can include or omit the "meta." prefix.
|
|
1301
|
-
:param search_term: Optional search term to filter
|
|
1302
|
-
|
|
1317
|
+
:param search_term: Optional search term to filter values, matched as a
|
|
1318
|
+
case-insensitive substring against the metadata field's value.
|
|
1303
1319
|
:param from_: The offset to start returning values from (for pagination).
|
|
1304
1320
|
:param size: The maximum number of unique values to return.
|
|
1305
1321
|
:returns: A tuple containing list of unique values and total count of unique values.
|
|
@@ -1309,11 +1325,7 @@ class ChromaDocumentStore:
|
|
|
1309
1325
|
|
|
1310
1326
|
field_name = _normalize_metadata_field_name(metadata_field)
|
|
1311
1327
|
|
|
1312
|
-
|
|
1313
|
-
if search_term:
|
|
1314
|
-
kwargs["include"] = ["metadatas", "documents"]
|
|
1315
|
-
|
|
1316
|
-
result = self._collection.get(**kwargs)
|
|
1328
|
+
result = self._collection.get(include=["metadatas"])
|
|
1317
1329
|
return self._compute_field_unique_values(result, field_name, search_term, from_, size)
|
|
1318
1330
|
|
|
1319
1331
|
async def get_metadata_field_unique_values_async(
|
|
@@ -1324,14 +1336,14 @@ class ChromaDocumentStore:
|
|
|
1324
1336
|
size: int = 10,
|
|
1325
1337
|
) -> tuple[list[str], int]:
|
|
1326
1338
|
"""
|
|
1327
|
-
Asynchronously return unique metadata field values, optionally filtered by
|
|
1339
|
+
Asynchronously return unique metadata field values, optionally filtered by a search term, with pagination.
|
|
1328
1340
|
|
|
1329
1341
|
Asynchronous methods are only supported for HTTP connections.
|
|
1330
1342
|
|
|
1331
1343
|
:param metadata_field: The metadata field to get unique values for.
|
|
1332
1344
|
Can include or omit the "meta." prefix.
|
|
1333
|
-
:param search_term: Optional search term to filter
|
|
1334
|
-
|
|
1345
|
+
:param search_term: Optional search term to filter values, matched as a
|
|
1346
|
+
case-insensitive substring against the metadata field's value.
|
|
1335
1347
|
:param from_: The offset to start returning values from (for pagination).
|
|
1336
1348
|
:param size: The maximum number of unique values to return.
|
|
1337
1349
|
:returns: A tuple containing list of unique values and total count of unique values.
|
|
@@ -1341,11 +1353,7 @@ class ChromaDocumentStore:
|
|
|
1341
1353
|
|
|
1342
1354
|
field_name = _normalize_metadata_field_name(metadata_field)
|
|
1343
1355
|
|
|
1344
|
-
|
|
1345
|
-
if search_term:
|
|
1346
|
-
kwargs["include"] = ["metadatas", "documents"]
|
|
1347
|
-
|
|
1348
|
-
result = await self._async_collection.get(**kwargs)
|
|
1356
|
+
result = await self._async_collection.get(include=["metadatas"])
|
|
1349
1357
|
return self._compute_field_unique_values(result, field_name, search_term, from_, size)
|
|
1350
1358
|
|
|
1351
1359
|
@classmethod
|
|
@@ -180,6 +180,29 @@ class TestDocumentStoreUnit:
|
|
|
180
180
|
with pytest.raises(ValueError, match="Invalid client_settings"):
|
|
181
181
|
store._ensure_initialized()
|
|
182
182
|
|
|
183
|
+
def test_close(self):
|
|
184
|
+
store = ChromaDocumentStore()
|
|
185
|
+
client = mock.Mock()
|
|
186
|
+
store._client = client
|
|
187
|
+
|
|
188
|
+
store.close()
|
|
189
|
+
|
|
190
|
+
client.close.assert_called_once()
|
|
191
|
+
assert store._client is None
|
|
192
|
+
|
|
193
|
+
store.close()
|
|
194
|
+
client.close.assert_called_once()
|
|
195
|
+
|
|
196
|
+
def test_close_is_exception_safe(self):
|
|
197
|
+
store = ChromaDocumentStore()
|
|
198
|
+
client = mock.Mock()
|
|
199
|
+
client.close.side_effect = RuntimeError("boom")
|
|
200
|
+
store._client = client
|
|
201
|
+
|
|
202
|
+
store.close()
|
|
203
|
+
|
|
204
|
+
assert store._client is None
|
|
205
|
+
|
|
183
206
|
def test_infer_type_from_value_fallback_for_unknown_type(self):
|
|
184
207
|
assert ChromaDocumentStore._infer_type_from_value(None) == "keyword"
|
|
185
208
|
assert ChromaDocumentStore._infer_type_from_value(["a", "b"]) == "keyword"
|
|
@@ -196,10 +219,11 @@ class TestDocumentStoreUnit:
|
|
|
196
219
|
@pytest.mark.parametrize(
|
|
197
220
|
"result",
|
|
198
221
|
[
|
|
199
|
-
{"ids": ["1"], "
|
|
200
|
-
{"ids": ["1"], "
|
|
222
|
+
{"ids": ["1"], "metadatas": [{"cat": "A"}]},
|
|
223
|
+
{"ids": ["1"], "metadatas": [None]},
|
|
224
|
+
{"ids": ["1"], "metadatas": [{"other": "A"}]},
|
|
201
225
|
],
|
|
202
|
-
ids=["
|
|
226
|
+
ids=["no_match", "metadata_none", "field_missing"],
|
|
203
227
|
)
|
|
204
228
|
def test_compute_field_unique_values_with_search_term_edge_cases(self, result):
|
|
205
229
|
values, total = ChromaDocumentStore._compute_field_unique_values(result, "cat", "absent", 0, 10)
|
|
@@ -377,6 +401,16 @@ class TestDocumentStore(
|
|
|
377
401
|
assert store._collection.metadata["hnsw:space"] == "ip"
|
|
378
402
|
assert new_store._collection.metadata["hnsw:space"] == "ip"
|
|
379
403
|
|
|
404
|
+
def test_close_and_reopen(self, tmp_path):
|
|
405
|
+
store = ChromaDocumentStore(collection_name="test_close_and_reopen", persist_path=str(tmp_path))
|
|
406
|
+
store.write_documents([Document(content="doc", embedding=TEST_EMBEDDING_1)])
|
|
407
|
+
assert store.count_documents() == 1
|
|
408
|
+
|
|
409
|
+
store.close()
|
|
410
|
+
assert store._client is None
|
|
411
|
+
|
|
412
|
+
assert store.count_documents() == 1
|
|
413
|
+
|
|
380
414
|
def test_delete_empty(self, document_store: ChromaDocumentStore):
|
|
381
415
|
"""
|
|
382
416
|
Deleting a non-existing document should not raise with Chroma
|
|
@@ -741,12 +775,57 @@ class TestMetadataOperations:
|
|
|
741
775
|
assert sorted(all_values) == ["A", "B", "C"]
|
|
742
776
|
|
|
743
777
|
def test_get_metadata_field_unique_values_with_search_term(self, populated_store):
|
|
744
|
-
"""Test getting unique values filtered by search term
|
|
745
|
-
|
|
778
|
+
"""Test getting unique values filtered by search term.
|
|
779
|
+
|
|
780
|
+
The search term is matched against the metadata field's own value, not document
|
|
781
|
+
content. "Doc 1" is content for one document (category "A"), but it is not a
|
|
782
|
+
substring of any "category" value, so no values should match.
|
|
783
|
+
"""
|
|
746
784
|
values, total = populated_store.get_metadata_field_unique_values(
|
|
747
785
|
"category", search_term="Doc 1", from_=0, size=10
|
|
748
786
|
)
|
|
749
|
-
assert values == [
|
|
787
|
+
assert values == []
|
|
788
|
+
assert total == 0
|
|
789
|
+
|
|
790
|
+
def test_get_metadata_field_unique_values_search_term_matches_field_value(self, populated_store):
|
|
791
|
+
"""Search term matches when it's a case-insensitive substring of the field's value."""
|
|
792
|
+
values, total = populated_store.get_metadata_field_unique_values("status", search_term="ACT", from_=0, size=10)
|
|
793
|
+
# "ACT" is a substring of both "active" and "inactive" (case-insensitive)
|
|
794
|
+
assert sorted(values) == ["active", "inactive"]
|
|
795
|
+
assert total == 2
|
|
796
|
+
|
|
797
|
+
values, total = populated_store.get_metadata_field_unique_values("status", search_term="ina", from_=0, size=10)
|
|
798
|
+
assert values == ["inactive"]
|
|
799
|
+
assert total == 1
|
|
800
|
+
|
|
801
|
+
def test_get_metadata_field_unique_values_search_term_excludes_content_only_match(self, document_store):
|
|
802
|
+
"""A search term present only in document content (not in the metadata field value)
|
|
803
|
+
must not match, proving search_term no longer filters on content."""
|
|
804
|
+
docs = [
|
|
805
|
+
Document(content="unique-marker-xyz", meta={"category": "A"}),
|
|
806
|
+
Document(content="plain content", meta={"category": "B"}),
|
|
807
|
+
]
|
|
808
|
+
document_store.write_documents(docs)
|
|
809
|
+
|
|
810
|
+
values, total = document_store.get_metadata_field_unique_values(
|
|
811
|
+
"category", search_term="unique-marker-xyz", from_=0, size=10
|
|
812
|
+
)
|
|
813
|
+
assert values == []
|
|
814
|
+
assert total == 0
|
|
815
|
+
|
|
816
|
+
def test_get_metadata_field_unique_values_search_term_matches_field_value_not_content(self, document_store):
|
|
817
|
+
"""A search term present in the metadata field's value but absent from the content
|
|
818
|
+
must match, proving search_term filters on the metadata field's value."""
|
|
819
|
+
docs = [
|
|
820
|
+
Document(content="Nothing special here", meta={"category": "special-value"}),
|
|
821
|
+
Document(content="Nothing special here either", meta={"category": "other"}),
|
|
822
|
+
]
|
|
823
|
+
document_store.write_documents(docs)
|
|
824
|
+
|
|
825
|
+
values, total = document_store.get_metadata_field_unique_values(
|
|
826
|
+
"category", search_term="SPECIAL", from_=0, size=10
|
|
827
|
+
)
|
|
828
|
+
assert values == ["special-value"]
|
|
750
829
|
assert total == 1
|
|
751
830
|
|
|
752
831
|
def test_get_metadata_field_unique_values_field_normalization(self, populated_store):
|
|
@@ -215,3 +215,37 @@ class TestDocumentStoreAsync(
|
|
|
215
215
|
)
|
|
216
216
|
assert values == []
|
|
217
217
|
assert total == 0
|
|
218
|
+
|
|
219
|
+
async def test_get_metadata_field_unique_values_async_search_term_excludes_content_only_match(
|
|
220
|
+
self, document_store: ChromaDocumentStore
|
|
221
|
+
):
|
|
222
|
+
"""A search term present only in document content (not in the metadata field value)
|
|
223
|
+
must not match, proving search_term no longer filters on content."""
|
|
224
|
+
docs = [
|
|
225
|
+
Document(content="unique-marker-xyz", meta={"category": "A"}),
|
|
226
|
+
Document(content="plain content", meta={"category": "B"}),
|
|
227
|
+
]
|
|
228
|
+
await document_store.write_documents_async(docs)
|
|
229
|
+
|
|
230
|
+
values, total = await document_store.get_metadata_field_unique_values_async(
|
|
231
|
+
"category", search_term="unique-marker-xyz", from_=0, size=10
|
|
232
|
+
)
|
|
233
|
+
assert values == []
|
|
234
|
+
assert total == 0
|
|
235
|
+
|
|
236
|
+
async def test_get_metadata_field_unique_values_async_search_term_matches_field_value(
|
|
237
|
+
self, document_store: ChromaDocumentStore
|
|
238
|
+
):
|
|
239
|
+
"""A search term present in the metadata field's value but absent from the content
|
|
240
|
+
must match, proving search_term filters on the metadata field's value (case-insensitively)."""
|
|
241
|
+
docs = [
|
|
242
|
+
Document(content="Nothing special here", meta={"category": "special-value"}),
|
|
243
|
+
Document(content="Nothing special here either", meta={"category": "other"}),
|
|
244
|
+
]
|
|
245
|
+
await document_store.write_documents_async(docs)
|
|
246
|
+
|
|
247
|
+
values, total = await document_store.get_metadata_field_unique_values_async(
|
|
248
|
+
"category", search_term="SPECIAL", from_=0, size=10
|
|
249
|
+
)
|
|
250
|
+
assert values == ["special-value"]
|
|
251
|
+
assert total == 1
|
|
@@ -106,6 +106,15 @@ class TestChromaQueryTextRetriever:
|
|
|
106
106
|
assert retriever.top_k == 42
|
|
107
107
|
assert retriever.filter_policy == FilterPolicy.REPLACE # default even if not specified
|
|
108
108
|
|
|
109
|
+
def test_close(self):
|
|
110
|
+
ds = mock.Mock(spec=ChromaDocumentStore)
|
|
111
|
+
retriever = ChromaQueryTextRetriever(ds)
|
|
112
|
+
|
|
113
|
+
retriever.close()
|
|
114
|
+
|
|
115
|
+
ds.close.assert_called_once()
|
|
116
|
+
assert retriever.document_store is ds
|
|
117
|
+
|
|
109
118
|
def test_run_delegates_to_document_store_search(self):
|
|
110
119
|
ds = mock.Mock(spec=ChromaDocumentStore)
|
|
111
120
|
expected = [Document(content="hit")]
|
|
@@ -215,6 +224,15 @@ class TestChromaEmbeddingRetriever:
|
|
|
215
224
|
retriever = ChromaEmbeddingRetriever.from_dict(data)
|
|
216
225
|
assert retriever.filter_policy == FilterPolicy.REPLACE
|
|
217
226
|
|
|
227
|
+
def test_close(self):
|
|
228
|
+
ds = mock.Mock(spec=ChromaDocumentStore)
|
|
229
|
+
retriever = ChromaEmbeddingRetriever(ds)
|
|
230
|
+
|
|
231
|
+
retriever.close()
|
|
232
|
+
|
|
233
|
+
ds.close.assert_called_once()
|
|
234
|
+
assert retriever.document_store is ds
|
|
235
|
+
|
|
218
236
|
def test_run_delegates_to_document_store_search_embeddings(self):
|
|
219
237
|
ds = mock.Mock(spec=ChromaDocumentStore)
|
|
220
238
|
expected = [Document(content="hit")]
|
|
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
|
|
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
|
|
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
|
|
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
|
{chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/src/haystack_integrations/document_stores/py.typed
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|