qdrant-haystack 11.1.0__tar.gz → 12.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.
- {qdrant_haystack-11.1.0 → qdrant_haystack-12.0.0}/CHANGELOG.md +11 -0
- {qdrant_haystack-11.1.0 → qdrant_haystack-12.0.0}/PKG-INFO +1 -1
- {qdrant_haystack-11.1.0 → qdrant_haystack-12.0.0}/src/haystack_integrations/document_stores/qdrant/document_store.py +1 -2
- {qdrant_haystack-11.1.0 → qdrant_haystack-12.0.0}/src/haystack_integrations/document_stores/qdrant/filters.py +7 -31
- {qdrant_haystack-11.1.0 → qdrant_haystack-12.0.0}/tests/test_filters.py +52 -10
- {qdrant_haystack-11.1.0 → qdrant_haystack-12.0.0}/.gitignore +0 -0
- {qdrant_haystack-11.1.0 → qdrant_haystack-12.0.0}/LICENSE.txt +0 -0
- {qdrant_haystack-11.1.0 → qdrant_haystack-12.0.0}/README.md +0 -0
- {qdrant_haystack-11.1.0 → qdrant_haystack-12.0.0}/examples/embedding_retrieval.py +0 -0
- {qdrant_haystack-11.1.0 → qdrant_haystack-12.0.0}/pydoc/config_docusaurus.yml +0 -0
- {qdrant_haystack-11.1.0 → qdrant_haystack-12.0.0}/pyproject.toml +0 -0
- {qdrant_haystack-11.1.0 → qdrant_haystack-12.0.0}/src/haystack_integrations/components/retrievers/py.typed +0 -0
- {qdrant_haystack-11.1.0 → qdrant_haystack-12.0.0}/src/haystack_integrations/components/retrievers/qdrant/__init__.py +0 -0
- {qdrant_haystack-11.1.0 → qdrant_haystack-12.0.0}/src/haystack_integrations/components/retrievers/qdrant/retriever.py +0 -0
- {qdrant_haystack-11.1.0 → qdrant_haystack-12.0.0}/src/haystack_integrations/document_stores/py.typed +0 -0
- {qdrant_haystack-11.1.0 → qdrant_haystack-12.0.0}/src/haystack_integrations/document_stores/qdrant/__init__.py +0 -0
- {qdrant_haystack-11.1.0 → qdrant_haystack-12.0.0}/src/haystack_integrations/document_stores/qdrant/converters.py +0 -0
- {qdrant_haystack-11.1.0 → qdrant_haystack-12.0.0}/src/haystack_integrations/document_stores/qdrant/migrate_to_sparse.py +0 -0
- {qdrant_haystack-11.1.0 → qdrant_haystack-12.0.0}/tests/__init__.py +0 -0
- {qdrant_haystack-11.1.0 → qdrant_haystack-12.0.0}/tests/conftest.py +0 -0
- {qdrant_haystack-11.1.0 → qdrant_haystack-12.0.0}/tests/test_converters.py +0 -0
- {qdrant_haystack-11.1.0 → qdrant_haystack-12.0.0}/tests/test_dict_converters.py +0 -0
- {qdrant_haystack-11.1.0 → qdrant_haystack-12.0.0}/tests/test_document_store.py +0 -0
- {qdrant_haystack-11.1.0 → qdrant_haystack-12.0.0}/tests/test_document_store_async.py +0 -0
- {qdrant_haystack-11.1.0 → qdrant_haystack-12.0.0}/tests/test_embedding_retriever.py +0 -0
- {qdrant_haystack-11.1.0 → qdrant_haystack-12.0.0}/tests/test_hybrid_retriever.py +0 -0
- {qdrant_haystack-11.1.0 → qdrant_haystack-12.0.0}/tests/test_sparse_embedding_retriever.py +0 -0
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [integrations/qdrant-v11.1.0] - 2026-10-01
|
|
4
|
+
|
|
5
|
+
### 🐛 Bug Fixes
|
|
6
|
+
|
|
7
|
+
- *(qdrant)* Respect falsy run() overrides in retrievers (#4007)
|
|
8
|
+
|
|
9
|
+
### 📚 Documentation
|
|
10
|
+
|
|
11
|
+
- Clarify score_threshold semantics for Qdrant hybrid retrieval (#4008)
|
|
12
|
+
|
|
13
|
+
|
|
3
14
|
## [integrations/qdrant-v11.0.0] - 2026-09-25
|
|
4
15
|
|
|
5
16
|
### 🚜 Refactor
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: qdrant-haystack
|
|
3
|
-
Version:
|
|
3
|
+
Version: 12.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
|
|
@@ -11,7 +11,7 @@ from haystack.dataclasses import Document
|
|
|
11
11
|
from haystack.dataclasses.sparse_embedding import SparseEmbedding
|
|
12
12
|
from haystack.document_stores.errors import DocumentStoreError, DuplicateDocumentError
|
|
13
13
|
from haystack.document_stores.types import DuplicatePolicy
|
|
14
|
-
from haystack.utils import Secret
|
|
14
|
+
from haystack.utils import Secret
|
|
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
|
|
@@ -1432,7 +1432,6 @@ class QdrantDocumentStore:
|
|
|
1432
1432
|
:returns:
|
|
1433
1433
|
The deserialized component.
|
|
1434
1434
|
"""
|
|
1435
|
-
deserialize_secrets_inplace(data["init_parameters"], keys=["api_key"])
|
|
1436
1435
|
return default_from_dict(cls, data)
|
|
1437
1436
|
|
|
1438
1437
|
def to_dict(self) -> dict[str, Any]:
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: 2023-present deepset GmbH <info@deepset.ai>
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
|
|
1
5
|
from collections.abc import Callable
|
|
2
6
|
from datetime import datetime
|
|
3
7
|
from typing import Any
|
|
@@ -131,8 +135,6 @@ def _build_comparison_condition(operator: str, key: str, value: Any) -> models.C
|
|
|
131
135
|
|
|
132
136
|
|
|
133
137
|
def _build_eq_condition(key: str, value: models.ValueVariants) -> models.Condition:
|
|
134
|
-
if isinstance(value, str) and " " in value:
|
|
135
|
-
return models.FieldCondition(key=key, match=models.MatchText(text=value))
|
|
136
138
|
return models.FieldCondition(key=key, match=models.MatchValue(value=value))
|
|
137
139
|
|
|
138
140
|
|
|
@@ -140,44 +142,18 @@ def _build_in_condition(key: str, value: list[models.ValueVariants]) -> models.C
|
|
|
140
142
|
if not isinstance(value, list):
|
|
141
143
|
msg = f"Value {value} is not a list"
|
|
142
144
|
raise FilterError(msg)
|
|
143
|
-
return models.Filter(
|
|
144
|
-
should=[
|
|
145
|
-
(
|
|
146
|
-
models.FieldCondition(key=key, match=models.MatchText(text=item))
|
|
147
|
-
if isinstance(item, str) and " " not in item
|
|
148
|
-
else models.FieldCondition(key=key, match=models.MatchValue(value=item))
|
|
149
|
-
)
|
|
150
|
-
for item in value
|
|
151
|
-
]
|
|
152
|
-
)
|
|
145
|
+
return models.Filter(should=[_build_eq_condition(key, item) for item in value])
|
|
153
146
|
|
|
154
147
|
|
|
155
148
|
def _build_ne_condition(key: str, value: models.ValueVariants) -> models.Condition:
|
|
156
|
-
return models.Filter(
|
|
157
|
-
must_not=[
|
|
158
|
-
(
|
|
159
|
-
models.FieldCondition(key=key, match=models.MatchText(text=value))
|
|
160
|
-
if isinstance(value, str) and " " not in value
|
|
161
|
-
else models.FieldCondition(key=key, match=models.MatchValue(value=value))
|
|
162
|
-
)
|
|
163
|
-
]
|
|
164
|
-
)
|
|
149
|
+
return models.Filter(must_not=[_build_eq_condition(key, value)])
|
|
165
150
|
|
|
166
151
|
|
|
167
152
|
def _build_nin_condition(key: str, value: list[models.ValueVariants]) -> models.Condition:
|
|
168
153
|
if not isinstance(value, list):
|
|
169
154
|
msg = f"Value {value} is not a list"
|
|
170
155
|
raise FilterError(msg)
|
|
171
|
-
return models.Filter(
|
|
172
|
-
must_not=[
|
|
173
|
-
(
|
|
174
|
-
models.FieldCondition(key=key, match=models.MatchText(text=item))
|
|
175
|
-
if isinstance(item, str) and " " in item
|
|
176
|
-
else models.FieldCondition(key=key, match=models.MatchValue(value=item))
|
|
177
|
-
)
|
|
178
|
-
for item in value
|
|
179
|
-
]
|
|
180
|
-
)
|
|
156
|
+
return models.Filter(must_not=[_build_eq_condition(key, item) for item in value])
|
|
181
157
|
|
|
182
158
|
|
|
183
159
|
def _build_lt_condition(key: str, value: str | float | int) -> models.Condition:
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: 2023-present deepset GmbH <info@deepset.ai>
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
|
|
1
5
|
import pytest
|
|
2
6
|
from haystack import Document
|
|
3
7
|
from haystack.testing.document_store import FilterDocumentsTest
|
|
@@ -49,16 +53,6 @@ class TestConvertFiltersToQdrantUnit:
|
|
|
49
53
|
)
|
|
50
54
|
assert isinstance(qdrant_filter, models.Filter)
|
|
51
55
|
|
|
52
|
-
def test_eq_with_spaces_uses_text_match(self):
|
|
53
|
-
qdrant_filter = convert_filters_to_qdrant({"operator": "==", "field": "meta.title", "value": "hello world"})
|
|
54
|
-
condition = qdrant_filter.must[0]
|
|
55
|
-
assert isinstance(condition.match, models.MatchText)
|
|
56
|
-
|
|
57
|
-
def test_eq_without_spaces_uses_value_match(self):
|
|
58
|
-
qdrant_filter = convert_filters_to_qdrant({"operator": "==", "field": "meta.name", "value": "name_0"})
|
|
59
|
-
condition = qdrant_filter.must[0]
|
|
60
|
-
assert isinstance(condition.match, models.MatchValue)
|
|
61
|
-
|
|
62
56
|
def test_single_logical_condition_unwrapped(self):
|
|
63
57
|
qdrant_filter = convert_filters_to_qdrant(
|
|
64
58
|
{
|
|
@@ -96,6 +90,54 @@ class TestQdrantFilters(FilterDocumentsTest):
|
|
|
96
90
|
wait_result_from_api=True,
|
|
97
91
|
)
|
|
98
92
|
|
|
93
|
+
@pytest.mark.parametrize(("value", "longer_value"), [("news", "newsletter"), ("New York", "New York City")])
|
|
94
|
+
def test_eq_matches_exact_string(self, document_store, value, longer_value):
|
|
95
|
+
exact_document = Document(content=value, meta={"name": value})
|
|
96
|
+
other_document = Document(content=longer_value, meta={"name": longer_value})
|
|
97
|
+
document_store.write_documents([exact_document, other_document])
|
|
98
|
+
|
|
99
|
+
result = document_store.filter_documents(filters={"field": "meta.name", "operator": "==", "value": value})
|
|
100
|
+
|
|
101
|
+
self.assert_documents_are_equal(result, [exact_document])
|
|
102
|
+
|
|
103
|
+
@pytest.mark.parametrize(("value", "longer_value"), [("news", "newsletter"), ("New York", "New York City")])
|
|
104
|
+
def test_ne_excludes_exact_string(self, document_store, value, longer_value):
|
|
105
|
+
exact_document = Document(content=value, meta={"name": value})
|
|
106
|
+
other_document = Document(content=longer_value, meta={"name": longer_value})
|
|
107
|
+
document_store.write_documents([exact_document, other_document])
|
|
108
|
+
|
|
109
|
+
result = document_store.filter_documents(filters={"field": "meta.name", "operator": "!=", "value": value})
|
|
110
|
+
|
|
111
|
+
self.assert_documents_are_equal(result, [other_document])
|
|
112
|
+
|
|
113
|
+
def test_in_matches_exact_strings(self, document_store):
|
|
114
|
+
document_store.write_documents(
|
|
115
|
+
[
|
|
116
|
+
Document(content=name, meta={"name": name})
|
|
117
|
+
for name in ["news", "newsletter", "New York", "New York City"]
|
|
118
|
+
]
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
result = document_store.filter_documents(
|
|
122
|
+
filters={"field": "meta.name", "operator": "in", "value": ["news", "New York"]}
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
assert sorted(doc.meta["name"] for doc in result) == ["New York", "news"]
|
|
126
|
+
|
|
127
|
+
def test_not_in_excludes_exact_strings(self, document_store):
|
|
128
|
+
document_store.write_documents(
|
|
129
|
+
[
|
|
130
|
+
Document(content=name, meta={"name": name})
|
|
131
|
+
for name in ["news", "newsletter", "New York", "New York City"]
|
|
132
|
+
]
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
result = document_store.filter_documents(
|
|
136
|
+
filters={"field": "meta.name", "operator": "not in", "value": ["news", "New York"]}
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
assert sorted(doc.meta["name"] for doc in result) == ["New York City", "newsletter"]
|
|
140
|
+
|
|
99
141
|
def test_filter_documents_with_qdrant_filters(self, document_store, filterable_docs):
|
|
100
142
|
document_store.write_documents(filterable_docs)
|
|
101
143
|
result = document_store.filter_documents(
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{qdrant_haystack-11.1.0 → qdrant_haystack-12.0.0}/src/haystack_integrations/document_stores/py.typed
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|