vectordb-bench 0.0.28__py3-none-any.whl → 0.0.30__py3-none-any.whl
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/__init__.py +3 -1
- vectordb_bench/backend/clients/__init__.py +16 -0
- vectordb_bench/backend/clients/aws_opensearch/aws_opensearch.py +180 -15
- vectordb_bench/backend/clients/aws_opensearch/cli.py +51 -21
- vectordb_bench/backend/clients/aws_opensearch/config.py +37 -14
- vectordb_bench/backend/clients/clickhouse/cli.py +1 -0
- vectordb_bench/backend/clients/clickhouse/clickhouse.py +3 -3
- vectordb_bench/backend/clients/clickhouse/config.py +2 -2
- vectordb_bench/backend/clients/lancedb/cli.py +62 -8
- vectordb_bench/backend/clients/lancedb/config.py +14 -1
- vectordb_bench/backend/clients/lancedb/lancedb.py +21 -3
- vectordb_bench/backend/clients/memorydb/memorydb.py +2 -2
- vectordb_bench/backend/clients/milvus/cli.py +30 -9
- vectordb_bench/backend/clients/milvus/config.py +2 -0
- vectordb_bench/backend/clients/milvus/milvus.py +7 -1
- vectordb_bench/backend/clients/qdrant_cloud/cli.py +43 -0
- vectordb_bench/backend/clients/qdrant_cloud/config.py +4 -4
- vectordb_bench/backend/clients/qdrant_local/cli.py +60 -0
- vectordb_bench/backend/clients/qdrant_local/config.py +47 -0
- vectordb_bench/backend/clients/qdrant_local/qdrant_local.py +232 -0
- vectordb_bench/backend/clients/weaviate_cloud/cli.py +29 -3
- vectordb_bench/backend/clients/weaviate_cloud/config.py +2 -0
- vectordb_bench/backend/clients/weaviate_cloud/weaviate_cloud.py +5 -0
- vectordb_bench/backend/runner/mp_runner.py +16 -5
- vectordb_bench/backend/task_runner.py +1 -0
- vectordb_bench/cli/batch_cli.py +121 -0
- vectordb_bench/cli/cli.py +13 -2
- vectordb_bench/cli/vectordbbench.py +6 -0
- vectordb_bench/config-files/batch_sample_config.yml +17 -0
- vectordb_bench/frontend/components/run_test/dbConfigSetting.py +10 -4
- vectordb_bench/frontend/config/dbCaseConfigs.py +113 -1
- vectordb_bench/models.py +13 -0
- {vectordb_bench-0.0.28.dist-info → vectordb_bench-0.0.30.dist-info}/METADATA +56 -5
- {vectordb_bench-0.0.28.dist-info → vectordb_bench-0.0.30.dist-info}/RECORD +38 -32
- {vectordb_bench-0.0.28.dist-info → vectordb_bench-0.0.30.dist-info}/WHEEL +1 -1
- {vectordb_bench-0.0.28.dist-info → vectordb_bench-0.0.30.dist-info}/entry_points.txt +0 -0
- {vectordb_bench-0.0.28.dist-info → vectordb_bench-0.0.30.dist-info}/licenses/LICENSE +0 -0
- {vectordb_bench-0.0.28.dist-info → vectordb_bench-0.0.30.dist-info}/top_level.txt +0 -0
@@ -58,10 +58,46 @@ def LanceDBAutoIndex(**parameters: Unpack[LanceDBTypedDict]):
|
|
58
58
|
)
|
59
59
|
|
60
60
|
|
61
|
+
class LanceDBIVFPQTypedDict(CommonTypedDict, LanceDBTypedDict):
|
62
|
+
num_partitions: Annotated[
|
63
|
+
int,
|
64
|
+
click.option(
|
65
|
+
"--num-partitions",
|
66
|
+
type=int,
|
67
|
+
default=0,
|
68
|
+
help="Number of partitions for IVFPQ index, unset = use LanceDB default",
|
69
|
+
),
|
70
|
+
]
|
71
|
+
num_sub_vectors: Annotated[
|
72
|
+
int,
|
73
|
+
click.option(
|
74
|
+
"--num-sub-vectors",
|
75
|
+
type=int,
|
76
|
+
default=0,
|
77
|
+
help="Number of sub-vectors for IVFPQ index, unset = use LanceDB default",
|
78
|
+
),
|
79
|
+
]
|
80
|
+
nbits: Annotated[
|
81
|
+
int,
|
82
|
+
click.option(
|
83
|
+
"--nbits",
|
84
|
+
type=int,
|
85
|
+
default=8,
|
86
|
+
help="Number of bits for IVFPQ index (must be 4 or 8), unset = use LanceDB default",
|
87
|
+
),
|
88
|
+
]
|
89
|
+
nprobes: Annotated[
|
90
|
+
int,
|
91
|
+
click.option(
|
92
|
+
"--nprobes", type=int, default=0, help="Number of probes for IVFPQ search, unset = use LanceDB default"
|
93
|
+
),
|
94
|
+
]
|
95
|
+
|
96
|
+
|
61
97
|
@cli.command()
|
62
|
-
@click_parameter_decorators_from_typed_dict(
|
63
|
-
def LanceDBIVFPQ(**parameters: Unpack[
|
64
|
-
from .config import LanceDBConfig,
|
98
|
+
@click_parameter_decorators_from_typed_dict(LanceDBIVFPQTypedDict)
|
99
|
+
def LanceDBIVFPQ(**parameters: Unpack[LanceDBIVFPQTypedDict]):
|
100
|
+
from .config import LanceDBConfig, LanceDBIndexConfig
|
65
101
|
|
66
102
|
run(
|
67
103
|
db=DB.LanceDB,
|
@@ -70,15 +106,29 @@ def LanceDBIVFPQ(**parameters: Unpack[LanceDBTypedDict]):
|
|
70
106
|
uri=parameters["uri"],
|
71
107
|
token=SecretStr(parameters["token"]) if parameters.get("token") else None,
|
72
108
|
),
|
73
|
-
db_case_config=
|
109
|
+
db_case_config=LanceDBIndexConfig(
|
110
|
+
index=IndexType.IVFPQ,
|
111
|
+
num_partitions=parameters["num_partitions"],
|
112
|
+
num_sub_vectors=parameters["num_sub_vectors"],
|
113
|
+
nbits=parameters["nbits"],
|
114
|
+
nprobes=parameters["nprobes"],
|
115
|
+
),
|
74
116
|
**parameters,
|
75
117
|
)
|
76
118
|
|
77
119
|
|
120
|
+
class LanceDBHNSWTypedDict(CommonTypedDict, LanceDBTypedDict):
|
121
|
+
m: Annotated[int, click.option("--m", type=int, default=0, help="HNSW parameter m")]
|
122
|
+
ef_construction: Annotated[
|
123
|
+
int, click.option("--ef-construction", type=int, default=0, help="HNSW parameter ef_construction")
|
124
|
+
]
|
125
|
+
ef: Annotated[int, click.option("--ef", type=int, default=0, help="HNSW search parameter ef")]
|
126
|
+
|
127
|
+
|
78
128
|
@cli.command()
|
79
|
-
@click_parameter_decorators_from_typed_dict(
|
80
|
-
def LanceDBHNSW(**parameters: Unpack[
|
81
|
-
from .config import LanceDBConfig,
|
129
|
+
@click_parameter_decorators_from_typed_dict(LanceDBHNSWTypedDict)
|
130
|
+
def LanceDBHNSW(**parameters: Unpack[LanceDBHNSWTypedDict]):
|
131
|
+
from .config import LanceDBConfig, LanceDBHNSWIndexConfig
|
82
132
|
|
83
133
|
run(
|
84
134
|
db=DB.LanceDB,
|
@@ -87,6 +137,10 @@ def LanceDBHNSW(**parameters: Unpack[LanceDBTypedDict]):
|
|
87
137
|
uri=parameters["uri"],
|
88
138
|
token=SecretStr(parameters["token"]) if parameters.get("token") else None,
|
89
139
|
),
|
90
|
-
db_case_config=
|
140
|
+
db_case_config=LanceDBHNSWIndexConfig(
|
141
|
+
m=parameters["m"],
|
142
|
+
ef_construction=parameters["ef_construction"],
|
143
|
+
ef=parameters["ef"],
|
144
|
+
),
|
91
145
|
**parameters,
|
92
146
|
)
|
@@ -25,6 +25,7 @@ class LanceDBIndexConfig(BaseModel, DBCaseConfig):
|
|
25
25
|
nbits: int = 8 # Must be 4 or 8
|
26
26
|
sample_rate: int = 256
|
27
27
|
max_iterations: int = 50
|
28
|
+
nprobes: int = 0
|
28
29
|
|
29
30
|
def index_param(self) -> dict:
|
30
31
|
if self.index not in [
|
@@ -52,7 +53,11 @@ class LanceDBIndexConfig(BaseModel, DBCaseConfig):
|
|
52
53
|
return params
|
53
54
|
|
54
55
|
def search_param(self) -> dict:
|
55
|
-
|
56
|
+
params = {}
|
57
|
+
if self.nprobes > 0:
|
58
|
+
params["nprobes"] = self.nprobes
|
59
|
+
|
60
|
+
return params
|
56
61
|
|
57
62
|
def parse_metric(self) -> str:
|
58
63
|
if self.metric_type in [MetricType.L2, MetricType.COSINE]:
|
@@ -81,6 +86,7 @@ class LanceDBHNSWIndexConfig(LanceDBIndexConfig):
|
|
81
86
|
index: IndexType = IndexType.HNSW
|
82
87
|
m: int = 0
|
83
88
|
ef_construction: int = 0
|
89
|
+
ef: int = 0
|
84
90
|
|
85
91
|
def index_param(self) -> dict:
|
86
92
|
params = LanceDBIndexConfig.index_param(self)
|
@@ -94,6 +100,13 @@ class LanceDBHNSWIndexConfig(LanceDBIndexConfig):
|
|
94
100
|
|
95
101
|
return params
|
96
102
|
|
103
|
+
def search_param(self) -> dict:
|
104
|
+
params = {}
|
105
|
+
if self.ef != 0:
|
106
|
+
params = {"ef": self.ef}
|
107
|
+
|
108
|
+
return params
|
109
|
+
|
97
110
|
|
98
111
|
_lancedb_case_config = {
|
99
112
|
IndexType.IVFPQ: LanceDBIndexConfig,
|
@@ -32,6 +32,10 @@ class LanceDB(VectorDB):
|
|
32
32
|
self.table_name = collection_name
|
33
33
|
self.dim = dim
|
34
34
|
self.uri = db_config["uri"]
|
35
|
+
# avoid the search_param being called every time during the search process
|
36
|
+
self.search_config = db_case_config.search_param()
|
37
|
+
|
38
|
+
log.info(f"Search config: {self.search_config}")
|
35
39
|
|
36
40
|
db = lancedb.connect(self.uri)
|
37
41
|
|
@@ -45,7 +49,7 @@ class LanceDB(VectorDB):
|
|
45
49
|
db.open_table(self.table_name)
|
46
50
|
except Exception:
|
47
51
|
schema = pa.schema(
|
48
|
-
[pa.field("id", pa.int64()), pa.field("vector", pa.list_(pa.
|
52
|
+
[pa.field("id", pa.int64()), pa.field("vector", pa.list_(pa.float32(), list_size=self.dim))]
|
49
53
|
)
|
50
54
|
db.create_table(self.table_name, schema=schema, mode="overwrite")
|
51
55
|
|
@@ -77,14 +81,28 @@ class LanceDB(VectorDB):
|
|
77
81
|
filters: dict | None = None,
|
78
82
|
) -> list[int]:
|
79
83
|
if filters:
|
80
|
-
results = self.table.search(query).where(f"id >= {filters['id']}", prefilter=True).limit(k)
|
84
|
+
results = self.table.search(query).select(["id"]).where(f"id >= {filters['id']}", prefilter=True).limit(k)
|
85
|
+
if self.case_config.index == IndexType.IVFPQ and "nprobes" in self.search_config:
|
86
|
+
results = results.nprobes(self.search_config["nprobes"]).to_list()
|
87
|
+
elif self.case_config.index == IndexType.HNSW and "ef" in self.search_config:
|
88
|
+
results = results.ef(self.search_config["ef"]).to_list()
|
89
|
+
else:
|
90
|
+
results = results.to_list()
|
81
91
|
else:
|
82
|
-
results = self.table.search(query).
|
92
|
+
results = self.table.search(query).select(["id"]).limit(k)
|
93
|
+
if self.case_config.index == IndexType.IVFPQ and "nprobes" in self.search_config:
|
94
|
+
results = results.nprobes(self.search_config["nprobes"]).to_list()
|
95
|
+
elif self.case_config.index == IndexType.HNSW and "ef" in self.search_config:
|
96
|
+
results = results.ef(self.search_config["ef"]).to_list()
|
97
|
+
else:
|
98
|
+
results = results.to_list()
|
99
|
+
|
83
100
|
return [int(result["id"]) for result in results]
|
84
101
|
|
85
102
|
def optimize(self, data_size: int | None = None):
|
86
103
|
if self.table and hasattr(self, "case_config") and self.case_config.index != IndexType.NONE:
|
87
104
|
log.info(f"Creating index for LanceDB table ({self.table_name})")
|
105
|
+
log.info(f"Index parameters: {self.case_config.index_param()}")
|
88
106
|
self.table.create_index(**self.case_config.index_param())
|
89
107
|
# Better recall with IVF_PQ (though still bad) but breaks HNSW: https://github.com/lancedb/lancedb/issues/2369
|
90
108
|
if self.case_config.index in (IndexType.IVFPQ, IndexType.AUTOINDEX):
|
@@ -9,10 +9,10 @@ import redis
|
|
9
9
|
from redis import Redis
|
10
10
|
from redis.cluster import RedisCluster
|
11
11
|
from redis.commands.search.field import NumericField, TagField, VectorField
|
12
|
-
from redis.commands.search.indexDefinition import IndexDefinition
|
12
|
+
from redis.commands.search.indexDefinition import IndexDefinition, IndexType
|
13
13
|
from redis.commands.search.query import Query
|
14
14
|
|
15
|
-
from ..api import
|
15
|
+
from ..api import VectorDB
|
16
16
|
from .config import MemoryDBIndexConfig
|
17
17
|
|
18
18
|
log = logging.getLogger(__name__)
|
@@ -29,6 +29,17 @@ class MilvusTypedDict(TypedDict):
|
|
29
29
|
str | None,
|
30
30
|
click.option("--password", type=str, help="Db password", required=False),
|
31
31
|
]
|
32
|
+
num_shards: Annotated[
|
33
|
+
int,
|
34
|
+
click.option(
|
35
|
+
"--num-shards",
|
36
|
+
type=int,
|
37
|
+
help="Number of shards",
|
38
|
+
required=False,
|
39
|
+
default=1,
|
40
|
+
show_default=True,
|
41
|
+
),
|
42
|
+
]
|
32
43
|
|
33
44
|
|
34
45
|
class MilvusAutoIndexTypedDict(CommonTypedDict, MilvusTypedDict): ...
|
@@ -45,7 +56,8 @@ def MilvusAutoIndex(**parameters: Unpack[MilvusAutoIndexTypedDict]):
|
|
45
56
|
db_label=parameters["db_label"],
|
46
57
|
uri=SecretStr(parameters["uri"]),
|
47
58
|
user=parameters["user_name"],
|
48
|
-
password=SecretStr(parameters["password"]),
|
59
|
+
password=SecretStr(parameters["password"]) if parameters["password"] else None,
|
60
|
+
num_shards=int(parameters["num_shards"]),
|
49
61
|
),
|
50
62
|
db_case_config=AutoIndexConfig(),
|
51
63
|
**parameters,
|
@@ -63,7 +75,8 @@ def MilvusFlat(**parameters: Unpack[MilvusAutoIndexTypedDict]):
|
|
63
75
|
db_label=parameters["db_label"],
|
64
76
|
uri=SecretStr(parameters["uri"]),
|
65
77
|
user=parameters["user_name"],
|
66
|
-
password=SecretStr(parameters["password"]),
|
78
|
+
password=SecretStr(parameters["password"]) if parameters["password"] else None,
|
79
|
+
num_shards=int(parameters["num_shards"]),
|
67
80
|
),
|
68
81
|
db_case_config=FLATConfig(),
|
69
82
|
**parameters,
|
@@ -85,6 +98,7 @@ def MilvusHNSW(**parameters: Unpack[MilvusHNSWTypedDict]):
|
|
85
98
|
uri=SecretStr(parameters["uri"]),
|
86
99
|
user=parameters["user_name"],
|
87
100
|
password=SecretStr(parameters["password"]) if parameters["password"] else None,
|
101
|
+
num_shards=int(parameters["num_shards"]),
|
88
102
|
),
|
89
103
|
db_case_config=HNSWConfig(
|
90
104
|
M=parameters["m"],
|
@@ -109,7 +123,8 @@ def MilvusIVFFlat(**parameters: Unpack[MilvusIVFFlatTypedDict]):
|
|
109
123
|
db_label=parameters["db_label"],
|
110
124
|
uri=SecretStr(parameters["uri"]),
|
111
125
|
user=parameters["user_name"],
|
112
|
-
password=SecretStr(parameters["password"]),
|
126
|
+
password=SecretStr(parameters["password"]) if parameters["password"] else None,
|
127
|
+
num_shards=int(parameters["num_shards"]),
|
113
128
|
),
|
114
129
|
db_case_config=IVFFlatConfig(
|
115
130
|
nlist=parameters["nlist"],
|
@@ -130,7 +145,8 @@ def MilvusIVFSQ8(**parameters: Unpack[MilvusIVFFlatTypedDict]):
|
|
130
145
|
db_label=parameters["db_label"],
|
131
146
|
uri=SecretStr(parameters["uri"]),
|
132
147
|
user=parameters["user_name"],
|
133
|
-
password=SecretStr(parameters["password"]),
|
148
|
+
password=SecretStr(parameters["password"]) if parameters["password"] else None,
|
149
|
+
num_shards=int(parameters["num_shards"]),
|
134
150
|
),
|
135
151
|
db_case_config=IVFSQ8Config(
|
136
152
|
nlist=parameters["nlist"],
|
@@ -155,7 +171,8 @@ def MilvusDISKANN(**parameters: Unpack[MilvusDISKANNTypedDict]):
|
|
155
171
|
db_label=parameters["db_label"],
|
156
172
|
uri=SecretStr(parameters["uri"]),
|
157
173
|
user=parameters["user_name"],
|
158
|
-
password=SecretStr(parameters["password"]),
|
174
|
+
password=SecretStr(parameters["password"]) if parameters["password"] else None,
|
175
|
+
num_shards=int(parameters["num_shards"]),
|
159
176
|
),
|
160
177
|
db_case_config=DISKANNConfig(
|
161
178
|
search_list=parameters["search_list"],
|
@@ -183,7 +200,8 @@ def MilvusGPUIVFFlat(**parameters: Unpack[MilvusGPUIVFTypedDict]):
|
|
183
200
|
db_label=parameters["db_label"],
|
184
201
|
uri=SecretStr(parameters["uri"]),
|
185
202
|
user=parameters["user_name"],
|
186
|
-
password=SecretStr(parameters["password"]),
|
203
|
+
password=SecretStr(parameters["password"]) if parameters["password"] else None,
|
204
|
+
num_shards=int(parameters["num_shards"]),
|
187
205
|
),
|
188
206
|
db_case_config=GPUIVFFlatConfig(
|
189
207
|
nlist=parameters["nlist"],
|
@@ -217,7 +235,8 @@ def MilvusGPUBruteForce(**parameters: Unpack[MilvusGPUBruteForceTypedDict]):
|
|
217
235
|
db_label=parameters["db_label"],
|
218
236
|
uri=SecretStr(parameters["uri"]),
|
219
237
|
user=parameters["user_name"],
|
220
|
-
password=SecretStr(parameters["password"]),
|
238
|
+
password=SecretStr(parameters["password"]) if parameters["password"] else None,
|
239
|
+
num_shards=int(parameters["num_shards"]),
|
221
240
|
),
|
222
241
|
db_case_config=GPUBruteForceConfig(
|
223
242
|
metric_type=parameters["metric_type"],
|
@@ -248,7 +267,8 @@ def MilvusGPUIVFPQ(**parameters: Unpack[MilvusGPUIVFPQTypedDict]):
|
|
248
267
|
db_label=parameters["db_label"],
|
249
268
|
uri=SecretStr(parameters["uri"]),
|
250
269
|
user=parameters["user_name"],
|
251
|
-
password=SecretStr(parameters["password"]),
|
270
|
+
password=SecretStr(parameters["password"]) if parameters["password"] else None,
|
271
|
+
num_shards=int(parameters["num_shards"]),
|
252
272
|
),
|
253
273
|
db_case_config=GPUIVFPQConfig(
|
254
274
|
nlist=parameters["nlist"],
|
@@ -287,7 +307,8 @@ def MilvusGPUCAGRA(**parameters: Unpack[MilvusGPUCAGRATypedDict]):
|
|
287
307
|
db_label=parameters["db_label"],
|
288
308
|
uri=SecretStr(parameters["uri"]),
|
289
309
|
user=parameters["user_name"],
|
290
|
-
password=SecretStr(parameters["password"]),
|
310
|
+
password=SecretStr(parameters["password"]) if parameters["password"] else None,
|
311
|
+
num_shards=int(parameters["num_shards"]),
|
291
312
|
),
|
292
313
|
db_case_config=GPUCAGRAConfig(
|
293
314
|
intermediate_graph_degree=parameters["intermediate_graph_degree"],
|
@@ -7,12 +7,14 @@ class MilvusConfig(DBConfig):
|
|
7
7
|
uri: SecretStr = "http://localhost:19530"
|
8
8
|
user: str | None = None
|
9
9
|
password: SecretStr | None = None
|
10
|
+
num_shards: int = 1
|
10
11
|
|
11
12
|
def to_dict(self) -> dict:
|
12
13
|
return {
|
13
14
|
"uri": self.uri.get_secret_value(),
|
14
15
|
"user": self.user if self.user else None,
|
15
16
|
"password": self.password.get_secret_value() if self.password else None,
|
17
|
+
"num_shards": self.num_shards,
|
16
18
|
}
|
17
19
|
|
18
20
|
@validator("*")
|
@@ -40,7 +40,12 @@ class Milvus(VectorDB):
|
|
40
40
|
|
41
41
|
from pymilvus import connections
|
42
42
|
|
43
|
-
connections.connect(
|
43
|
+
connections.connect(
|
44
|
+
uri=self.db_config.get("uri"),
|
45
|
+
user=self.db_config.get("user"),
|
46
|
+
password=self.db_config.get("password"),
|
47
|
+
timeout=30,
|
48
|
+
)
|
44
49
|
if drop_old and utility.has_collection(self.collection_name):
|
45
50
|
log.info(f"{self.name} client drop_old collection: {self.collection_name}")
|
46
51
|
utility.drop_collection(self.collection_name)
|
@@ -59,6 +64,7 @@ class Milvus(VectorDB):
|
|
59
64
|
name=self.collection_name,
|
60
65
|
schema=CollectionSchema(fields),
|
61
66
|
consistency_level="Session",
|
67
|
+
num_shards=self.db_config.get("num_shards"),
|
62
68
|
)
|
63
69
|
|
64
70
|
log.info(f"{self.name} create index: index_params: {self.case_config.index_param()}")
|
@@ -0,0 +1,43 @@
|
|
1
|
+
from typing import Annotated, Unpack
|
2
|
+
|
3
|
+
import click
|
4
|
+
from pydantic import SecretStr
|
5
|
+
|
6
|
+
from ....cli.cli import (
|
7
|
+
CommonTypedDict,
|
8
|
+
cli,
|
9
|
+
click_parameter_decorators_from_typed_dict,
|
10
|
+
run,
|
11
|
+
)
|
12
|
+
from .. import DB
|
13
|
+
|
14
|
+
|
15
|
+
class QdrantTypedDict(CommonTypedDict):
|
16
|
+
url: Annotated[
|
17
|
+
str,
|
18
|
+
click.option("--url", type=str, help="URL connection string", required=True),
|
19
|
+
]
|
20
|
+
api_key: Annotated[
|
21
|
+
str | None,
|
22
|
+
click.option("--api-key", type=str, help="API key for authentication", required=False),
|
23
|
+
]
|
24
|
+
|
25
|
+
|
26
|
+
@cli.command()
|
27
|
+
@click_parameter_decorators_from_typed_dict(QdrantTypedDict)
|
28
|
+
def QdrantCloud(**parameters: Unpack[QdrantTypedDict]):
|
29
|
+
from .config import QdrantConfig, QdrantIndexConfig
|
30
|
+
|
31
|
+
config_params = {
|
32
|
+
"db_label": parameters["db_label"],
|
33
|
+
"url": SecretStr(parameters["url"]),
|
34
|
+
}
|
35
|
+
|
36
|
+
config_params["api_key"] = SecretStr(parameters["api_key"]) if parameters["api_key"] else None
|
37
|
+
|
38
|
+
run(
|
39
|
+
db=DB.QdrantCloud,
|
40
|
+
db_config=QdrantConfig(**config_params),
|
41
|
+
db_case_config=QdrantIndexConfig(),
|
42
|
+
**parameters,
|
43
|
+
)
|
@@ -6,14 +6,14 @@ from ..api import DBCaseConfig, DBConfig, MetricType
|
|
6
6
|
# Allowing `api_key` to be left empty, to ensure compatibility with the open-source Qdrant.
|
7
7
|
class QdrantConfig(DBConfig):
|
8
8
|
url: SecretStr
|
9
|
-
api_key: SecretStr
|
9
|
+
api_key: SecretStr | None = None
|
10
10
|
|
11
11
|
def to_dict(self) -> dict:
|
12
|
-
|
13
|
-
if
|
12
|
+
api_key_value = self.api_key.get_secret_value() if self.api_key else None
|
13
|
+
if api_key_value:
|
14
14
|
return {
|
15
15
|
"url": self.url.get_secret_value(),
|
16
|
-
"api_key":
|
16
|
+
"api_key": api_key_value,
|
17
17
|
"prefer_grpc": True,
|
18
18
|
}
|
19
19
|
return {
|
@@ -0,0 +1,60 @@
|
|
1
|
+
from typing import Annotated, Unpack
|
2
|
+
|
3
|
+
import click
|
4
|
+
from pydantic import SecretStr
|
5
|
+
|
6
|
+
from vectordb_bench.backend.clients import DB
|
7
|
+
from vectordb_bench.cli.cli import (
|
8
|
+
CommonTypedDict,
|
9
|
+
cli,
|
10
|
+
click_parameter_decorators_from_typed_dict,
|
11
|
+
run,
|
12
|
+
)
|
13
|
+
|
14
|
+
DBTYPE = DB.QdrantLocal
|
15
|
+
|
16
|
+
|
17
|
+
class QdrantLocalTypedDict(CommonTypedDict):
|
18
|
+
url: Annotated[
|
19
|
+
str,
|
20
|
+
click.option("--url", type=str, help="Qdrant url", required=True),
|
21
|
+
]
|
22
|
+
on_disk: Annotated[
|
23
|
+
bool,
|
24
|
+
click.option("--on-disk", type=bool, default=False, help="Store the vectors and the HNSW index on disk"),
|
25
|
+
]
|
26
|
+
m: Annotated[
|
27
|
+
int,
|
28
|
+
click.option("--m", type=int, default=16, help="HNSW index parameter m, set 0 to disable the index"),
|
29
|
+
]
|
30
|
+
ef_construct: Annotated[
|
31
|
+
int,
|
32
|
+
click.option("--ef-construct", type=int, default=200, help="HNSW index parameter ef_construct"),
|
33
|
+
]
|
34
|
+
hnsw_ef: Annotated[
|
35
|
+
int,
|
36
|
+
click.option(
|
37
|
+
"--hnsw-ef",
|
38
|
+
type=int,
|
39
|
+
default=0,
|
40
|
+
help="HNSW index parameter hnsw_ef, set 0 to use ef_construct for search",
|
41
|
+
),
|
42
|
+
]
|
43
|
+
|
44
|
+
|
45
|
+
@cli.command()
|
46
|
+
@click_parameter_decorators_from_typed_dict(QdrantLocalTypedDict)
|
47
|
+
def QdrantLocal(**parameters: Unpack[QdrantLocalTypedDict]):
|
48
|
+
from .config import QdrantLocalConfig, QdrantLocalIndexConfig
|
49
|
+
|
50
|
+
run(
|
51
|
+
db=DBTYPE,
|
52
|
+
db_config=QdrantLocalConfig(url=SecretStr(parameters["url"])),
|
53
|
+
db_case_config=QdrantLocalIndexConfig(
|
54
|
+
on_disk=parameters["on_disk"],
|
55
|
+
m=parameters["m"],
|
56
|
+
ef_construct=parameters["ef_construct"],
|
57
|
+
hnsw_ef=parameters["hnsw_ef"],
|
58
|
+
),
|
59
|
+
**parameters,
|
60
|
+
)
|
@@ -0,0 +1,47 @@
|
|
1
|
+
from pydantic import BaseModel, SecretStr
|
2
|
+
|
3
|
+
from ..api import DBCaseConfig, DBConfig, MetricType
|
4
|
+
|
5
|
+
|
6
|
+
class QdrantLocalConfig(DBConfig):
|
7
|
+
url: SecretStr
|
8
|
+
|
9
|
+
def to_dict(self) -> dict:
|
10
|
+
return {
|
11
|
+
"url": self.url.get_secret_value(),
|
12
|
+
}
|
13
|
+
|
14
|
+
|
15
|
+
class QdrantLocalIndexConfig(BaseModel, DBCaseConfig):
|
16
|
+
metric_type: MetricType | None = None
|
17
|
+
m: int
|
18
|
+
ef_construct: int
|
19
|
+
hnsw_ef: int | None = 0
|
20
|
+
on_disk: bool | None = False
|
21
|
+
|
22
|
+
def parse_metric(self) -> str:
|
23
|
+
if self.metric_type == MetricType.L2:
|
24
|
+
return "Euclid"
|
25
|
+
|
26
|
+
if self.metric_type == MetricType.IP:
|
27
|
+
return "Dot"
|
28
|
+
|
29
|
+
return "Cosine"
|
30
|
+
|
31
|
+
def index_param(self) -> dict:
|
32
|
+
return {
|
33
|
+
"distance": self.parse_metric(),
|
34
|
+
"m": self.m,
|
35
|
+
"ef_construct": self.ef_construct,
|
36
|
+
"on_disk": self.on_disk,
|
37
|
+
}
|
38
|
+
|
39
|
+
def search_param(self) -> dict:
|
40
|
+
search_params = {
|
41
|
+
"exact": False, # Force to use ANNs
|
42
|
+
}
|
43
|
+
|
44
|
+
if self.hnsw_ef != 0:
|
45
|
+
search_params["hnsw_ef"] = self.hnsw_ef
|
46
|
+
|
47
|
+
return search_params
|