pgvector 0.4.0__tar.gz → 0.4.2__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.
Files changed (63) hide show
  1. {pgvector-0.4.0/pgvector.egg-info → pgvector-0.4.2}/PKG-INFO +40 -8
  2. pgvector-0.4.0/PKG-INFO → pgvector-0.4.2/README.md +36 -17
  3. pgvector-0.4.2/pgvector/django/extensions.py +11 -0
  4. {pgvector-0.4.0 → pgvector-0.4.2}/pgvector/sparsevec.py +1 -1
  5. {pgvector-0.4.0 → pgvector-0.4.2}/pgvector/sqlalchemy/bit.py +12 -0
  6. pgvector-0.4.0/README.md → pgvector-0.4.2/pgvector.egg-info/PKG-INFO +49 -5
  7. {pgvector-0.4.0 → pgvector-0.4.2}/pyproject.toml +2 -2
  8. {pgvector-0.4.0 → pgvector-0.4.2}/tests/test_sparse_vector.py +19 -1
  9. {pgvector-0.4.0 → pgvector-0.4.2}/tests/test_sqlalchemy.py +23 -4
  10. pgvector-0.4.0/pgvector/django/extensions.py +0 -6
  11. {pgvector-0.4.0 → pgvector-0.4.2}/LICENSE.txt +0 -0
  12. {pgvector-0.4.0 → pgvector-0.4.2}/pgvector/__init__.py +0 -0
  13. {pgvector-0.4.0 → pgvector-0.4.2}/pgvector/asyncpg/__init__.py +0 -0
  14. {pgvector-0.4.0 → pgvector-0.4.2}/pgvector/asyncpg/register.py +0 -0
  15. {pgvector-0.4.0 → pgvector-0.4.2}/pgvector/bit.py +0 -0
  16. {pgvector-0.4.0 → pgvector-0.4.2}/pgvector/django/__init__.py +0 -0
  17. {pgvector-0.4.0 → pgvector-0.4.2}/pgvector/django/bit.py +0 -0
  18. {pgvector-0.4.0 → pgvector-0.4.2}/pgvector/django/functions.py +0 -0
  19. {pgvector-0.4.0 → pgvector-0.4.2}/pgvector/django/halfvec.py +0 -0
  20. {pgvector-0.4.0 → pgvector-0.4.2}/pgvector/django/indexes.py +0 -0
  21. {pgvector-0.4.0 → pgvector-0.4.2}/pgvector/django/sparsevec.py +0 -0
  22. {pgvector-0.4.0 → pgvector-0.4.2}/pgvector/django/vector.py +0 -0
  23. {pgvector-0.4.0 → pgvector-0.4.2}/pgvector/halfvec.py +0 -0
  24. {pgvector-0.4.0 → pgvector-0.4.2}/pgvector/peewee/__init__.py +0 -0
  25. {pgvector-0.4.0 → pgvector-0.4.2}/pgvector/peewee/bit.py +0 -0
  26. {pgvector-0.4.0 → pgvector-0.4.2}/pgvector/peewee/halfvec.py +0 -0
  27. {pgvector-0.4.0 → pgvector-0.4.2}/pgvector/peewee/sparsevec.py +0 -0
  28. {pgvector-0.4.0 → pgvector-0.4.2}/pgvector/peewee/vector.py +0 -0
  29. {pgvector-0.4.0 → pgvector-0.4.2}/pgvector/pg8000/__init__.py +0 -0
  30. {pgvector-0.4.0 → pgvector-0.4.2}/pgvector/pg8000/register.py +0 -0
  31. {pgvector-0.4.0 → pgvector-0.4.2}/pgvector/psycopg/__init__.py +0 -0
  32. {pgvector-0.4.0 → pgvector-0.4.2}/pgvector/psycopg/bit.py +0 -0
  33. {pgvector-0.4.0 → pgvector-0.4.2}/pgvector/psycopg/halfvec.py +0 -0
  34. {pgvector-0.4.0 → pgvector-0.4.2}/pgvector/psycopg/register.py +0 -0
  35. {pgvector-0.4.0 → pgvector-0.4.2}/pgvector/psycopg/sparsevec.py +0 -0
  36. {pgvector-0.4.0 → pgvector-0.4.2}/pgvector/psycopg/vector.py +0 -0
  37. {pgvector-0.4.0 → pgvector-0.4.2}/pgvector/psycopg2/__init__.py +0 -0
  38. {pgvector-0.4.0 → pgvector-0.4.2}/pgvector/psycopg2/halfvec.py +0 -0
  39. {pgvector-0.4.0 → pgvector-0.4.2}/pgvector/psycopg2/register.py +0 -0
  40. {pgvector-0.4.0 → pgvector-0.4.2}/pgvector/psycopg2/sparsevec.py +0 -0
  41. {pgvector-0.4.0 → pgvector-0.4.2}/pgvector/psycopg2/vector.py +0 -0
  42. {pgvector-0.4.0 → pgvector-0.4.2}/pgvector/sqlalchemy/__init__.py +0 -0
  43. {pgvector-0.4.0 → pgvector-0.4.2}/pgvector/sqlalchemy/functions.py +0 -0
  44. {pgvector-0.4.0 → pgvector-0.4.2}/pgvector/sqlalchemy/halfvec.py +0 -0
  45. {pgvector-0.4.0 → pgvector-0.4.2}/pgvector/sqlalchemy/sparsevec.py +0 -0
  46. {pgvector-0.4.0 → pgvector-0.4.2}/pgvector/sqlalchemy/vector.py +0 -0
  47. {pgvector-0.4.0 → pgvector-0.4.2}/pgvector/utils/__init__.py +0 -0
  48. {pgvector-0.4.0 → pgvector-0.4.2}/pgvector/vector.py +0 -0
  49. {pgvector-0.4.0 → pgvector-0.4.2}/pgvector.egg-info/SOURCES.txt +0 -0
  50. {pgvector-0.4.0 → pgvector-0.4.2}/pgvector.egg-info/dependency_links.txt +0 -0
  51. {pgvector-0.4.0 → pgvector-0.4.2}/pgvector.egg-info/requires.txt +0 -0
  52. {pgvector-0.4.0 → pgvector-0.4.2}/pgvector.egg-info/top_level.txt +0 -0
  53. {pgvector-0.4.0 → pgvector-0.4.2}/setup.cfg +0 -0
  54. {pgvector-0.4.0 → pgvector-0.4.2}/tests/test_asyncpg.py +0 -0
  55. {pgvector-0.4.0 → pgvector-0.4.2}/tests/test_bit.py +0 -0
  56. {pgvector-0.4.0 → pgvector-0.4.2}/tests/test_django.py +0 -0
  57. {pgvector-0.4.0 → pgvector-0.4.2}/tests/test_half_vector.py +0 -0
  58. {pgvector-0.4.0 → pgvector-0.4.2}/tests/test_peewee.py +0 -0
  59. {pgvector-0.4.0 → pgvector-0.4.2}/tests/test_pg8000.py +0 -0
  60. {pgvector-0.4.0 → pgvector-0.4.2}/tests/test_psycopg.py +0 -0
  61. {pgvector-0.4.0 → pgvector-0.4.2}/tests/test_psycopg2.py +0 -0
  62. {pgvector-0.4.0 → pgvector-0.4.2}/tests/test_sqlmodel.py +0 -0
  63. {pgvector-0.4.0 → pgvector-0.4.2}/tests/test_vector.py +0 -0
