vicinity 0.3.4__tar.gz → 0.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.
- {vicinity-0.3.4 → vicinity-0.4.0}/PKG-INFO +1 -1
- {vicinity-0.3.4 → vicinity-0.4.0}/uv.lock +1 -1
- {vicinity-0.3.4 → vicinity-0.4.0}/vicinity/backends/annoy.py +5 -4
- {vicinity-0.3.4 → vicinity-0.4.0}/vicinity/backends/base.py +1 -1
- {vicinity-0.3.4 → vicinity-0.4.0}/vicinity/backends/basic.py +9 -6
- {vicinity-0.3.4 → vicinity-0.4.0}/vicinity/backends/faiss.py +7 -5
- {vicinity-0.3.4 → vicinity-0.4.0}/vicinity/backends/hnsw.py +5 -4
- {vicinity-0.3.4 → vicinity-0.4.0}/vicinity/backends/pynndescent.py +6 -6
- {vicinity-0.3.4 → vicinity-0.4.0}/vicinity/backends/usearch.py +9 -6
- {vicinity-0.3.4 → vicinity-0.4.0}/vicinity/backends/voyager.py +5 -4
- {vicinity-0.3.4 → vicinity-0.4.0}/vicinity/version.py +1 -1
- {vicinity-0.3.4 → vicinity-0.4.0}/vicinity/vicinity.py +12 -8
- {vicinity-0.3.4 → vicinity-0.4.0}/vicinity.egg-info/PKG-INFO +1 -1
- {vicinity-0.3.4 → vicinity-0.4.0}/.github/workflows/ci.yaml +0 -0
- {vicinity-0.3.4 → vicinity-0.4.0}/.gitignore +0 -0
- {vicinity-0.3.4 → vicinity-0.4.0}/.pre-commit-config.yaml +0 -0
- {vicinity-0.3.4 → vicinity-0.4.0}/LICENSE +0 -0
- {vicinity-0.3.4 → vicinity-0.4.0}/Makefile +0 -0
- {vicinity-0.3.4 → vicinity-0.4.0}/README.md +0 -0
- {vicinity-0.3.4 → vicinity-0.4.0}/assets/images/vicinity_logo.png +0 -0
- {vicinity-0.3.4 → vicinity-0.4.0}/pyproject.toml +0 -0
- {vicinity-0.3.4 → vicinity-0.4.0}/setup.cfg +0 -0
- {vicinity-0.3.4 → vicinity-0.4.0}/tests/conftest.py +0 -0
- {vicinity-0.3.4 → vicinity-0.4.0}/tests/test_utils.py +0 -0
- {vicinity-0.3.4 → vicinity-0.4.0}/tests/test_vicinity.py +0 -0
- {vicinity-0.3.4 → vicinity-0.4.0}/vicinity/__init__.py +0 -0
- {vicinity-0.3.4 → vicinity-0.4.0}/vicinity/backends/__init__.py +0 -0
- {vicinity-0.3.4 → vicinity-0.4.0}/vicinity/datatypes.py +0 -0
- {vicinity-0.3.4 → vicinity-0.4.0}/vicinity/py.typed +0 -0
- {vicinity-0.3.4 → vicinity-0.4.0}/vicinity/utils.py +0 -0
- {vicinity-0.3.4 → vicinity-0.4.0}/vicinity.egg-info/SOURCES.txt +0 -0
- {vicinity-0.3.4 → vicinity-0.4.0}/vicinity.egg-info/dependency_links.txt +0 -0
- {vicinity-0.3.4 → vicinity-0.4.0}/vicinity.egg-info/requires.txt +0 -0
- {vicinity-0.3.4 → vicinity-0.4.0}/vicinity.egg-info/top_level.txt +0 -0
|
@@ -126,9 +126,10 @@ class AnnoyBackend(AbstractBackend[AnnoyArgs]):
|
|
|
126
126
|
"""Delete vectors from the backend."""
|
|
127
127
|
raise NotImplementedError("Deletion is not supported in Annoy backend.")
|
|
128
128
|
|
|
129
|
-
def threshold(self, vectors: npt.NDArray, threshold: float) ->
|
|
129
|
+
def threshold(self, vectors: npt.NDArray, threshold: float, max_k: int) -> QueryResult:
|
|
130
130
|
"""Threshold the backend."""
|
|
131
|
-
out:
|
|
132
|
-
for x, y in self.query(vectors,
|
|
133
|
-
|
|
131
|
+
out: QueryResult = []
|
|
132
|
+
for x, y in self.query(vectors, max_k):
|
|
133
|
+
mask = y < threshold
|
|
134
|
+
out.append((x[mask], y[mask]))
|
|
134
135
|
return out
|
|
@@ -92,7 +92,7 @@ class AbstractBackend(ABC, Generic[ArgType]):
|
|
|
92
92
|
raise NotImplementedError()
|
|
93
93
|
|
|
94
94
|
@abstractmethod
|
|
95
|
-
def threshold(self, vectors: npt.NDArray, threshold: float) ->
|
|
95
|
+
def threshold(self, vectors: npt.NDArray, threshold: float, max_k: int) -> QueryResult:
|
|
96
96
|
"""Threshold the backend."""
|
|
97
97
|
raise NotImplementedError()
|
|
98
98
|
|
|
@@ -150,22 +150,25 @@ class BasicBackend(BasicVectorStore, AbstractBackend[BasicArgs], ABC):
|
|
|
150
150
|
self,
|
|
151
151
|
vectors: npt.NDArray,
|
|
152
152
|
threshold: float,
|
|
153
|
-
|
|
153
|
+
max_k: int,
|
|
154
|
+
) -> QueryResult:
|
|
154
155
|
"""
|
|
155
156
|
Batched distance thresholding.
|
|
156
157
|
|
|
157
158
|
:param vectors: The vectors to threshold.
|
|
158
159
|
:param threshold: The threshold to use.
|
|
159
|
-
:
|
|
160
|
+
:param max_k: The maximum number of neighbors to consider.
|
|
161
|
+
:return: A list of tuples with the indices and distances.
|
|
160
162
|
"""
|
|
161
|
-
out:
|
|
163
|
+
out: QueryResult = []
|
|
162
164
|
for i in range(0, len(vectors), 1024):
|
|
163
165
|
batch = vectors[i : i + 1024]
|
|
164
166
|
distances = self._dist(batch)
|
|
165
167
|
for dists in distances:
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
168
|
+
mask = dists <= threshold
|
|
169
|
+
indices = np.flatnonzero(mask)
|
|
170
|
+
filtered_distances = dists[mask]
|
|
171
|
+
out.append((indices, filtered_distances))
|
|
169
172
|
return out
|
|
170
173
|
|
|
171
174
|
def query(
|
|
@@ -164,9 +164,9 @@ class FaissBackend(AbstractBackend[FaissArgs]):
|
|
|
164
164
|
"""Delete vectors from the backend."""
|
|
165
165
|
raise NotImplementedError("Deletion is not supported in FAISS backends.")
|
|
166
166
|
|
|
167
|
-
def threshold(self, vectors: npt.NDArray, threshold: float) ->
|
|
167
|
+
def threshold(self, vectors: npt.NDArray, threshold: float, max_k: int) -> QueryResult:
|
|
168
168
|
"""Query vectors within a distance threshold, using range_search if supported."""
|
|
169
|
-
out:
|
|
169
|
+
out: QueryResult = []
|
|
170
170
|
if self.arguments.metric == "cosine":
|
|
171
171
|
vectors = normalize(vectors)
|
|
172
172
|
|
|
@@ -179,13 +179,15 @@ class FaissBackend(AbstractBackend[FaissArgs]):
|
|
|
179
179
|
dist = D[start:end]
|
|
180
180
|
if self.arguments.metric == "cosine":
|
|
181
181
|
dist = 1 - dist
|
|
182
|
-
|
|
182
|
+
mask = dist < threshold
|
|
183
|
+
out.append((idx[mask], dist[mask]))
|
|
183
184
|
else:
|
|
184
|
-
distances, indices = self.index.search(vectors,
|
|
185
|
+
distances, indices = self.index.search(vectors, max_k)
|
|
185
186
|
for dist, idx in zip(distances, indices):
|
|
186
187
|
if self.arguments.metric == "cosine":
|
|
187
188
|
dist = 1 - dist
|
|
188
|
-
|
|
189
|
+
mask = dist < threshold
|
|
190
|
+
out.append((idx[mask], dist[mask]))
|
|
189
191
|
|
|
190
192
|
return out
|
|
191
193
|
|
|
@@ -104,10 +104,11 @@ class HNSWBackend(AbstractBackend[HNSWArgs]):
|
|
|
104
104
|
"""Delete vectors from the backend."""
|
|
105
105
|
raise NotImplementedError("Deletion is not supported in HNSW backend.")
|
|
106
106
|
|
|
107
|
-
def threshold(self, vectors: npt.NDArray, threshold: float) ->
|
|
107
|
+
def threshold(self, vectors: npt.NDArray, threshold: float, max_k: int) -> QueryResult:
|
|
108
108
|
"""Threshold the backend."""
|
|
109
|
-
out:
|
|
110
|
-
for x, y in self.query(vectors,
|
|
111
|
-
|
|
109
|
+
out: QueryResult = []
|
|
110
|
+
for x, y in self.query(vectors, max_k):
|
|
111
|
+
mask = y < threshold
|
|
112
|
+
out.append((x[mask], y[mask]))
|
|
112
113
|
|
|
113
114
|
return out
|
|
@@ -80,15 +80,15 @@ class PyNNDescentBackend(AbstractBackend[PyNNDescentArgs]):
|
|
|
80
80
|
"""Delete vectors from the backend."""
|
|
81
81
|
raise NotImplementedError("Deletion is not supported in PyNNDescent backend.")
|
|
82
82
|
|
|
83
|
-
def threshold(self, vectors: npt.NDArray, threshold: float) ->
|
|
83
|
+
def threshold(self, vectors: npt.NDArray, threshold: float, max_k: int) -> QueryResult:
|
|
84
84
|
"""Find neighbors within a distance threshold."""
|
|
85
85
|
normalized_vectors = normalize_or_copy(vectors)
|
|
86
|
-
indices, distances = self.index.query(normalized_vectors, k=
|
|
87
|
-
|
|
86
|
+
indices, distances = self.index.query(normalized_vectors, k=max_k)
|
|
87
|
+
out: QueryResult = []
|
|
88
88
|
for idx, dist in zip(indices, distances):
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
return
|
|
89
|
+
mask = dist < threshold
|
|
90
|
+
out.append((idx[mask], dist[mask]))
|
|
91
|
+
return out
|
|
92
92
|
|
|
93
93
|
def save(self, base_path: Path) -> None:
|
|
94
94
|
"""Save the vectors and configuration to a specified path."""
|
|
@@ -129,9 +129,12 @@ class UsearchBackend(AbstractBackend[UsearchArgs]):
|
|
|
129
129
|
"""Delete vectors from the index (not supported by Usearch)."""
|
|
130
130
|
raise NotImplementedError("Dynamic deletion is not supported in Usearch.")
|
|
131
131
|
|
|
132
|
-
def threshold(self, vectors: npt.NDArray, threshold: float) ->
|
|
133
|
-
"""
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
132
|
+
def threshold(self, vectors: npt.NDArray, threshold: float, max_k: int) -> QueryResult:
|
|
133
|
+
"""Query vectors within a distance threshold and return keys and distances."""
|
|
134
|
+
out: QueryResult = []
|
|
135
|
+
for keys_row, distances_row in self.query(vectors, max_k):
|
|
136
|
+
keys_row = np.array(keys_row)
|
|
137
|
+
distances_row = np.array(distances_row, dtype=np.float32)
|
|
138
|
+
mask = distances_row < threshold
|
|
139
|
+
out.append((keys_row[mask], distances_row[mask]))
|
|
140
|
+
return out
|
|
@@ -94,11 +94,12 @@ class VoyagerBackend(AbstractBackend[VoyagerArgs]):
|
|
|
94
94
|
"""Delete vectors from the backend."""
|
|
95
95
|
raise NotImplementedError("Deletion is not supported in Voyager backend.")
|
|
96
96
|
|
|
97
|
-
def threshold(self, vectors: npt.NDArray, threshold: float) ->
|
|
97
|
+
def threshold(self, vectors: npt.NDArray, threshold: float, max_k: int) -> QueryResult:
|
|
98
98
|
"""Threshold the backend."""
|
|
99
|
-
out: list[npt.NDArray] = []
|
|
100
|
-
for x, y in self.query(vectors,
|
|
101
|
-
|
|
99
|
+
out: list[tuple[npt.NDArray, npt.NDArray]] = []
|
|
100
|
+
for x, y in self.query(vectors, max_k):
|
|
101
|
+
mask = y < threshold
|
|
102
|
+
out.append((x[mask], y[mask]))
|
|
102
103
|
|
|
103
104
|
return out
|
|
104
105
|
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
__version_triple__ = (0,
|
|
1
|
+
__version_triple__ = (0, 4, 0)
|
|
2
2
|
__version__ = ".".join(map(str, __version_triple__))
|
|
@@ -14,7 +14,7 @@ from numpy import typing as npt
|
|
|
14
14
|
|
|
15
15
|
from vicinity import Metric
|
|
16
16
|
from vicinity.backends import AbstractBackend, BasicBackend, BasicVectorStore, get_backend_class
|
|
17
|
-
from vicinity.datatypes import Backend, PathLike
|
|
17
|
+
from vicinity.datatypes import Backend, PathLike, QueryResult
|
|
18
18
|
|
|
19
19
|
logger = logging.getLogger(__name__)
|
|
20
20
|
|
|
@@ -114,7 +114,7 @@ class Vicinity:
|
|
|
114
114
|
self,
|
|
115
115
|
vectors: npt.NDArray,
|
|
116
116
|
k: int = 10,
|
|
117
|
-
) -> list[
|
|
117
|
+
) -> list[QueryResult]:
|
|
118
118
|
"""
|
|
119
119
|
Find the nearest neighbors to some arbitrary vector.
|
|
120
120
|
|
|
@@ -140,22 +140,26 @@ class Vicinity:
|
|
|
140
140
|
self,
|
|
141
141
|
vectors: npt.NDArray,
|
|
142
142
|
threshold: float = 0.5,
|
|
143
|
-
|
|
143
|
+
max_k: int = 100,
|
|
144
|
+
) -> list[QueryResult]:
|
|
144
145
|
"""
|
|
145
|
-
Find the nearest neighbors to some arbitrary vector with some threshold.
|
|
146
|
+
Find the nearest neighbors to some arbitrary vector with some threshold. Note: the output is not sorted.
|
|
146
147
|
|
|
147
148
|
:param vectors: The vectors to find the most similar vectors to.
|
|
148
149
|
:param threshold: The threshold to use.
|
|
150
|
+
:param max_k: The maximum number of neighbors to consider for the threshold query.
|
|
149
151
|
|
|
150
|
-
:return: For each item in the input,
|
|
152
|
+
:return: For each item in the input, the items above the threshold are returned in the form of
|
|
153
|
+
(NAME, SIMILARITY) tuples.
|
|
151
154
|
"""
|
|
152
|
-
vectors = np.
|
|
155
|
+
vectors = np.asarray(vectors)
|
|
153
156
|
if np.ndim(vectors) == 1:
|
|
154
157
|
vectors = vectors[None, :]
|
|
155
158
|
|
|
156
159
|
out = []
|
|
157
|
-
for
|
|
158
|
-
|
|
160
|
+
for indices, distances in self.backend.threshold(vectors, threshold, max_k=max_k):
|
|
161
|
+
distances.clip(min=0, out=distances)
|
|
162
|
+
out.append([(self.items[idx], dist) for idx, dist in zip(indices, distances)])
|
|
159
163
|
|
|
160
164
|
return out
|
|
161
165
|
|
|
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
|