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.
Files changed (38) hide show
  1. vectordb_bench/__init__.py +3 -1
  2. vectordb_bench/backend/clients/__init__.py +16 -0
  3. vectordb_bench/backend/clients/aws_opensearch/aws_opensearch.py +180 -15
  4. vectordb_bench/backend/clients/aws_opensearch/cli.py +51 -21
  5. vectordb_bench/backend/clients/aws_opensearch/config.py +37 -14
  6. vectordb_bench/backend/clients/clickhouse/cli.py +1 -0
  7. vectordb_bench/backend/clients/clickhouse/clickhouse.py +3 -3
  8. vectordb_bench/backend/clients/clickhouse/config.py +2 -2
  9. vectordb_bench/backend/clients/lancedb/cli.py +62 -8
  10. vectordb_bench/backend/clients/lancedb/config.py +14 -1
  11. vectordb_bench/backend/clients/lancedb/lancedb.py +21 -3
  12. vectordb_bench/backend/clients/memorydb/memorydb.py +2 -2
  13. vectordb_bench/backend/clients/milvus/cli.py +30 -9
  14. vectordb_bench/backend/clients/milvus/config.py +2 -0
  15. vectordb_bench/backend/clients/milvus/milvus.py +7 -1
  16. vectordb_bench/backend/clients/qdrant_cloud/cli.py +43 -0
  17. vectordb_bench/backend/clients/qdrant_cloud/config.py +4 -4
  18. vectordb_bench/backend/clients/qdrant_local/cli.py +60 -0
  19. vectordb_bench/backend/clients/qdrant_local/config.py +47 -0
  20. vectordb_bench/backend/clients/qdrant_local/qdrant_local.py +232 -0
  21. vectordb_bench/backend/clients/weaviate_cloud/cli.py +29 -3
  22. vectordb_bench/backend/clients/weaviate_cloud/config.py +2 -0
  23. vectordb_bench/backend/clients/weaviate_cloud/weaviate_cloud.py +5 -0
  24. vectordb_bench/backend/runner/mp_runner.py +16 -5
  25. vectordb_bench/backend/task_runner.py +1 -0
  26. vectordb_bench/cli/batch_cli.py +121 -0
  27. vectordb_bench/cli/cli.py +13 -2
  28. vectordb_bench/cli/vectordbbench.py +6 -0
  29. vectordb_bench/config-files/batch_sample_config.yml +17 -0
  30. vectordb_bench/frontend/components/run_test/dbConfigSetting.py +10 -4
  31. vectordb_bench/frontend/config/dbCaseConfigs.py +113 -1
  32. vectordb_bench/models.py +13 -0
  33. {vectordb_bench-0.0.28.dist-info → vectordb_bench-0.0.30.dist-info}/METADATA +56 -5
  34. {vectordb_bench-0.0.28.dist-info → vectordb_bench-0.0.30.dist-info}/RECORD +38 -32
  35. {vectordb_bench-0.0.28.dist-info → vectordb_bench-0.0.30.dist-info}/WHEEL +1 -1
  36. {vectordb_bench-0.0.28.dist-info → vectordb_bench-0.0.30.dist-info}/entry_points.txt +0 -0
  37. {vectordb_bench-0.0.28.dist-info → vectordb_bench-0.0.30.dist-info}/licenses/LICENSE +0 -0
  38. {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(LanceDBTypedDict)
63
- def LanceDBIVFPQ(**parameters: Unpack[LanceDBTypedDict]):
64
- from .config import LanceDBConfig, _lancedb_case_config
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=_lancedb_case_config.get(IndexType.IVFPQ)(),
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(LanceDBTypedDict)
80
- def LanceDBHNSW(**parameters: Unpack[LanceDBTypedDict]):
81
- from .config import LanceDBConfig, _lancedb_case_config
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=_lancedb_case_config.get(IndexType.HNSW)(),
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
- pass
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.float64(), list_size=self.dim))]
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).to_list()
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).limit(k).to_list()
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 IndexType, VectorDB
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(**self.db_config, timeout=30)
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
- api_key = self.api_key.get_secret_value()
13
- if len(api_key) > 0:
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": self.api_key.get_secret_value(),
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