sie-qdrant 0.1.8__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.
- sie_qdrant/__init__.py +93 -0
- sie_qdrant/vectorizer.py +299 -0
- sie_qdrant-0.1.8.dist-info/METADATA +109 -0
- sie_qdrant-0.1.8.dist-info/RECORD +5 -0
- sie_qdrant-0.1.8.dist-info/WHEEL +4 -0
sie_qdrant/__init__.py
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
"""SIE integration for Qdrant.
|
|
2
|
+
|
|
3
|
+
This package provides vectorizer helpers for Qdrant:
|
|
4
|
+
|
|
5
|
+
- SIEVectorizer: Compute dense embeddings via SIE for Qdrant collections
|
|
6
|
+
- SIENamedVectorizer: Compute multiple vector types (dense + sparse) for Qdrant named vectors
|
|
7
|
+
|
|
8
|
+
Qdrant supports both dense and sparse vectors natively. Dense vectors are
|
|
9
|
+
stored as ``list[float]``, and sparse vectors use ``SparseVector(indices, values)``
|
|
10
|
+
— no expansion to full vocabulary length is needed (unlike Weaviate).
|
|
11
|
+
|
|
12
|
+
Example usage (dense):
|
|
13
|
+
|
|
14
|
+
from qdrant_client import QdrantClient
|
|
15
|
+
from qdrant_client.models import Distance, VectorParams, PointStruct
|
|
16
|
+
from sie_qdrant import SIEVectorizer
|
|
17
|
+
|
|
18
|
+
vectorizer = SIEVectorizer(
|
|
19
|
+
base_url="http://localhost:8080",
|
|
20
|
+
model="BAAI/bge-m3",
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
qdrant = QdrantClient("http://localhost:6333")
|
|
24
|
+
qdrant.create_collection(
|
|
25
|
+
collection_name="documents",
|
|
26
|
+
vectors_config=VectorParams(size=1024, distance=Distance.COSINE),
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
# Embed and insert
|
|
30
|
+
texts = ["first doc", "second doc"]
|
|
31
|
+
vectors = vectorizer.embed_documents(texts)
|
|
32
|
+
qdrant.upsert(
|
|
33
|
+
collection_name="documents",
|
|
34
|
+
points=[
|
|
35
|
+
PointStruct(id=i, vector=v, payload={"text": t})
|
|
36
|
+
for i, (t, v) in enumerate(zip(texts, vectors))
|
|
37
|
+
],
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
# Embed query and search
|
|
41
|
+
query_vector = vectorizer.embed_query("search text")
|
|
42
|
+
results = qdrant.query_points(
|
|
43
|
+
collection_name="documents",
|
|
44
|
+
query=query_vector,
|
|
45
|
+
limit=5,
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
Example usage (named vectors for hybrid search):
|
|
49
|
+
|
|
50
|
+
from qdrant_client import QdrantClient
|
|
51
|
+
from qdrant_client.models import (
|
|
52
|
+
Distance, VectorParams, PointStruct,
|
|
53
|
+
SparseVectorParams, SparseVector,
|
|
54
|
+
)
|
|
55
|
+
from sie_qdrant import SIENamedVectorizer
|
|
56
|
+
|
|
57
|
+
vectorizer = SIENamedVectorizer(
|
|
58
|
+
base_url="http://localhost:8080",
|
|
59
|
+
model="BAAI/bge-m3",
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
qdrant = QdrantClient("http://localhost:6333")
|
|
63
|
+
qdrant.create_collection(
|
|
64
|
+
collection_name="documents",
|
|
65
|
+
vectors_config={"dense": VectorParams(size=1024, distance=Distance.COSINE)},
|
|
66
|
+
sparse_vectors_config={"sparse": SparseVectorParams()},
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
# Embed with both dense and sparse in one SIE call
|
|
70
|
+
texts = ["first doc", "second doc"]
|
|
71
|
+
named = vectorizer.embed_documents(texts)
|
|
72
|
+
qdrant.upsert(
|
|
73
|
+
collection_name="documents",
|
|
74
|
+
points=[
|
|
75
|
+
PointStruct(
|
|
76
|
+
id=i,
|
|
77
|
+
vector={
|
|
78
|
+
"dense": v["dense"],
|
|
79
|
+
"sparse": SparseVector(**v["sparse"]),
|
|
80
|
+
},
|
|
81
|
+
payload={"text": t},
|
|
82
|
+
)
|
|
83
|
+
for i, (t, v) in enumerate(zip(texts, named))
|
|
84
|
+
],
|
|
85
|
+
)
|
|
86
|
+
"""
|
|
87
|
+
|
|
88
|
+
from sie_qdrant.vectorizer import SIENamedVectorizer, SIEVectorizer
|
|
89
|
+
|
|
90
|
+
__all__ = [
|
|
91
|
+
"SIENamedVectorizer",
|
|
92
|
+
"SIEVectorizer",
|
|
93
|
+
]
|
sie_qdrant/vectorizer.py
ADDED
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
"""SIE vectorizer helpers for Qdrant.
|
|
2
|
+
|
|
3
|
+
Qdrant supports both dense and sparse vectors natively. Dense vectors are
|
|
4
|
+
stored as ``list[float]``, and sparse vectors use Qdrant's native
|
|
5
|
+
``SparseVector(indices=..., values=...)`` format — no expansion needed.
|
|
6
|
+
|
|
7
|
+
These helpers wrap SIE's encode() to produce vectors in the format
|
|
8
|
+
Qdrant expects, handling Item creation and output type selection.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
from typing import Any
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class SIEVectorizer:
|
|
17
|
+
"""Compute dense embeddings via SIE for Qdrant collections.
|
|
18
|
+
|
|
19
|
+
Wraps ``SIEClient.encode()`` with ``output_types=["dense"]`` and
|
|
20
|
+
converts results to ``list[float]`` — the format Qdrant's
|
|
21
|
+
``PointStruct(vector=...)`` expects for flat vector collections.
|
|
22
|
+
|
|
23
|
+
Example:
|
|
24
|
+
>>> vectorizer = SIEVectorizer(
|
|
25
|
+
... base_url="http://localhost:8080",
|
|
26
|
+
... model="BAAI/bge-m3",
|
|
27
|
+
... )
|
|
28
|
+
>>> vectors = vectorizer.embed_documents(["hello", "world"])
|
|
29
|
+
>>> query_vec = vectorizer.embed_query("search text")
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
def __init__(
|
|
33
|
+
self,
|
|
34
|
+
base_url: str = "http://localhost:8080",
|
|
35
|
+
model: str = "BAAI/bge-m3",
|
|
36
|
+
*,
|
|
37
|
+
instruction: str | None = None,
|
|
38
|
+
output_dtype: str | None = None,
|
|
39
|
+
gpu: str | None = None,
|
|
40
|
+
options: dict[str, Any] | None = None,
|
|
41
|
+
timeout_s: float = 180.0,
|
|
42
|
+
) -> None:
|
|
43
|
+
"""Initialize SIE vectorizer.
|
|
44
|
+
|
|
45
|
+
Args:
|
|
46
|
+
base_url: SIE server URL.
|
|
47
|
+
model: Model name for embedding.
|
|
48
|
+
instruction: Instruction prefix for instruction-tuned models (e.g., E5).
|
|
49
|
+
output_dtype: Output data type (e.g., "float32", "float16", "int8", "binary").
|
|
50
|
+
gpu: GPU type for routing (e.g., "l4", "a100").
|
|
51
|
+
options: Model-specific options.
|
|
52
|
+
timeout_s: Request timeout in seconds.
|
|
53
|
+
"""
|
|
54
|
+
self._base_url = base_url
|
|
55
|
+
self._model = model
|
|
56
|
+
self._instruction = instruction
|
|
57
|
+
self._output_dtype = output_dtype
|
|
58
|
+
self._gpu = gpu
|
|
59
|
+
self._options = options
|
|
60
|
+
self._timeout_s = timeout_s
|
|
61
|
+
self._client: Any = None
|
|
62
|
+
|
|
63
|
+
@property
|
|
64
|
+
def client(self) -> Any:
|
|
65
|
+
"""Lazily initialize the SIE client."""
|
|
66
|
+
if self._client is None:
|
|
67
|
+
from sie_sdk import SIEClient
|
|
68
|
+
|
|
69
|
+
self._client = SIEClient(
|
|
70
|
+
self._base_url,
|
|
71
|
+
timeout_s=self._timeout_s,
|
|
72
|
+
gpu=self._gpu,
|
|
73
|
+
options=self._options,
|
|
74
|
+
)
|
|
75
|
+
return self._client
|
|
76
|
+
|
|
77
|
+
def embed_documents(self, texts: list[str]) -> list[list[float]]:
|
|
78
|
+
"""Embed a list of documents.
|
|
79
|
+
|
|
80
|
+
Args:
|
|
81
|
+
texts: Document texts to embed.
|
|
82
|
+
|
|
83
|
+
Returns:
|
|
84
|
+
List of dense vectors, one per document. Each vector is a
|
|
85
|
+
``list[float]`` ready for ``PointStruct(vector=...)``.
|
|
86
|
+
"""
|
|
87
|
+
if not texts:
|
|
88
|
+
return []
|
|
89
|
+
|
|
90
|
+
from sie_sdk.types import Item
|
|
91
|
+
|
|
92
|
+
items = [Item(text=text) for text in texts]
|
|
93
|
+
results = self.client.encode(
|
|
94
|
+
self._model,
|
|
95
|
+
items,
|
|
96
|
+
output_types=["dense"],
|
|
97
|
+
instruction=self._instruction,
|
|
98
|
+
output_dtype=self._output_dtype,
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
return [self._extract_dense(result) for result in results]
|
|
102
|
+
|
|
103
|
+
def embed_query(self, text: str) -> list[float]:
|
|
104
|
+
"""Embed a single query text.
|
|
105
|
+
|
|
106
|
+
Passes ``is_query=True`` so instruction-tuned models (e.g., E5)
|
|
107
|
+
apply query-specific prefixes or behavior.
|
|
108
|
+
|
|
109
|
+
Args:
|
|
110
|
+
text: Query text to embed.
|
|
111
|
+
|
|
112
|
+
Returns:
|
|
113
|
+
Dense vector as ``list[float]``, ready for
|
|
114
|
+
``client.query_points()``.
|
|
115
|
+
"""
|
|
116
|
+
from sie_sdk.types import Item
|
|
117
|
+
|
|
118
|
+
result = self.client.encode(
|
|
119
|
+
self._model,
|
|
120
|
+
Item(text=text),
|
|
121
|
+
output_types=["dense"],
|
|
122
|
+
instruction=self._instruction,
|
|
123
|
+
output_dtype=self._output_dtype,
|
|
124
|
+
options={"is_query": True},
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
return self._extract_dense(result)
|
|
128
|
+
|
|
129
|
+
def _extract_dense(self, result: Any) -> list[float]:
|
|
130
|
+
"""Extract dense embedding values from SDK result."""
|
|
131
|
+
dense = result.get("dense") if isinstance(result, dict) else getattr(result, "dense", None)
|
|
132
|
+
if dense is None:
|
|
133
|
+
msg = "Encode result missing dense embedding"
|
|
134
|
+
raise ValueError(msg)
|
|
135
|
+
return dense.tolist() if hasattr(dense, "tolist") else list(dense)
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
class SIENamedVectorizer:
|
|
139
|
+
"""Compute multiple vector types via SIE for Qdrant named vectors.
|
|
140
|
+
|
|
141
|
+
Uses a single SIE encode() call to produce multiple output types
|
|
142
|
+
(e.g., dense + sparse) for Qdrant's named vector feature. This
|
|
143
|
+
maps to collections configured with multiple vector configs.
|
|
144
|
+
|
|
145
|
+
Unlike Weaviate, Qdrant supports sparse vectors natively via
|
|
146
|
+
``SparseVector(indices=..., values=...)``, so sparse output is
|
|
147
|
+
returned in its native dict format without expansion.
|
|
148
|
+
|
|
149
|
+
Example:
|
|
150
|
+
>>> vectorizer = SIENamedVectorizer(
|
|
151
|
+
... base_url="http://localhost:8080",
|
|
152
|
+
... model="BAAI/bge-m3",
|
|
153
|
+
... output_types=["dense", "sparse"],
|
|
154
|
+
... )
|
|
155
|
+
>>> named_vectors = vectorizer.embed_documents(["hello", "world"])
|
|
156
|
+
>>> # [{"dense": [0.1, ...], "sparse": {"indices": [...], "values": [...]}}, ...]
|
|
157
|
+
"""
|
|
158
|
+
|
|
159
|
+
def __init__(
|
|
160
|
+
self,
|
|
161
|
+
base_url: str = "http://localhost:8080",
|
|
162
|
+
model: str = "BAAI/bge-m3",
|
|
163
|
+
*,
|
|
164
|
+
output_types: list[str] | None = None,
|
|
165
|
+
instruction: str | None = None,
|
|
166
|
+
output_dtype: str | None = None,
|
|
167
|
+
gpu: str | None = None,
|
|
168
|
+
options: dict[str, Any] | None = None,
|
|
169
|
+
timeout_s: float = 180.0,
|
|
170
|
+
) -> None:
|
|
171
|
+
"""Initialize SIE named vectorizer.
|
|
172
|
+
|
|
173
|
+
Args:
|
|
174
|
+
base_url: SIE server URL.
|
|
175
|
+
model: Model name for embedding.
|
|
176
|
+
output_types: Vector types to produce (default: ["dense", "sparse"]).
|
|
177
|
+
Must match the named vector config on the Qdrant collection.
|
|
178
|
+
instruction: Instruction prefix for instruction-tuned models (e.g., E5).
|
|
179
|
+
output_dtype: Output data type (e.g., "float32", "float16", "int8", "binary").
|
|
180
|
+
gpu: GPU type for routing (e.g., "l4", "a100").
|
|
181
|
+
options: Model-specific options.
|
|
182
|
+
timeout_s: Request timeout in seconds.
|
|
183
|
+
"""
|
|
184
|
+
self._base_url = base_url
|
|
185
|
+
self._model = model
|
|
186
|
+
self._output_types = output_types or ["dense", "sparse"]
|
|
187
|
+
self._instruction = instruction
|
|
188
|
+
self._output_dtype = output_dtype
|
|
189
|
+
self._gpu = gpu
|
|
190
|
+
self._options = options
|
|
191
|
+
self._timeout_s = timeout_s
|
|
192
|
+
self._client: Any = None
|
|
193
|
+
|
|
194
|
+
@property
|
|
195
|
+
def client(self) -> Any:
|
|
196
|
+
"""Lazily initialize the SIE client."""
|
|
197
|
+
if self._client is None:
|
|
198
|
+
from sie_sdk import SIEClient
|
|
199
|
+
|
|
200
|
+
self._client = SIEClient(
|
|
201
|
+
self._base_url,
|
|
202
|
+
timeout_s=self._timeout_s,
|
|
203
|
+
gpu=self._gpu,
|
|
204
|
+
options=self._options,
|
|
205
|
+
)
|
|
206
|
+
return self._client
|
|
207
|
+
|
|
208
|
+
def embed_documents(self, texts: list[str]) -> list[dict[str, Any]]:
|
|
209
|
+
"""Embed documents with multiple vector types.
|
|
210
|
+
|
|
211
|
+
Args:
|
|
212
|
+
texts: Document texts to embed.
|
|
213
|
+
|
|
214
|
+
Returns:
|
|
215
|
+
List of dicts mapping vector name to vector values.
|
|
216
|
+
Dense vectors are ``list[float]``, sparse vectors are
|
|
217
|
+
``{"indices": list[int], "values": list[float]}``.
|
|
218
|
+
"""
|
|
219
|
+
if not texts:
|
|
220
|
+
return []
|
|
221
|
+
|
|
222
|
+
from sie_sdk.types import Item
|
|
223
|
+
|
|
224
|
+
items = [Item(text=text) for text in texts]
|
|
225
|
+
results = self.client.encode(
|
|
226
|
+
self._model,
|
|
227
|
+
items,
|
|
228
|
+
output_types=self._output_types,
|
|
229
|
+
instruction=self._instruction,
|
|
230
|
+
output_dtype=self._output_dtype,
|
|
231
|
+
)
|
|
232
|
+
|
|
233
|
+
return [self._extract_named(result) for result in results]
|
|
234
|
+
|
|
235
|
+
def embed_query(self, text: str) -> dict[str, Any]:
|
|
236
|
+
"""Embed a query with multiple vector types.
|
|
237
|
+
|
|
238
|
+
Passes ``is_query=True`` so instruction-tuned models apply
|
|
239
|
+
query-specific behavior.
|
|
240
|
+
|
|
241
|
+
Args:
|
|
242
|
+
text: Query text to embed.
|
|
243
|
+
|
|
244
|
+
Returns:
|
|
245
|
+
Dict mapping vector name to vector values.
|
|
246
|
+
"""
|
|
247
|
+
from sie_sdk.types import Item
|
|
248
|
+
|
|
249
|
+
result = self.client.encode(
|
|
250
|
+
self._model,
|
|
251
|
+
Item(text=text),
|
|
252
|
+
output_types=self._output_types,
|
|
253
|
+
instruction=self._instruction,
|
|
254
|
+
output_dtype=self._output_dtype,
|
|
255
|
+
options={"is_query": True},
|
|
256
|
+
)
|
|
257
|
+
|
|
258
|
+
return self._extract_named(result)
|
|
259
|
+
|
|
260
|
+
def _extract_named(self, result: Any) -> dict[str, Any]:
|
|
261
|
+
"""Extract all requested vector types from SDK result.
|
|
262
|
+
|
|
263
|
+
Dense vectors are converted to ``list[float]``.
|
|
264
|
+
Sparse vectors are returned as ``{"indices": list[int], "values": list[float]}``
|
|
265
|
+
matching Qdrant's native ``SparseVector`` format.
|
|
266
|
+
"""
|
|
267
|
+
named: dict[str, Any] = {}
|
|
268
|
+
for output_type in self._output_types:
|
|
269
|
+
raw = result.get(output_type) if isinstance(result, dict) else getattr(result, output_type, None)
|
|
270
|
+
if raw is None:
|
|
271
|
+
continue
|
|
272
|
+
if output_type == "sparse":
|
|
273
|
+
named[output_type] = self._format_sparse(raw)
|
|
274
|
+
else:
|
|
275
|
+
named[output_type] = raw.tolist() if hasattr(raw, "tolist") else list(raw)
|
|
276
|
+
return named
|
|
277
|
+
|
|
278
|
+
@staticmethod
|
|
279
|
+
def _format_sparse(sparse: Any) -> dict[str, list]:
|
|
280
|
+
"""Format SIE sparse output for Qdrant's SparseVector.
|
|
281
|
+
|
|
282
|
+
SIE returns sparse vectors as ``{"indices": [...], "values": [...]}``.
|
|
283
|
+
Qdrant's ``SparseVector`` accepts the same format natively, so we
|
|
284
|
+
just convert numpy arrays to Python lists.
|
|
285
|
+
|
|
286
|
+
Unlike Weaviate (which requires expanding sparse to full vocabulary
|
|
287
|
+
length), Qdrant stores sparse vectors efficiently in their native
|
|
288
|
+
indices+values form.
|
|
289
|
+
"""
|
|
290
|
+
indices = sparse.get("indices") if isinstance(sparse, dict) else getattr(sparse, "indices", None)
|
|
291
|
+
values = sparse.get("values") if isinstance(sparse, dict) else getattr(sparse, "values", None)
|
|
292
|
+
|
|
293
|
+
if indices is None or values is None:
|
|
294
|
+
return {"indices": [], "values": []}
|
|
295
|
+
|
|
296
|
+
indices_list = indices.tolist() if hasattr(indices, "tolist") else list(indices)
|
|
297
|
+
values_list = values.tolist() if hasattr(values, "tolist") else list(values)
|
|
298
|
+
|
|
299
|
+
return {"indices": indices_list, "values": values_list}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: sie-qdrant
|
|
3
|
+
Version: 0.1.8
|
|
4
|
+
Summary: SIE integration for Qdrant
|
|
5
|
+
Requires-Python: >=3.10
|
|
6
|
+
Requires-Dist: qdrant-client>=1.7
|
|
7
|
+
Requires-Dist: sie-sdk>=0.1.0
|
|
8
|
+
Provides-Extra: dev
|
|
9
|
+
Requires-Dist: pytest-asyncio>=0.24; extra == 'dev'
|
|
10
|
+
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
11
|
+
Description-Content-Type: text/markdown
|
|
12
|
+
|
|
13
|
+
# sie-qdrant
|
|
14
|
+
|
|
15
|
+
SIE integration for Qdrant.
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
pip install sie-qdrant
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Dense embeddings
|
|
24
|
+
|
|
25
|
+
```python
|
|
26
|
+
from qdrant_client import QdrantClient
|
|
27
|
+
from qdrant_client.models import Distance, VectorParams, PointStruct
|
|
28
|
+
from sie_qdrant import SIEVectorizer
|
|
29
|
+
|
|
30
|
+
vectorizer = SIEVectorizer(base_url="http://localhost:8080", model="BAAI/bge-m3")
|
|
31
|
+
|
|
32
|
+
qdrant = QdrantClient("http://localhost:6333")
|
|
33
|
+
qdrant.create_collection(
|
|
34
|
+
collection_name="documents",
|
|
35
|
+
vectors_config=VectorParams(size=1024, distance=Distance.COSINE),
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
texts = ["first doc", "second doc"]
|
|
39
|
+
vectors = vectorizer.embed_documents(texts)
|
|
40
|
+
qdrant.upsert(
|
|
41
|
+
collection_name="documents",
|
|
42
|
+
points=[
|
|
43
|
+
PointStruct(id=i, vector=v, payload={"text": t})
|
|
44
|
+
for i, (t, v) in enumerate(zip(texts, vectors))
|
|
45
|
+
],
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
query_vec = vectorizer.embed_query("search text")
|
|
49
|
+
results = qdrant.query_points(
|
|
50
|
+
collection_name="documents", query=query_vec, limit=5
|
|
51
|
+
)
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Named vectors (dense + sparse)
|
|
55
|
+
|
|
56
|
+
SIE's multi-output encode produces dense and sparse vectors in one call.
|
|
57
|
+
Qdrant supports sparse vectors natively via `SparseVector(indices, values)`,
|
|
58
|
+
so no expansion to full vocabulary length is needed:
|
|
59
|
+
|
|
60
|
+
```python
|
|
61
|
+
from qdrant_client import QdrantClient
|
|
62
|
+
from qdrant_client.models import (
|
|
63
|
+
Distance, VectorParams, PointStruct,
|
|
64
|
+
SparseVectorParams, SparseVector,
|
|
65
|
+
)
|
|
66
|
+
from sie_qdrant import SIENamedVectorizer
|
|
67
|
+
|
|
68
|
+
vectorizer = SIENamedVectorizer(
|
|
69
|
+
base_url="http://localhost:8080",
|
|
70
|
+
model="BAAI/bge-m3",
|
|
71
|
+
output_types=["dense", "sparse"],
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
qdrant = QdrantClient("http://localhost:6333")
|
|
75
|
+
qdrant.create_collection(
|
|
76
|
+
collection_name="documents",
|
|
77
|
+
vectors_config={"dense": VectorParams(size=1024, distance=Distance.COSINE)},
|
|
78
|
+
sparse_vectors_config={"sparse": SparseVectorParams()},
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
named = vectorizer.embed_documents(["hello world"])
|
|
82
|
+
qdrant.upsert(
|
|
83
|
+
collection_name="documents",
|
|
84
|
+
points=[
|
|
85
|
+
PointStruct(
|
|
86
|
+
id=0,
|
|
87
|
+
vector={
|
|
88
|
+
"dense": named[0]["dense"],
|
|
89
|
+
"sparse": SparseVector(**named[0]["sparse"]),
|
|
90
|
+
},
|
|
91
|
+
payload={"text": "hello world"},
|
|
92
|
+
)
|
|
93
|
+
],
|
|
94
|
+
)
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
**Storage advantage:** Unlike integrations that expand sparse vectors to full
|
|
98
|
+
vocabulary length (~30K floats), Qdrant stores sparse vectors in their native
|
|
99
|
+
indices+values form, making hybrid search storage-efficient.
|
|
100
|
+
|
|
101
|
+
## Testing
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
# Unit tests (no server needed)
|
|
105
|
+
pytest
|
|
106
|
+
|
|
107
|
+
# Integration tests (requires SIE + Qdrant)
|
|
108
|
+
pytest -m integration
|
|
109
|
+
```
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
sie_qdrant/__init__.py,sha256=ublrXDeyfPEJg5gmYT1myTr0JyLJMYuajDqp1NOQ-Xw,2836
|
|
2
|
+
sie_qdrant/vectorizer.py,sha256=lB2UB3Ug-bXs-IUmmSGM9GpoQqUiCXFDephBfOHrEK0,10507
|
|
3
|
+
sie_qdrant-0.1.8.dist-info/METADATA,sha256=1yZ95vr_A02Od4W290Mj8vTOYm_8WHvyqE7kHxuqc44,2824
|
|
4
|
+
sie_qdrant-0.1.8.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
|
|
5
|
+
sie_qdrant-0.1.8.dist-info/RECORD,,
|