@@ -1,14 +1,15 @@
1
- Metadata-Version: 2.2
1
+ Metadata-Version: 2.4
2
2
  Name: pgvector
3
- Version: 0.4.0
3
+ Version: 0.4.2
4
4
  Summary: pgvector support for Python
5
5
  Author-email: Andrew Kane <andrew@ankane.org>
6
- License: MIT
6
+ License-Expression: MIT
7
7
  Project-URL: Homepage, https://github.com/pgvector/pgvector-python
8
8
  Requires-Python: >=3.9
9
9
  Description-Content-Type: text/markdown
10
10
  License-File: LICENSE.txt
11
11
  Requires-Dist: numpy
12
+ Dynamic: license-file
12
13
 
13
14
  # pgvector-python
14
15
 
@@ -39,6 +40,7 @@ And follow the instructions for your database library:
39
40
 
40
41
  Or check out some examples:
41
42
 
43
+ - [Retrieval-augmented generation](https://github.com/pgvector/pgvector-python/blob/master/examples/rag/example.py) with Ollama
42
44
  - [Embeddings](https://github.com/pgvector/pgvector-python/blob/master/examples/openai/example.py) with OpenAI
43
45
  - [Binary embeddings](https://github.com/pgvector/pgvector-python/blob/master/examples/cohere/example.py) with Cohere
44
46
  - [Sentence embeddings](https://github.com/pgvector/pgvector-python/blob/master/examples/sentence_transformers/example.py) with SentenceTransformers
@@ -270,7 +272,6 @@ index = Index(
270
272
  'my_index',
271
273
  func.cast(Item.embedding, HALFVEC(3)).label('embedding'),
272
274
  postgresql_using='hnsw',
273
- postgresql_with={'m': 16, 'ef_construction': 64},
274
275
  postgresql_ops={'embedding': 'halfvec_l2_ops'}
275
276
  )
276
277
  ```
@@ -282,6 +283,37 @@ order = func.cast(Item.embedding, HALFVEC(3)).l2_distance([3, 1, 2])
282
283
  session.scalars(select(Item).order_by(order).limit(5))
283
284
  ```
284
285
 
286
+ #### Binary Quantization
287
+
288
+ Use expression indexing for binary quantization
289
+
290
+ ```python
291
+ from pgvector.sqlalchemy import BIT
292
+ from sqlalchemy.sql import func
293
+
294
+ index = Index(
295
+ 'my_index',
296
+ func.cast(func.binary_quantize(Item.embedding), BIT(3)).label('embedding'),
297
+ postgresql_using='hnsw',
298
+ postgresql_ops={'embedding': 'bit_hamming_ops'}
299
+ )
300
+ ```
301
+
302
+ Get the nearest neighbors by Hamming distance
303
+
304
+ ```python
305
+ order = func.cast(func.binary_quantize(Item.embedding), BIT(3)).hamming_distance(func.binary_quantize(func.cast([3, -1, 2], VECTOR(3))))
306
+ session.scalars(select(Item).order_by(order).limit(5))
307
+ ```
308
+
309
+ Re-rank by the original vectors for better recall
310
+
311
+ ```python
312
+ order = func.cast(func.binary_quantize(Item.embedding), BIT(3)).hamming_distance(func.binary_quantize(func.cast([3, -1, 2], VECTOR(3))))
313
+ subquery = session.query(Item).order_by(order).limit(20).subquery()
314
+ session.scalars(select(subquery).order_by(subquery.c.embedding.cosine_distance([3, -1, 2])).limit(5))
315
+ ```
316
+
285
317
  #### Arrays
286
318
 
287
319
  Add an array column
@@ -420,7 +452,7 @@ Enable the extension
420
452
  conn.execute('CREATE EXTENSION IF NOT EXISTS vector')
421
453
  ```
422
454
 
423
- Register the vector type with your connection
455
+ Register the types with your connection
424
456
 
425
457
  ```python
426
458
  from pgvector.psycopg import register_vector
@@ -483,7 +515,7 @@ cur = conn.cursor()
483
515
  cur.execute('CREATE EXTENSION IF NOT EXISTS vector')
484
516
  ```
485
517
 
486
- Register the vector type with your connection or cursor
518
+ Register the types with your connection or cursor
487
519
 
488
520
  ```python
489
521
  from pgvector.psycopg2 import register_vector
@@ -529,7 +561,7 @@ Enable the extension
529
561
  await conn.execute('CREATE EXTENSION IF NOT EXISTS vector')
530
562
  ```
531
563
 
532
- Register the vector type with your connection
564
+ Register the types with your connection
533
565
 
534
566
  ```python
535
567
  from pgvector.asyncpg import register_vector
@@ -583,7 +615,7 @@ Enable the extension
583
615
  conn.run('CREATE EXTENSION IF NOT EXISTS vector')
584
616
  ```
585
617
 
586
- Register the vector type with your connection
618
+ Register the types with your connection
587
619
 
588
620
  ```python
589
621
  from pgvector.pg8000 import register_vector
@@ -1,15 +1,3 @@
1
- Metadata-Version: 2.2
2
- Name: pgvector
3
- Version: 0.4.0
4
- Summary: pgvector support for Python
5
- Author-email: Andrew Kane <andrew@ankane.org>
6
- License: MIT
7
- Project-URL: Homepage, https://github.com/pgvector/pgvector-python
8
- Requires-Python: >=3.9
9
- Description-Content-Type: text/markdown
10
- License-File: LICENSE.txt
11
- Requires-Dist: numpy
12
-
13
1
  # pgvector-python
14
2
 
15
3
  [pgvector](https://github.com/pgvector/pgvector) support for Python
@@ -39,6 +27,7 @@ And follow the instructions for your database library:
39
27
 
40
28
  Or check out some examples:
41
29
 
30
+ - [Retrieval-augmented generation](https://github.com/pgvector/pgvector-python/blob/master/examples/rag/example.py) with Ollama
42
31
  - [Embeddings](https://github.com/pgvector/pgvector-python/blob/master/examples/openai/example.py) with OpenAI
43
32
  - [Binary embeddings](https://github.com/pgvector/pgvector-python/blob/master/examples/cohere/example.py) with Cohere
44
33
  - [Sentence embeddings](https://github.com/pgvector/pgvector-python/blob/master/examples/sentence_transformers/example.py) with SentenceTransformers
@@ -270,7 +259,6 @@ index = Index(
270
259
  'my_index',
271
260
  func.cast(Item.embedding, HALFVEC(3)).label('embedding'),
272
261
  postgresql_using='hnsw',
273
- postgresql_with={'m': 16, 'ef_construction': 64},
274
262
  postgresql_ops={'embedding': 'halfvec_l2_ops'}
275
263
  )
276
264
  ```
@@ -282,6 +270,37 @@ order = func.cast(Item.embedding, HALFVEC(3)).l2_distance([3, 1, 2])
282
270
  session.scalars(select(Item).order_by(order).limit(5))
283
271
  ```
284
272
 
273
+ #### Binary Quantization
274
+
275
+ Use expression indexing for binary quantization
276
+
277
+ ```python
278
+ from pgvector.sqlalchemy import BIT
279
+ from sqlalchemy.sql import func
280
+
281
+ index = Index(
282
+ 'my_index',
283
+ func.cast(func.binary_quantize(Item.embedding), BIT(3)).label('embedding'),
284
+ postgresql_using='hnsw',
285
+ postgresql_ops={'embedding': 'bit_hamming_ops'}
286
+ )
287
+ ```
288
+
289
+ Get the nearest neighbors by Hamming distance
290
+
291
+ ```python
292
+ order = func.cast(func.binary_quantize(Item.embedding), BIT(3)).hamming_distance(func.binary_quantize(func.cast([3, -1, 2], VECTOR(3))))
293
+ session.scalars(select(Item).order_by(order).limit(5))
294
+ ```
295
+
296
+ Re-rank by the original vectors for better recall
297
+
298
+ ```python
299
+ order = func.cast(func.binary_quantize(Item.embedding), BIT(3)).hamming_distance(func.binary_quantize(func.cast([3, -1, 2], VECTOR(3))))
300
+ subquery = session.query(Item).order_by(order).limit(20).subquery()
301
+ session.scalars(select(subquery).order_by(subquery.c.embedding.cosine_distance([3, -1, 2])).limit(5))
302
+ ```
303
+
285
304
  #### Arrays
286
305
 
287
306
  Add an array column
@@ -420,7 +439,7 @@ Enable the extension
420
439
  conn.execute('CREATE EXTENSION IF NOT EXISTS vector')
421
440
  ```
422
441
 
423
- Register the vector type with your connection
442
+ Register the types with your connection
424
443
 
425
444
  ```python
426
445
  from pgvector.psycopg import register_vector
@@ -483,7 +502,7 @@ cur = conn.cursor()
483
502
  cur.execute('CREATE EXTENSION IF NOT EXISTS vector')
484
503
  ```
485
504
 
486
- Register the vector type with your connection or cursor
505
+ Register the types with your connection or cursor
487
506
 
488
507
  ```python
489
508
  from pgvector.psycopg2 import register_vector
@@ -529,7 +548,7 @@ Enable the extension
529
548
  await conn.execute('CREATE EXTENSION IF NOT EXISTS vector')
530
549
  ```
531
550
 
532
- Register the vector type with your connection
551
+ Register the types with your connection
533
552
 
534
553
  ```python
535
554
  from pgvector.asyncpg import register_vector
@@ -583,7 +602,7 @@ Enable the extension
583
602
  conn.run('CREATE EXTENSION IF NOT EXISTS vector')
584
603
  ```
585
604
 
586
- Register the vector type with your connection
605
+ Register the types with your connection
587
606
 
588
607
  ```python
589
608
  from pgvector.pg8000 import register_vector
@@ -0,0 +1,11 @@
1
+ from django import VERSION
2
+ from django.contrib.postgres.operations import CreateExtension
3
+
4
+
5
+ class VectorExtension(CreateExtension):
6
+ if VERSION[0] >= 6:
7
+ def __init__(self, hints=None):
8
+ super().__init__('vector', hints=hints)
9
+ else:
10
+ def __init__(self):
11
+ self.name = 'vector'
@@ -85,7 +85,7 @@ class SparseVector:
85
85
 
86
86
  if hasattr(value, 'coords'):
87
87
  # scipy 1.13+
88
- self._indices = value.coords[0].tolist()
88
+ self._indices = value.coords[-1].tolist()
89
89
  else:
90
90
  self._indices = value.col.tolist()
91
91
  self._values = value.data.tolist()
@@ -14,6 +14,18 @@ class BIT(UserDefinedType):
14
14
  return 'BIT'
15
15
  return 'BIT(%d)' % self.length
16
16
 
17
+ def bind_processor(self, dialect):
18
+ if dialect.__class__.__name__ == 'PGDialect_asyncpg':
19
+ import asyncpg
20
+
21
+ def process(value):
22
+ if isinstance(value, str):
23
+ return asyncpg.BitString(value)
24
+ return value
25
+ return process
26
+ else:
27
+ return super().bind_processor(dialect)
28
+
17
29
  class comparator_factory(UserDefinedType.Comparator):
18
30
  def hamming_distance(self, other):
19
31
  return self.op('<~>', return_type=Float)(other)
@@ -1,3 +1,16 @@
1
+ Metadata-Version: 2.4
2
+ Name: pgvector
3
+ Version: 0.4.2
4
+ Summary: pgvector support for Python
5
+ Author-email: Andrew Kane <andrew@ankane.org>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/pgvector/pgvector-python
8
+ Requires-Python: >=3.9
9
+ Description-Content-Type: text/markdown
10
+ License-File: LICENSE.txt
11
+ Requires-Dist: numpy
12
+ Dynamic: license-file
13
+
1
14
  # pgvector-python
2
15
 
3
16
  [pgvector](https://github.com/pgvector/pgvector) support for Python
@@ -27,6 +40,7 @@ And follow the instructions for your database library:
27
40
 
28
41
  Or check out some examples:
29
42
 
43
+ - [Retrieval-augmented generation](https://github.com/pgvector/pgvector-python/blob/master/examples/rag/example.py) with Ollama
30
44
  - [Embeddings](https://github.com/pgvector/pgvector-python/blob/master/examples/openai/example.py) with OpenAI
31
45
  - [Binary embeddings](https://github.com/pgvector/pgvector-python/blob/master/examples/cohere/example.py) with Cohere
32
46
  - [Sentence embeddings](https://github.com/pgvector/pgvector-python/blob/master/examples/sentence_transformers/example.py) with SentenceTransformers
@@ -258,7 +272,6 @@ index = Index(
258
272
  'my_index',
259
273
  func.cast(Item.embedding, HALFVEC(3)).label('embedding'),
260
274
  postgresql_using='hnsw',
261
- postgresql_with={'m': 16, 'ef_construction': 64},
262
275
  postgresql_ops={'embedding': 'halfvec_l2_ops'}
263
276
  )
264
277
  ```
@@ -270,6 +283,37 @@ order = func.cast(Item.embedding, HALFVEC(3)).l2_distance([3, 1, 2])
270
283
  session.scalars(select(Item).order_by(order).limit(5))
271
284
  ```
272
285
 
286
+ #### Binary Quantization
287
+
288
+ Use expression indexing for binary quantization
289
+
290
+ ```python
291
+ from pgvector.sqlalchemy import BIT
292
+ from sqlalchemy.sql import func
293
+
294
+ index = Index(
295
+ 'my_index',
296
+ func.cast(func.binary_quantize(Item.embedding), BIT(3)).label('embedding'),
297
+ postgresql_using='hnsw',
298
+ postgresql_ops={'embedding': 'bit_hamming_ops'}
299
+ )
300
+ ```
301
+
302
+ Get the nearest neighbors by Hamming distance
303
+
304
+ ```python
305
+ order = func.cast(func.binary_quantize(Item.embedding), BIT(3)).hamming_distance(func.binary_quantize(func.cast([3, -1, 2], VECTOR(3))))
306
+ session.scalars(select(Item).order_by(order).limit(5))
307
+ ```
308
+
309
+ Re-rank by the original vectors for better recall
310
+
311
+ ```python
312
+ order = func.cast(func.binary_quantize(Item.embedding), BIT(3)).hamming_distance(func.binary_quantize(func.cast([3, -1, 2], VECTOR(3))))
313
+ subquery = session.query(Item).order_by(order).limit(20).subquery()
314
+ session.scalars(select(subquery).order_by(subquery.c.embedding.cosine_distance([3, -1, 2])).limit(5))
315
+ ```
316
+
273
317
  #### Arrays
274
318
 
275
319
  Add an array column
@@ -408,7 +452,7 @@ Enable the extension
408
452
  conn.execute('CREATE EXTENSION IF NOT EXISTS vector')
409
453
  ```
410
454
 
411
- Register the vector type with your connection
455
+ Register the types with your connection
412
456
 
413
457
  ```python
414
458
  from pgvector.psycopg import register_vector
@@ -471,7 +515,7 @@ cur = conn.cursor()
471
515
  cur.execute('CREATE EXTENSION IF NOT EXISTS vector')
472
516
  ```
473
517
 
474
- Register the vector type with your connection or cursor
518
+ Register the types with your connection or cursor
475
519
 
476
520
  ```python
477
521
  from pgvector.psycopg2 import register_vector
@@ -517,7 +561,7 @@ Enable the extension
517
561
  await conn.execute('CREATE EXTENSION IF NOT EXISTS vector')
518
562
  ```
519
563
 
520
- Register the vector type with your connection
564
+ Register the types with your connection
521
565
 
522
566
  ```python
523
567
  from pgvector.asyncpg import register_vector
@@ -571,7 +615,7 @@ Enable the extension
571
615
  conn.run('CREATE EXTENSION IF NOT EXISTS vector')
572
616
  ```
573
617
 
574
- Register the vector type with your connection
618
+ Register the types with your connection
575
619
 
576
620
  ```python
577
621
  from pgvector.pg8000 import register_vector
@@ -4,13 +4,13 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "pgvector"
7
- version = "0.4.0"
7
+ version = "0.4.2"
8
8
  description = "pgvector support for Python"
9
9
  readme = "README.md"
10
10
  authors = [
11
11
  {name = "Andrew Kane", email = "andrew@ankane.org"}
12
12
  ]
13
- license = {text = "MIT"}
13
+ license = "MIT"
14
14
  requires-python = ">= 3.9"
15
15
  dependencies = [
16
16
  "numpy"
@@ -1,7 +1,7 @@
1
1
  import numpy as np
2
2
  from pgvector import SparseVector
3
3
  import pytest
4
- from scipy.sparse import coo_array
4
+ from scipy.sparse import coo_array, coo_matrix, csr_array, csr_matrix
5
5
  from struct import pack
6
6
 
7
7
 
@@ -43,12 +43,30 @@ class TestSparseVector:
43
43
  SparseVector(coo_array(np.array([1, 0, 2, 0, 3, 0])), 6)
44
44
  assert str(error.value) == 'extra argument'
45
45
 
46
+ def test_coo_matrix(self):
47
+ mat = coo_matrix(np.array([1, 0, 2, 0, 3, 0]))
48
+ vec = SparseVector(mat)
49
+ assert vec.to_list() == [1, 0, 2, 0, 3, 0]
50
+ assert vec.indices() == [0, 2, 4]
51
+
46
52
  def test_dok_array(self):
47
53
  arr = coo_array(np.array([1, 0, 2, 0, 3, 0])).todok()
48
54
  vec = SparseVector(arr)
49
55
  assert vec.to_list() == [1, 0, 2, 0, 3, 0]
50
56
  assert vec.indices() == [0, 2, 4]
51
57
 
58
+ def test_csr_array(self):
59
+ arr = csr_array(np.array([[1, 0, 2, 0, 3, 0]]))
60
+ vec = SparseVector(arr)
61
+ assert vec.to_list() == [1, 0, 2, 0, 3, 0]
62
+ assert vec.indices() == [0, 2, 4]
63
+
64
+ def test_csr_matrix(self):
65
+ mat = csr_matrix(np.array([1, 0, 2, 0, 3, 0]))
66
+ vec = SparseVector(mat)
67
+ assert vec.to_list() == [1, 0, 2, 0, 3, 0]
68
+ assert vec.indices() == [0, 2, 4]
69
+
52
70
  def test_repr(self):
53
71
  assert repr(SparseVector([1, 0, 2, 0, 3, 0])) == 'SparseVector({0: 1.0, 2: 2.0, 4: 3.0}, 6)'
54
72
  assert str(SparseVector([1, 0, 2, 0, 3, 0])) == 'SparseVector({0: 1.0, 2: 2.0, 4: 3.0}, 6)'
@@ -43,7 +43,7 @@ if sqlalchemy_version > 1:
43
43
  psycopg_async_type_engine = create_async_engine('postgresql+psycopg://localhost/pgvector_python_test')
44
44
 
45
45
  @event.listens_for(psycopg_async_type_engine.sync_engine, "connect")
46
- def connect(dbapi_connection, connection_record):
46
+ def psycopg_async_connect(dbapi_connection, connection_record):
47
47
  from pgvector.psycopg import register_vector_async
48
48
  dbapi_connection.run_async(register_vector_async)
49
49
 
@@ -51,7 +51,7 @@ if sqlalchemy_version > 1:
51
51
  asyncpg_type_engine = create_async_engine('postgresql+asyncpg://localhost/pgvector_python_test')
52
52
 
53
53
  @event.listens_for(asyncpg_type_engine.sync_engine, "connect")
54
- def connect(dbapi_connection, connection_record):
54
+ def asyncpg_connect(dbapi_connection, connection_record):
55
55
  from pgvector.asyncpg import register_vector
56
56
  dbapi_connection.run_async(register_vector)
57
57
 
@@ -103,7 +103,6 @@ half_precision_index = Index(
103
103
  'sqlalchemy_orm_half_precision_index',
104
104
  func.cast(Item.embedding, HALFVEC(3)).label('embedding'),
105
105
  postgresql_using='hnsw',
106
- postgresql_with={'m': 16, 'ef_construction': 64},
107
106
  postgresql_ops={'embedding': 'halfvec_l2_ops'}
108
107
  )
109
108
  half_precision_index.create(setup_engine)
@@ -112,7 +111,6 @@ binary_quantize_index = Index(
112
111
  'sqlalchemy_orm_binary_quantize_index',
113
112
  func.cast(func.binary_quantize(Item.embedding), BIT(3)).label('embedding'),
114
113
  postgresql_using='hnsw',
115
- postgresql_with={'m': 16, 'ef_construction': 64},
116
114
  postgresql_ops={'embedding': 'bit_hamming_ops'}
117
115
  )
118
116
  binary_quantize_index.create(setup_engine)
@@ -528,6 +526,22 @@ class TestSqlalchemy:
528
526
  items = session.query(Item).order_by(distance).all()
529
527
  assert [v.id for v in items] == [2, 3, 1]
530
528
 
529
+ def test_binary_quantize_reranking(self, engine):
530
+ # recreate index (could also vacuum table)
531
+ binary_quantize_index.drop(setup_engine)
532
+ binary_quantize_index.create(setup_engine)
533
+
534
+ with Session(engine) as session:
535
+ session.add(Item(id=1, embedding=[-1, -2, -3]))
536
+ session.add(Item(id=2, embedding=[1, -2, 3]))
537
+ session.add(Item(id=3, embedding=[1, 2, 3]))
538
+ session.commit()
539
+
540
+ distance = func.cast(func.binary_quantize(Item.embedding), BIT(3)).hamming_distance(func.binary_quantize(func.cast([3, -1, 2], VECTOR(3))))
541
+ subquery = session.query(Item).order_by(distance).limit(20).subquery()
542
+ items = session.query(subquery).order_by(subquery.c.embedding.cosine_distance([3, -1, 2])).limit(5).all()
543
+ assert [v.id for v in items] == [2, 3, 1]
544
+
531
545
 
532
546
  @pytest.mark.parametrize('engine', array_engines)
533
547
  class TestSqlalchemyArray:
@@ -596,6 +610,11 @@ class TestSqlalchemyAsync:
596
610
  item = await session.get(Item, 1)
597
611
  assert item.binary_embedding == embedding
598
612
 
613
+ if engine == asyncpg_engine:
614
+ session.add(Item(id=2, binary_embedding='101'))
615
+ item = await session.get(Item, 2)
616
+ assert item.binary_embedding == embedding
617
+
599
618
  await engine.dispose()
600
619
 
601
620
  @pytest.mark.asyncio
@@ -1,6 +0,0 @@
1
- from django.contrib.postgres.operations import CreateExtension
2
-
3
-
4
- class VectorExtension(CreateExtension):
5
- def __init__(self):
6
- self.name = 'vector'
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes