numpy-vector-store 0.1.0__tar.gz → 0.2.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.
@@ -0,0 +1,200 @@
1
+ Metadata-Version: 2.4
2
+ Name: numpy-vector-store
3
+ Version: 0.2.0
4
+ Summary: A fast, lightweight, and zero-setup in-memory vector store powered by NumPy
5
+ Project-URL: Homepage, https://github.com/tvanreenen/numpy-vector-store
6
+ Project-URL: Repository, https://github.com/tvanreenen/numpy-vector-store
7
+ Project-URL: Issues, https://github.com/tvanreenen/numpy-vector-store/issues
8
+ Author: Tim VanReenen
9
+ License: MIT
10
+ License-File: LICENSE
11
+ Keywords: embeddings,numpy,search,store,vector
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Programming Language :: Python :: 3.13
20
+ Classifier: Programming Language :: Python :: 3.14
21
+ Requires-Python: >=3.10
22
+ Requires-Dist: numpy>=1.20.0
23
+ Description-Content-Type: text/markdown
24
+
25
+ # NumPy Vector Store
26
+
27
+ A fast, lightweight, zero-setup in-memory vector store powered by NumPy.
28
+
29
+ - **Tiny local vector search** for projects that do not need a vector database
30
+ - **Fast exact cosine search** using vectorized NumPy operations
31
+ - **Simple typed API** returning `VectorHit(index, value, metadata)`
32
+ - **Composable filtering** by passing prefiltered row indexes with `within_rows`
33
+ - **Portable persistence** as trusted local `.npz` files with `vectors` + `metadata`
34
+ - **No framework opinions**: bring your own embeddings, chunking, async, and metadata model
35
+
36
+ ## Why?
37
+
38
+ This library is purpose-built for small to medium-scale vector search tasks and
39
+ offers a simple alternative to heavyweight vector databases when you do not need
40
+ network services, indexing infrastructure, ingestion pipelines, or domain-specific
41
+ metadata filtering.
42
+
43
+ ## When/Where?
44
+
45
+ Below are benchmark results for cosine similarity search to help you assess its
46
+ suitability for your use case.
47
+
48
+ | Embedding Type | Dimensions | ~5ms | ~25ms | ~100ms | ~500ms |
49
+ |----------------|------------|------|--------|---------|---------|
50
+ | **Sentence Transformers** | 384 | 1K vectors<br/>1.5MB | 10K vectors<br/>15MB | 100K vectors<br/>147MB | 500K vectors<br/>732MB |
51
+ | **OpenAI Small** | 1536 | 500 vectors<br/>3MB | 5K vectors<br/>29MB | 25K vectors<br/>147MB | 100K vectors<br/>586MB |
52
+ | **OpenAI Large** | 3072 | 200 vectors<br/>2MB | 2.5K vectors<br/>29MB | 5K vectors<br/>59MB | 25K vectors<br/>293MB |
53
+
54
+ *Benchmarks performed on Apple M2 hardware.*
55
+
56
+ ## Installation
57
+
58
+ ```bash
59
+ uv add numpy-vector-store
60
+ ```
61
+
62
+ ## Quick Start
63
+
64
+ ```python
65
+ import numpy as np
66
+ from numpy_vector_store import VectorStore
67
+
68
+ store = VectorStore[dict[str, str]](dimensions=3)
69
+
70
+ store.add(
71
+ vectors=np.array([
72
+ [1.0, 0.0, 0.0],
73
+ [0.0, 1.0, 0.0],
74
+ [0.0, 0.0, 1.0],
75
+ ]),
76
+ metadata=[
77
+ {"title": "x-axis"},
78
+ {"title": "y-axis"},
79
+ {"title": "z-axis"},
80
+ ],
81
+ )
82
+
83
+ hits = store.cosine_search(
84
+ query=np.array([0.9, 0.1, 0.0]),
85
+ top_k=2,
86
+ )
87
+
88
+ for hit in hits:
89
+ print(f"{hit.metadata['title']}: {hit.value:.3f}")
90
+ ```
91
+
92
+ `metadata` is an opaque row payload returned with hits. It can be a dict,
93
+ dataclass, string, integer row ID, or any other Python object that fits your
94
+ application.
95
+
96
+ ## Prefiltering
97
+
98
+ The store does not implement a metadata query language. To filter by metadata,
99
+ produce row indexes first, then pass them with `within_rows`.
100
+
101
+ ```python
102
+ rows = [
103
+ i
104
+ for i, metadata in enumerate(store.metadata)
105
+ if metadata["title"].startswith("x")
106
+ ]
107
+
108
+ hits = store.cosine_search(query, top_k=10, within_rows=rows)
109
+ ```
110
+
111
+ For structured NumPy metadata, use NumPy to produce the row indexes:
112
+
113
+ ```python
114
+ metadata_table = np.array(
115
+ [
116
+ ("intro", "A", 2024),
117
+ ("setup", "A", 2023),
118
+ ("guide", "B", 2024),
119
+ ],
120
+ dtype=[("title", "U20"), ("product", "U10"), ("year", "i4")],
121
+ )
122
+
123
+ store = VectorStore[int](dimensions=3)
124
+ store.add(vectors, metadata=np.arange(len(metadata_table)))
125
+
126
+ mask = (metadata_table["product"] == "A") & (metadata_table["year"] >= 2024)
127
+ rows = np.flatnonzero(mask)
128
+
129
+ hits = store.cosine_search(query, within_rows=rows)
130
+
131
+ for hit in hits:
132
+ row = metadata_table[hit.metadata]
133
+ print(row["title"], hit.value)
134
+ ```
135
+
136
+ ## Persistence
137
+
138
+ Pass a `file_path` and call `save()` / `load()` explicitly:
139
+
140
+ ```python
141
+ store = VectorStore[dict[str, str]](dimensions=1536, file_path="vectors.npz")
142
+ store.add(embeddings, metadata)
143
+ store.save()
144
+
145
+ loaded = VectorStore[dict[str, str]](dimensions=1536, file_path="vectors.npz")
146
+ loaded.load()
147
+ ```
148
+
149
+ Context manager usage auto-saves on exit:
150
+
151
+ ```python
152
+ with VectorStore[dict[str, str]](dimensions=1536, file_path="vectors.npz") as store:
153
+ store.add(embeddings, metadata)
154
+ ```
155
+
156
+ Persistence uses a minimal NumPy `.npz` contract with `vectors` and `metadata`
157
+ arrays. Vectors are normalized when added or loaded, and similarity search only
158
+ normalizes the query vector. Loading validates shape, dimensions, row counts, and
159
+ zero-norm vectors. It also uses `allow_pickle=True` for flexible Python metadata
160
+ payloads, so only load files generated by your own application or another trusted
161
+ local process. Loading untrusted `.npz` files is not a supported security model.
162
+
163
+ ## Migrating from 0.1
164
+
165
+ The preferred 0.2 API is `add(...)` and `cosine_search(...)`.
166
+
167
+ The 0.1 methods remain temporarily available, but emit `DeprecationWarning` and
168
+ will be removed in a future 0.x release:
169
+
170
+ ```python
171
+ store.add_vectors(vectors_2d, metadata_array)
172
+ results = store.search(query, top_k=3, score_cutoff=0.5)
173
+ for index, value, metadata in results:
174
+ ...
175
+ ```
176
+
177
+ Legacy `search(...)` keeps returning tuples. New `cosine_search(...)` returns
178
+ `VectorHit` objects.
179
+
180
+ `metadata_schema` was removed. For vectorized metadata filtering, keep metadata
181
+ in a sidecar table and pass matching row indexes with `within_rows`.
182
+
183
+ ## Contributing
184
+
185
+ ```bash
186
+ git clone https://github.com/tvanreenen/numpy-vector-store.git
187
+ cd numpy-vector-store
188
+ uv sync --frozen --group dev
189
+ ```
190
+
191
+ Before submitting a pull request:
192
+
193
+ 1. Run `uv run ruff check`
194
+ 2. Run `uv run ruff format --check`
195
+ 3. Run `uv run mypy src/`
196
+ 4. Run `uv run pytest`
197
+
198
+ ## License
199
+
200
+ MIT License - see [LICENSE](LICENSE) file for details.
@@ -0,0 +1,176 @@
1
+ # NumPy Vector Store
2
+
3
+ A fast, lightweight, zero-setup in-memory vector store powered by NumPy.
4
+
5
+ - **Tiny local vector search** for projects that do not need a vector database
6
+ - **Fast exact cosine search** using vectorized NumPy operations
7
+ - **Simple typed API** returning `VectorHit(index, value, metadata)`
8
+ - **Composable filtering** by passing prefiltered row indexes with `within_rows`
9
+ - **Portable persistence** as trusted local `.npz` files with `vectors` + `metadata`
10
+ - **No framework opinions**: bring your own embeddings, chunking, async, and metadata model
11
+
12
+ ## Why?
13
+
14
+ This library is purpose-built for small to medium-scale vector search tasks and
15
+ offers a simple alternative to heavyweight vector databases when you do not need
16
+ network services, indexing infrastructure, ingestion pipelines, or domain-specific
17
+ metadata filtering.
18
+
19
+ ## When/Where?
20
+
21
+ Below are benchmark results for cosine similarity search to help you assess its
22
+ suitability for your use case.
23
+
24
+ | Embedding Type | Dimensions | ~5ms | ~25ms | ~100ms | ~500ms |
25
+ |----------------|------------|------|--------|---------|---------|
26
+ | **Sentence Transformers** | 384 | 1K vectors<br/>1.5MB | 10K vectors<br/>15MB | 100K vectors<br/>147MB | 500K vectors<br/>732MB |
27
+ | **OpenAI Small** | 1536 | 500 vectors<br/>3MB | 5K vectors<br/>29MB | 25K vectors<br/>147MB | 100K vectors<br/>586MB |
28
+ | **OpenAI Large** | 3072 | 200 vectors<br/>2MB | 2.5K vectors<br/>29MB | 5K vectors<br/>59MB | 25K vectors<br/>293MB |
29
+
30
+ *Benchmarks performed on Apple M2 hardware.*
31
+
32
+ ## Installation
33
+
34
+ ```bash
35
+ uv add numpy-vector-store
36
+ ```
37
+
38
+ ## Quick Start
39
+
40
+ ```python
41
+ import numpy as np
42
+ from numpy_vector_store import VectorStore
43
+
44
+ store = VectorStore[dict[str, str]](dimensions=3)
45
+
46
+ store.add(
47
+ vectors=np.array([
48
+ [1.0, 0.0, 0.0],
49
+ [0.0, 1.0, 0.0],
50
+ [0.0, 0.0, 1.0],
51
+ ]),
52
+ metadata=[
53
+ {"title": "x-axis"},
54
+ {"title": "y-axis"},
55
+ {"title": "z-axis"},
56
+ ],
57
+ )
58
+
59
+ hits = store.cosine_search(
60
+ query=np.array([0.9, 0.1, 0.0]),
61
+ top_k=2,
62
+ )
63
+
64
+ for hit in hits:
65
+ print(f"{hit.metadata['title']}: {hit.value:.3f}")
66
+ ```
67
+
68
+ `metadata` is an opaque row payload returned with hits. It can be a dict,
69
+ dataclass, string, integer row ID, or any other Python object that fits your
70
+ application.
71
+
72
+ ## Prefiltering
73
+
74
+ The store does not implement a metadata query language. To filter by metadata,
75
+ produce row indexes first, then pass them with `within_rows`.
76
+
77
+ ```python
78
+ rows = [
79
+ i
80
+ for i, metadata in enumerate(store.metadata)
81
+ if metadata["title"].startswith("x")
82
+ ]
83
+
84
+ hits = store.cosine_search(query, top_k=10, within_rows=rows)
85
+ ```
86
+
87
+ For structured NumPy metadata, use NumPy to produce the row indexes:
88
+
89
+ ```python
90
+ metadata_table = np.array(
91
+ [
92
+ ("intro", "A", 2024),
93
+ ("setup", "A", 2023),
94
+ ("guide", "B", 2024),
95
+ ],
96
+ dtype=[("title", "U20"), ("product", "U10"), ("year", "i4")],
97
+ )
98
+
99
+ store = VectorStore[int](dimensions=3)
100
+ store.add(vectors, metadata=np.arange(len(metadata_table)))
101
+
102
+ mask = (metadata_table["product"] == "A") & (metadata_table["year"] >= 2024)
103
+ rows = np.flatnonzero(mask)
104
+
105
+ hits = store.cosine_search(query, within_rows=rows)
106
+
107
+ for hit in hits:
108
+ row = metadata_table[hit.metadata]
109
+ print(row["title"], hit.value)
110
+ ```
111
+
112
+ ## Persistence
113
+
114
+ Pass a `file_path` and call `save()` / `load()` explicitly:
115
+
116
+ ```python
117
+ store = VectorStore[dict[str, str]](dimensions=1536, file_path="vectors.npz")
118
+ store.add(embeddings, metadata)
119
+ store.save()
120
+
121
+ loaded = VectorStore[dict[str, str]](dimensions=1536, file_path="vectors.npz")
122
+ loaded.load()
123
+ ```
124
+
125
+ Context manager usage auto-saves on exit:
126
+
127
+ ```python
128
+ with VectorStore[dict[str, str]](dimensions=1536, file_path="vectors.npz") as store:
129
+ store.add(embeddings, metadata)
130
+ ```
131
+
132
+ Persistence uses a minimal NumPy `.npz` contract with `vectors` and `metadata`
133
+ arrays. Vectors are normalized when added or loaded, and similarity search only
134
+ normalizes the query vector. Loading validates shape, dimensions, row counts, and
135
+ zero-norm vectors. It also uses `allow_pickle=True` for flexible Python metadata
136
+ payloads, so only load files generated by your own application or another trusted
137
+ local process. Loading untrusted `.npz` files is not a supported security model.
138
+
139
+ ## Migrating from 0.1
140
+
141
+ The preferred 0.2 API is `add(...)` and `cosine_search(...)`.
142
+
143
+ The 0.1 methods remain temporarily available, but emit `DeprecationWarning` and
144
+ will be removed in a future 0.x release:
145
+
146
+ ```python
147
+ store.add_vectors(vectors_2d, metadata_array)
148
+ results = store.search(query, top_k=3, score_cutoff=0.5)
149
+ for index, value, metadata in results:
150
+ ...
151
+ ```
152
+
153
+ Legacy `search(...)` keeps returning tuples. New `cosine_search(...)` returns
154
+ `VectorHit` objects.
155
+
156
+ `metadata_schema` was removed. For vectorized metadata filtering, keep metadata
157
+ in a sidecar table and pass matching row indexes with `within_rows`.
158
+
159
+ ## Contributing
160
+
161
+ ```bash
162
+ git clone https://github.com/tvanreenen/numpy-vector-store.git
163
+ cd numpy-vector-store
164
+ uv sync --frozen --group dev
165
+ ```
166
+
167
+ Before submitting a pull request:
168
+
169
+ 1. Run `uv run ruff check`
170
+ 2. Run `uv run ruff format --check`
171
+ 3. Run `uv run mypy src/`
172
+ 4. Run `uv run pytest`
173
+
174
+ ## License
175
+
176
+ MIT License - see [LICENSE](LICENSE) file for details.
@@ -7,7 +7,7 @@ name = "numpy-vector-store"
7
7
  dynamic = ["version"]
