vicinity 0.3.2__tar.gz → 0.3.4__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.
Files changed (34) hide show
  1. {vicinity-0.3.2 → vicinity-0.3.4}/PKG-INFO +9 -4
  2. {vicinity-0.3.2 → vicinity-0.3.4}/README.md +8 -3
  3. {vicinity-0.3.2 → vicinity-0.3.4}/tests/conftest.py +1 -1
  4. {vicinity-0.3.2 → vicinity-0.3.4}/tests/test_vicinity.py +42 -5
  5. {vicinity-0.3.2 → vicinity-0.3.4}/uv.lock +41 -1
  6. {vicinity-0.3.2 → vicinity-0.3.4}/vicinity/backends/faiss.py +1 -0
  7. {vicinity-0.3.2 → vicinity-0.3.4}/vicinity/backends/hnsw.py +1 -0
  8. {vicinity-0.3.2 → vicinity-0.3.4}/vicinity/backends/usearch.py +3 -2
  9. {vicinity-0.3.2 → vicinity-0.3.4}/vicinity/backends/voyager.py +1 -0
  10. {vicinity-0.3.2 → vicinity-0.3.4}/vicinity/version.py +1 -1
  11. {vicinity-0.3.2 → vicinity-0.3.4}/vicinity/vicinity.py +4 -0
  12. {vicinity-0.3.2 → vicinity-0.3.4}/vicinity.egg-info/PKG-INFO +9 -4
  13. {vicinity-0.3.2 → vicinity-0.3.4}/.github/workflows/ci.yaml +0 -0
  14. {vicinity-0.3.2 → vicinity-0.3.4}/.gitignore +0 -0
  15. {vicinity-0.3.2 → vicinity-0.3.4}/.pre-commit-config.yaml +0 -0
  16. {vicinity-0.3.2 → vicinity-0.3.4}/LICENSE +0 -0
  17. {vicinity-0.3.2 → vicinity-0.3.4}/Makefile +0 -0
  18. {vicinity-0.3.2 → vicinity-0.3.4}/assets/images/vicinity_logo.png +0 -0
  19. {vicinity-0.3.2 → vicinity-0.3.4}/pyproject.toml +0 -0
  20. {vicinity-0.3.2 → vicinity-0.3.4}/setup.cfg +0 -0
  21. {vicinity-0.3.2 → vicinity-0.3.4}/tests/test_utils.py +0 -0
  22. {vicinity-0.3.2 → vicinity-0.3.4}/vicinity/__init__.py +0 -0
  23. {vicinity-0.3.2 → vicinity-0.3.4}/vicinity/backends/__init__.py +0 -0
  24. {vicinity-0.3.2 → vicinity-0.3.4}/vicinity/backends/annoy.py +0 -0
  25. {vicinity-0.3.2 → vicinity-0.3.4}/vicinity/backends/base.py +0 -0
  26. {vicinity-0.3.2 → vicinity-0.3.4}/vicinity/backends/basic.py +4 -4
  27. {vicinity-0.3.2 → vicinity-0.3.4}/vicinity/backends/pynndescent.py +0 -0
  28. {vicinity-0.3.2 → vicinity-0.3.4}/vicinity/datatypes.py +0 -0
  29. {vicinity-0.3.2 → vicinity-0.3.4}/vicinity/py.typed +0 -0
  30. {vicinity-0.3.2 → vicinity-0.3.4}/vicinity/utils.py +0 -0
  31. {vicinity-0.3.2 → vicinity-0.3.4}/vicinity.egg-info/SOURCES.txt +0 -0
  32. {vicinity-0.3.2 → vicinity-0.3.4}/vicinity.egg-info/dependency_links.txt +0 -0
  33. {vicinity-0.3.2 → vicinity-0.3.4}/vicinity.egg-info/requires.txt +0 -0
  34. {vicinity-0.3.2 → vicinity-0.3.4}/vicinity.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: vicinity
3
- Version: 0.3.2
3
+ Version: 0.3.4
4
4
  Summary: Lightweight Nearest Neighbors with Flexible Backends
