Skip to content

Commit 0f3214c

Browse files
author
Dmitry Yashunin
committed
Add stress test to check multithreading
1 parent c4bedcf commit 0f3214c

File tree

3 files changed

+64
-1
lines changed

3 files changed

+64
-1
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,4 @@ var/
99
.idea/
1010
.vscode/
1111
.vs/
12+
**.DS_Store

python_bindings/tests/bindings_test_replace.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ def testRandomSelf(self):
5757
for l in labels2_deleted:
5858
hnsw_index.mark_deleted(l[0])
5959
labels1_found, _ = hnsw_index.knn_query(data1, k=1)
60-
items = hnsw_index.get_items(labels1)
60+
items = hnsw_index.get_items(labels1_found)
6161
diff_with_gt_labels = np.mean(np.abs(data1-items))
6262
self.assertAlmostEqual(diff_with_gt_labels, 0, delta=1e-3)
6363

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import unittest
2+
3+
import numpy as np
4+
5+
import hnswlib
6+
7+
8+
class RandomSelfTestCase(unittest.TestCase):
9+
def testRandomSelf(self):
10+
dim = 16
11+
num_elements = 1_000
12+
max_num_elements = 2 * num_elements
13+
14+
# Generating sample data
15+
# batch 1
16+
first_id = 0
17+
last_id = num_elements
18+
labels1 = np.arange(first_id, last_id)
19+
data1 = np.float32(np.random.random((num_elements, dim)))
20+
# batch 2
21+
first_id += num_elements
22+
last_id += num_elements
23+
labels2 = np.arange(first_id, last_id)
24+
data2 = np.float32(np.random.random((num_elements, dim)))
25+
# batch 3
26+
first_id += num_elements
27+
last_id += num_elements
28+
labels3 = np.arange(first_id, last_id)
29+
data3 = np.float32(np.random.random((num_elements, dim)))
30+
31+
# Declaring index
32+
for _ in range(100):
33+
hnsw_index = hnswlib.Index(space='l2', dim=dim)
34+
hnsw_index.init_index(max_elements=max_num_elements, ef_construction=200, M=16, replace_deleted=True)
35+
36+
hnsw_index.set_ef(100)
37+
hnsw_index.set_num_threads(50)
38+
39+
# Add batch 1 and 2
40+
hnsw_index.add_items(data1, labels1)
41+
hnsw_index.add_items(data2, labels2) # maximum number of elements is reached
42+
43+
# Delete nearest neighbors of batch 2
44+
labels2_deleted, _ = hnsw_index.knn_query(data2, k=1)
45+
for l in labels2_deleted:
46+
hnsw_index.mark_deleted(l[0])
47+
labels1_found, _ = hnsw_index.knn_query(data1, k=1)
48+
items = hnsw_index.get_items(labels1_found)
49+
diff_with_gt_labels = np.mean(np.abs(data1-items))
50+
self.assertAlmostEqual(diff_with_gt_labels, 0, delta=1e-3)
51+
52+
labels2_after, _ = hnsw_index.knn_query(data2, k=1)
53+
labels2_after_flat = labels2_after.flatten()
54+
labels2_deleted_flat = labels2_deleted.flatten()
55+
common = np.intersect1d(labels2_after_flat, labels2_deleted_flat)
56+
self.assertTrue(common.size == 0)
57+
58+
# Replace deleted elements
59+
# Maximum number of elements is reached therefore we cannot add new items
60+
# but we can replace the deleted ones
61+
labels_replaced = hnsw_index.add_items_to_vacant_place(data3, labels3)
62+

0 commit comments

Comments
 (0)