8
8
  description = "A fast, lightweight, and zero-setup in-memory vector store powered by NumPy"
9
9
  readme = "README.md"
10
- requires-python = ">=3.9"
10
+ requires-python = ">=3.10"
11
11
  license = {text = "MIT"}
12
12
  authors = [
13
13
  {name = "Tim VanReenen"},
@@ -18,10 +18,11 @@ classifiers = [
18
18
  "Intended Audience :: Developers",
19
19
  "License :: OSI Approved :: MIT License",
20
20
  "Programming Language :: Python :: 3",
21
- "Programming Language :: Python :: 3.9",
22
21
  "Programming Language :: Python :: 3.10",
23
22
  "Programming Language :: Python :: 3.11",
24
23
  "Programming Language :: Python :: 3.12",
24
+ "Programming Language :: Python :: 3.13",
25
+ "Programming Language :: Python :: 3.14",
25
26
  ]
26
27
  dependencies = [
27
28
  "numpy>=1.20.0",
@@ -41,7 +42,7 @@ path = "src/numpy_vector_store/__init__.py"
41
42
 
42
43
  [tool.ruff]
43
44
  line-length = 88
44
- target-version = "py39"
45
+ target-version = "py310"
45
46
 
46
47
  [tool.ruff.lint]
47
48
  select = [
@@ -62,7 +63,7 @@ ignore = [
62
63
  known-first-party = ["numpy_vector_store"]
63
64
 
64
65
  [tool.mypy]
65
- python_version = "3.9"
66
+ python_version = "3.10"
66
67
  warn_return_any = true
67
68
  warn_unused_configs = true
68
69
  disallow_untyped_defs = true
@@ -5,9 +5,9 @@ This package provides a lightweight vector store implementation for storing
5
5
  and searching vector embeddings using NumPy arrays.
6
6
  """
7
7
 
8
- __version__ = "0.1.0"
8
+ __version__ = "0.2.0"
9
9
  __author__ = "Tim VanReenen"
10
10
 
11
- from .vector_store import VectorStore
11
+ from .vector_store import VectorHit, VectorStore
12
12
 
13
- __all__ = ["VectorStore"]
13
+ __all__ = ["VectorHit", "VectorStore"]