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.
- {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/PKG-INFO +4 -3
- {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/pyproject.toml +3 -2
- {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/backend/clients/__init__.py +4 -4
- {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/backend/clients/api.py +1 -0
- {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/backend/clients/milvus/milvus.py +2 -3
- {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/backend/clients/pgvecto_rs/config.py +44 -32
- {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/backend/clients/pgvecto_rs/pgvecto_rs.py +16 -16
- vectordb_bench-0.0.9/vectordb_bench/backend/clients/pgvector/config.py +215 -0
- vectordb_bench-0.0.9/vectordb_bench/backend/clients/pgvector/pgvector.py +347 -0
- vectordb_bench-0.0.9/vectordb_bench/backend/clients/qdrant_cloud/config.py +47 -0
- {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/backend/clients/qdrant_cloud/qdrant_cloud.py +11 -7
- {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/backend/runner/serial_runner.py +0 -2
- {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/frontend/components/run_test/caseSelector.py +6 -3
- {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/frontend/const/dbCaseConfigs.py +128 -3
- {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/models.py +6 -3
- {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/results/PgVector/result_20230727_standard_pgvector.json +8 -0
- {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/results/PgVector/result_20230808_standard_pgvector.json +9 -3
- 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
- {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/results/getLeaderboardData.py +1 -1
- vectordb_bench-0.0.9/vectordb_bench/results/leaderboard.json +1 -0
- {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench.egg-info/PKG-INFO +4 -3
- {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench.egg-info/SOURCES.txt +1 -1
- {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench.egg-info/requires.txt +3 -2
- vectordb-bench-0.0.7/vectordb_bench/backend/clients/pgvector/config.py +0 -61
- vectordb-bench-0.0.7/vectordb_bench/backend/clients/pgvector/pgvector.py +0 -173
- vectordb-bench-0.0.7/vectordb_bench/backend/clients/qdrant_cloud/config.py +0 -34
- vectordb-bench-0.0.7/vectordb_bench/results/leaderboard.json +0 -1
- {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/.devcontainer/Dockerfile +0 -0
- {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/.devcontainer/devcontainer.json +0 -0
- {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/.env.example +0 -0
- {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/.github/workflows/publish_package_on_release.yml +0 -0
- {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/.github/workflows/pull_request.yml +0 -0
- {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/.gitignore +0 -0
- {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/.ruff.toml +0 -0
- {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/Dockerfile +0 -0
- {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/LICENSE +0 -0
- {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/Makefile +0 -0
- {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/OWNERS +0 -0
- {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/README.md +0 -0
- {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/install/requirements_py3.11.txt +0 -0
- {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/install.py +0 -0
- {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/setup.cfg +0 -0
- {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/tests/conftest.py +0 -0
- {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/tests/pytest.ini +0 -0
- {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/tests/test_bench_runner.py +0 -0
- {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/tests/test_chroma.py +0 -0
- {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/tests/test_data_source.py +0 -0
- {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/tests/test_dataset.py +0 -0
- {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/tests/test_elasticsearch_cloud.py +0 -0
- {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/tests/test_models.py +0 -0
- {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/tests/test_redis.py +0 -0
- {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/tests/test_utils.py +0 -0
- {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/tests/ut_cases.py +0 -0
- {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/__init__.py +0 -0
- {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/__main__.py +0 -0
- {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/backend/__init__.py +0 -0
- {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/backend/assembler.py +0 -0
- {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/backend/cases.py +0 -0
- {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/backend/clients/chroma/chroma.py +0 -0
- {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/backend/clients/chroma/config.py +0 -0
- {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/backend/clients/elastic_cloud/config.py +0 -0
- {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/backend/clients/elastic_cloud/elastic_cloud.py +0 -0
- {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/backend/clients/milvus/config.py +0 -0
- {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/backend/clients/pinecone/config.py +0 -0
- {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/backend/clients/pinecone/pinecone.py +0 -0
- {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/backend/clients/redis/config.py +0 -0
- {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/backend/clients/redis/redis.py +0 -0
- {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/backend/clients/weaviate_cloud/config.py +0 -0
- {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/backend/clients/weaviate_cloud/weaviate_cloud.py +0 -0
- {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/backend/clients/zilliz_cloud/config.py +0 -0
- {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/backend/clients/zilliz_cloud/zilliz_cloud.py +0 -0
- {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/backend/data_source.py +0 -0
- {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/backend/dataset.py +0 -0
- {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/backend/result_collector.py +0 -0
- {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/backend/runner/__init__.py +0 -0
- {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/backend/runner/mp_runner.py +0 -0
- {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/backend/task_runner.py +1 -1
- {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/backend/utils.py +0 -0
- {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/base.py +0 -0
- {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/frontend/components/check_results/charts.py +0 -0
- {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/frontend/components/check_results/data.py +0 -0
- {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/frontend/components/check_results/expanderStyle.py +0 -0
- {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/frontend/components/check_results/filters.py +0 -0
- {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/frontend/components/check_results/footer.py +0 -0
- {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/frontend/components/check_results/headerIcon.py +0 -0
- {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/frontend/components/check_results/nav.py +0 -0
- {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/frontend/components/check_results/priceTable.py +0 -0
- {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/frontend/components/check_results/stPageConfig.py +0 -0
- {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/frontend/components/get_results/saveAsImage.py +0 -0
- {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/frontend/components/run_test/autoRefresh.py +0 -0
- {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/frontend/components/run_test/dbConfigSetting.py +0 -0
- {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/frontend/components/run_test/dbSelector.py +0 -0
- {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/frontend/components/run_test/generateTasks.py +0 -0
- {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/frontend/components/run_test/hideSidebar.py +0 -0
- {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/frontend/components/run_test/submitTask.py +0 -0
- {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/frontend/const/dbPrices.py +0 -0
- {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/frontend/const/styles.py +0 -0
- {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/frontend/pages/quries_per_dollar.py +0 -0
- {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/frontend/pages/run_test.py +0 -0
- {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/frontend/utils.py +0 -0
- {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/frontend/vdb_benchmark.py +0 -0
- {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/interface.py +0 -0
- {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/log_util.py +0 -0
- {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/metric.py +0 -0
- {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/results/ElasticCloud/result_20230727_standard_elasticcloud.json +0 -0
- {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/results/ElasticCloud/result_20230808_standard_elasticcloud.json +0 -0
- {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/results/Milvus/result_20230727_standard_milvus.json +0 -0
- {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/results/Milvus/result_20230808_standard_milvus.json +0 -0
- {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/results/Pinecone/result_20230727_standard_pinecone.json +0 -0
- {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/results/Pinecone/result_20230808_standard_pinecone.json +0 -0
- {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/results/QdrantCloud/result_20230727_standard_qdrantcloud.json +0 -0
- {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/results/QdrantCloud/result_20230808_standard_qdrantcloud.json +0 -0
- {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/results/WeaviateCloud/result_20230727_standard_weaviatecloud.json +0 -0
- {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/results/WeaviateCloud/result_20230808_standard_weaviatecloud.json +0 -0
- {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/results/ZillizCloud/result_20230727_standard_zillizcloud.json +0 -0
- {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/results/ZillizCloud/result_20230808_standard_zillizcloud.json +0 -0
- {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/results/dbPrices.json +0 -0
- {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench.egg-info/dependency_links.txt +0 -0
- {vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench.egg-info/entry_points.txt +0 -0
- {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.
|
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
|
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:
|
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
|
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", "
|
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
|
58
|
-
return
|
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
|
146
|
-
return
|
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
|
{vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/backend/clients/milvus/milvus.py
RENAMED
@@ -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)
|
{vectordb-bench-0.0.7 → vectordb_bench-0.0.9}/vectordb_bench/backend/clients/pgvecto_rs/config.py
RENAMED
@@ -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
|
-
|
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 "
|
31
|
+
return "vector_l2_ops"
|
44
32
|
elif self.metric_type == MetricType.IP:
|
45
|
-
return "
|
46
|
-
return "
|
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
|
-
|
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
|
-
|
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(
|
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
|
-
|
83
|
-
[algorithm.ivf]
|
81
|
+
[indexing.ivf]
|
84
82
|
nlist = {self.nlist}
|
85
|
-
|
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(
|
108
|
+
class FLATConfig(PgVectoRSQuantConfig):
|
95
109
|
index: IndexType = IndexType.Flat
|
96
110
|
|
97
111
|
def index_param(self) -> dict:
|
98
112
|
options = f"""
|
99
|
-
|
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
|
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
|
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
|
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 = {
|
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
|
-
|
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
|
+
}
|