Skip to content
This repository was archived by the owner on Sep 9, 2026. It is now read-only.

Commit e24be8d

Browse files
author
Joan Fontanals
authored
fix: allow update on HNSWLibIndex (#1604)
Signed-off-by: Joan Fontanals Martinez <joan.martinez@jina.ai>
1 parent de8c654 commit e24be8d

3 files changed

Lines changed: 104 additions & 2 deletions

File tree

‎docarray/index/backends/hnswlib.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -446,7 +446,7 @@ def _create_docs_table(self):
446446
def _send_docs_to_sqlite(self, docs: Sequence[BaseDoc]):
447447
ids = (self._to_hashed_id(doc.id) for doc in docs)
448448
self._sqlite_cursor.executemany(
449-
'INSERT INTO docs VALUES (?, ?)',
449+
'INSERT OR REPLACE INTO docs VALUES (?, ?)',
450450
((id_, self._doc_to_bytes(doc)) for id_, doc in zip(ids, docs)),
451451
)
452452

‎docs/user_guide/storing/index_hnswlib.md‎

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -213,4 +213,56 @@ To delete nested data, you need to specify the `id`.
213213
del doc_index[index_docs[6].id]
214214
```
215215

216-
Check [here](docindex#nested-data-with-subindex) for nested data with subindex.
216+
Check [here](../docindex#nested-data-with-subindex) for nested data with subindex.
217+
218+
### Update elements
219+
In order to update a Document inside the index, you only need to reindex it with the updated attributes.
220+
221+
First lets create a schema for our Index
222+
```python
223+
import numpy as np
224+
from docarray import BaseDoc, DocList
225+
from docarray.typing import NdArray
226+
from docarray.index import HnswDocumentIndex
227+
class MyDoc(BaseDoc):
228+
text: str
229+
embedding: NdArray[128]
230+
```
231+
Now we can instantiate our Index and index some data.
232+
233+
```python
234+
docs = DocList[MyDoc](
235+
[MyDoc(embedding=np.random.rand(10), text=f'I am the first version of Document {i}') for i in range(100)]
236+
)
237+
index = HnswDocumentIndex[MyDoc]()
238+
index.index(docs)
239+
assert index.num_docs() == 100
240+
```
241+
242+
Now we can find relevant documents
243+
244+
```python
245+
res = index.find(query=docs[0], search_field='tens', limit=100)
246+
assert len(res.documents) == 100
247+
for doc in res.documents:
248+
assert 'I am the first version' in doc.text
249+
```
250+
251+
and update all of the text of this documents and reindex them
252+
253+
```python
254+
for i, doc in enumerate(docs):
255+
doc.text = f'I am the second version of Document {i}'
256+
257+
index.index(docs)
258+
assert index.num_docs() == 100
259+
```
260+
261+
When we retrieve them again we can see that their text attribute has been updated accordingly
262+
263+
```python
264+
res = index.find(query=docs[0], search_field='tens', limit=100)
265+
assert len(res.documents) == 100
266+
for doc in res.documents:
267+
assert 'I am the second version' in doc.text
268+
```

‎tests/index/hnswlib/test_index_get_del.py‎

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -362,3 +362,53 @@ def test_num_docs(ten_simple_docs, tmp_path):
362362

363363
del index[more_docs[2].id, ten_simple_docs[7].id]
364364
assert index.num_docs() == 10
365+
366+
367+
def test_update_payload(tmp_path):
368+
class TextSimpleDoc(SimpleDoc):
369+
text: str = 'hey'
370+
371+
docs = DocList[TextSimpleDoc](
372+
[TextSimpleDoc(tens=np.random.rand(10), text=f'hey {i}') for i in range(100)]
373+
)
374+
index = HnswDocumentIndex[TextSimpleDoc](work_dir=str(tmp_path))
375+
index.index(docs)
376+
assert index.num_docs() == 100
377+
378+
for doc in docs:
379+
doc.text += '_changed'
380+
381+
index.index(docs)
382+
assert index.num_docs() == 100
383+
384+
res = index.find(query=docs[0], search_field='tens', limit=100)
385+
assert len(res.documents) == 100
386+
for doc in res.documents:
387+
assert '_changed' in doc.text
388+
389+
390+
def test_update_embedding(tmp_path):
391+
class TextSimpleDoc(SimpleDoc):
392+
text: str = 'hey'
393+
394+
docs = DocList[TextSimpleDoc](
395+
[TextSimpleDoc(tens=np.random.rand(10), text=f'hey {i}') for i in range(100)]
396+
)
397+
index = HnswDocumentIndex[TextSimpleDoc](work_dir=str(tmp_path))
398+
index.index(docs)
399+
assert index.num_docs() == 100
400+
401+
new_tensor = np.random.rand(10)
402+
docs[0].tens = new_tensor
403+
404+
index.index(docs[0])
405+
assert index.num_docs() == 100
406+
407+
res = index.find(query=docs[0], search_field='tens', limit=100)
408+
assert len(res.documents) == 100
409+
found = False
410+
for doc in res.documents:
411+
if doc.id == docs[0].id:
412+
found = True
413+
assert (doc.tens == new_tensor).all()
414+
assert found

0 commit comments

Comments
 (0)