pgvector 0.3.6__tar.gz → 0.4.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.
- {pgvector-0.3.6 → pgvector-0.4.0}/LICENSE.txt +1 -1
- {pgvector-0.3.6 → pgvector-0.4.0}/PKG-INFO +256 -7
- {pgvector-0.3.6 → pgvector-0.4.0}/README.md +253 -4
- {pgvector-0.3.6 → pgvector-0.4.0}/pgvector/asyncpg/__init__.py +3 -1
- {pgvector-0.3.6 → pgvector-0.4.0}/pgvector/asyncpg/register.py +1 -1
- pgvector-0.4.0/pgvector/bit.py +75 -0
- {pgvector-0.3.6 → pgvector-0.4.0}/pgvector/django/__init__.py +3 -1
- {pgvector-0.3.6 → pgvector-0.4.0}/pgvector/django/functions.py +5 -1
- {pgvector-0.3.6 → pgvector-0.4.0}/pgvector/django/halfvec.py +1 -1
- {pgvector-0.3.6 → pgvector-0.4.0}/pgvector/django/sparsevec.py +1 -1
- {pgvector-0.3.6 → pgvector-0.4.0}/pgvector/django/vector.py +1 -1
- {pgvector-0.3.6/pgvector/utils → pgvector-0.4.0/pgvector}/halfvec.py +5 -0
- {pgvector-0.3.6 → pgvector-0.4.0}/pgvector/peewee/__init__.py +3 -1
- {pgvector-0.3.6 → pgvector-0.4.0}/pgvector/peewee/halfvec.py +1 -1
- {pgvector-0.3.6 → pgvector-0.4.0}/pgvector/peewee/sparsevec.py +1 -1
- {pgvector-0.3.6 → pgvector-0.4.0}/pgvector/peewee/vector.py +1 -1
- pgvector-0.4.0/pgvector/pg8000/__init__.py +5 -0
- pgvector-0.4.0/pgvector/pg8000/register.py +23 -0
- {pgvector-0.3.6 → pgvector-0.4.0}/pgvector/psycopg/__init__.py +3 -1
- {pgvector-0.3.6 → pgvector-0.4.0}/pgvector/psycopg/bit.py +1 -1
- {pgvector-0.3.6 → pgvector-0.4.0}/pgvector/psycopg/halfvec.py +1 -1
- {pgvector-0.3.6 → pgvector-0.4.0}/pgvector/psycopg/sparsevec.py +1 -1
- {pgvector-0.3.6 → pgvector-0.4.0}/pgvector/psycopg/vector.py +1 -1
- {pgvector-0.3.6 → pgvector-0.4.0}/pgvector/psycopg2/__init__.py +3 -1
- {pgvector-0.3.6 → pgvector-0.4.0}/pgvector/psycopg2/halfvec.py +1 -1
- {pgvector-0.3.6 → pgvector-0.4.0}/pgvector/psycopg2/register.py +1 -3
- {pgvector-0.3.6 → pgvector-0.4.0}/pgvector/psycopg2/sparsevec.py +1 -1
- {pgvector-0.3.6 → pgvector-0.4.0}/pgvector/psycopg2/vector.py +2 -1
- {pgvector-0.3.6/pgvector/utils → pgvector-0.4.0/pgvector}/sparsevec.py +6 -1
- {pgvector-0.3.6 → pgvector-0.4.0}/pgvector/sqlalchemy/__init__.py +3 -1
- {pgvector-0.3.6 → pgvector-0.4.0}/pgvector/sqlalchemy/halfvec.py +1 -1
- {pgvector-0.3.6 → pgvector-0.4.0}/pgvector/sqlalchemy/sparsevec.py +1 -1
- {pgvector-0.3.6 → pgvector-0.4.0}/pgvector/sqlalchemy/vector.py +1 -1
- pgvector-0.4.0/pgvector/utils/__init__.py +9 -0
- {pgvector-0.3.6/pgvector/utils → pgvector-0.4.0/pgvector}/vector.py +5 -0
- {pgvector-0.3.6 → pgvector-0.4.0}/pgvector.egg-info/PKG-INFO +256 -7
- {pgvector-0.3.6 → pgvector-0.4.0}/pgvector.egg-info/SOURCES.txt +8 -4
- {pgvector-0.3.6 → pgvector-0.4.0}/pyproject.toml +2 -2
- {pgvector-0.3.6 → pgvector-0.4.0}/tests/test_asyncpg.py +32 -19
- pgvector-0.4.0/tests/test_bit.py +63 -0
- {pgvector-0.3.6 → pgvector-0.4.0}/tests/test_django.py +40 -19
- {pgvector-0.3.6 → pgvector-0.4.0}/tests/test_half_vector.py +18 -1
- {pgvector-0.3.6 → pgvector-0.4.0}/tests/test_peewee.py +12 -11
- pgvector-0.4.0/tests/test_pg8000.py +60 -0
- {pgvector-0.3.6 → pgvector-0.4.0}/tests/test_psycopg.py +45 -19
- {pgvector-0.3.6 → pgvector-0.4.0}/tests/test_psycopg2.py +51 -11
- {pgvector-0.3.6 → pgvector-0.4.0}/tests/test_sparse_vector.py +28 -3
- pgvector-0.4.0/tests/test_sqlalchemy.py +649 -0
- {pgvector-0.3.6 → pgvector-0.4.0}/tests/test_sqlmodel.py +44 -44
- {pgvector-0.3.6 → pgvector-0.4.0}/tests/test_vector.py +18 -1
- pgvector-0.3.6/pgvector/utils/bit.py +0 -61
- pgvector-0.3.6/tests/test_bit.py +0 -39
- pgvector-0.3.6/tests/test_sqlalchemy.py +0 -454
- {pgvector-0.3.6/pgvector/utils → pgvector-0.4.0/pgvector}/__init__.py +0 -0
- {pgvector-0.3.6 → pgvector-0.4.0}/pgvector/django/bit.py +0 -0
- {pgvector-0.3.6 → pgvector-0.4.0}/pgvector/django/extensions.py +0 -0
- {pgvector-0.3.6 → pgvector-0.4.0}/pgvector/django/indexes.py +0 -0
- {pgvector-0.3.6 → pgvector-0.4.0}/pgvector/peewee/bit.py +0 -0
- {pgvector-0.3.6 → pgvector-0.4.0}/pgvector/psycopg/register.py +0 -0
- {pgvector-0.3.6 → pgvector-0.4.0}/pgvector/sqlalchemy/bit.py +0 -0
- {pgvector-0.3.6 → pgvector-0.4.0}/pgvector/sqlalchemy/functions.py +0 -0
- {pgvector-0.3.6 → pgvector-0.4.0}/pgvector.egg-info/dependency_links.txt +0 -0
- {pgvector-0.3.6 → pgvector-0.4.0}/pgvector.egg-info/requires.txt +0 -0
- {pgvector-0.3.6 → pgvector-0.4.0}/pgvector.egg-info/top_level.txt +0 -0
- {pgvector-0.3.6 → pgvector-0.4.0}/setup.cfg +0 -0
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
2
|
Name: pgvector
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: pgvector support for Python
|
|
5
5
|
Author-email: Andrew Kane <andrew@ankane.org>
|
|
6
6
|
License: MIT
|
|
7
7
|
Project-URL: Homepage, https://github.com/pgvector/pgvector-python
|
|
8
|
-
Requires-Python: >=3.
|
|
8
|
+
Requires-Python: >=3.9
|
|
9
9
|
Description-Content-Type: text/markdown
|
|
10
10
|
License-File: LICENSE.txt
|
|
11
11
|
Requires-Dist: numpy
|
|
@@ -14,7 +14,7 @@ Requires-Dist: numpy
|
|
|
14
14
|
|
|
15
15
|
[pgvector](https://github.com/pgvector/pgvector) support for Python
|
|
16
16
|
|
|
17
|
-
Supports [Django](https://github.com/django/django), [SQLAlchemy](https://github.com/sqlalchemy/sqlalchemy), [SQLModel](https://github.com/tiangolo/sqlmodel), [Psycopg 3](https://github.com/psycopg/psycopg), [Psycopg 2](https://github.com/psycopg/psycopg2), [asyncpg](https://github.com/MagicStack/asyncpg), and [Peewee](https://github.com/coleifer/peewee)
|
|
17
|
+
Supports [Django](https://github.com/django/django), [SQLAlchemy](https://github.com/sqlalchemy/sqlalchemy), [SQLModel](https://github.com/tiangolo/sqlmodel), [Psycopg 3](https://github.com/psycopg/psycopg), [Psycopg 2](https://github.com/psycopg/psycopg2), [asyncpg](https://github.com/MagicStack/asyncpg), [pg8000](https://github.com/tlocke/pg8000), and [Peewee](https://github.com/coleifer/peewee)
|
|
18
18
|
|
|
19
19
|
[](https://github.com/pgvector/pgvector-python/actions)
|
|
20
20
|
|
|
@@ -34,6 +34,7 @@ And follow the instructions for your database library:
|
|
|
34
34
|
- [Psycopg 3](#psycopg-3)
|
|
35
35
|
- [Psycopg 2](#psycopg-2)
|
|
36
36
|
- [asyncpg](#asyncpg)
|
|
37
|
+
- [pg8000](#pg8000)
|
|
37
38
|
- [Peewee](#peewee)
|
|
38
39
|
|
|
39
40
|
Or check out some examples:
|
|
@@ -45,6 +46,7 @@ Or check out some examples:
|
|
|
45
46
|
- [Hybrid search](https://github.com/pgvector/pgvector-python/blob/master/examples/hybrid_search/cross_encoder.py) with SentenceTransformers (cross-encoder)
|
|
46
47
|
- [Sparse search](https://github.com/pgvector/pgvector-python/blob/master/examples/sparse_search/example.py) with Transformers
|
|
47
48
|
- [Late interaction search](https://github.com/pgvector/pgvector-python/blob/master/examples/colbert/exact.py) with ColBERT
|
|
49
|
+
- [Visual document retrieval](https://github.com/pgvector/pgvector-python/blob/master/examples/colpali/exact.py) with ColPali
|
|
48
50
|
- [Image search](https://github.com/pgvector/pgvector-python/blob/master/examples/image_search/example.py) with PyTorch
|
|
49
51
|
- [Image search](https://github.com/pgvector/pgvector-python/blob/master/examples/imagehash/example.py) with perceptual hashing
|
|
50
52
|
- [Morgan fingerprints](https://github.com/pgvector/pgvector-python/blob/master/examples/rdkit/example.py) with RDKit
|
|
@@ -145,6 +147,36 @@ class Item(models.Model):
|
|
|
145
147
|
|
|
146
148
|
Use `vector_ip_ops` for inner product and `vector_cosine_ops` for cosine distance
|
|
147
149
|
|
|
150
|
+
#### Half-Precision Indexing
|
|
151
|
+
|
|
152
|
+
Index vectors at half-precision
|
|
153
|
+
|
|
154
|
+
```python
|
|
155
|
+
from django.contrib.postgres.indexes import OpClass
|
|
156
|
+
from django.db.models.functions import Cast
|
|
157
|
+
from pgvector.django import HnswIndex, HalfVectorField
|
|
158
|
+
|
|
159
|
+
class Item(models.Model):
|
|
160
|
+
class Meta:
|
|
161
|
+
indexes = [
|
|
162
|
+
HnswIndex(
|
|
163
|
+
OpClass(Cast('embedding', HalfVectorField(dimensions=3)), name='halfvec_l2_ops'),
|
|
164
|
+
name='my_index',
|
|
165
|
+
m=16,
|
|
166
|
+
ef_construction=64
|
|
167
|
+
)
|
|
168
|
+
]
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
Note: Add `'django.contrib.postgres'` to `INSTALLED_APPS` to use `OpClass`
|
|
172
|
+
|
|
173
|
+
Get the nearest neighbors
|
|
174
|
+
|
|
175
|
+
```python
|
|
176
|
+
distance = L2Distance(Cast('embedding', HalfVectorField(dimensions=3)), [3, 1, 2])
|
|
177
|
+
Item.objects.order_by(distance)[:5]
|
|
178
|
+
```
|
|
179
|
+
|
|
148
180
|
## SQLAlchemy
|
|
149
181
|
|
|
150
182
|
Enable the extension
|
|
@@ -226,6 +258,77 @@ index.create(engine)
|
|
|
226
258
|
|
|
227
259
|
Use `vector_ip_ops` for inner product and `vector_cosine_ops` for cosine distance
|
|
228
260
|
|
|
261
|
+
#### Half-Precision Indexing
|
|
262
|
+
|
|
263
|
+
Index vectors at half-precision
|
|
264
|
+
|
|
265
|
+
```python
|
|
266
|
+
from pgvector.sqlalchemy import HALFVEC
|
|
267
|
+
from sqlalchemy.sql import func
|
|
268
|
+
|
|
269
|
+
index = Index(
|
|
270
|
+
'my_index',
|
|
271
|
+
func.cast(Item.embedding, HALFVEC(3)).label('embedding'),
|
|
272
|
+
postgresql_using='hnsw',
|
|
273
|
+
postgresql_with={'m': 16, 'ef_construction': 64},
|
|
274
|
+
postgresql_ops={'embedding': 'halfvec_l2_ops'}
|
|
275
|
+
)
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
Get the nearest neighbors
|
|
279
|
+
|
|
280
|
+
```python
|
|
281
|
+
order = func.cast(Item.embedding, HALFVEC(3)).l2_distance([3, 1, 2])
|
|
282
|
+
session.scalars(select(Item).order_by(order).limit(5))
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
#### Arrays
|
|
286
|
+
|
|
287
|
+
Add an array column
|
|
288
|
+
|
|
289
|
+
```python
|
|
290
|
+
from pgvector.sqlalchemy import Vector
|
|
291
|
+
from sqlalchemy import ARRAY
|
|
292
|
+
|
|
293
|
+
class Item(Base):
|
|
294
|
+
embeddings = mapped_column(ARRAY(Vector(3)))
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
And register the types with the underlying driver
|
|
298
|
+
|
|
299
|
+
For Psycopg 3, use
|
|
300
|
+
|
|
301
|
+
```python
|
|
302
|
+
from pgvector.psycopg import register_vector
|
|
303
|
+
from sqlalchemy import event
|
|
304
|
+
|
|
305
|
+
@event.listens_for(engine, "connect")
|
|
306
|
+
def connect(dbapi_connection, connection_record):
|
|
307
|
+
register_vector(dbapi_connection)
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
For [async connections](https://docs.sqlalchemy.org/en/20/orm/extensions/asyncio.html) with Psycopg 3, use
|
|
311
|
+
|
|
312
|
+
```python
|
|
313
|
+
from pgvector.psycopg import register_vector_async
|
|
314
|
+
from sqlalchemy import event
|
|
315
|
+
|
|
316
|
+
@event.listens_for(engine.sync_engine, "connect")
|
|
317
|
+
def connect(dbapi_connection, connection_record):
|
|
318
|
+
dbapi_connection.run_async(register_vector_async)
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
For Psycopg 2, use
|
|
322
|
+
|
|
323
|
+
```python
|
|
324
|
+
from pgvector.psycopg2 import register_vector
|
|
325
|
+
from sqlalchemy import event
|
|
326
|
+
|
|
327
|
+
@event.listens_for(engine, "connect")
|
|
328
|
+
def connect(dbapi_connection, connection_record):
|
|
329
|
+
register_vector(dbapi_connection, arrays=True)
|
|
330
|
+
```
|
|
331
|
+
|
|
229
332
|
## SQLModel
|
|
230
333
|
|
|
231
334
|
Enable the extension
|
|
@@ -238,10 +341,9 @@ Add a vector column
|
|
|
238
341
|
|
|
239
342
|
```python
|
|
240
343
|
from pgvector.sqlalchemy import Vector
|
|
241
|
-
from sqlalchemy import Column
|
|
242
344
|
|
|
243
345
|
class Item(SQLModel, table=True):
|
|
244
|
-
embedding: Any = Field(
|
|
346
|
+
embedding: Any = Field(sa_type=Vector(3))
|
|
245
347
|
```
|
|
246
348
|
|
|
247
349
|
Also supports `HALFVEC`, `BIT`, and `SPARSEVEC`
|
|
@@ -287,7 +389,7 @@ Also supports `sum`
|
|
|
287
389
|
Add an approximate index
|
|
288
390
|
|
|
289
391
|
```python
|
|
290
|
-
from
|
|
392
|
+
from sqlmodel import Index
|
|
291
393
|
|
|
292
394
|
index = Index(
|
|
293
395
|
'my_index',
|
|
@@ -326,6 +428,15 @@ from pgvector.psycopg import register_vector
|
|
|
326
428
|
register_vector(conn)
|
|
327
429
|
```
|
|
328
430
|
|
|
431
|
+
For [connection pools](https://www.psycopg.org/psycopg3/docs/advanced/pool.html), use
|
|
432
|
+
|
|
433
|
+
```python
|
|
434
|
+
def configure(conn):
|
|
435
|
+
register_vector(conn)
|
|
436
|
+
|
|
437
|
+
pool = ConnectionPool(..., configure=configure)
|
|
438
|
+
```
|
|
439
|
+
|
|
329
440
|
For [async connections](https://www.psycopg.org/psycopg3/docs/advanced/async.html), use
|
|
330
441
|
|
|
331
442
|
```python
|
|
@@ -464,6 +575,51 @@ await conn.execute('CREATE INDEX ON items USING ivfflat (embedding vector_l2_ops
|
|
|
464
575
|
|
|
465
576
|
Use `vector_ip_ops` for inner product and `vector_cosine_ops` for cosine distance
|
|
466
577
|
|
|
578
|
+
## pg8000
|
|
579
|
+
|
|
580
|
+
Enable the extension
|
|
581
|
+
|
|
582
|
+
```python
|
|
583
|
+
conn.run('CREATE EXTENSION IF NOT EXISTS vector')
|
|
584
|
+
```
|
|
585
|
+
|
|
586
|
+
Register the vector type with your connection
|
|
587
|
+
|
|
588
|
+
```python
|
|
589
|
+
from pgvector.pg8000 import register_vector
|
|
590
|
+
|
|
591
|
+
register_vector(conn)
|
|
592
|
+
```
|
|
593
|
+
|
|
594
|
+
Create a table
|
|
595
|
+
|
|
596
|
+
```python
|
|
597
|
+
conn.run('CREATE TABLE items (id bigserial PRIMARY KEY, embedding vector(3))')
|
|
598
|
+
```
|
|
599
|
+
|
|
600
|
+
Insert a vector
|
|
601
|
+
|
|
602
|
+
```python
|
|
603
|
+
embedding = np.array([1, 2, 3])
|
|
604
|
+
conn.run('INSERT INTO items (embedding) VALUES (:embedding)', embedding=embedding)
|
|
605
|
+
```
|
|
606
|
+
|
|
607
|
+
Get the nearest neighbors to a vector
|
|
608
|
+
|
|
609
|
+
```python
|
|
610
|
+
conn.run('SELECT * FROM items ORDER BY embedding <-> :embedding LIMIT 5', embedding=embedding)
|
|
611
|
+
```
|
|
612
|
+
|
|
613
|
+
Add an approximate index
|
|
614
|
+
|
|
615
|
+
```python
|
|
616
|
+
conn.run('CREATE INDEX ON items USING hnsw (embedding vector_l2_ops)')
|
|
617
|
+
# or
|
|
618
|
+
conn.run('CREATE INDEX ON items USING ivfflat (embedding vector_l2_ops) WITH (lists = 100)')
|
|
619
|
+
```
|
|
620
|
+
|
|
621
|
+
Use `vector_ip_ops` for inner product and `vector_cosine_ops` for cosine distance
|
|
622
|
+
|
|
467
623
|
## Peewee
|
|
468
624
|
|
|
469
625
|
Add a vector column
|
|
@@ -521,6 +677,99 @@ Item.add_index('embedding vector_l2_ops', using='hnsw')
|
|
|
521
677
|
|
|
522
678
|
Use `vector_ip_ops` for inner product and `vector_cosine_ops` for cosine distance
|
|
523
679
|
|
|
680
|
+
## Reference
|
|
681
|
+
|
|
682
|
+
### Half Vectors
|
|
683
|
+
|
|
684
|
+
Create a half vector from a list
|
|
685
|
+
|
|
686
|
+
```python
|
|
687
|
+
vec = HalfVector([1, 2, 3])
|
|
688
|
+
```
|
|
689
|
+
|
|
690
|
+
Or a NumPy array
|
|
691
|
+
|
|
692
|
+
```python
|
|
693
|
+
vec = HalfVector(np.array([1, 2, 3]))
|
|
694
|
+
```
|
|
695
|
+
|
|
696
|
+
Get a list
|
|
697
|
+
|
|
698
|
+
```python
|
|
699
|
+
lst = vec.to_list()
|
|
700
|
+
```
|
|
701
|
+
|
|
702
|
+
Get a NumPy array
|
|
703
|
+
|
|
704
|
+
```python
|
|
705
|
+
arr = vec.to_numpy()
|
|
706
|
+
```
|
|
707
|
+
|
|
708
|
+
### Sparse Vectors
|
|
709
|
+
|
|
710
|
+
Create a sparse vector from a list
|
|
711
|
+
|
|
712
|
+
```python
|
|
713
|
+
vec = SparseVector([1, 0, 2, 0, 3, 0])
|
|
714
|
+
```
|
|
715
|
+
|
|
716
|
+
Or a NumPy array
|
|
717
|
+
|
|
718
|
+
```python
|
|
719
|
+
vec = SparseVector(np.array([1, 0, 2, 0, 3, 0]))
|
|
720
|
+
```
|
|
721
|
+
|
|
722
|
+
Or a SciPy sparse array
|
|
723
|
+
|
|
724
|
+
```python
|
|
725
|
+
arr = coo_array(([1, 2, 3], ([0, 2, 4],)), shape=(6,))
|
|
726
|
+
vec = SparseVector(arr)
|
|
727
|
+
```
|
|
728
|
+
|
|
729
|
+
Or a dictionary of non-zero elements
|
|
730
|
+
|
|
731
|
+
```python
|
|
732
|
+
vec = SparseVector({0: 1, 2: 2, 4: 3}, 6)
|
|
733
|
+
```
|
|
734
|
+
|
|
735
|
+
Note: Indices start at 0
|
|
736
|
+
|
|
737
|
+
Get the number of dimensions
|
|
738
|
+
|
|
739
|
+
```python
|
|
740
|
+
dim = vec.dimensions()
|
|
741
|
+
```
|
|
742
|
+
|
|
743
|
+
Get the indices of non-zero elements
|
|
744
|
+
|
|
745
|
+
```python
|
|
746
|
+
indices = vec.indices()
|
|
747
|
+
```
|
|
748
|
+
|
|
749
|
+
Get the values of non-zero elements
|
|
750
|
+
|
|
751
|
+
```python
|
|
752
|
+
values = vec.values()
|
|
753
|
+
```
|
|
754
|
+
|
|
755
|
+
Get a list
|
|
756
|
+
|
|
757
|
+
```python
|
|
758
|
+
lst = vec.to_list()
|
|
759
|
+
```
|
|
760
|
+
|
|
761
|
+
Get a NumPy array
|
|
762
|
+
|
|
763
|
+
```python
|
|
764
|
+
arr = vec.to_numpy()
|
|
765
|
+
```
|
|
766
|
+
|
|
767
|
+
Get a SciPy sparse array
|
|
768
|
+
|
|
769
|
+
```python
|
|
770
|
+
arr = vec.to_coo()
|
|
771
|
+
```
|
|
772
|
+
|
|
524
773
|
## History
|
|
525
774
|
|
|
526
775
|
View the [changelog](https://github.com/pgvector/pgvector-python/blob/master/CHANGELOG.md)
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
[pgvector](https://github.com/pgvector/pgvector) support for Python
|
|
4
4
|
|
|
5
|
-
Supports [Django](https://github.com/django/django), [SQLAlchemy](https://github.com/sqlalchemy/sqlalchemy), [SQLModel](https://github.com/tiangolo/sqlmodel), [Psycopg 3](https://github.com/psycopg/psycopg), [Psycopg 2](https://github.com/psycopg/psycopg2), [asyncpg](https://github.com/MagicStack/asyncpg), and [Peewee](https://github.com/coleifer/peewee)
|
|
5
|
+
Supports [Django](https://github.com/django/django), [SQLAlchemy](https://github.com/sqlalchemy/sqlalchemy), [SQLModel](https://github.com/tiangolo/sqlmodel), [Psycopg 3](https://github.com/psycopg/psycopg), [Psycopg 2](https://github.com/psycopg/psycopg2), [asyncpg](https://github.com/MagicStack/asyncpg), [pg8000](https://github.com/tlocke/pg8000), and [Peewee](https://github.com/coleifer/peewee)
|
|
6
6
|
|
|
7
7
|
[](https://github.com/pgvector/pgvector-python/actions)
|
|
8
8
|
|
|
@@ -22,6 +22,7 @@ And follow the instructions for your database library:
|
|
|
22
22
|
- [Psycopg 3](#psycopg-3)
|
|
23
23
|
- [Psycopg 2](#psycopg-2)
|
|
24
24
|
- [asyncpg](#asyncpg)
|
|
25
|
+
- [pg8000](#pg8000)
|
|
25
26
|
- [Peewee](#peewee)
|
|
26
27
|
|
|
27
28
|
Or check out some examples:
|
|
@@ -33,6 +34,7 @@ Or check out some examples:
|
|
|
33
34
|
- [Hybrid search](https://github.com/pgvector/pgvector-python/blob/master/examples/hybrid_search/cross_encoder.py) with SentenceTransformers (cross-encoder)
|
|
34
35
|
- [Sparse search](https://github.com/pgvector/pgvector-python/blob/master/examples/sparse_search/example.py) with Transformers
|
|
35
36
|
- [Late interaction search](https://github.com/pgvector/pgvector-python/blob/master/examples/colbert/exact.py) with ColBERT
|
|
37
|
+
- [Visual document retrieval](https://github.com/pgvector/pgvector-python/blob/master/examples/colpali/exact.py) with ColPali
|
|
36
38
|
- [Image search](https://github.com/pgvector/pgvector-python/blob/master/examples/image_search/example.py) with PyTorch
|
|
37
39
|
- [Image search](https://github.com/pgvector/pgvector-python/blob/master/examples/imagehash/example.py) with perceptual hashing
|
|
38
40
|
- [Morgan fingerprints](https://github.com/pgvector/pgvector-python/blob/master/examples/rdkit/example.py) with RDKit
|
|
@@ -133,6 +135,36 @@ class Item(models.Model):
|
|
|
133
135
|
|
|
134
136
|
Use `vector_ip_ops` for inner product and `vector_cosine_ops` for cosine distance
|
|
135
137
|
|
|
138
|
+
#### Half-Precision Indexing
|
|
139
|
+
|
|
140
|
+
Index vectors at half-precision
|
|
141
|
+
|
|
142
|
+
```python
|
|
143
|
+
from django.contrib.postgres.indexes import OpClass
|
|
144
|
+
from django.db.models.functions import Cast
|
|
145
|
+
from pgvector.django import HnswIndex, HalfVectorField
|
|
146
|
+
|
|
147
|
+
class Item(models.Model):
|
|
148
|
+
class Meta:
|
|
149
|
+
indexes = [
|
|
150
|
+
HnswIndex(
|
|
151
|
+
OpClass(Cast('embedding', HalfVectorField(dimensions=3)), name='halfvec_l2_ops'),
|
|
152
|
+
name='my_index',
|
|
153
|
+
m=16,
|
|
154
|
+
ef_construction=64
|
|
155
|
+
)
|
|
156
|
+
]
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
Note: Add `'django.contrib.postgres'` to `INSTALLED_APPS` to use `OpClass`
|
|
160
|
+
|
|
161
|
+
Get the nearest neighbors
|
|
162
|
+
|
|
163
|
+
```python
|
|
164
|
+
distance = L2Distance(Cast('embedding', HalfVectorField(dimensions=3)), [3, 1, 2])
|
|
165
|
+
Item.objects.order_by(distance)[:5]
|
|
166
|
+
```
|
|
167
|
+
|
|
136
168
|
## SQLAlchemy
|
|
137
169
|
|
|
138
170
|
Enable the extension
|
|
@@ -214,6 +246,77 @@ index.create(engine)
|
|
|
214
246
|
|
|
215
247
|
Use `vector_ip_ops` for inner product and `vector_cosine_ops` for cosine distance
|
|
216
248
|
|
|
249
|
+
#### Half-Precision Indexing
|
|
250
|
+
|
|
251
|
+
Index vectors at half-precision
|
|
252
|
+
|
|
253
|
+
```python
|
|
254
|
+
from pgvector.sqlalchemy import HALFVEC
|
|
255
|
+
from sqlalchemy.sql import func
|
|
256
|
+
|
|
257
|
+
index = Index(
|
|
258
|
+
'my_index',
|
|
259
|
+
func.cast(Item.embedding, HALFVEC(3)).label('embedding'),
|
|
260
|
+
postgresql_using='hnsw',
|
|
261
|
+
postgresql_with={'m': 16, 'ef_construction': 64},
|
|
262
|
+
postgresql_ops={'embedding': 'halfvec_l2_ops'}
|
|
263
|
+
)
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
Get the nearest neighbors
|
|
267
|
+
|
|
268
|
+
```python
|
|
269
|
+
order = func.cast(Item.embedding, HALFVEC(3)).l2_distance([3, 1, 2])
|
|
270
|
+
session.scalars(select(Item).order_by(order).limit(5))
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
#### Arrays
|
|
274
|
+
|
|
275
|
+
Add an array column
|
|
276
|
+
|
|
277
|
+
```python
|
|
278
|
+
from pgvector.sqlalchemy import Vector
|
|
279
|
+
from sqlalchemy import ARRAY
|
|
280
|
+
|
|
281
|
+
class Item(Base):
|
|
282
|
+
embeddings = mapped_column(ARRAY(Vector(3)))
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
And register the types with the underlying driver
|
|
286
|
+
|
|
287
|
+
For Psycopg 3, use
|
|
288
|
+
|
|
289
|
+
```python
|
|
290
|
+
from pgvector.psycopg import register_vector
|
|
291
|
+
from sqlalchemy import event
|
|
292
|
+
|
|
293
|
+
@event.listens_for(engine, "connect")
|
|
294
|
+
def connect(dbapi_connection, connection_record):
|
|
295
|
+
register_vector(dbapi_connection)
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
For [async connections](https://docs.sqlalchemy.org/en/20/orm/extensions/asyncio.html) with Psycopg 3, use
|
|
299
|
+
|
|
300
|
+
```python
|
|
301
|
+
from pgvector.psycopg import register_vector_async
|
|
302
|
+
from sqlalchemy import event
|
|
303
|
+
|
|
304
|
+
@event.listens_for(engine.sync_engine, "connect")
|
|
305
|
+
def connect(dbapi_connection, connection_record):
|
|
306
|
+
dbapi_connection.run_async(register_vector_async)
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
For Psycopg 2, use
|
|
310
|
+
|
|
311
|
+
```python
|
|
312
|
+
from pgvector.psycopg2 import register_vector
|
|
313
|
+
from sqlalchemy import event
|
|
314
|
+
|
|
315
|
+
@event.listens_for(engine, "connect")
|
|
316
|
+
def connect(dbapi_connection, connection_record):
|
|
317
|
+
register_vector(dbapi_connection, arrays=True)
|
|
318
|
+
```
|
|
319
|
+
|
|
217
320
|
## SQLModel
|
|
218
321
|
|
|
219
322
|
Enable the extension
|
|
@@ -226,10 +329,9 @@ Add a vector column
|
|
|
226
329
|
|
|
227
330
|
```python
|
|
228
331
|
from pgvector.sqlalchemy import Vector
|
|
229
|
-
from sqlalchemy import Column
|
|
230
332
|
|
|
231
333
|
class Item(SQLModel, table=True):
|
|
232
|
-
embedding: Any = Field(
|
|
334
|
+
embedding: Any = Field(sa_type=Vector(3))
|
|
233
335
|
```
|
|
234
336
|
|
|
235
337
|
Also supports `HALFVEC`, `BIT`, and `SPARSEVEC`
|
|
@@ -275,7 +377,7 @@ Also supports `sum`
|
|
|
275
377
|
Add an approximate index
|
|
276
378
|
|
|
277
379
|
```python
|
|
278
|
-
from
|
|
380
|
+
from sqlmodel import Index
|
|
279
381
|
|
|
280
382
|
index = Index(
|
|
281
383
|
'my_index',
|
|
@@ -314,6 +416,15 @@ from pgvector.psycopg import register_vector
|
|
|
314
416
|
register_vector(conn)
|
|
315
417
|
```
|
|
316
418
|
|
|
419
|
+
For [connection pools](https://www.psycopg.org/psycopg3/docs/advanced/pool.html), use
|
|
420
|
+
|
|
421
|
+
```python
|
|
422
|
+
def configure(conn):
|
|
423
|
+
register_vector(conn)
|
|
424
|
+
|
|
425
|
+
pool = ConnectionPool(..., configure=configure)
|
|
426
|
+
```
|
|
427
|
+
|
|
317
428
|
For [async connections](https://www.psycopg.org/psycopg3/docs/advanced/async.html), use
|
|
318
429
|
|
|
319
430
|
```python
|
|
@@ -452,6 +563,51 @@ await conn.execute('CREATE INDEX ON items USING ivfflat (embedding vector_l2_ops
|
|
|
452
563
|
|
|
453
564
|
Use `vector_ip_ops` for inner product and `vector_cosine_ops` for cosine distance
|
|
454
565
|
|
|
566
|
+
## pg8000
|
|
567
|
+
|
|
568
|
+
Enable the extension
|
|
569
|
+
|
|
570
|
+
```python
|
|
571
|
+
conn.run('CREATE EXTENSION IF NOT EXISTS vector')
|
|
572
|
+
```
|
|
573
|
+
|
|
574
|
+
Register the vector type with your connection
|
|
575
|
+
|
|
576
|
+
```python
|
|
577
|
+
from pgvector.pg8000 import register_vector
|
|
578
|
+
|
|
579
|
+
register_vector(conn)
|
|
580
|
+
```
|
|
581
|
+
|
|
582
|
+
Create a table
|
|
583
|
+
|
|
584
|
+
```python
|
|
585
|
+
conn.run('CREATE TABLE items (id bigserial PRIMARY KEY, embedding vector(3))')
|
|
586
|
+
```
|
|
587
|
+
|
|
588
|
+
Insert a vector
|
|
589
|
+
|
|
590
|
+
```python
|
|
591
|
+
embedding = np.array([1, 2, 3])
|
|
592
|
+
conn.run('INSERT INTO items (embedding) VALUES (:embedding)', embedding=embedding)
|
|
593
|
+
```
|
|
594
|
+
|
|
595
|
+
Get the nearest neighbors to a vector
|
|
596
|
+
|
|
597
|
+
```python
|
|
598
|
+
conn.run('SELECT * FROM items ORDER BY embedding <-> :embedding LIMIT 5', embedding=embedding)
|
|
599
|
+
```
|
|
600
|
+
|
|
601
|
+
Add an approximate index
|
|
602
|
+
|
|
603
|
+
```python
|
|
604
|
+
conn.run('CREATE INDEX ON items USING hnsw (embedding vector_l2_ops)')
|
|
605
|
+
# or
|
|
606
|
+
conn.run('CREATE INDEX ON items USING ivfflat (embedding vector_l2_ops) WITH (lists = 100)')
|
|
607
|
+
```
|
|
608
|
+
|
|
609
|
+
Use `vector_ip_ops` for inner product and `vector_cosine_ops` for cosine distance
|
|
610
|
+
|
|
455
611
|
## Peewee
|
|
456
612
|
|
|
457
613
|
Add a vector column
|
|
@@ -509,6 +665,99 @@ Item.add_index('embedding vector_l2_ops', using='hnsw')
|
|
|
509
665
|
|
|
510
666
|
Use `vector_ip_ops` for inner product and `vector_cosine_ops` for cosine distance
|
|
511
667
|
|
|
668
|
+
## Reference
|
|
669
|
+
|
|
670
|
+
### Half Vectors
|
|
671
|
+
|
|
672
|
+
Create a half vector from a list
|
|
673
|
+
|
|
674
|
+
```python
|
|
675
|
+
vec = HalfVector([1, 2, 3])
|
|
676
|
+
```
|
|
677
|
+
|
|
678
|
+
Or a NumPy array
|
|
679
|
+
|
|
680
|
+
```python
|
|
681
|
+
vec = HalfVector(np.array([1, 2, 3]))
|
|
682
|
+
```
|
|
683
|
+
|
|
684
|
+
Get a list
|
|
685
|
+
|
|
686
|
+
```python
|
|
687
|
+
lst = vec.to_list()
|
|
688
|
+
```
|
|
689
|
+
|
|
690
|
+
Get a NumPy array
|
|
691
|
+
|
|
692
|
+
```python
|
|
693
|
+
arr = vec.to_numpy()
|
|
694
|
+
```
|
|
695
|
+
|
|
696
|
+
### Sparse Vectors
|
|
697
|
+
|
|
698
|
+
Create a sparse vector from a list
|
|
699
|
+
|
|
700
|
+
```python
|
|
701
|
+
vec = SparseVector([1, 0, 2, 0, 3, 0])
|
|
702
|
+
```
|
|
703
|
+
|
|
704
|
+
Or a NumPy array
|
|
705
|
+
|
|
706
|
+
```python
|
|
707
|
+
vec = SparseVector(np.array([1, 0, 2, 0, 3, 0]))
|
|
708
|
+
```
|
|
709
|
+
|
|
710
|
+
Or a SciPy sparse array
|
|
711
|
+
|
|
712
|
+
```python
|
|
713
|
+
arr = coo_array(([1, 2, 3], ([0, 2, 4],)), shape=(6,))
|
|
714
|
+
vec = SparseVector(arr)
|
|
715
|
+
```
|
|
716
|
+
|
|
717
|
+
Or a dictionary of non-zero elements
|
|
718
|
+
|
|
719
|
+
```python
|
|
720
|
+
vec = SparseVector({0: 1, 2: 2, 4: 3}, 6)
|
|
721
|
+
```
|
|
722
|
+
|
|
723
|
+
Note: Indices start at 0
|
|
724
|
+
|
|
725
|
+
Get the number of dimensions
|
|
726
|
+
|
|
727
|
+
```python
|
|
728
|
+
dim = vec.dimensions()
|
|
729
|
+
```
|
|
730
|
+
|
|
731
|
+
Get the indices of non-zero elements
|
|
732
|
+
|
|
733
|
+
```python
|
|
734
|
+
indices = vec.indices()
|
|
735
|
+
```
|
|
736
|
+
|
|
737
|
+
Get the values of non-zero elements
|
|
738
|
+
|
|
739
|
+
```python
|
|
740
|
+
values = vec.values()
|
|
741
|
+
```
|
|
742
|
+
|
|
743
|
+
Get a list
|
|
744
|
+
|
|
745
|
+
```python
|
|
746
|
+
lst = vec.to_list()
|
|
747
|
+
```
|
|
748
|
+
|
|
749
|
+
Get a NumPy array
|
|
750
|
+
|
|
751
|
+
```python
|
|
752
|
+
arr = vec.to_numpy()
|
|
753
|
+
```
|
|
754
|
+
|
|
755
|
+
Get a SciPy sparse array
|
|
756
|
+
|
|
757
|
+
```python
|
|
758
|
+
arr = vec.to_coo()
|
|
759
|
+
```
|
|
760
|
+
|
|
512
761
|
## History
|
|
513
762
|
|
|
514
763
|
View the [changelog](https://github.com/pgvector/pgvector-python/blob/master/CHANGELOG.md)
|