vectordb-bench 0.0.7__tar.gz → 0.0.9__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 (120) hide show
  1. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/PKG-INFO +4 -3
  2. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/pyproject.toml +3 -2
  3. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/backend/clients/__init__.py +4 -4
  4. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/backend/clients/api.py +1 -0
  5. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/backend/clients/milvus/milvus.py +2 -3
  6. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/backend/clients/pgvecto_rs/config.py +44 -32
  7. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/backend/clients/pgvecto_rs/pgvecto_rs.py +16 -16
  8. vectordb_bench-0.0.9/vectordb_bench/backend/clients/pgvector/config.py +215 -0
  9. vectordb_bench-0.0.9/vectordb_bench/backend/clients/pgvector/pgvector.py +347 -0
  10. vectordb_bench-0.0.9/vectordb_bench/backend/clients/qdrant_cloud/config.py +47 -0
  11. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/backend/clients/qdrant_cloud/qdrant_cloud.py +11 -7
  12. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/backend/runner/serial_runner.py +0 -2
  13. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/frontend/components/run_test/caseSelector.py +6 -3
  14. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/frontend/const/dbCaseConfigs.py +128 -3
  15. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/models.py +6 -3
  16. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/results/PgVector/result_20230727_standard_pgvector.json +8 -0
  17. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/results/PgVector/result_20230808_standard_pgvector.json +9 -3
  18. vectordb-bench-0.0.7/vectordb_bench/results/ZillizCloud/result_20240105_beta_202401_zillizcloud.json → vectordb_bench-0.0.9/vectordb_bench/results/ZillizCloud/result_20240105_standard_202401_zillizcloud.json +365 -41
  19. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/results/getLeaderboardData.py +1 -1
  20. vectordb_bench-0.0.9/vectordb_bench/results/leaderboard.json +1 -0
  21. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench.egg-info/PKG-INFO +4 -3
  22. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench.egg-info/SOURCES.txt +1 -1
  23. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench.egg-info/requires.txt +3 -2
  24. vectordb-bench-0.0.7/vectordb_bench/backend/clients/pgvector/config.py +0 -61
  25. vectordb-bench-0.0.7/vectordb_bench/backend/clients/pgvector/pgvector.py +0 -173
  26. vectordb-bench-0.0.7/vectordb_bench/backend/clients/qdrant_cloud/config.py +0 -34
  27. vectordb-bench-0.0.7/vectordb_bench/results/leaderboard.json +0 -1
  28. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/.devcontainer/Dockerfile +0 -0
  29. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/.devcontainer/devcontainer.json +0 -0
  30. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/.env.example +0 -0
  31. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/.github/workflows/publish_package_on_release.yml +0 -0
  32. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/.github/workflows/pull_request.yml +0 -0
  33. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/.gitignore +0 -0
  34. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/.ruff.toml +0 -0
  35. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/Dockerfile +0 -0
  36. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/LICENSE +0 -0
  37. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/Makefile +0 -0
  38. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/OWNERS +0 -0
  39. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/README.md +0 -0
  40. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/install/requirements_py3.11.txt +0 -0
  41. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/install.py +0 -0
  42. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/setup.cfg +0 -0
  43. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/tests/conftest.py +0 -0
  44. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/tests/pytest.ini +0 -0
  45. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/tests/test_bench_runner.py +0 -0
  46. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/tests/test_chroma.py +0 -0
  47. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/tests/test_data_source.py +0 -0
  48. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/tests/test_dataset.py +0 -0
  49. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/tests/test_elasticsearch_cloud.py +0 -0
  50. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/tests/test_models.py +0 -0
  51. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/tests/test_redis.py +0 -0
  52. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/tests/test_utils.py +0 -0
  53. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/tests/ut_cases.py +0 -0
  54. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/__init__.py +0 -0
  55. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/__main__.py +0 -0
  56. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/backend/__init__.py +0 -0
  57. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/backend/assembler.py +0 -0
  58. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/backend/cases.py +0 -0
  59. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/backend/clients/chroma/chroma.py +0 -0
  60. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/backend/clients/chroma/config.py +0 -0
  61. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/backend/clients/elastic_cloud/config.py +0 -0
  62. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/backend/clients/elastic_cloud/elastic_cloud.py +0 -0
  63. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/backend/clients/milvus/config.py +0 -0
  64. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/backend/clients/pinecone/config.py +0 -0
  65. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/backend/clients/pinecone/pinecone.py +0 -0
  66. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/backend/clients/redis/config.py +0 -0
  67. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/backend/clients/redis/redis.py +0 -0
  68. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/backend/clients/weaviate_cloud/config.py +0 -0
  69. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/backend/clients/weaviate_cloud/weaviate_cloud.py +0 -0
  70. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/backend/clients/zilliz_cloud/config.py +0 -0
  71. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/backend/clients/zilliz_cloud/zilliz_cloud.py +0 -0
  72. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/backend/data_source.py +0 -0
  73. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/backend/dataset.py +0 -0
  74. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/backend/result_collector.py +0 -0
  75. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/backend/runner/__init__.py +0 -0
  76. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/backend/runner/mp_runner.py +0 -0
  77. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/backend/task_runner.py +1 -1
  78. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/backend/utils.py +0 -0
  79. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/base.py +0 -0
  80. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/frontend/components/check_results/charts.py +0 -0
  81. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/frontend/components/check_results/data.py +0 -0
  82. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/frontend/components/check_results/expanderStyle.py +0 -0
  83. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/frontend/components/check_results/filters.py +0 -0
  84. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/frontend/components/check_results/footer.py +0 -0
  85. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/frontend/components/check_results/headerIcon.py +0 -0
  86. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/frontend/components/check_results/nav.py +0 -0
  87. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/frontend/components/check_results/priceTable.py +0 -0
  88. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/frontend/components/check_results/stPageConfig.py +0 -0
  89. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/frontend/components/get_results/saveAsImage.py +0 -0
  90. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/frontend/components/run_test/autoRefresh.py +0 -0
  91. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/frontend/components/run_test/dbConfigSetting.py +0 -0
  92. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/frontend/components/run_test/dbSelector.py +0 -0
  93. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/frontend/components/run_test/generateTasks.py +0 -0
  94. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/frontend/components/run_test/hideSidebar.py +0 -0
  95. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/frontend/components/run_test/submitTask.py +0 -0
  96. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/frontend/const/dbPrices.py +0 -0
  97. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/frontend/const/styles.py +0 -0
  98. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/frontend/pages/quries_per_dollar.py +0 -0
  99. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/frontend/pages/run_test.py +0 -0
  100. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/frontend/utils.py +0 -0
  101. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/frontend/vdb_benchmark.py +0 -0
  102. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/interface.py +0 -0
  103. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/log_util.py +0 -0
  104. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/metric.py +0 -0
  105. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/results/ElasticCloud/result_20230727_standard_elasticcloud.json +0 -0
  106. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/results/ElasticCloud/result_20230808_standard_elasticcloud.json +0 -0
  107. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/results/Milvus/result_20230727_standard_milvus.json +0 -0
  108. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/results/Milvus/result_20230808_standard_milvus.json +0 -0
  109. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/results/Pinecone/result_20230727_standard_pinecone.json +0 -0
  110. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/results/Pinecone/result_20230808_standard_pinecone.json +0 -0
  111. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/results/QdrantCloud/result_20230727_standard_qdrantcloud.json +0 -0
  112. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/results/QdrantCloud/result_20230808_standard_qdrantcloud.json +0 -0
  113. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/results/WeaviateCloud/result_20230727_standard_weaviatecloud.json +0 -0
  114. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/results/WeaviateCloud/result_20230808_standard_weaviatecloud.json +0 -0
  115. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/results/ZillizCloud/result_20230727_standard_zillizcloud.json +0 -0
  116. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/results/ZillizCloud/result_20230808_standard_zillizcloud.json +0 -0
  117. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/results/dbPrices.json +0 -0
  118. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench.egg-info/dependency_links.txt +0 -0
  119. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench.egg-info/entry_points.txt +0 -0
  120. {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: vectordb-bench
3
- Version: 0.0.7
3
+ Version: 0.0.9
4
4
  Summary: VectorDBBench is not just an offering of benchmark results for mainstream vector databases and cloud services, it's your go-to tool for the ultimate performance and cost-effectiveness comparison. Designed with ease-of-use in mind, VectorDBBench is devised to help users, even non-professionals, reproduce results or test new systems, making the hunt for the optimal choice amongst a plethora of cloud services and open-source vector databases a breeze.
5
5
  Author-email: XuanYang-cn <xuan.yang@zilliz.com>
6
6
  Project-URL: repository, https://github.com/zilliztech/VectorDBBench
@@ -12,7 +12,7 @@ Description-Content-Type: text/markdown
12
12
  License-File: LICENSE
13
13
  Requires-Dist: pytz
14
14
  Requires-Dist: streamlit-autorefresh
15
- Requires-Dist: streamlit>=1.23.0
15
+ Requires-Dist: streamlit!=1.34.0
16
16
  Requires-Dist: streamlit_extras
17
17
  Requires-Dist: tqdm
18
18
  Requires-Dist: s3fs
@@ -39,6 +39,7 @@ Requires-Dist: sqlalchemy; extra == "all"
39
39
  Requires-Dist: redis; extra == "all"
40
40
  Requires-Dist: chromadb; extra == "all"
41
41
  Requires-Dist: psycopg2; extra == "all"
42
+ Requires-Dist: psycopg; extra == "all"
42
43
  Provides-Extra: qdrant
43
44
  Requires-Dist: qdrant-client; extra == "qdrant"
44
45
  Provides-Extra: pinecone
@@ -49,7 +50,7 @@ Provides-Extra: elastic
49
50
  Requires-Dist: elasticsearch; extra == "elastic"
50
51
  Provides-Extra: pgvector
51
52
  Requires-Dist: pgvector; extra == "pgvector"
52
- Requires-Dist: sqlalchemy; extra == "pgvector"
53
+ Requires-Dist: psycopg; extra == "pgvector"
53
54
  Provides-Extra: pgvecto-rs
54
55
  Requires-Dist: psycopg2; extra == "pgvecto-rs"
55
56
  Provides-Extra: redis
@@ -26,7 +26,7 @@ classifiers = [
26
26
  dependencies = [
27
27
  "pytz",
28
28
  "streamlit-autorefresh",
29
- "streamlit>=1.23.0",
29
+ "streamlit!=1.34.0",
30
30
  "streamlit_extras",
31
31
  "tqdm",
32
32
  "s3fs",
@@ -59,13 +59,14 @@ all = [
59
59
  "redis",
60
60
  "chromadb",
61
61
  "psycopg2",
62
+ "psycopg",
62
63
  ]
63
64
 
64
65
  qdrant = [ "qdrant-client" ]
65
66
  pinecone = [ "pinecone-client" ]
66
67
  weaviate = [ "weaviate-client" ]
67
68
  elastic = [ "elasticsearch" ]
68
- pgvector = [ "pgvector", "sqlalchemy" ]
69
+ pgvector = [ "pgvector", "psycopg" ]
69
70
  pgvecto_rs = [ "psycopg2" ]
70
71
  redis = [ "redis" ]
71
72
  chromadb = [ "chromadb" ]
@@ -54,8 +54,8 @@ class DB(Enum):
54
54
  return ElasticCloud
55
55
 
56
56
  if self == DB.QdrantCloud:
57
- from .qdrant_cloud.qdrant_cloud import QdrantClient
58
- return QdrantClient
57
+ from .qdrant_cloud.qdrant_cloud import QdrantCloud
58
+ return QdrantCloud
59
59
 
60
60
  if self == DB.WeaviateCloud:
61
61
  from .weaviate_cloud.weaviate_cloud import WeaviateCloud
@@ -142,8 +142,8 @@ class DB(Enum):
142
142
  return WeaviateIndexConfig
143
143
 
144
144
  if self == DB.PgVector:
145
- from .pgvector.config import PgVectorIndexConfig
146
- return PgVectorIndexConfig
145
+ from .pgvector.config import _pgvector_case_config
146
+ return _pgvector_case_config.get(index_type)
147
147
 
148
148
  if self == DB.PgVectoRS:
149
149
  from .pgvecto_rs.config import _pgvecto_rs_case_config
@@ -20,6 +20,7 @@ class IndexType(str, Enum):
20
20
  Flat = "FLAT"
21
21
  AUTOINDEX = "AUTOINDEX"
22
22
  ES_HNSW = "hnsw"
23
+ ES_IVFFlat = "ivfflat"
23
24
  GPU_IVF_FLAT = "GPU_IVF_FLAT"
24
25
  GPU_IVF_PQ = "GPU_IVF_PQ"
25
26
  GPU_CAGRA = "GPU_CAGRA"
@@ -89,6 +89,7 @@ class Milvus(VectorDB):
89
89
  connections.disconnect("default")
90
90
 
91
91
  def _optimize(self):
92
+ self._post_insert()
92
93
  log.info(f"{self.name} optimizing before search")
93
94
  try:
94
95
  self.col.load()
@@ -116,7 +117,7 @@ class Milvus(VectorDB):
116
117
  time.sleep(5)
117
118
 
118
119
  wait_index()
119
-
120
+
120
121
  # Skip compaction if use GPU indexType
121
122
  if self.case_config.index in [IndexType.GPU_CAGRA, IndexType.GPU_IVF_FLAT, IndexType.GPU_IVF_PQ]:
122
123
  log.debug("skip compaction for gpu index type.")
@@ -179,8 +180,6 @@ class Milvus(VectorDB):
179
180
  ]
180
181
  res = self.col.insert(insert_data)
181
182
  insert_count += len(res.primary_keys)
182
- if kwargs.get("last_batch"):
183
- self._post_insert()
184
183
  except MilvusException as e:
185
184
  log.info(f"Failed to insert data: {e}")
186
185
  return (insert_count, e)
@@ -8,42 +8,30 @@ POSTGRE_URL_PLACEHOLDER = "postgresql://%s:%s@%s/%s"
8
8
  class PgVectoRSConfig(DBConfig):
9
9
  user_name: SecretStr = "postgres"
10
10
  password: SecretStr
11
- url: SecretStr
11
+ host: str = "localhost"
12
+ port: int = 5432
12
13
  db_name: str
13
14
 
14
15
  def to_dict(self) -> dict:
15
16
  user_str = self.user_name.get_secret_value()
16
17
  pwd_str = self.password.get_secret_value()
17
- url_str = self.url.get_secret_value()
18
- host, port = url_str.split(":")
19
18
  return {
20
- "host": host,
21
- "port": port,
19
+ "host": self.host,
20
+ "port": self.port,
22
21
  "dbname": self.db_name,
23
22
  "user": user_str,
24
- "password": pwd_str,
23
+ "password": pwd_str
25
24
  }
26
25
 
27
-
28
26
  class PgVectoRSIndexConfig(BaseModel, DBCaseConfig):
29
27
  metric_type: MetricType | None = None
30
- quantizationType: Literal["trivial", "scalar", "product"]
31
- quantizationRatio: None | Literal["x4", "x8", "x16", "x32", "x64"]
32
-
33
- def parse_quantization(self) -> str:
34
- if self.quantizationType == "trivial":
35
- return "quantization = { trivial = { } }"
36
- elif self.quantizationType == "scalar":
37
- return "quantization = { scalar = { } }"
38
- else:
39
- return f'quantization = {{ product = {{ ratio = "{self.quantizationRatio}" }} }}'
40
28
 
41
29
  def parse_metric(self) -> str:
42
30
  if self.metric_type == MetricType.L2:
43
- return "l2_ops"
31
+ return "vector_l2_ops"
44
32
  elif self.metric_type == MetricType.IP:
45
- return "dot_ops"
46
- return "cosine_ops"
33
+ return "vector_dot_ops"
34
+ return "vector_cos_ops"
47
35
 
48
36
  def parse_metric_fun_op(self) -> str:
49
37
  if self.metric_type == MetricType.L2:
@@ -52,16 +40,27 @@ class PgVectoRSIndexConfig(BaseModel, DBCaseConfig):
52
40
  return "<#>"
53
41
  return "<=>"
54
42
 
43
+ class PgVectoRSQuantConfig(PgVectoRSIndexConfig):
44
+ quantizationType: Literal["trivial", "scalar", "product"]
45
+ quantizationRatio: None | Literal["x4", "x8", "x16", "x32", "x64"]
55
46
 
56
- class HNSWConfig(PgVectoRSIndexConfig):
47
+ def parse_quantization(self) -> str:
48
+ if self.quantizationType == "trivial":
49
+ return "quantization = { trivial = { } }"
50
+ elif self.quantizationType == "scalar":
51
+ return "quantization = { scalar = { } }"
52
+ else:
53
+ return f'quantization = {{ product = {{ ratio = "{self.quantizationRatio}" }} }}'
54
+
55
+
56
+ class HNSWConfig(PgVectoRSQuantConfig):
57
57
  M: int
58
58
  efConstruction: int
59
59
  index: IndexType = IndexType.HNSW
60
60
 
61
61
  def index_param(self) -> dict:
62
62
  options = f"""
63
- capacity = 1048576
64
- [algorithm.hnsw]
63
+ [indexing.hnsw]
65
64
  m = {self.M}
66
65
  ef_construction = {self.efConstruction}
67
66
  {self.parse_quantization()}
@@ -72,17 +71,16 @@ ef_construction = {self.efConstruction}
72
71
  return {"metrics_op": self.parse_metric_fun_op()}
73
72
 
74
73
 
75
- class IVFFlatConfig(PgVectoRSIndexConfig):
74
+ class IVFFlatConfig(PgVectoRSQuantConfig):
76
75
  nlist: int
77
76
  nprobe: int | None = None
78
77
  index: IndexType = IndexType.IVFFlat
79
78
 
80
79
  def index_param(self) -> dict:
81
80
  options = f"""
82
- capacity = 1048576
83
- [algorithm.ivf]
81
+ [indexing.ivf]
84
82
  nlist = {self.nlist}
85
- nprob = {self.nprobe if self.nprobe else 10}
83
+ nsample = {self.nprobe if self.nprobe else 10}
86
84
  {self.parse_quantization()}
87
85
  """
88
86
  return {"options": options, "metric": self.parse_metric()}
@@ -90,14 +88,29 @@ nprob = {self.nprobe if self.nprobe else 10}
90
88
  def search_param(self) -> dict:
91
89
  return {"metrics_op": self.parse_metric_fun_op()}
92
90
 
91
+ class IVFFlatSQ8Config(PgVectoRSIndexConfig):
92
+ nlist: int
93
+ nprobe: int | None = None
94
+ index: IndexType = IndexType.IVFSQ8
95
+
96
+ def index_param(self) -> dict:
97
+ options = f"""
98
+ [indexing.ivf]
99
+ nlist = {self.nlist}
100
+ nsample = {self.nprobe if self.nprobe else 10}
101
+ quantization = {{ scalar = {{ }} }}
102
+ """
103
+ return {"options": options, "metric": self.parse_metric()}
104
+
105
+ def search_param(self) -> dict:
106
+ return {"metrics_op": self.parse_metric_fun_op()}
93
107
 
94
- class FLATConfig(PgVectoRSIndexConfig):
108
+ class FLATConfig(PgVectoRSQuantConfig):
95
109
  index: IndexType = IndexType.Flat
96
110
 
97
111
  def index_param(self) -> dict:
98
112
  options = f"""
99
- capacity = 1048576
100
- [algorithm.flat]
113
+ [indexing.flat]
101
114
  {self.parse_quantization()}
102
115
  """
103
116
  return {"options": options, "metric": self.parse_metric()}
@@ -107,9 +120,8 @@ capacity = 1048576
107
120
 
108
121
 
109
122
  _pgvecto_rs_case_config = {
110
- IndexType.AUTOINDEX: HNSWConfig,
111
123
  IndexType.HNSW: HNSWConfig,
112
- IndexType.DISKANN: HNSWConfig,
113
124
  IndexType.IVFFlat: IVFFlatConfig,
125
+ IndexType.IVFSQ8: IVFFlatSQ8Config,
114
126
  IndexType.Flat: FLATConfig,
115
127
  }
@@ -1,18 +1,17 @@
1
- """Wrapper around the Pgvector vector database over VectorDB"""
1
+ """Wrapper around the Pgvecto.rs vector database over VectorDB"""
2
2
 
3
3
  import io
4
4
  import logging
5
5
  from contextlib import contextmanager
6
6
  from typing import Any
7
7
  import pandas as pd
8
-
9
8
  import psycopg2
9
+ import psycopg2.extras
10
10
 
11
11
  from ..api import VectorDB, DBCaseConfig
12
12
 
13
13
  log = logging.getLogger(__name__)
14
14
 
15
-
16
15
  class PgVectoRS(VectorDB):
17
16
  """Use SQLAlchemy instructions"""
18
17
 
@@ -66,6 +65,8 @@ class PgVectoRS(VectorDB):
66
65
  self.conn = psycopg2.connect(**self.db_config)
67
66
  self.conn.autocommit = False
68
67
  self.cursor = self.conn.cursor()
68
+ self.cursor.execute('SET search_path = "$user", public, vectors')
69
+ self.conn.commit()
69
70
 
70
71
  try:
71
72
  yield
@@ -113,7 +114,7 @@ class PgVectoRS(VectorDB):
113
114
  self.conn.commit()
114
115
  except Exception as e:
115
116
  log.warning(
116
- f"Failed to create pgvector table: {self.table_name} error: {e}"
117
+ f"Failed to create pgvecto.rs table: {self.table_name} error: {e}"
117
118
  )
118
119
  raise e from None
119
120
 
@@ -127,13 +128,10 @@ class PgVectoRS(VectorDB):
127
128
  f'CREATE TABLE IF NOT EXISTS public."{self.table_name}" \
128
129
  (id Integer PRIMARY KEY, embedding vector({dim}));'
129
130
  )
130
- self.cursor.execute(
131
- f'ALTER TABLE public."{self.table_name}" ALTER COLUMN embedding SET STORAGE PLAIN;'
132
- )
133
131
  self.conn.commit()
134
132
  except Exception as e:
135
133
  log.warning(
136
- f"Failed to create pgvector table: {self.table_name} error: {e}"
134
+ f"Failed to create pgvecto.rs table: {self.table_name} error: {e}"
137
135
  )
138
136
  raise e from None
139
137
 
@@ -146,22 +144,24 @@ class PgVectoRS(VectorDB):
146
144
  assert self.conn is not None, "Connection is not initialized"
147
145
  assert self.cursor is not None, "Cursor is not initialized"
148
146
 
147
+ assert self.conn is not None, "Connection is not initialized"
148
+ assert self.cursor is not None, "Cursor is not initialized"
149
+
149
150
  try:
150
- items = {"id": metadata, "embedding": embeddings}
151
+ items = {
152
+ "id": metadata,
153
+ "embedding": embeddings
154
+ }
151
155
  df = pd.DataFrame(items)
152
156
  csv_buffer = io.StringIO()
153
157
  df.to_csv(csv_buffer, index=False, header=False)
154
158
  csv_buffer.seek(0)
155
- self.cursor.copy_expert(
156
- f'COPY public."{self.table_name}" FROM STDIN WITH (FORMAT CSV)',
157
- csv_buffer,
158
- )
159
+ self.cursor.copy_expert(f"COPY public.\"{self.table_name}\" FROM STDIN WITH (FORMAT CSV)", csv_buffer)
159
160
  self.conn.commit()
160
161
  return len(metadata), None
161
162
  except Exception as e:
162
- log.warning(
163
- f"Failed to insert data into pgvector table ({self.table_name}), error: {e}"
164
- )
163
+ log.warning(f"Failed to insert data into pgvecto.rs table ({self.table_name}), error: {e}")
164
+ return 0, e
165
165
 
166
166
  def search_embedding(
167
167
  self,
@@ -0,0 +1,215 @@
1
+ from abc import abstractmethod
2
+ from typing import Any, Mapping, Optional, Sequence, TypedDict
3
+ from pydantic import BaseModel, SecretStr
4
+ from typing_extensions import LiteralString
5
+ from ..api import DBCaseConfig, DBConfig, IndexType, MetricType
6
+
7
+ POSTGRE_URL_PLACEHOLDER = "postgresql://%s:%s@%s/%s"
8
+
9
+
10
+ class PgVectorConfigDict(TypedDict):
11
+ """These keys will be directly used as kwargs in psycopg connection string,
12
+ so the names must match exactly psycopg API"""
13
+
14
+ user: str
15
+ password: str
16
+ host: str
17
+ port: int
18
+ dbname: str
19
+
20
+
21
+ class PgVectorConfig(DBConfig):
22
+ user_name: SecretStr = SecretStr("postgres")
23
+ password: SecretStr
24
+ host: str = "localhost"
25
+ port: int = 5432
26
+ db_name: str
27
+
28
+ def to_dict(self) -> PgVectorConfigDict:
29
+ user_str = self.user_name.get_secret_value()
30
+ pwd_str = self.password.get_secret_value()
31
+ return {
32
+ "host": self.host,
33
+ "port": self.port,
34
+ "dbname": self.db_name,
35
+ "user": user_str,
36
+ "password": pwd_str,
37
+ }
38
+
39
+
40
+ class PgVectorIndexParam(TypedDict):
41
+ metric: str
42
+ index_type: str
43
+ index_creation_with_options: Sequence[dict[str, Any]]
44
+ maintenance_work_mem: Optional[str]
45
+ max_parallel_workers: Optional[int]
46
+
47
+
48
+ class PgVectorSearchParam(TypedDict):
49
+ metric_fun_op: LiteralString
50
+
51
+
52
+ class PgVectorSessionCommands(TypedDict):
53
+ session_options: Sequence[dict[str, Any]]
54
+
55
+
56
+ class PgVectorIndexConfig(BaseModel, DBCaseConfig):
57
+ metric_type: MetricType | None = None
58
+ create_index_before_load: bool = False
59
+ create_index_after_load: bool = True
60
+
61
+ def parse_metric(self) -> str:
62
+ if self.metric_type == MetricType.L2:
63
+ return "vector_l2_ops"
64
+ elif self.metric_type == MetricType.IP:
65
+ return "vector_ip_ops"
66
+ return "vector_cosine_ops"
67
+
68
+ def parse_metric_fun_op(self) -> LiteralString:
69
+ if self.metric_type == MetricType.L2:
70
+ return "<->"
71
+ elif self.metric_type == MetricType.IP:
72
+ return "<#>"
73
+ return "<=>"
74
+
75
+ def parse_metric_fun_str(self) -> str:
76
+ if self.metric_type == MetricType.L2:
77
+ return "l2_distance"
78
+ elif self.metric_type == MetricType.IP:
79
+ return "max_inner_product"
80
+ return "cosine_distance"
81
+
82
+ @abstractmethod
83
+ def index_param(self) -> PgVectorIndexParam:
84
+ ...
85
+
86
+ @abstractmethod
87
+ def search_param(self) -> PgVectorSearchParam:
88
+ ...
89
+
90
+ @abstractmethod
91
+ def session_param(self) -> PgVectorSessionCommands:
92
+ ...
93
+
94
+ @staticmethod
95
+ def _optionally_build_with_options(with_options: Mapping[str, Any]) -> Sequence[dict[str, Any]]:
96
+ """Walk through mappings, creating a List of {key1 = value} pairs. That will be used to build a where clause"""
97
+ options = []
98
+ for option_name, value in with_options.items():
99
+ if value is not None:
100
+ options.append(
101
+ {
102
+ "option_name": option_name,
103
+ "val": str(value),
104
+ }
105
+ )
106
+ return options
107
+
108
+ @staticmethod
109
+ def _optionally_build_set_options(
110
+ set_mapping: Mapping[str, Any]
111
+ ) -> Sequence[dict[str, Any]]:
112
+ """Walk through options, creating 'SET 'key1 = "value1";' commands"""
113
+ session_options = []
114
+ for setting_name, value in set_mapping.items():
115
+ if value:
116
+ session_options.append(
117
+ {"parameter": {
118
+ "setting_name": setting_name,
119
+ "val": str(value),
120
+ },
121
+ }
122
+ )
123
+ return session_options
124
+
125
+
126
+ class PgVectorIVFFlatConfig(PgVectorIndexConfig):
127
+ """
128
+ An IVFFlat index divides vectors into lists, and then searches a subset of those lists that are
129
+ closest to the query vector. It has faster build times and uses less memory than HNSW,
130
+ but has lower query performance (in terms of speed-recall tradeoff).
131
+
132
+ Three keys to achieving good recall are:
133
+
134
+ Create the index after the table has some data
135
+ Choose an appropriate number of lists - a good place to start is rows / 1000 for up to 1M rows and sqrt(rows) for
136
+ over 1M rows.
137
+ When querying, specify an appropriate number of probes (higher is better for recall, lower is better for speed) -
138
+ a good place to start is sqrt(lists)
139
+ """
140
+
141
+ lists: int | None
142
+ probes: int | None
143
+ index: IndexType = IndexType.ES_IVFFlat
144
+ maintenance_work_mem: Optional[str] = None
145
+ max_parallel_workers: Optional[int] = None
146
+
147
+ def index_param(self) -> PgVectorIndexParam:
148
+ index_parameters = {"lists": self.lists}
149
+ return {
150
+ "metric": self.parse_metric(),
151
+ "index_type": self.index.value,
152
+ "index_creation_with_options": self._optionally_build_with_options(
153
+ index_parameters
154
+ ),
155
+ "maintenance_work_mem": self.maintenance_work_mem,
156
+ "max_parallel_workers": self.max_parallel_workers,
157
+ }
158
+
159
+ def search_param(self) -> PgVectorSearchParam:
160
+ return {
161
+ "metric_fun_op": self.parse_metric_fun_op(),
162
+ }
163
+
164
+ def session_param(self) -> PgVectorSessionCommands:
165
+ session_parameters = {"ivfflat.probes": self.probes}
166
+ return {
167
+ "session_options": self._optionally_build_set_options(session_parameters)
168
+ }
169
+
170
+
171
+ class PgVectorHNSWConfig(PgVectorIndexConfig):
172
+ """
173
+ An HNSW index creates a multilayer graph. It has better query performance than IVFFlat (in terms of
174
+ speed-recall tradeoff), but has slower build times and uses more memory. Also, an index can be
175
+ created without any data in the table since there isn't a training step like IVFFlat.
176
+ """
177
+
178
+ m: int | None # DETAIL: Valid values are between "2" and "100".
179
+ ef_construction: (
180
+ int | None
181
+ ) # ef_construction must be greater than or equal to 2 * m
182
+ ef_search: int | None
183
+ index: IndexType = IndexType.ES_HNSW
184
+ maintenance_work_mem: Optional[str] = None
185
+ max_parallel_workers: Optional[int] = None
186
+
187
+ def index_param(self) -> PgVectorIndexParam:
188
+ index_parameters = {"m": self.m, "ef_construction": self.ef_construction}
189
+ return {
190
+ "metric": self.parse_metric(),
191
+ "index_type": self.index.value,
192
+ "index_creation_with_options": self._optionally_build_with_options(
193
+ index_parameters
194
+ ),
195
+ "maintenance_work_mem": self.maintenance_work_mem,
196
+ "max_parallel_workers": self.max_parallel_workers,
197
+ }
198
+
199
+ def search_param(self) -> PgVectorSearchParam:
200
+ return {
201
+ "metric_fun_op": self.parse_metric_fun_op(),
202
+ }
203
+
204
+ def session_param(self) -> PgVectorSessionCommands:
205
+ session_parameters = {"hnsw.ef_search": self.ef_search}
206
+ return {
207
+ "session_options": self._optionally_build_set_options(session_parameters)
208
+ }
209
+
210
+
211
+ _pgvector_case_config = {
212
+ IndexType.HNSW: PgVectorHNSWConfig,
213
+ IndexType.ES_HNSW: PgVectorHNSWConfig,
214
+ IndexType.IVFFlat: PgVectorIVFFlatConfig,
215
+ }