zeusdb-vector-database 0.6.0__tar.gz → 0.7.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.
- {zeusdb_vector_database-0.6.0 → zeusdb_vector_database-0.7.0}/NOTICE +9 -15
- {zeusdb_vector_database-0.6.0 → zeusdb_vector_database-0.7.0}/PKG-INFO +34 -20
- {zeusdb_vector_database-0.6.0 → zeusdb_vector_database-0.7.0}/README.md +33 -19
- {zeusdb_vector_database-0.6.0 → zeusdb_vector_database-0.7.0}/pyproject.toml +1 -5
- {zeusdb_vector_database-0.6.0 → zeusdb_vector_database-0.7.0}/src/zeusdb_vector_database/__init__.py +1 -1
- {zeusdb_vector_database-0.6.0 → zeusdb_vector_database-0.7.0}/src/zeusdb_vector_database/vector_database.py +7 -5
- {zeusdb_vector_database-0.6.0 → zeusdb_vector_database-0.7.0}/vdb-core/Cargo.lock +4 -369
- {zeusdb_vector_database-0.6.0 → zeusdb_vector_database-0.7.0}/vdb-core/Cargo.toml +10 -12
- {zeusdb_vector_database-0.6.0 → zeusdb_vector_database-0.7.0}/vdb-core/src/distance.rs +817 -311
- zeusdb_vector_database-0.7.0/vdb-core/src/graph/dump.rs +1642 -0
- zeusdb_vector_database-0.7.0/vdb-core/src/graph/levels.rs +129 -0
- zeusdb_vector_database-0.7.0/vdb-core/src/graph/mod.rs +758 -0
- zeusdb_vector_database-0.7.0/vdb-core/src/graph/mutable/insert.rs +538 -0
- zeusdb_vector_database-0.7.0/vdb-core/src/graph/mutable/mod.rs +1590 -0
- zeusdb_vector_database-0.7.0/vdb-core/src/graph/structure.rs +802 -0
- zeusdb_vector_database-0.7.0/vdb-core/src/graph/test_graph.rs +116 -0
- zeusdb_vector_database-0.7.0/vdb-core/src/graph/traverse.rs +320 -0
- {zeusdb_vector_database-0.6.0 → zeusdb_vector_database-0.7.0}/vdb-core/src/hnsw_index/construct.rs +2 -0
- {zeusdb_vector_database-0.6.0 → zeusdb_vector_database-0.7.0}/vdb-core/src/hnsw_index/graph_guard_tests.rs +127 -137
- {zeusdb_vector_database-0.6.0 → zeusdb_vector_database-0.7.0}/vdb-core/src/hnsw_index/insert.rs +63 -14
- {zeusdb_vector_database-0.6.0 → zeusdb_vector_database-0.7.0}/vdb-core/src/hnsw_index/mod.rs +36 -20
- {zeusdb_vector_database-0.6.0 → zeusdb_vector_database-0.7.0}/vdb-core/src/hnsw_index/persist.rs +4 -8
- {zeusdb_vector_database-0.6.0 → zeusdb_vector_database-0.7.0}/vdb-core/src/hnsw_index/stats.rs +168 -15
- {zeusdb_vector_database-0.6.0 → zeusdb_vector_database-0.7.0}/vdb-core/src/hnsw_index/training.rs +5 -3
- {zeusdb_vector_database-0.6.0 → zeusdb_vector_database-0.7.0}/vdb-core/src/lib.rs +3 -0
- {zeusdb_vector_database-0.6.0 → zeusdb_vector_database-0.7.0}/vdb-core/src/logging.rs +3 -3
- {zeusdb_vector_database-0.6.0 → zeusdb_vector_database-0.7.0}/vdb-core/src/persistence.rs +20 -18
- {zeusdb_vector_database-0.6.0 → zeusdb_vector_database-0.7.0}/vdb-core/src/pq.rs +7 -5
- {zeusdb_vector_database-0.6.0 → zeusdb_vector_database-0.7.0}/vdb-core/src/rerank.rs +50 -13
- zeusdb_vector_database-0.7.0/vdb-core/src/rng.rs +171 -0
- {zeusdb_vector_database-0.6.0 → zeusdb_vector_database-0.7.0}/vdb-core/src/test_vectors.rs +3 -3
- zeusdb_vector_database-0.6.0/LICENSES/hnsw_rs-Apache-2.0.txt +0 -176
- zeusdb_vector_database-0.6.0/LICENSES/hnsw_rs-MIT.txt +0 -25
- zeusdb_vector_database-0.6.0/vdb-core/src/graph.rs +0 -950
- zeusdb_vector_database-0.6.0/vendor/hnsw_rs/.cargo-ok +0 -1
- zeusdb_vector_database-0.6.0/vendor/hnsw_rs/.cargo_vcs_info.json +0 -6
- zeusdb_vector_database-0.6.0/vendor/hnsw_rs/.gitignore +0 -9
- zeusdb_vector_database-0.6.0/vendor/hnsw_rs/Cargo.lock +0 -1296
- zeusdb_vector_database-0.6.0/vendor/hnsw_rs/Cargo.toml +0 -153
- zeusdb_vector_database-0.6.0/vendor/hnsw_rs/Cargo.toml.orig +0 -119
- zeusdb_vector_database-0.6.0/vendor/hnsw_rs/Changes.md +0 -59
- zeusdb_vector_database-0.6.0/vendor/hnsw_rs/LICENSE-APACHE +0 -13
- zeusdb_vector_database-0.6.0/vendor/hnsw_rs/LICENSE-MIT +0 -25
- zeusdb_vector_database-0.6.0/vendor/hnsw_rs/README.md +0 -168
- zeusdb_vector_database-0.6.0/vendor/hnsw_rs/ZEUSDB-PATCH.md +0 -595
- zeusdb_vector_database-0.6.0/vendor/hnsw_rs/examples/ann-glove25-angular.rs +0 -220
- zeusdb_vector_database-0.6.0/vendor/hnsw_rs/examples/ann-mnist-784-euclidean.rs +0 -162
- zeusdb_vector_database-0.6.0/vendor/hnsw_rs/examples/ann-sift1m-128-euclidean.rs +0 -196
- zeusdb_vector_database-0.6.0/vendor/hnsw_rs/examples/levensthein.rs +0 -63
- zeusdb_vector_database-0.6.0/vendor/hnsw_rs/examples/random.rs +0 -80
- zeusdb_vector_database-0.6.0/vendor/hnsw_rs/examples/utils/annhdf5.rs +0 -233
- zeusdb_vector_database-0.6.0/vendor/hnsw_rs/examples/utils/mod.rs +0 -3
- zeusdb_vector_database-0.6.0/vendor/hnsw_rs/src/api.rs +0 -94
- zeusdb_vector_database-0.6.0/vendor/hnsw_rs/src/datamap.rs +0 -456
- zeusdb_vector_database-0.6.0/vendor/hnsw_rs/src/filter.rs +0 -24
- zeusdb_vector_database-0.6.0/vendor/hnsw_rs/src/flatten.rs +0 -200
- zeusdb_vector_database-0.6.0/vendor/hnsw_rs/src/hnsw.rs +0 -2023
- zeusdb_vector_database-0.6.0/vendor/hnsw_rs/src/hnswio.rs +0 -1749
- zeusdb_vector_database-0.6.0/vendor/hnsw_rs/src/lib.rs +0 -36
- zeusdb_vector_database-0.6.0/vendor/hnsw_rs/src/libext.rs +0 -1240
- zeusdb_vector_database-0.6.0/vendor/hnsw_rs/src/prelude.rs +0 -11
- zeusdb_vector_database-0.6.0/vendor/hnsw_rs/tests/deallocation_test.rs +0 -34
- zeusdb_vector_database-0.6.0/vendor/hnsw_rs/tests/filtertest.rs +0 -266
- zeusdb_vector_database-0.6.0/vendor/hnsw_rs/tests/serpar.rs +0 -328
- {zeusdb_vector_database-0.6.0 → zeusdb_vector_database-0.7.0}/LICENSE +0 -0
- {zeusdb_vector_database-0.6.0 → zeusdb_vector_database-0.7.0}/src/zeusdb_vector_database/logging_config.py +0 -0
- {zeusdb_vector_database-0.6.0 → zeusdb_vector_database-0.7.0}/src/zeusdb_vector_database/py.typed +0 -0
- {zeusdb_vector_database-0.6.0 → zeusdb_vector_database-0.7.0}/vdb-core/src/conversion.rs +0 -0
- {zeusdb_vector_database-0.6.0 → zeusdb_vector_database-0.7.0}/vdb-core/src/filter.rs +0 -0
- {zeusdb_vector_database-0.6.0 → zeusdb_vector_database-0.7.0}/vdb-core/src/hnsw_index/input.rs +0 -0
- {zeusdb_vector_database-0.6.0 → zeusdb_vector_database-0.7.0}/vdb-core/src/hnsw_index/search.rs +0 -0
|
@@ -6,21 +6,15 @@ This product includes software developed by:
|
|
|
6
6
|
- The Python Software Foundation (https://www.python.org/psf/)
|
|
7
7
|
- The Rust Project Developers (https://www.rust-lang.org/)
|
|
8
8
|
- The PyO3 Project (https://pyo3.rs/)
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
correcting the level scale a reload installs, and one putting three modules
|
|
19
|
-
ZeusDB never reaches behind default-off cargo features. See
|
|
20
|
-
vendor/hnsw_rs/ZEUSDB-PATCH.md for the patch record. hnsw_rs is dual licensed
|
|
21
|
-
under MIT or Apache-2.0.
|
|
22
|
-
|
|
23
|
-
Third-party components may be licensed under their respective terms. See LICENSES/ for full license texts.
|
|
9
|
+
|
|
10
|
+
Releases up to and including 0.6.0 were built on a vendored copy of a Rust HNSW
|
|
11
|
+
crate by Jean-Pierre Both, dual licensed under MIT or Apache-2.0. From 0.7.0 the
|
|
12
|
+
graph structure, its traversal, its insert, its level stream and its on-disk
|
|
13
|
+
format are ZeusDB's own, and neither that crate nor its source is part of this
|
|
14
|
+
package. ZeusDB's graph reproduces the behaviour of that implementation, and the
|
|
15
|
+
acknowledgement is kept here for that reason.
|
|
16
|
+
|
|
17
|
+
Third-party components may be licensed under their respective terms.
|
|
24
18
|
|
|
25
19
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
26
20
|
you may not use this file except in compliance with the License.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: zeusdb-vector-database
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.7.0
|
|
4
4
|
Classifier: Programming Language :: Rust
|
|
5
5
|
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
6
6
|
Requires-Dist: numpy>=2.2.6,<3.0.0
|
|
@@ -35,7 +35,7 @@ Project-URL: Repository, https://github.com/zeusdb/zeusdb-vector-database
|
|
|
35
35
|
<td><strong>Meta</strong></td>
|
|
36
36
|
<td>
|
|
37
37
|
<a href="https://pypi.org/project/zeusdb-vector-database/"><img src="https://img.shields.io/pypi/v/zeusdb-vector-database?label=PyPI&color=blue"></a>
|
|
38
|
-
<a href="https://www.python.org/downloads/"><img src="https://img.shields.io/badge/python-3.10%7C3.11%7C3.12%7C3.13-blue?logo=python&logoColor=ffdd54"></a>
|
|
38
|
+
<a href="https://www.python.org/downloads/"><img src="https://img.shields.io/badge/python-3.10%7C3.11%7C3.12%7C3.13%7C3.14-blue?logo=python&logoColor=ffdd54"></a>
|
|
39
39
|
<a href="https://github.com/zeusdb/zeusdb-vector-database/blob/main/LICENSE"><img src="https://img.shields.io/badge/License-Apache_2.0-blue.svg"></a>
|
|
40
40
|
<a href="https://www.rust-lang.org"><img src="https://img.shields.io/badge/Powered%20by-Rust-black?logo=rust&logoColor=white" alt="Powered by Rust"></a>
|
|
41
41
|
<a href="https://github.com/ZeusDB"><img src="https://github.com/user-attachments/assets/e140d900-1160-4eaa-85c0-2b3507a5f0f5" alt="ZeusDB"></a>
|
|
@@ -643,17 +643,21 @@ storage_mode_description: raw_only
|
|
|
643
643
|
|
|
644
644
|
`get_stats()` returns a `str` to `str` map. It also carries `dimension`, `space`, `m`, `ef_construction`, `expected_size`, `index_type`, `raw_vectors_stored`, `quantized_codes_stored` and `storage_mode`, plus training and compression fields once quantization is configured.
|
|
645
645
|
|
|
646
|
-
It is also where the memory figures live, on every index rather than only on a quantized one. `graph_memory_mb` is the HNSW graph, `raw_vectors_memory_mb` is the raw vector store and `total_memory_mb` is the sum of everything below. On a quantized index `quantized_codes_memory_mb` scales with the record count, while `codebook_memory_mb` and `sdc_table_memory_mb` are fixed by `dim`, `subvectors` and `bits` and do not move as records arrive. `raw_vectors_retained` states the mode's policy: `none_once_trained` for `quantized_only`, whose raw vectors are released when training completes, and `all_records` for `quantized_with_raw`.
|
|
646
|
+
It is also where the memory figures live, on every index rather than only on a quantized one. `graph_memory_mb` is the HNSW graph, `raw_vectors_memory_mb` is the raw vector store, `index_bookkeeping_memory_mb` is the hash tables that find a record, and `total_memory_mb` is the sum of everything below. On a quantized index `quantized_codes_memory_mb` scales with the record count, while `codebook_memory_mb` and `sdc_table_memory_mb` are fixed by `dim`, `subvectors` and `bits` and do not move as records arrive. `raw_vectors_retained` states the mode's policy: `none_once_trained` for `quantized_only`, whose raw vectors are released when training completes, and `all_records` for `quantized_with_raw`.
|
|
647
647
|
|
|
648
648
|
**The graph is usually the largest of those figures, and on a memory optimized index it is nearly all of it.** It owns a second copy of every point on top of its neighbour lists, its sixteen per point layer headers and the counters around them. At 50,000 records of `dim=1536` a trained `quantized_only` index reports 98.1 MB of graph against 2.3 MB of codes and 7.5 MB of fixed tables.
|
|
649
649
|
|
|
650
|
-
|
|
650
|
+
`index_bookkeeping_memory_mb` is what the index spends on finding a record rather than on holding one. Five hash tables carry a record, being `id_map`, `rev_map`, the metadata map, the raw vector store and the code store, and two of them carry a second copy of its id. It is proportional to the record count and independent of the dimension, at 265 bytes per record with no quantization, 334 under `quantized_with_raw` and 265 under `quantized_only` at 50,000 records.
|
|
651
651
|
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
|
655
|
-
|
|
656
|
-
|
|
|
652
|
+
**`total_memory_mb` is not the resident set and it does not claim to be.** It prices the six structures above, meaning the bytes the index asked the allocator for. What it leaves out is the allocator itself, being its own block headers, its rounding and its fragmentation, and that is a property of the platform rather than something the index holds. Measured on three loaded indexes of 50,000 real 1,536-dimensional embeddings, one process each, with the interpreter's own resident set subtracted:
|
|
653
|
+
|
|
654
|
+
| storage mode | `total_memory_mb` | resident | share reported | unpriced |
|
|
655
|
+
|---|---:|---:|---:|---:|
|
|
656
|
+
| no quantization | 705.1 MB | 805.4 MiB | 0.88 | 2,103 B per record |
|
|
657
|
+
| `quantized_with_raw` | 415.9 MB | 473.3 MiB | 0.88 | 1,202 B per record |
|
|
658
|
+
| `quantized_only` | 119.7 MB | 181.0 MiB | 0.66 | 1,285 B per record |
|
|
659
|
+
|
|
660
|
+
The unpriced share is almost all allocator overhead on the graph, which asks for six small blocks per point. It runs 1.25 times the graph figure with no quantization, where the per point data block is 6,144 bytes and rounding is a small share of it, and 1.63 and 1.67 times under the two quantized modes, where that block is 48 bytes. That is why `quantized_only` reports the smallest share of its resident set.
|
|
657
661
|
|
|
658
662
|
Size infrastructure from the resident column rather than the reported one. The reported figure is what the index holds; the process holds that plus what the allocator takes to hold it.
|
|
659
663
|
|
|
@@ -1030,13 +1034,22 @@ The relation is curved as well as sublinear. On dbpedia-openai the calibration m
|
|
|
1030
1034
|
|
|
1031
1035
|
What the calibration asks for at 100,000 records, against what the data needs and against the fixed 2%. Every figure is measured on a built index through the ordinary search path, 1,000 queries at `top_k=10` against exact ground truth. The requirement is the smallest fetch on that same index reaching recall at 10 of 0.99, read off a sweep of the explicit `rerank` argument:
|
|
1032
1036
|
|
|
1033
|
-
| dataset | calibrated fetch | measured requirement |
|
|
1034
|
-
|
|
1035
|
-
| dbpedia-openai |
|
|
1036
|
-
| glove-100 |
|
|
1037
|
-
| sift-128 |
|
|
1037
|
+
| dataset | records | calibrated fetch | measured requirement | ratio | recall at 10 | mean query |
|
|
1038
|
+
|---|---:|---:|---:|---:|---:|---:|
|
|
1039
|
+
| dbpedia-openai | 50,000 | 554 | 860 | 0.64 | 0.9883 | 3.33 ms |
|
|
1040
|
+
| glove-100 | 50,000 | 6,534 | 3,060 | 2.14 | 0.9982 | 35.79 ms |
|
|
1041
|
+
| sift-128 | 50,000 | 465 | 370 | 1.26 | 0.9953 | 1.88 ms |
|
|
1042
|
+
| dbpedia-openai | 100,000 | 747 | 620 | 1.20 | 0.9907 | 5.02 ms |
|
|
1043
|
+
| glove-100 | 100,000 | 11,439 | 4,620 | 2.48 | 0.9985 | 140.08 ms |
|
|
1044
|
+
| sift-128 | 100,000 | 656 | 450 | 1.46 | 0.9968 | 3.19 ms |
|
|
1038
1045
|
|
|
1039
|
-
The
|
|
1046
|
+
**The margin is not the same on the three, and glove-100 carries most of it.** The rule is one measurement per index scaled by two constants that are the same everywhere, being a safety factor of 1.75 and a bias of 0.15 on the fitted exponent. Taking the fitted exponent alone with neither constant, the extrapolation to 100,000 records asks for 4,626 candidates on glove-100 against a requirement of 4,620, which is 1.001 times what that index needs. On the other two it asks for 0.49 and 0.59 times what they need. The constants exist for those two, and on glove-100 they are margin over a fetch that was already right.
|
|
1047
|
+
|
|
1048
|
+
Neither constant can come down without costing recall elsewhere. The constant that would bring glove-100 to the 1.20 ratio dbpedia-openai has at 100,000 records takes the dbpedia-openai fetch from 747 to 359, and a sweep of that same index reads recall 0.9787 at 360 candidates. dbpedia-openai also sits under 0.99 at 10,000, 25,000 and 50,000 records, at 0.9878, 0.9800 and 0.9883, so it has nothing to give back. What separates the datasets is the ratio between the requirement on a built index and the depth the calibration measures in the code ordering over its training sample, and the training sample cannot measure that ratio because the graph does not exist yet when it runs.
|
|
1049
|
+
|
|
1050
|
+
**If query time on glove-like data matters more to you than the last thousandth of recall, name `rerank` yourself.** On glove-100 at 50,000 records a fetch of 3,060 reads recall 0.9900 at 18.14 ms against 0.9982 at 35.79 ms, so half the query time buys back 0.008 of recall.
|
|
1051
|
+
|
|
1052
|
+
The two tables below carry fetch figures measured before the codebook seeding this release ships, which moved the calibrated fetch upward on glove-100. Read their ratios as the shape rather than as current figures.
|
|
1040
1053
|
|
|
1041
1054
|
**On data with no resolvable structure no fetch works.** Once the group the codes cannot separate is smaller than `top_k`, the true top ten span groups, the distances between groups differ in the fourth decimal, and nothing reaches them. At 5,000 clusters over 25,000 records, being five records to a cluster, recall at 10 reaches 0.917 at a fetch of half the corpus, and uniform points on the sphere reach 0.859. Measure recall on your own data before you rely on quantization.
|
|
1042
1055
|
|
|
@@ -1154,7 +1167,7 @@ print("saved:", sorted(os.listdir("my_index.zdb")))
|
|
|
1154
1167
|
|
|
1155
1168
|
*Output, with the progress lines omitted*
|
|
1156
1169
|
```
|
|
1157
|
-
saved: ['config.json', 'hnsw_index.
|
|
1170
|
+
saved: ['config.json', 'hnsw_index.zdbgraph', 'manifest.json', 'mappings.bin', 'metadata.json', 'vectors.bin']
|
|
1158
1171
|
```
|
|
1159
1172
|
|
|
1160
1173
|
<br />
|
|
@@ -1224,7 +1237,7 @@ print("saved:", sorted(os.listdir("quantized_index.zdb")))
|
|
|
1224
1237
|
quantization active: True
|
|
1225
1238
|
quantization active after load: True
|
|
1226
1239
|
storage mode after load: quantized_active
|
|
1227
|
-
saved: ['config.json', 'hnsw_index.
|
|
1240
|
+
saved: ['config.json', 'hnsw_index.zdbgraph', 'manifest.json', 'mappings.bin', 'metadata.json', 'pq_centroids.bin', 'pq_codes.bin', 'quantization.json', 'vectors.bin']
|
|
1228
1241
|
```
|
|
1229
1242
|
|
|
1230
1243
|
<br/>
|
|
@@ -1242,11 +1255,12 @@ my_index.zdb/
|
|
|
1242
1255
|
├── quantization.json # PQ configuration (if enabled)
|
|
1243
1256
|
├── pq_centroids.bin # Trained centroids (if PQ trained)
|
|
1244
1257
|
├── pq_codes.bin # Quantized codes (if PQ active)
|
|
1245
|
-
|
|
1246
|
-
└── hnsw_index.hnsw.data # HNSW graph payload
|
|
1258
|
+
└── hnsw_index.zdbgraph # HNSW graph structure and payload
|
|
1247
1259
|
```
|
|
1248
1260
|
|
|
1249
|
-
`manifest.json` lists
|
|
1261
|
+
`manifest.json` lists the graph file under `files_included`. The load path restores the saved graph rather than rebuilding it, so the file is required to reopen a directory holding records.
|
|
1262
|
+
|
|
1263
|
+
A directory saved by 0.6.0 or earlier holds `hnsw_index.hnsw.graph` and `hnsw_index.hnsw.data` instead. Opening it still works: the graph is rebuilt once from the stored records, and the next `.save()` writes the single file.
|
|
1250
1264
|
|
|
1251
1265
|
<br/>
|
|
1252
1266
|
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
<td><strong>Meta</strong></td>
|
|
15
15
|
<td>
|
|
16
16
|
<a href="https://pypi.org/project/zeusdb-vector-database/"><img src="https://img.shields.io/pypi/v/zeusdb-vector-database?label=PyPI&color=blue"></a>
|
|
17
|
-
<a href="https://www.python.org/downloads/"><img src="https://img.shields.io/badge/python-3.10%7C3.11%7C3.12%7C3.13-blue?logo=python&logoColor=ffdd54"></a>
|
|
17
|
+
<a href="https://www.python.org/downloads/"><img src="https://img.shields.io/badge/python-3.10%7C3.11%7C3.12%7C3.13%7C3.14-blue?logo=python&logoColor=ffdd54"></a>
|
|
18
18
|
<a href="https://github.com/zeusdb/zeusdb-vector-database/blob/main/LICENSE"><img src="https://img.shields.io/badge/License-Apache_2.0-blue.svg"></a>
|
|
19
19
|
<a href="https://www.rust-lang.org"><img src="https://img.shields.io/badge/Powered%20by-Rust-black?logo=rust&logoColor=white" alt="Powered by Rust"></a>
|
|
20
20
|
<a href="https://github.com/ZeusDB"><img src="https://github.com/user-attachments/assets/e140d900-1160-4eaa-85c0-2b3507a5f0f5" alt="ZeusDB"></a>
|
|
@@ -622,17 +622,21 @@ storage_mode_description: raw_only
|
|
|
622
622
|
|
|
623
623
|
`get_stats()` returns a `str` to `str` map. It also carries `dimension`, `space`, `m`, `ef_construction`, `expected_size`, `index_type`, `raw_vectors_stored`, `quantized_codes_stored` and `storage_mode`, plus training and compression fields once quantization is configured.
|
|
624
624
|
|
|
625
|
-
It is also where the memory figures live, on every index rather than only on a quantized one. `graph_memory_mb` is the HNSW graph, `raw_vectors_memory_mb` is the raw vector store and `total_memory_mb` is the sum of everything below. On a quantized index `quantized_codes_memory_mb` scales with the record count, while `codebook_memory_mb` and `sdc_table_memory_mb` are fixed by `dim`, `subvectors` and `bits` and do not move as records arrive. `raw_vectors_retained` states the mode's policy: `none_once_trained` for `quantized_only`, whose raw vectors are released when training completes, and `all_records` for `quantized_with_raw`.
|
|
625
|
+
It is also where the memory figures live, on every index rather than only on a quantized one. `graph_memory_mb` is the HNSW graph, `raw_vectors_memory_mb` is the raw vector store, `index_bookkeeping_memory_mb` is the hash tables that find a record, and `total_memory_mb` is the sum of everything below. On a quantized index `quantized_codes_memory_mb` scales with the record count, while `codebook_memory_mb` and `sdc_table_memory_mb` are fixed by `dim`, `subvectors` and `bits` and do not move as records arrive. `raw_vectors_retained` states the mode's policy: `none_once_trained` for `quantized_only`, whose raw vectors are released when training completes, and `all_records` for `quantized_with_raw`.
|
|
626
626
|
|
|
627
627
|
**The graph is usually the largest of those figures, and on a memory optimized index it is nearly all of it.** It owns a second copy of every point on top of its neighbour lists, its sixteen per point layer headers and the counters around them. At 50,000 records of `dim=1536` a trained `quantized_only` index reports 98.1 MB of graph against 2.3 MB of codes and 7.5 MB of fixed tables.
|
|
628
628
|
|
|
629
|
-
|
|
629
|
+
`index_bookkeeping_memory_mb` is what the index spends on finding a record rather than on holding one. Five hash tables carry a record, being `id_map`, `rev_map`, the metadata map, the raw vector store and the code store, and two of them carry a second copy of its id. It is proportional to the record count and independent of the dimension, at 265 bytes per record with no quantization, 334 under `quantized_with_raw` and 265 under `quantized_only` at 50,000 records.
|
|
630
630
|
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
|
634
|
-
|
|
635
|
-
|
|
|
631
|
+
**`total_memory_mb` is not the resident set and it does not claim to be.** It prices the six structures above, meaning the bytes the index asked the allocator for. What it leaves out is the allocator itself, being its own block headers, its rounding and its fragmentation, and that is a property of the platform rather than something the index holds. Measured on three loaded indexes of 50,000 real 1,536-dimensional embeddings, one process each, with the interpreter's own resident set subtracted:
|
|
632
|
+
|
|
633
|
+
| storage mode | `total_memory_mb` | resident | share reported | unpriced |
|
|
634
|
+
|---|---:|---:|---:|---:|
|
|
635
|
+
| no quantization | 705.1 MB | 805.4 MiB | 0.88 | 2,103 B per record |
|
|
636
|
+
| `quantized_with_raw` | 415.9 MB | 473.3 MiB | 0.88 | 1,202 B per record |
|
|
637
|
+
| `quantized_only` | 119.7 MB | 181.0 MiB | 0.66 | 1,285 B per record |
|
|
638
|
+
|
|
639
|
+
The unpriced share is almost all allocator overhead on the graph, which asks for six small blocks per point. It runs 1.25 times the graph figure with no quantization, where the per point data block is 6,144 bytes and rounding is a small share of it, and 1.63 and 1.67 times under the two quantized modes, where that block is 48 bytes. That is why `quantized_only` reports the smallest share of its resident set.
|
|
636
640
|
|
|
637
641
|
Size infrastructure from the resident column rather than the reported one. The reported figure is what the index holds; the process holds that plus what the allocator takes to hold it.
|
|
638
642
|
|
|
@@ -1009,13 +1013,22 @@ The relation is curved as well as sublinear. On dbpedia-openai the calibration m
|
|
|
1009
1013
|
|
|
1010
1014
|
What the calibration asks for at 100,000 records, against what the data needs and against the fixed 2%. Every figure is measured on a built index through the ordinary search path, 1,000 queries at `top_k=10` against exact ground truth. The requirement is the smallest fetch on that same index reaching recall at 10 of 0.99, read off a sweep of the explicit `rerank` argument:
|
|
1011
1015
|
|
|
1012
|
-
| dataset | calibrated fetch | measured requirement |
|
|
1013
|
-
|
|
1014
|
-
| dbpedia-openai |
|
|
1015
|
-
| glove-100 |
|
|
1016
|
-
| sift-128 |
|
|
1016
|
+
| dataset | records | calibrated fetch | measured requirement | ratio | recall at 10 | mean query |
|
|
1017
|
+
|---|---:|---:|---:|---:|---:|---:|
|
|
1018
|
+
| dbpedia-openai | 50,000 | 554 | 860 | 0.64 | 0.9883 | 3.33 ms |
|
|
1019
|
+
| glove-100 | 50,000 | 6,534 | 3,060 | 2.14 | 0.9982 | 35.79 ms |
|
|
1020
|
+
| sift-128 | 50,000 | 465 | 370 | 1.26 | 0.9953 | 1.88 ms |
|
|
1021
|
+
| dbpedia-openai | 100,000 | 747 | 620 | 1.20 | 0.9907 | 5.02 ms |
|
|
1022
|
+
| glove-100 | 100,000 | 11,439 | 4,620 | 2.48 | 0.9985 | 140.08 ms |
|
|
1023
|
+
| sift-128 | 100,000 | 656 | 450 | 1.46 | 0.9968 | 3.19 ms |
|
|
1017
1024
|
|
|
1018
|
-
The
|
|
1025
|
+
**The margin is not the same on the three, and glove-100 carries most of it.** The rule is one measurement per index scaled by two constants that are the same everywhere, being a safety factor of 1.75 and a bias of 0.15 on the fitted exponent. Taking the fitted exponent alone with neither constant, the extrapolation to 100,000 records asks for 4,626 candidates on glove-100 against a requirement of 4,620, which is 1.001 times what that index needs. On the other two it asks for 0.49 and 0.59 times what they need. The constants exist for those two, and on glove-100 they are margin over a fetch that was already right.
|
|
1026
|
+
|
|
1027
|
+
Neither constant can come down without costing recall elsewhere. The constant that would bring glove-100 to the 1.20 ratio dbpedia-openai has at 100,000 records takes the dbpedia-openai fetch from 747 to 359, and a sweep of that same index reads recall 0.9787 at 360 candidates. dbpedia-openai also sits under 0.99 at 10,000, 25,000 and 50,000 records, at 0.9878, 0.9800 and 0.9883, so it has nothing to give back. What separates the datasets is the ratio between the requirement on a built index and the depth the calibration measures in the code ordering over its training sample, and the training sample cannot measure that ratio because the graph does not exist yet when it runs.
|
|
1028
|
+
|
|
1029
|
+
**If query time on glove-like data matters more to you than the last thousandth of recall, name `rerank` yourself.** On glove-100 at 50,000 records a fetch of 3,060 reads recall 0.9900 at 18.14 ms against 0.9982 at 35.79 ms, so half the query time buys back 0.008 of recall.
|
|
1030
|
+
|
|
1031
|
+
The two tables below carry fetch figures measured before the codebook seeding this release ships, which moved the calibrated fetch upward on glove-100. Read their ratios as the shape rather than as current figures.
|
|
1019
1032
|
|
|
1020
1033
|
**On data with no resolvable structure no fetch works.** Once the group the codes cannot separate is smaller than `top_k`, the true top ten span groups, the distances between groups differ in the fourth decimal, and nothing reaches them. At 5,000 clusters over 25,000 records, being five records to a cluster, recall at 10 reaches 0.917 at a fetch of half the corpus, and uniform points on the sphere reach 0.859. Measure recall on your own data before you rely on quantization.
|
|
1021
1034
|
|
|
@@ -1133,7 +1146,7 @@ print("saved:", sorted(os.listdir("my_index.zdb")))
|
|
|
1133
1146
|
|
|
1134
1147
|
*Output, with the progress lines omitted*
|
|
1135
1148
|
```
|
|
1136
|
-
saved: ['config.json', 'hnsw_index.
|
|
1149
|
+
saved: ['config.json', 'hnsw_index.zdbgraph', 'manifest.json', 'mappings.bin', 'metadata.json', 'vectors.bin']
|
|
1137
1150
|
```
|
|
1138
1151
|
|
|
1139
1152
|
<br />
|
|
@@ -1203,7 +1216,7 @@ print("saved:", sorted(os.listdir("quantized_index.zdb")))
|
|
|
1203
1216
|
quantization active: True
|
|
1204
1217
|
quantization active after load: True
|
|
1205
1218
|
storage mode after load: quantized_active
|
|
1206
|
-
saved: ['config.json', 'hnsw_index.
|
|
1219
|
+
saved: ['config.json', 'hnsw_index.zdbgraph', 'manifest.json', 'mappings.bin', 'metadata.json', 'pq_centroids.bin', 'pq_codes.bin', 'quantization.json', 'vectors.bin']
|
|
1207
1220
|
```
|
|
1208
1221
|
|
|
1209
1222
|
<br/>
|
|
@@ -1221,11 +1234,12 @@ my_index.zdb/
|
|
|
1221
1234
|
├── quantization.json # PQ configuration (if enabled)
|
|
1222
1235
|
├── pq_centroids.bin # Trained centroids (if PQ trained)
|
|
1223
1236
|
├── pq_codes.bin # Quantized codes (if PQ active)
|
|
1224
|
-
|
|
1225
|
-
└── hnsw_index.hnsw.data # HNSW graph payload
|
|
1237
|
+
└── hnsw_index.zdbgraph # HNSW graph structure and payload
|
|
1226
1238
|
```
|
|
1227
1239
|
|
|
1228
|
-
`manifest.json` lists
|
|
1240
|
+
`manifest.json` lists the graph file under `files_included`. The load path restores the saved graph rather than rebuilding it, so the file is required to reopen a directory holding records.
|
|
1241
|
+
|
|
1242
|
+
A directory saved by 0.6.0 or earlier holds `hnsw_index.hnsw.graph` and `hnsw_index.hnsw.data` instead. Opening it still works: the graph is rebuilt once from the stored records, and the next `.save()` writes the single file.
|
|
1229
1243
|
|
|
1230
1244
|
<br/>
|
|
1231
1245
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "zeusdb-vector-database"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.7.0"
|
|
4
4
|
description = "Blazing-fast vector DB with real-time similarity search and metadata filtering."
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
authors = [
|
|
@@ -36,15 +36,11 @@ python-source = "src"
|
|
|
36
36
|
manifest-path = "vdb-core/Cargo.toml"
|
|
37
37
|
module-name = "zeusdb_vector_database" # <-- matches Rust crate name
|
|
38
38
|
bindings = "pyo3" # <-- explicitly state to maturin that it's a PyO3 project
|
|
39
|
-
# vendor/** must ship in the sdist, or an sdist build cannot resolve the
|
|
40
|
-
# patched hnsw_rs path dependency declared in vdb-core/Cargo.toml.
|
|
41
39
|
include = [
|
|
42
40
|
"LICENSE",
|
|
43
41
|
"NOTICE",
|
|
44
42
|
"README.md",
|
|
45
43
|
"src/**",
|
|
46
|
-
{ path = "vendor/**/*", format = "sdist" },
|
|
47
|
-
{ path = "LICENSES/*", format = "sdist" },
|
|
48
44
|
]
|
|
49
45
|
|
|
50
46
|
[project.optional-dependencies]
|
|
@@ -196,10 +196,11 @@ class VectorDatabase:
|
|
|
196
196
|
Under 'quantized_only' the records collected for training are held at
|
|
197
197
|
full width only until training completes, then released. get_stats()
|
|
198
198
|
reports the codes, the raw vectors, the codebook, the centroid
|
|
199
|
-
distance table
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
199
|
+
distance table, the graph and the hash tables that find a record,
|
|
200
|
+
and sums them under total_memory_mb. That sum is what the index
|
|
201
|
+
asked the allocator for rather than what the process holds, since
|
|
202
|
+
the allocator's own headers and its rounding sit outside it at
|
|
203
|
+
between 1,200 and 2,100 bytes a record. Recall falls sharply,
|
|
203
204
|
not slightly. Only 'quantized_with_raw' can recover it, by reranking
|
|
204
205
|
against the raw vectors it keeps. Training triggers automatically on
|
|
205
206
|
the first .add() call that reaches the training_size threshold, and
|
|
@@ -438,7 +439,8 @@ class VectorDatabase:
|
|
|
438
439
|
"holds 0.69 times an unquantized index at 10,000 records and 0.59 "
|
|
439
440
|
"times at 100,000. "
|
|
440
441
|
"get_stats() reports the memory the codes, the raw vectors, the codebook, "
|
|
441
|
-
"the centroid distance table
|
|
442
|
+
"the centroid distance table, the graph and the index bookkeeping hold "
|
|
443
|
+
"once records are loaded, "
|
|
442
444
|
"and sums them under total_memory_mb. This mode is required for rerank "
|
|
443
445
|
"and for exact vector reconstruction.",
|
|
444
446
|
UserWarning,
|