qdrant-haystack 9.1.1__py3-none-any.whl → 10.2.0__py3-none-any.whl
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.
- haystack_integrations/components/retrievers/py.typed +0 -0
- haystack_integrations/components/retrievers/qdrant/retriever.py +158 -87
- haystack_integrations/document_stores/py.typed +0 -0
- haystack_integrations/document_stores/qdrant/converters.py +13 -12
- haystack_integrations/document_stores/qdrant/document_store.py +945 -171
- haystack_integrations/document_stores/qdrant/filters.py +87 -168
- haystack_integrations/document_stores/qdrant/migrate_to_sparse.py +11 -7
- {qdrant_haystack-9.1.1.dist-info → qdrant_haystack-10.2.0.dist-info}/METADATA +9 -25
- qdrant_haystack-10.2.0.dist-info/RECORD +13 -0
- {qdrant_haystack-9.1.1.dist-info → qdrant_haystack-10.2.0.dist-info}/WHEEL +1 -1
- qdrant_haystack-9.1.1.dist-info/RECORD +0 -11
- {qdrant_haystack-9.1.1.dist-info → qdrant_haystack-10.2.0.dist-info}/licenses/LICENSE.txt +0 -0
|
@@ -1,198 +1,116 @@
|
|
|
1
|
+
from collections.abc import Callable
|
|
1
2
|
from datetime import datetime
|
|
2
|
-
from typing import
|
|
3
|
+
from typing import Any
|
|
3
4
|
|
|
4
5
|
from haystack.utils.filters import COMPARISON_OPERATORS, LOGICAL_OPERATORS, FilterError
|
|
5
6
|
from qdrant_client.http import models
|
|
6
7
|
|
|
7
|
-
COMPARISON_OPERATORS = COMPARISON_OPERATORS.keys()
|
|
8
|
-
LOGICAL_OPERATORS = LOGICAL_OPERATORS.keys()
|
|
9
|
-
|
|
10
8
|
|
|
11
9
|
def convert_filters_to_qdrant(
|
|
12
|
-
filter_term:
|
|
13
|
-
) ->
|
|
10
|
+
filter_term: list[dict[str, Any]] | dict[str, Any] | models.Filter | None = None,
|
|
11
|
+
) -> models.Filter | None:
|
|
14
12
|
"""Converts Haystack filters to the format used by Qdrant.
|
|
15
13
|
|
|
16
14
|
:param filter_term: the haystack filter to be converted to qdrant.
|
|
17
|
-
:
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
:returns: a single Qdrant Filter in the parent call or a list of such Filters in recursive calls.
|
|
21
|
-
|
|
22
|
-
:raises FilterError: If the invalid filter criteria is provided or if an unknown operator is encountered.
|
|
23
|
-
|
|
15
|
+
:returns: a single Qdrant Filter or None.
|
|
16
|
+
:raises FilterError: If invalid filter criteria is provided.
|
|
24
17
|
"""
|
|
25
|
-
|
|
26
18
|
if isinstance(filter_term, models.Filter):
|
|
27
19
|
return filter_term
|
|
28
20
|
if not filter_term:
|
|
29
21
|
return None
|
|
30
22
|
|
|
31
|
-
must_clauses: List[models.Filter] = []
|
|
32
|
-
should_clauses: List[models.Filter] = []
|
|
33
|
-
must_not_clauses: List[models.Filter] = []
|
|
34
|
-
# Indicates if there are multiple same LOGICAL OPERATORS on each level
|
|
35
|
-
# and prevents them from being combined
|
|
36
|
-
same_operator_flag = False
|
|
37
|
-
conditions, qdrant_filter, current_level_operators = (
|
|
38
|
-
[],
|
|
39
|
-
[],
|
|
40
|
-
[],
|
|
41
|
-
)
|
|
42
|
-
|
|
43
23
|
if isinstance(filter_term, dict):
|
|
44
24
|
filter_term = [filter_term]
|
|
45
25
|
|
|
46
|
-
|
|
26
|
+
conditions = _process_filter_items(filter_term)
|
|
27
|
+
|
|
28
|
+
return _build_final_filter(conditions)
|
|
47
29
|
|
|
48
|
-
for item in filter_term:
|
|
49
|
-
operator = item.get("operator")
|
|
50
30
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
current_level_operators.append(operator)
|
|
31
|
+
def _process_filter_items(filter_items: list[dict[str, Any]]) -> list[models.Condition]:
|
|
32
|
+
"""Process a list of filter items and return all conditions."""
|
|
33
|
+
all_conditions: list[models.Condition] = []
|
|
55
34
|
|
|
35
|
+
for item in filter_items:
|
|
36
|
+
operator = item.get("operator")
|
|
56
37
|
if operator is None:
|
|
57
38
|
msg = "Operator not found in filters"
|
|
58
39
|
raise FilterError(msg)
|
|
59
40
|
|
|
60
|
-
if operator in LOGICAL_OPERATORS
|
|
61
|
-
|
|
41
|
+
if operator in LOGICAL_OPERATORS:
|
|
42
|
+
condition = _process_logical_operator(item)
|
|
43
|
+
if condition:
|
|
44
|
+
all_conditions.append(condition)
|
|
45
|
+
elif operator in COMPARISON_OPERATORS:
|
|
46
|
+
condition = _process_comparison_operator(item)
|
|
47
|
+
if condition:
|
|
48
|
+
all_conditions.append(condition)
|
|
49
|
+
else:
|
|
50
|
+
msg = f"Unknown operator {operator} used in filters"
|
|
62
51
|
raise FilterError(msg)
|
|
63
52
|
|
|
64
|
-
|
|
65
|
-
# Recursively process nested conditions
|
|
66
|
-
current_filter = convert_filters_to_qdrant(item.get("conditions", []), is_parent_call=False) or []
|
|
67
|
-
|
|
68
|
-
# When same_operator_flag is set to True,
|
|
69
|
-
# ensure each clause is appended as an independent list to avoid merging distinct clauses.
|
|
70
|
-
if operator == "AND":
|
|
71
|
-
must_clauses = [must_clauses, current_filter] if same_operator_flag else must_clauses + current_filter
|
|
72
|
-
elif operator == "OR":
|
|
73
|
-
should_clauses = (
|
|
74
|
-
[should_clauses, current_filter] if same_operator_flag else should_clauses + current_filter
|
|
75
|
-
)
|
|
76
|
-
elif operator == "NOT":
|
|
77
|
-
must_not_clauses = (
|
|
78
|
-
[must_not_clauses, current_filter] if same_operator_flag else must_not_clauses + current_filter
|
|
79
|
-
)
|
|
53
|
+
return all_conditions
|
|
80
54
|
|
|
81
|
-
elif operator in COMPARISON_OPERATORS:
|
|
82
|
-
field = item.get("field")
|
|
83
|
-
value = item.get("value")
|
|
84
|
-
if field is None or value is None:
|
|
85
|
-
msg = f"'field' or 'value' not found for '{operator}'"
|
|
86
|
-
raise FilterError(msg)
|
|
87
55
|
|
|
88
|
-
|
|
56
|
+
def _process_logical_operator(item: dict[str, Any]) -> models.Condition | None:
|
|
57
|
+
"""Process a logical operator (AND, OR, NOT) and return the corresponding condition."""
|
|
58
|
+
operator = item["operator"]
|
|
59
|
+
conditions = item.get("conditions")
|
|
89
60
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
qdrant_filter.append(condition)
|
|
94
|
-
else:
|
|
95
|
-
conditions.append(condition)
|
|
61
|
+
if not conditions:
|
|
62
|
+
msg = f"'conditions' not found for '{operator}'"
|
|
63
|
+
raise FilterError(msg)
|
|
96
64
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
raise FilterError(msg)
|
|
65
|
+
# Recursively process nested conditions
|
|
66
|
+
nested_conditions = _process_filter_items(conditions)
|
|
100
67
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
# If same logical operators have separate clauses, create separate filters
|
|
104
|
-
if same_operator_flag:
|
|
105
|
-
qdrant_filter = build_filters_for_repeated_operators(
|
|
106
|
-
must_clauses, should_clauses, must_not_clauses, qdrant_filter
|
|
107
|
-
)
|
|
108
|
-
|
|
109
|
-
# else append a single Filter for existing clauses
|
|
110
|
-
elif must_clauses or should_clauses or must_not_clauses:
|
|
111
|
-
qdrant_filter.append(
|
|
112
|
-
models.Filter(
|
|
113
|
-
must=must_clauses or None,
|
|
114
|
-
should=should_clauses or None,
|
|
115
|
-
must_not=must_not_clauses or None,
|
|
116
|
-
)
|
|
117
|
-
)
|
|
118
|
-
|
|
119
|
-
# In case of parent call, a single Filter is returned
|
|
120
|
-
if is_parent_call:
|
|
121
|
-
# If qdrant_filter has just a single Filter in parent call,
|
|
122
|
-
# then it might be returned instead.
|
|
123
|
-
if len(qdrant_filter) == 1 and isinstance(qdrant_filter[0], models.Filter):
|
|
124
|
-
return qdrant_filter[0]
|
|
125
|
-
else:
|
|
126
|
-
must_clauses.extend(conditions)
|
|
127
|
-
return models.Filter(
|
|
128
|
-
must=must_clauses or None,
|
|
129
|
-
should=should_clauses or None,
|
|
130
|
-
must_not=must_not_clauses or None,
|
|
131
|
-
)
|
|
68
|
+
if not nested_conditions:
|
|
69
|
+
return None
|
|
132
70
|
|
|
133
|
-
#
|
|
134
|
-
|
|
135
|
-
|
|
71
|
+
# Build the appropriate filter based on operator
|
|
72
|
+
if operator == "AND":
|
|
73
|
+
return models.Filter(must=nested_conditions)
|
|
74
|
+
elif operator == "OR":
|
|
75
|
+
return models.Filter(should=nested_conditions)
|
|
76
|
+
elif operator == "NOT":
|
|
77
|
+
return models.Filter(must_not=nested_conditions)
|
|
136
78
|
|
|
137
|
-
return
|
|
79
|
+
return None
|
|
138
80
|
|
|
139
81
|
|
|
140
|
-
def
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
) -> List[models.Filter]:
|
|
146
|
-
"""
|
|
147
|
-
Flattens the nested lists of clauses by creating separate Filters for each clause of a logical operator.
|
|
82
|
+
def _process_comparison_operator(item: dict[str, Any]) -> models.Condition | None:
|
|
83
|
+
"""Process a comparison operator and return the corresponding condition."""
|
|
84
|
+
operator = item["operator"]
|
|
85
|
+
field = item.get("field")
|
|
86
|
+
value = item.get("value")
|
|
148
87
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
:param qdrant_filter: a list where the generated Filter objects will be appended.
|
|
153
|
-
This list will be modified in-place.
|
|
88
|
+
if field is None or value is None:
|
|
89
|
+
msg = f"'field' or 'value' not found for '{operator}'"
|
|
90
|
+
raise FilterError(msg)
|
|
154
91
|
|
|
92
|
+
return _build_comparison_condition(operator, field, value)
|
|
155
93
|
|
|
156
|
-
:returns: the modified `qdrant_filter` list with appended generated Filter objects.
|
|
157
|
-
"""
|
|
158
94
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
must=i or None,
|
|
164
|
-
should=should_clauses or None,
|
|
165
|
-
must_not=must_not_clauses or None,
|
|
166
|
-
)
|
|
167
|
-
)
|
|
168
|
-
if any(isinstance(i, list) for i in should_clauses):
|
|
169
|
-
for i in should_clauses:
|
|
170
|
-
qdrant_filter.append(
|
|
171
|
-
models.Filter(
|
|
172
|
-
must=must_clauses or None,
|
|
173
|
-
should=i or None,
|
|
174
|
-
must_not=must_not_clauses or None,
|
|
175
|
-
)
|
|
176
|
-
)
|
|
177
|
-
if any(isinstance(i, list) for i in must_not_clauses):
|
|
178
|
-
for i in must_clauses:
|
|
179
|
-
qdrant_filter.append(
|
|
180
|
-
models.Filter(
|
|
181
|
-
must=must_clauses or None,
|
|
182
|
-
should=should_clauses or None,
|
|
183
|
-
must_not=i or None,
|
|
184
|
-
)
|
|
185
|
-
)
|
|
95
|
+
def _build_final_filter(conditions: list[models.Condition]) -> models.Filter | None:
|
|
96
|
+
"""Build the final filter from a list of conditions."""
|
|
97
|
+
if not conditions:
|
|
98
|
+
return None
|
|
186
99
|
|
|
187
|
-
|
|
100
|
+
if len(conditions) == 1:
|
|
101
|
+
# If single condition and it's already a Filter, return it
|
|
102
|
+
if isinstance(conditions[0], models.Filter):
|
|
103
|
+
return conditions[0]
|
|
104
|
+
# Otherwise wrap it in a Filter
|
|
105
|
+
return models.Filter(must=[conditions[0]])
|
|
188
106
|
|
|
107
|
+
# Multiple conditions - combine with AND logic
|
|
108
|
+
return models.Filter(must=conditions)
|
|
189
109
|
|
|
190
|
-
def _parse_comparison_operation(
|
|
191
|
-
comparison_operation: str, key: str, value: Union[dict, List, str, float]
|
|
192
|
-
) -> List[models.Condition]:
|
|
193
|
-
conditions: List[models.Condition] = []
|
|
194
110
|
|
|
195
|
-
|
|
111
|
+
def _build_comparison_condition(operator: str, key: str, value: Any) -> models.Condition:
|
|
112
|
+
"""Build a comparison condition based on operator, key, and value."""
|
|
113
|
+
condition_builders: dict[str, Callable[[str, Any], models.Condition]] = {
|
|
196
114
|
"==": _build_eq_condition,
|
|
197
115
|
"in": _build_in_condition,
|
|
198
116
|
"!=": _build_ne_condition,
|
|
@@ -203,15 +121,12 @@ def _parse_comparison_operation(
|
|
|
203
121
|
"<=": _build_lte_condition,
|
|
204
122
|
}
|
|
205
123
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
msg
|
|
210
|
-
raise ValueError(msg)
|
|
211
|
-
|
|
212
|
-
conditions.append(condition_builder(key, value))
|
|
124
|
+
builder = condition_builders.get(operator)
|
|
125
|
+
if builder is None:
|
|
126
|
+
msg = f"Unknown operator {operator} used in filters"
|
|
127
|
+
raise FilterError(msg)
|
|
213
128
|
|
|
214
|
-
return
|
|
129
|
+
return builder(key, value)
|
|
215
130
|
|
|
216
131
|
|
|
217
132
|
def _build_eq_condition(key: str, value: models.ValueVariants) -> models.Condition:
|
|
@@ -220,7 +135,7 @@ def _build_eq_condition(key: str, value: models.ValueVariants) -> models.Conditi
|
|
|
220
135
|
return models.FieldCondition(key=key, match=models.MatchValue(value=value))
|
|
221
136
|
|
|
222
137
|
|
|
223
|
-
def _build_in_condition(key: str, value:
|
|
138
|
+
def _build_in_condition(key: str, value: list[models.ValueVariants]) -> models.Condition:
|
|
224
139
|
if not isinstance(value, list):
|
|
225
140
|
msg = f"Value {value} is not a list"
|
|
226
141
|
raise FilterError(msg)
|
|
@@ -248,7 +163,7 @@ def _build_ne_condition(key: str, value: models.ValueVariants) -> models.Conditi
|
|
|
248
163
|
)
|
|
249
164
|
|
|
250
165
|
|
|
251
|
-
def _build_nin_condition(key: str, value:
|
|
166
|
+
def _build_nin_condition(key: str, value: list[models.ValueVariants]) -> models.Condition:
|
|
252
167
|
if not isinstance(value, list):
|
|
253
168
|
msg = f"Value {value} is not a list"
|
|
254
169
|
raise FilterError(msg)
|
|
@@ -264,9 +179,10 @@ def _build_nin_condition(key: str, value: List[models.ValueVariants]) -> models.
|
|
|
264
179
|
)
|
|
265
180
|
|
|
266
181
|
|
|
267
|
-
def _build_lt_condition(key: str, value:
|
|
182
|
+
def _build_lt_condition(key: str, value: str | float | int) -> models.Condition:
|
|
268
183
|
if isinstance(value, str) and is_datetime_string(value):
|
|
269
|
-
|
|
184
|
+
dt_value = datetime.fromisoformat(value)
|
|
185
|
+
return models.FieldCondition(key=key, range=models.DatetimeRange(lt=dt_value))
|
|
270
186
|
|
|
271
187
|
if isinstance(value, (int, float)):
|
|
272
188
|
return models.FieldCondition(key=key, range=models.Range(lt=value))
|
|
@@ -275,9 +191,10 @@ def _build_lt_condition(key: str, value: Union[str, float, int]) -> models.Condi
|
|
|
275
191
|
raise FilterError(msg)
|
|
276
192
|
|
|
277
193
|
|
|
278
|
-
def _build_lte_condition(key: str, value:
|
|
194
|
+
def _build_lte_condition(key: str, value: str | float | int) -> models.Condition:
|
|
279
195
|
if isinstance(value, str) and is_datetime_string(value):
|
|
280
|
-
|
|
196
|
+
dt_value = datetime.fromisoformat(value)
|
|
197
|
+
return models.FieldCondition(key=key, range=models.DatetimeRange(lte=dt_value))
|
|
281
198
|
|
|
282
199
|
if isinstance(value, (int, float)):
|
|
283
200
|
return models.FieldCondition(key=key, range=models.Range(lte=value))
|
|
@@ -286,9 +203,10 @@ def _build_lte_condition(key: str, value: Union[str, float, int]) -> models.Cond
|
|
|
286
203
|
raise FilterError(msg)
|
|
287
204
|
|
|
288
205
|
|
|
289
|
-
def _build_gt_condition(key: str, value:
|
|
206
|
+
def _build_gt_condition(key: str, value: str | float | int) -> models.Condition:
|
|
290
207
|
if isinstance(value, str) and is_datetime_string(value):
|
|
291
|
-
|
|
208
|
+
dt_value = datetime.fromisoformat(value)
|
|
209
|
+
return models.FieldCondition(key=key, range=models.DatetimeRange(gt=dt_value))
|
|
292
210
|
|
|
293
211
|
if isinstance(value, (int, float)):
|
|
294
212
|
return models.FieldCondition(key=key, range=models.Range(gt=value))
|
|
@@ -297,9 +215,10 @@ def _build_gt_condition(key: str, value: Union[str, float, int]) -> models.Condi
|
|
|
297
215
|
raise FilterError(msg)
|
|
298
216
|
|
|
299
217
|
|
|
300
|
-
def _build_gte_condition(key: str, value:
|
|
218
|
+
def _build_gte_condition(key: str, value: str | float | int) -> models.Condition:
|
|
301
219
|
if isinstance(value, str) and is_datetime_string(value):
|
|
302
|
-
|
|
220
|
+
dt_value = datetime.fromisoformat(value)
|
|
221
|
+
return models.FieldCondition(key=key, range=models.DatetimeRange(gte=dt_value))
|
|
303
222
|
|
|
304
223
|
if isinstance(value, (int, float)):
|
|
305
224
|
return models.FieldCondition(key=key, range=models.Range(gte=value))
|
|
@@ -1,17 +1,19 @@
|
|
|
1
|
-
|
|
1
|
+
# mypy: disable-error-code="assignment, arg-type"
|
|
2
|
+
|
|
3
|
+
import logging
|
|
2
4
|
import time
|
|
3
5
|
|
|
4
|
-
from haystack import logging
|
|
5
6
|
from qdrant_client.http import models
|
|
6
7
|
|
|
7
8
|
from haystack_integrations.document_stores.qdrant import QdrantDocumentStore
|
|
8
9
|
|
|
10
|
+
# using Haystack logging is problematic here
|
|
9
11
|
logger = logging.getLogger(__name__)
|
|
10
|
-
logger.addHandler(
|
|
11
|
-
logger.setLevel(
|
|
12
|
+
logger.addHandler(logging.StreamHandler())
|
|
13
|
+
logger.setLevel(logging.INFO)
|
|
12
14
|
|
|
13
15
|
|
|
14
|
-
def migrate_to_sparse_embeddings_support(old_document_store: QdrantDocumentStore, new_index: str):
|
|
16
|
+
def migrate_to_sparse_embeddings_support(old_document_store: QdrantDocumentStore, new_index: str) -> None: # type: ignore
|
|
15
17
|
"""
|
|
16
18
|
Utility function to migrate an existing `QdrantDocumentStore` to a new one with support for sparse embeddings.
|
|
17
19
|
|
|
@@ -61,8 +63,10 @@ def migrate_to_sparse_embeddings_support(old_document_store: QdrantDocumentStore
|
|
|
61
63
|
init_parameters["recreate_index"] = True
|
|
62
64
|
|
|
63
65
|
new_document_store = QdrantDocumentStore(**init_parameters)
|
|
66
|
+
new_document_store._initialize_client()
|
|
67
|
+
assert new_document_store._client is not None
|
|
64
68
|
|
|
65
|
-
client = new_document_store.
|
|
69
|
+
client = new_document_store._client
|
|
66
70
|
|
|
67
71
|
original_indexing_threshold = client.get_collection(
|
|
68
72
|
collection_name=new_index
|
|
@@ -115,7 +119,7 @@ def migrate_to_sparse_embeddings_support(old_document_store: QdrantDocumentStore
|
|
|
115
119
|
|
|
116
120
|
message = (
|
|
117
121
|
f"Points transmitted: {points_transmitted}/{total_points}\n"
|
|
118
|
-
f"Percent done {points_transmitted/total_points*100:.2f}%\n"
|
|
122
|
+
f"Percent done {points_transmitted / total_points * 100:.2f}%\n"
|
|
119
123
|
f"Time elapsed: {time.time() - start:.2f} seconds\n"
|
|
120
124
|
f"Time remaining: {(((time.time() - start) / points_transmitted) * points_remaining) / 60:.2f} minutes\n"
|
|
121
125
|
f"Current offset: {next_page_offset}\n"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: qdrant-haystack
|
|
3
|
-
Version:
|
|
3
|
+
Version: 10.2.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,16 +11,15 @@ License-File: LICENSE.txt
|
|
|
11
11
|
Classifier: Development Status :: 4 - Beta
|
|
12
12
|
Classifier: License :: OSI Approved :: Apache Software License
|
|
13
13
|
Classifier: Programming Language :: Python
|
|
14
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
15
14
|
Classifier: Programming Language :: Python :: 3.10
|
|
16
15
|
Classifier: Programming Language :: Python :: 3.11
|
|
17
16
|
Classifier: Programming Language :: Python :: 3.12
|
|
18
17
|
Classifier: Programming Language :: Python :: 3.13
|
|
19
18
|
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
20
19
|
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
|
21
|
-
Requires-Python: >=3.
|
|
22
|
-
Requires-Dist: haystack-ai>=2.
|
|
23
|
-
Requires-Dist: qdrant-client>=1.
|
|
20
|
+
Requires-Python: >=3.10
|
|
21
|
+
Requires-Dist: haystack-ai>=2.22.0
|
|
22
|
+
Requires-Dist: qdrant-client>=1.12.0
|
|
24
23
|
Description-Content-Type: text/markdown
|
|
25
24
|
|
|
26
25
|
# qdrant-haystack
|
|
@@ -28,26 +27,11 @@ Description-Content-Type: text/markdown
|
|
|
28
27
|
[](https://pypi.org/project/qdrant-haystack)
|
|
29
28
|
[](https://pypi.org/project/qdrant-haystack)
|
|
30
29
|
|
|
31
|
-
|
|
30
|
+
- [Integration page](https://haystack.deepset.ai/integrations/qdrant-document-store)
|
|
31
|
+
- [Changelog](https://github.com/deepset-ai/haystack-core-integrations/blob/main/integrations/qdrant/CHANGELOG.md)
|
|
32
32
|
|
|
33
|
-
|
|
33
|
+
---
|
|
34
34
|
|
|
35
|
-
|
|
36
|
-
- [License](#license)
|
|
35
|
+
## Contributing
|
|
37
36
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
```console
|
|
41
|
-
pip install qdrant-haystack
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
## Testing
|
|
45
|
-
The test suites use Qdrant's in-memory instance. No additional steps required.
|
|
46
|
-
|
|
47
|
-
```console
|
|
48
|
-
hatch run test
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
## License
|
|
52
|
-
|
|
53
|
-
`qdrant-haystack` is distributed under the terms of the [Apache-2.0](https://spdx.org/licenses/Apache-2.0.html) license.
|
|
37
|
+
Refer to the general [Contribution Guidelines](https://github.com/deepset-ai/haystack-core-integrations/blob/main/CONTRIBUTING.md).
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
haystack_integrations/components/retrievers/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
+
haystack_integrations/components/retrievers/qdrant/__init__.py,sha256=AE1hdw4sqb0rTSqfAxKCRUOZVE8gbHdQ1wDccdN86hc,313
|
|
3
|
+
haystack_integrations/components/retrievers/qdrant/retriever.py,sha256=UFloH86KQGuLPu3dAVf7bS6EgTVX0FzjdxEqaSMvu4k,32593
|
|
4
|
+
haystack_integrations/document_stores/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
5
|
+
haystack_integrations/document_stores/qdrant/__init__.py,sha256=kUGc5uewqArhmVR-JqB_NmJ4kNkTIQIvYDNSoO2ELn0,302
|
|
6
|
+
haystack_integrations/document_stores/qdrant/converters.py,sha256=Rm5LI3Aw5gBuXwpZzvaECvpLhgSEI3zp9Va97-SfipU,2605
|
|
7
|
+
haystack_integrations/document_stores/qdrant/document_store.py,sha256=XYKLXzhHdnzK6q4LFbAAxF3IBPVXnjkTMaIdC1hl9Iw,103894
|
|
8
|
+
haystack_integrations/document_stores/qdrant/filters.py,sha256=uiac8igBikWb6hWpiS6SaE9N1GX52II2tOEGLC4izb0,8319
|
|
9
|
+
haystack_integrations/document_stores/qdrant/migrate_to_sparse.py,sha256=DcQ9_Ilx1fgXOzjsUDpuaM9TKh2utmVm2hYFn-V2CkQ,5129
|
|
10
|
+
qdrant_haystack-10.2.0.dist-info/METADATA,sha256=YfmwvqF3VOLrFWDS2znUhVUFnLmRBO59TPtra_M2XZs,1829
|
|
11
|
+
qdrant_haystack-10.2.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
12
|
+
qdrant_haystack-10.2.0.dist-info/licenses/LICENSE.txt,sha256=B05uMshqTA74s-0ltyHKI6yoPfJ3zYgQbvcXfDVGFf8,10280
|
|
13
|
+
qdrant_haystack-10.2.0.dist-info/RECORD,,
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
haystack_integrations/components/retrievers/qdrant/__init__.py,sha256=AE1hdw4sqb0rTSqfAxKCRUOZVE8gbHdQ1wDccdN86hc,313
|
|
2
|
-
haystack_integrations/components/retrievers/qdrant/retriever.py,sha256=IKl3gHaOhDiwIgPsQm1fTBkgSPPd5OIl3XXFevnVJvk,29100
|
|
3
|
-
haystack_integrations/document_stores/qdrant/__init__.py,sha256=kUGc5uewqArhmVR-JqB_NmJ4kNkTIQIvYDNSoO2ELn0,302
|
|
4
|
-
haystack_integrations/document_stores/qdrant/converters.py,sha256=iVhAZ7wdRxRjfLVMHB1JdAhn7LpU5bwza1obGmEePWU,2506
|
|
5
|
-
haystack_integrations/document_stores/qdrant/document_store.py,sha256=a56IX_7mfESF8T4tj4Ew9aripvTkui-sl9FXCl3E1jc,70046
|
|
6
|
-
haystack_integrations/document_stores/qdrant/filters.py,sha256=Nv_eKIYKwUWvldJfa0omfFQ0kgqi6L3DUFeMuIWziOY,11751
|
|
7
|
-
haystack_integrations/document_stores/qdrant/migrate_to_sparse.py,sha256=2xyet1fhy2lpVTs3E75f7oR521zcjT6U2jHd4pLLgKM,4971
|
|
8
|
-
qdrant_haystack-9.1.1.dist-info/METADATA,sha256=6zapHfuuI12SdXaFjpW5atJ8GKfZ6EXo_AVLGT5GT7s,1923
|
|
9
|
-
qdrant_haystack-9.1.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
10
|
-
qdrant_haystack-9.1.1.dist-info/licenses/LICENSE.txt,sha256=B05uMshqTA74s-0ltyHKI6yoPfJ3zYgQbvcXfDVGFf8,10280
|
|
11
|
-
qdrant_haystack-9.1.1.dist-info/RECORD,,
|
|
File without changes
|