5
5
  Author-email: Stéphan Tulkens <stephantul@gmail.com>, Thomas van Dongen <thomas123@live.nl>
6
6
  License: MIT License
@@ -153,10 +153,14 @@ vicinity = Vicinity.from_vectors_and_items(
153
153
  query_vector = np.random.rand(128)
154
154
 
155
155
  # Query for nearest neighbors with a top-k search
156
- results = vicinity.query([query_vector], k=3)
156
+ results = vicinity.query(query_vector, k=3)
157
157
 
158
158
  # Query for nearest neighbors with a threshold search
159
- results = vicinity.query_threshold([query_vector], threshold=0.9)
159
+ results = vicinity.query_threshold(query_vector, threshold=0.9)
160
+
161
+ # Query with a list of query vectors
162
+ query_vectors = np.random.rand(5, 128)
163
+ results = vicinity.query(query_vectors, k=3)
160
164
  ```
161
165
 
162
166
  Saving and loading a vector store:
@@ -191,7 +195,7 @@ The following backends are supported:
191
195
  - [HNSW](https://github.com/nmslib/hnswlib): Hierarchical Navigable Small World Graph (HNSW) for ANN search using hnswlib.
192
196
  - [USEARCH](https://github.com/unum-cloud/usearch): ANN search using Usearch. This uses a highly optimized version of the HNSW algorithm.
193
197
  - [ANNOY](https://github.com/spotify/annoy): "Approximate Nearest Neighbors Oh Yeah" for approximate nearest neighbor search.
194
- - [PYNNDescent](https://github.com/lmcinnes/pynndescent): ANN search using PyNNDescent.
198
+ - [PYNNDESCENT](https://github.com/lmcinnes/pynndescent): ANN search using PyNNDescent.
195
199
  - [FAISS](https://github.com/facebookresearch/faiss): All FAISS indexes are supported:
196
200
  - `flat`: Exact search.
197
201
  - `ivf`: Inverted file search.
@@ -213,6 +217,7 @@ NOTE: the ANN backends do not support dynamic deletion. To delete items, you nee
213
217
 
214
218
  | Backend | Parameter | Description | Default Value |
215
219
  |-----------------|---------------------|-----------------------------------------------------------------------------------------------|---------------------|
220
+ | **BASIC** | `metric` | Similarity metric to use (`cosine`, `euclidean`). | `"cosine"` |
216
221
  | **ANNOY** | `metric` | Similarity metric to use (`dot`, `euclidean`, `cosine`). | `"cosine"` |
217
222
  | | `trees` | Number of trees to use for indexing. | `100` |
218
223
  | | `length` | Optional length of the dataset. | `None` |
@@ -71,10 +71,14 @@ vicinity = Vicinity.from_vectors_and_items(
71
71
  query_vector = np.random.rand(128)
72
72
 
73
73
  # Query for nearest neighbors with a top-k search
74
- results = vicinity.query([query_vector], k=3)
74
+ results = vicinity.query(query_vector, k=3)
75
75
 
76
76
  # Query for nearest neighbors with a threshold search
77
- results = vicinity.query_threshold([query_vector], threshold=0.9)
77
+ results = vicinity.query_threshold(query_vector, threshold=0.9)
78
+
79
+ # Query with a list of query vectors
80
+ query_vectors = np.random.rand(5, 128)
81
+ results = vicinity.query(query_vectors, k=3)
78
82
  ```
79
83
 
80
84
  Saving and loading a vector store:
@@ -109,7 +113,7 @@ The following backends are supported:
109
113
  - [HNSW](https://github.com/nmslib/hnswlib): Hierarchical Navigable Small World Graph (HNSW) for ANN search using hnswlib.
110
114
  - [USEARCH](https://github.com/unum-cloud/usearch): ANN search using Usearch. This uses a highly optimized version of the HNSW algorithm.
111
115
  - [ANNOY](https://github.com/spotify/annoy): "Approximate Nearest Neighbors Oh Yeah" for approximate nearest neighbor search.
112
- - [PYNNDescent](https://github.com/lmcinnes/pynndescent): ANN search using PyNNDescent.
116
+ - [PYNNDESCENT](https://github.com/lmcinnes/pynndescent): ANN search using PyNNDescent.
113
117
  - [FAISS](https://github.com/facebookresearch/faiss): All FAISS indexes are supported:
114
118
  - `flat`: Exact search.
115
119
  - `ivf`: Inverted file search.
@@ -131,6 +135,7 @@ NOTE: the ANN backends do not support dynamic deletion. To delete items, you nee
131
135
 
132
136
  | Backend | Parameter | Description | Default Value |
133
137
  |-----------------|---------------------|-----------------------------------------------------------------------------------------------|---------------------|
138
+ | **BASIC** | `metric` | Similarity metric to use (`cosine`, `euclidean`). | `"cosine"` |
134
139
  | **ANNOY** | `metric` | Similarity metric to use (`dot`, `euclidean`, `cosine`). | `"cosine"` |
135
140
  | | `trees` | Number of trees to use for indexing. | `100` |
136
141
  | | `length` | Optional length of the dataset. | `None` |
@@ -110,6 +110,6 @@ def vicinity_instance_with_stored_vectors(
110
110
 
111
111
 
112
112
  @pytest.fixture()
113
- def vicinity_with_basic_backend(vectors: np.ndarray, items: list[str]) -> Vicinity:
113
+ def vicinity_with_basic_backend_and_store(vectors: np.ndarray, items: list[str]) -> Vicinity:
114
114
  """Fixture providing a BasicBackend instance."""
115
115
  return Vicinity.from_vectors_and_items(vectors, items, backend_type=Backend.BASIC, store_vectors=True)
@@ -58,6 +58,10 @@ def test_vicinity_query(vicinity_instance: Vicinity, query_vector: np.ndarray) -
58
58
 
59
59
  assert len(results) == 1
60
60
 
61
+ results = vicinity_instance.query(np.stack([query_vector, query_vector]), k=2)
62
+
63
+ assert results[0] == results[1]
64
+
61
65
 
62
66
  def test_vicinity_query_threshold(vicinity_instance: Vicinity, query_vector: np.ndarray) -> None:
63
67
  """
@@ -70,6 +74,10 @@ def test_vicinity_query_threshold(vicinity_instance: Vicinity, query_vector: np.
70
74
 
71
75
  assert len(results) >= 1
72
76
 
77
+ results = vicinity_instance.query_threshold(np.stack([query_vector, query_vector]), threshold=0.7)
78
+
79
+ assert results[0] == results[1]
80
+
73
81
 
74
82
  def test_vicinity_insert(vicinity_instance: Vicinity, query_vector: np.ndarray) -> None:
75
83
  """
@@ -154,25 +162,25 @@ def test_vicinity_save_and_load_vector_store(tmp_path: Path, vicinity_instance_w
154
162
  assert v.vector_store is not None
155
163
 
156
164
 
157
- def test_index_vector_store(vicinity_with_basic_backend: Vicinity, vectors: np.ndarray) -> None:
165
+ def test_index_vector_store(vicinity_with_basic_backend_and_store: Vicinity, vectors: np.ndarray) -> None:
158
166
  """
159
167
  Index vectors in the Vicinity instance.
160
168
 
161
169
  :param vicinity_instance: A Vicinity instance.
162
170
  :param vectors: Array of vectors to index.
163
171
  """
164
- v = vicinity_with_basic_backend.get_vector_by_index(0)
172
+ v = vicinity_with_basic_backend_and_store.get_vector_by_index(0)
165
173
  assert np.allclose(v, vectors[0])
166
174
 
167
175
  idx = [0, 1, 2, 3, 4, 10]
168
- v = vicinity_with_basic_backend.get_vector_by_index(idx)
176
+ v = vicinity_with_basic_backend_and_store.get_vector_by_index(idx)
169
177
  assert np.allclose(v, vectors[idx])
170
178
 
171
179
  with pytest.raises(ValueError):
172
- vicinity_with_basic_backend.get_vector_by_index([10_000])
180
+ vicinity_with_basic_backend_and_store.get_vector_by_index([10_000])
173
181
 
174
182
  with pytest.raises(ValueError):
175
- vicinity_with_basic_backend.get_vector_by_index([-1])
183
+ vicinity_with_basic_backend_and_store.get_vector_by_index([-1])
176
184
 
177
185
 
178
186
  def test_vicinity_insert_duplicate(vicinity_instance: Vicinity, query_vector: np.ndarray) -> None:
@@ -203,6 +211,35 @@ def test_vicinity_delete_nonexistent(vicinity_instance: Vicinity) -> None:
203
211
  vicinity_instance.delete(["item10002"])
204
212
 
205
213
 
214
+ def test_vicinity_insert_with_store(vicinity_with_basic_backend_and_store: Vicinity) -> None:
215
+ """
216
+ Test that Vicinity.insert raises ValueError when trying to insert vectors into a Vicinity instance with stored vectors.
217
+
218
+ :param vicinity_with_basic_backend_and_store: A Vicinity instance with stored vectors.
219
+ """
220
+ new_item = ["item10002"]
221
+ new_vector = np.full((1, vicinity_with_basic_backend_and_store.dim), 0.5)
222
+
223
+ vicinity_with_basic_backend_and_store.insert(new_item, new_vector)
224
+ assert vicinity_with_basic_backend_and_store.vector_store is not None
225
+ assert len(vicinity_with_basic_backend_and_store) == len(vicinity_with_basic_backend_and_store.vector_store)
226
+
227
+
228
+ def test_vicinity_delete_with_store(vicinity_with_basic_backend_and_store: Vicinity) -> None:
229
+ """
230
+ Test Vicinity.delete method by verifying that the vector for a deleted item is not returned in subsequent queries.
231
+
232
+ :param vicinity_with_basic_backend_and_store: A Vicinity instance.
233
+ """
234
+ assert vicinity_with_basic_backend_and_store.vector_store is not None
235
+ # Delete "item2" from the Vicinity instance
236
+ vicinity_with_basic_backend_and_store.delete(["item2"])
237
+
238
+ # Ensure "item2" is no longer in the items list
239
+ assert "item2" not in vicinity_with_basic_backend_and_store.items
240
+ assert len(vicinity_with_basic_backend_and_store) == len(vicinity_with_basic_backend_and_store.vector_store)
241
+
242
+
206
243
  def test_vicinity_insert_mismatched_lengths(vicinity_instance: Vicinity, query_vector: np.ndarray) -> None:
207
244
  """
208
245
  Test that Vicinity.insert raises ValueError when tokens and vectors lengths do not match.
@@ -1087,7 +1087,7 @@ wheels = [
1087
1087
 
1088
1088
  [[package]]
1089
1089
  name = "vicinity"
1090
- version = "0.3.0"
1090
+ version = "0.3.1"
1091
1091
  source = { editable = "." }
1092
1092
  dependencies = [
1093
1093
  { name = "numpy" },
@@ -1105,6 +1105,7 @@ all = [
1105
1105
  { name = "numpy" },
1106
1106
  { name = "pynndescent" },
1107
1107
  { name = "usearch" },
1108
+ { name = "voyager" },
1108
1109
  ]
1109
1110
  annoy = [
1110
1111
  { name = "annoy" },
@@ -1134,6 +1135,9 @@ pynndescent = [
1134
1135
  usearch = [
1135
1136
  { name = "usearch" },
1136
1137
  ]
1138
+ voyager = [
1139
+ { name = "voyager" },
1140
+ ]
1137
1141
 
1138
1142
  [package.metadata]
1139
1143
  requires-dist = [
@@ -1164,6 +1168,8 @@ requires-dist = [
1164
1168
  { name = "tqdm" },
1165
1169
  { name = "usearch", marker = "extra == 'all'" },
1166
1170
  { name = "usearch", marker = "extra == 'usearch'" },
1171
+ { name = "voyager", marker = "extra == 'all'" },
1172
+ { name = "voyager", marker = "extra == 'voyager'" },
1167
1173
  ]
1168
1174
 
1169
1175
  [[package]]
@@ -1180,6 +1186,40 @@ wheels = [
1180
1186
  { url = "https://files.pythonhosted.org/packages/ae/92/78324ff89391e00c8f4cf6b8526c41c6ef36b4ea2d2c132250b1a6fc2b8d/virtualenv-20.27.1-py3-none-any.whl", hash = "sha256:f11f1b8a29525562925f745563bfd48b189450f61fb34c4f9cc79dd5aa32a1f4", size = 3117838 },
1181
1187
  ]
1182
1188
 
1189
+ [[package]]
1190
+ name = "voyager"
1191
+ version = "2.0.9"
1192
+ source = { registry = "https://pypi.org/simple" }
1193
+ dependencies = [
1194
+ { name = "numpy" },
1195
+ ]
1196
+ wheels = [
1197
+ { url = "https://files.pythonhosted.org/packages/79/d9/62399eb8a907da7f9eba0e2facf78925d54ba644a9be671cd98e7b4f547f/voyager-2.0.9-cp310-cp310-macosx_10_13_universal2.whl", hash = "sha256:f3cfe84666314daaf51836f77dabaafeb064bcbe5d9435d9c97886af19ae2876", size = 731200 },
1198
+ { url = "https://files.pythonhosted.org/packages/51/70/0d90ebf90ca6fa415513b63925f4b21aeebd9f6400ecce5dffdb3743039f/voyager-2.0.9-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:956a60f864a586991cdde09373caf5630ab3319c47b6cdad4bf05ea8ba96a578", size = 377180 },
1199
+ { url = "https://files.pythonhosted.org/packages/6e/af/76bb88b390bbf9c1dcbab90acd669168294c6d20b6a230b7333b432eee1b/voyager-2.0.9-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:56e6e7d6f1597207141d224d5420dc690ae27a2feb6c4164180cecc453cd5816", size = 356644 },
1200
+ { url = "https://files.pythonhosted.org/packages/2b/b9/a514e2f88b7cdf35cb182064d5859258488cfe7e7b82bfff012d9cffd746/voyager-2.0.9-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7be032a8ae5447ce289f1c95f349e825e9d4edc915db7ea1b2c273940de2acbe", size = 4211154 },
1201
+ { url = "https://files.pythonhosted.org/packages/db/95/1032e54e27eeac13f9affaf1fdeb834cc389f728316c9e7244c0e57c3e98/voyager-2.0.9-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ed85d23006f98091a137f637894560d1020ba25217b5332729417ac0a200b0bd", size = 4280843 },
1202
+ { url = "https://files.pythonhosted.org/packages/2c/dc/395551a312110ad53cdac4f0126708d02c2d5c11c9f63ecf6a64985fab56/voyager-2.0.9-cp310-cp310-win_amd64.whl", hash = "sha256:053f22b23bd090f6376cf026c31653d3c040f9eaf0c6d1267e766a442a5b8ff8", size = 199722 },
1203
+ { url = "https://files.pythonhosted.org/packages/c2/17/ace9aaf1e65553dae2ce3ba947e922e6bd16aa89abe558543471b5fe065c/voyager-2.0.9-cp311-cp311-macosx_10_13_universal2.whl", hash = "sha256:d270b29bafb5a133abd611a03b1b9ec7b03a44361966609abef72dde2518eb5e", size = 734474 },
1204
+ { url = "https://files.pythonhosted.org/packages/3b/73/83d047ad7f6cb4fad426ed6f8b6c249c3ffecffa85ebb017e6d4e725aa0c/voyager-2.0.9-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:216c517dd66e0095f5f14277627a233c081797119028737f71168f094bacb9d0", size = 378460 },
1205
+ { url = "https://files.pythonhosted.org/packages/92/3e/7648441cf72258fc2e5cb9be6f39890684f15a06f66db42f12a8041e4e30/voyager-2.0.9-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a2ea7f5e61bb7de06d0196b1fbd43826908c6f2811576c94d97e353e7b32cb78", size = 358415 },
1206
+ { url = "https://files.pythonhosted.org/packages/42/02/0f7c5e4d9eaf83d932ab0c89e93117166575163f670a6200f55a56dae268/voyager-2.0.9-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4c451b25d449ac6923f7424a3255995f97263ed694fa873119703da01a09f6d7", size = 4237185 },
1207
+ { url = "https://files.pythonhosted.org/packages/38/7c/47598f5630b97cf7cf8f29ac390b8beab24adeb3f322d004244660b96e8f/voyager-2.0.9-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ecd1e690a69a044b988fd102676bb8584ed423af4b7aa9e69349203690263aad", size = 4304425 },
1208
+ { url = "https://files.pythonhosted.org/packages/1a/95/fa3f090d8e1bdbd8401e9944080f3c12d1e8f1385980da4151f6ab62a783/voyager-2.0.9-cp311-cp311-win_amd64.whl", hash = "sha256:5e1c264f4202b551ca8cb5a33d456f451c598ea7b9680134177dc5443819f328", size = 200738 },
1209
+ { url = "https://files.pythonhosted.org/packages/22/fa/455fbd3a709403dd98f910b1ba5bfd9bf38db3e718edd03c8758ecb3b750/voyager-2.0.9-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:2d344617a1c97d6b317f13e801b3377a55f1e5b91786f9354dcde12b7945b3e0", size = 736030 },
1210
+ { url = "https://files.pythonhosted.org/packages/d4/9f/ee29e306901be0ea521b464c3533bd95d49dbe08c54df64cd49bbb13918e/voyager-2.0.9-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d58682f2f8d9cfccb95d2278eeec01ed76f90636cf6123db7850eb9a4b7e70e7", size = 380145 },
1211
+ { url = "https://files.pythonhosted.org/packages/e5/83/d9b40742c17f674cbafec55b751804e68ee9b492cfb02fddc72f060beb17/voyager-2.0.9-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:510485dafa539ae130f2ad8bf7c95b21a2fa454f0b25581b37be3ca36bab29a1", size = 358094 },
1212
+ { url = "https://files.pythonhosted.org/packages/33/61/e705ee3154450802912d35e881261182c01ba0e65cc83c6ef16b84c56e1b/voyager-2.0.9-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a4015db48c0c5d596e8bc536f4b05b601a2138e6439e00b06410e18286896273", size = 4234321 },
1213
+ { url = "https://files.pythonhosted.org/packages/13/7a/4ac271fb5a8068f97dd6446622d679d26237a772ab12d1e6241cc0848dca/voyager-2.0.9-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:805f1736e5fe309ae8884e572b78d9816ff4fd6f1ef364298a2f62566ea86bc9", size = 4312789 },
1214
+ { url = "https://files.pythonhosted.org/packages/b4/f6/906b21d4b42df264fc231c74753ca164f14cb09d40cd6b3a32d293aa0418/voyager-2.0.9-cp312-cp312-win_amd64.whl", hash = "sha256:abc7041ba8047d25942afe457db597be6f33161a669aac00dfffc00b7d833bfa", size = 201868 },
1215
+ { url = "https://files.pythonhosted.org/packages/9f/9a/f5467d52356995c9f64cb27a99211142abead24290bfb8ccfb38168ef91d/voyager-2.0.9-cp39-cp39-macosx_10_13_universal2.whl", hash = "sha256:a38b7a232367095ef28350889b0c4ec8ce9f53c0a7839f2b06f517b652938e2c", size = 731403 },
1216
+ { url = "https://files.pythonhosted.org/packages/ab/be/ecef9dfce07c535af6d11a4011a4a8693c4174ca8f87495e9ba30c8c7884/voyager-2.0.9-cp39-cp39-macosx_10_13_x86_64.whl", hash = "sha256:e5968f516a94832a599c9c1b64246b7f81344ed3fb49247fbdaba7e673c1e8a9", size = 377365 },
1217
+ { url = "https://files.pythonhosted.org/packages/55/99/d31f596e887d998c81671b8e345925f07ccc36dee7144dbf80f1c86fb187/voyager-2.0.9-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f4095d4012479fa53b21f8a65c7790e844c3634a8ead1fca04f69a4a34ebc362", size = 356976 },
1218
+ { url = "https://files.pythonhosted.org/packages/6f/43/096fcfa3443d37d8b5e4163b49b0d91f0456022df59017a8ae25ae4482d9/voyager-2.0.9-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d55f85d36111e950d42e7d78accca84c582d5606ec1bae2d4b2da41ccc3e7f2e", size = 4209912 },
1219
+ { url = "https://files.pythonhosted.org/packages/ff/51/c35a343471746e8964cb5d002a3367f5e28f5787c2c0689e0566a7406f66/voyager-2.0.9-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:83e1dd648040df093ddda74a6f361ec912caf981d20dfdd4b0d3bd7fb230147b", size = 4280035 },
1220
+ { url = "https://files.pythonhosted.org/packages/ba/6c/5643effb7e495f8ee5c346e7b41961cb8d4dd6ef6952b24ec929a868f41c/voyager-2.0.9-cp39-cp39-win_amd64.whl", hash = "sha256:a2b17036c9b825f7062eb09ac613ca1e3fdb11712b1fc6d58bbbc201698e09c9", size = 196377 },
1221
+ ]
1222
+
1183
1223
  [[package]]
1184
1224
  name = "wcwidth"
1185
1225
  version = "0.2.13"
@@ -146,6 +146,7 @@ class FaissBackend(AbstractBackend[FaissArgs]):
146
146
 
147
147
  def query(self, vectors: npt.NDArray, k: int) -> QueryResult:
148
148
  """Perform a k-NN search in the FAISS index."""
149
+ k = min(len(self), k)
149
150
  if self.arguments.metric == "cosine":
150
151
  vectors = normalize(vectors)
151
152
  distances, indices = self.index.search(vectors, k)
@@ -93,6 +93,7 @@ class HNSWBackend(AbstractBackend[HNSWArgs]):
93
93
 
94
94
  def query(self, vectors: npt.NDArray, k: int) -> QueryResult:
95
95
  """Query the backend."""
96
+ k = min(k, len(self))
96
97
  return list(zip(*self.index.knn_query(vectors, k)))
97
98
 
98
99
  def insert(self, vectors: npt.NDArray) -> None:
@@ -115,9 +115,10 @@ class UsearchBackend(AbstractBackend[UsearchArgs]):
115
115
 
116
116
  def query(self, vectors: npt.NDArray, k: int) -> QueryResult:
117
117
  """Query the backend and return results as tuples of keys and distances."""
118
+ k = min(k, len(self))
118
119
  results = self.index.search(vectors, k)
119
- keys = np.array(results.keys).reshape(-1, k)
120
- distances = np.array(results.distances, dtype=np.float32).reshape(-1, k)
120
+ keys = np.atleast_2d(results.keys)
121
+ distances = np.atleast_2d(results.distances)
121
122
  return list(zip(keys, distances))
122
123
 
123
124
  def insert(self, vectors: npt.NDArray) -> None:
@@ -68,6 +68,7 @@ class VoyagerBackend(AbstractBackend[VoyagerArgs]):
68
68
 
69
69
  def query(self, query: npt.NDArray, k: int) -> QueryResult:
70
70
  """Query the backend for the nearest neighbors."""
71
+ k = min(k, len(self))
71
72
  indices, distances = self.index.query(query, k)
72
73
  return list(zip(indices, distances))
73
74
 
@@ -1,2 +1,2 @@
1
- __version_triple__ = (0, 3, 2)
1
+ __version_triple__ = (0, 3, 4)
2
2
  __version__ = ".".join(map(str, __version_triple__))
@@ -243,6 +243,8 @@ class Vicinity:
243
243
  raise ValueError(f"Token {token} is already in the vector space.")
244
244
  self.items.append(token)
245
245
  self.backend.insert(vectors)
246
+ if self.vector_store is not None:
247
+ self.vector_store.insert(vectors)
246
248
 
247
249
  def delete(self, tokens: Sequence[str]) -> None:
248
250
  """
@@ -260,6 +262,8 @@ class Vicinity:
260
262
  raise ValueError(f"Token {exc} was not in the vector space.") from exc
261
263
 
262
264
  self.backend.delete(curr_indices)
265
+ if self.vector_store is not None:
266
+ self.vector_store.delete(curr_indices)
263
267
 
264
268
  # Delete items starting from the highest index
265
269
  for index in sorted(curr_indices, reverse=True):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: vicinity
3
- Version: 0.3.2
3
+ Version: 0.3.4
4
4
  Summary: Lightweight Nearest Neighbors with Flexible Backends
5
5
  Author-email: Stéphan Tulkens <stephantul@gmail.com>, Thomas van Dongen <thomas123@live.nl>
6
6
  License: MIT License
@@ -153,10 +153,14 @@ vicinity = Vicinity.from_vectors_and_items(
153
153
  query_vector = np.random.rand(128)
154
154
 
155
155
  # Query for nearest neighbors with a top-k search
156
- results = vicinity.query([query_vector], k=3)
156
+ results = vicinity.query(query_vector, k=3)
157
157
 
158
158
  # Query for nearest neighbors with a threshold search
159
- results = vicinity.query_threshold([query_vector], threshold=0.9)
159
+ results = vicinity.query_threshold(query_vector, threshold=0.9)
160
+
161
+ # Query with a list of query vectors
162
+ query_vectors = np.random.rand(5, 128)
163
+ results = vicinity.query(query_vectors, k=3)
160
164
  ```
161
165
 
162
166
  Saving and loading a vector store:
@@ -191,7 +195,7 @@ The following backends are supported:
191
195
  - [HNSW](https://github.com/nmslib/hnswlib): Hierarchical Navigable Small World Graph (HNSW) for ANN search using hnswlib.
192
196
  - [USEARCH](https://github.com/unum-cloud/usearch): ANN search using Usearch. This uses a highly optimized version of the HNSW algorithm.
193
197
  - [ANNOY](https://github.com/spotify/annoy): "Approximate Nearest Neighbors Oh Yeah" for approximate nearest neighbor search.
194
- - [PYNNDescent](https://github.com/lmcinnes/pynndescent): ANN search using PyNNDescent.
198
+ - [PYNNDESCENT](https://github.com/lmcinnes/pynndescent): ANN search using PyNNDescent.
195
199
  - [FAISS](https://github.com/facebookresearch/faiss): All FAISS indexes are supported:
196
200
  - `flat`: Exact search.
197
201
  - `ivf`: Inverted file search.
@@ -213,6 +217,7 @@ NOTE: the ANN backends do not support dynamic deletion. To delete items, you nee
213
217
 
214
218
  | Backend | Parameter | Description | Default Value |
215
219
  |-----------------|---------------------|-----------------------------------------------------------------------------------------------|---------------------|
220
+ | **BASIC** | `metric` | Similarity metric to use (`cosine`, `euclidean`). | `"cosine"` |
216
221
  | **ANNOY** | `metric` | Similarity metric to use (`dot`, `euclidean`, `cosine`). | `"cosine"` |
217
222
  | | `trees` | Number of trees to use for indexing. | `100` |
218
223
  | | `length` | Optional length of the dataset. | `None` |
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -90,6 +90,10 @@ class BasicVectorStore:
90
90
  self._vectors = matrix
91
91
  self._update_precomputed_data()
92
92
 
93
+ def __len__(self) -> int:
94
+ """Get the number of vectors."""
95
+ return self.vectors.shape[0]
96
+
93
97
 
94
98
  class BasicBackend(BasicVectorStore, AbstractBackend[BasicArgs], ABC):
95
99
  argument_class = BasicArgs
@@ -100,10 +104,6 @@ class BasicBackend(BasicVectorStore, AbstractBackend[BasicArgs], ABC):
100
104
  """Initialize the backend."""
101
105
  super().__init__(vectors=vectors, arguments=arguments)
102
106
 
103
- def __len__(self) -> int:
104
- """Get the number of vectors."""
105
- return self.vectors.shape[0]
106
-
107
107
  @property
108
108
  def backend_type(self) -> Backend:
109
109
  """The type of the backend."""
File without changes
File without changes
File without changes