vectordb-bench 1.0.5__py3-none-any.whl → 1.0.7__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 +1 -0
- vectordb_bench/backend/clients/__init__.py +15 -0
- vectordb_bench/backend/clients/api.py +2 -0
- vectordb_bench/backend/clients/aws_opensearch/aws_opensearch.py +104 -40
- vectordb_bench/backend/clients/aws_opensearch/cli.py +52 -15
- vectordb_bench/backend/clients/aws_opensearch/config.py +27 -7
- vectordb_bench/backend/clients/hologres/cli.py +50 -0
- vectordb_bench/backend/clients/hologres/config.py +121 -0
- vectordb_bench/backend/clients/hologres/hologres.py +365 -0
- vectordb_bench/backend/clients/lancedb/lancedb.py +1 -0
- vectordb_bench/backend/clients/milvus/cli.py +25 -0
- vectordb_bench/backend/clients/milvus/config.py +2 -0
- vectordb_bench/backend/clients/milvus/milvus.py +1 -1
- vectordb_bench/backend/clients/oceanbase/cli.py +1 -0
- vectordb_bench/backend/clients/oceanbase/config.py +3 -1
- vectordb_bench/backend/clients/oceanbase/oceanbase.py +20 -4
- vectordb_bench/backend/clients/pgdiskann/cli.py +45 -0
- vectordb_bench/backend/clients/pgdiskann/config.py +16 -0
- vectordb_bench/backend/clients/pgdiskann/pgdiskann.py +94 -26
- vectordb_bench/backend/clients/zilliz_cloud/cli.py +14 -1
- vectordb_bench/backend/clients/zilliz_cloud/config.py +4 -1
- vectordb_bench/backend/runner/rate_runner.py +23 -11
- vectordb_bench/cli/cli.py +36 -0
- vectordb_bench/cli/vectordbbench.py +2 -0
- vectordb_bench/frontend/config/dbCaseConfigs.py +82 -3
- vectordb_bench/frontend/config/styles.py +1 -0
- vectordb_bench/interface.py +5 -1
- vectordb_bench/models.py +3 -0
- vectordb_bench/results/getLeaderboardDataV2.py +23 -2
- vectordb_bench/results/leaderboard_v2.json +200 -0
- vectordb_bench/results/leaderboard_v2_streaming.json +128 -0
- {vectordb_bench-1.0.5.dist-info → vectordb_bench-1.0.7.dist-info}/METADATA +40 -8
- {vectordb_bench-1.0.5.dist-info → vectordb_bench-1.0.7.dist-info}/RECORD +37 -33
- {vectordb_bench-1.0.5.dist-info → vectordb_bench-1.0.7.dist-info}/WHEEL +0 -0
- {vectordb_bench-1.0.5.dist-info → vectordb_bench-1.0.7.dist-info}/entry_points.txt +0 -0
- {vectordb_bench-1.0.5.dist-info → vectordb_bench-1.0.7.dist-info}/licenses/LICENSE +0 -0
- {vectordb_bench-1.0.5.dist-info → vectordb_bench-1.0.7.dist-info}/top_level.txt +0 -0
@@ -60,6 +60,13 @@ class PgDiskANNIndexConfig(BaseModel, DBCaseConfig):
|
|
60
60
|
return "<#>"
|
61
61
|
return "<=>"
|
62
62
|
|
63
|
+
def parse_reranking_metric_fun_op(self) -> LiteralString:
|
64
|
+
if self.reranking_metric == MetricType.L2:
|
65
|
+
return "<->"
|
66
|
+
if self.reranking_metric == MetricType.IP:
|
67
|
+
return "<#>"
|
68
|
+
return "<=>"
|
69
|
+
|
63
70
|
def parse_metric_fun_str(self) -> str:
|
64
71
|
if self.metric_type == MetricType.L2:
|
65
72
|
return "l2_distance"
|
@@ -115,7 +122,11 @@ class PgDiskANNImplConfig(PgDiskANNIndexConfig):
|
|
115
122
|
index: IndexType = IndexType.DISKANN
|
116
123
|
max_neighbors: int | None
|
117
124
|
l_value_ib: int | None
|
125
|
+
pq_param_num_chunks: int | None
|
118
126
|
l_value_is: float | None
|
127
|
+
reranking: bool | None = None
|
128
|
+
reranking_metric: str | None = None
|
129
|
+
quantized_fetch_limit: int | None = None
|
119
130
|
maintenance_work_mem: str | None = None
|
120
131
|
max_parallel_workers: int | None = None
|
121
132
|
|
@@ -126,6 +137,8 @@ class PgDiskANNImplConfig(PgDiskANNIndexConfig):
|
|
126
137
|
"options": {
|
127
138
|
"max_neighbors": self.max_neighbors,
|
128
139
|
"l_value_ib": self.l_value_ib,
|
140
|
+
"pq_param_num_chunks": self.pq_param_num_chunks,
|
141
|
+
"product_quantized": str(self.reranking),
|
129
142
|
},
|
130
143
|
"maintenance_work_mem": self.maintenance_work_mem,
|
131
144
|
"max_parallel_workers": self.max_parallel_workers,
|
@@ -135,6 +148,9 @@ class PgDiskANNImplConfig(PgDiskANNIndexConfig):
|
|
135
148
|
return {
|
136
149
|
"metric": self.parse_metric(),
|
137
150
|
"metric_fun_op": self.parse_metric_fun_op(),
|
151
|
+
"reranking": self.reranking,
|
152
|
+
"reranking_metric_fun_op": self.parse_reranking_metric_fun_op(),
|
153
|
+
"quantized_fetch_limit": self.quantized_fetch_limit,
|
138
154
|
}
|
139
155
|
|
140
156
|
def session_param(self) -> dict:
|
@@ -90,38 +90,83 @@ class PgDiskANN(VectorDB):
|
|
90
90
|
def init(self) -> Generator[None, None, None]:
|
91
91
|
self.conn, self.cursor = self._create_connection(**self.db_config)
|
92
92
|
|
93
|
-
# index configuration may have commands defined that we should set during each client session
|
94
93
|
session_options: dict[str, Any] = self.case_config.session_param()
|
95
94
|
|
96
95
|
if len(session_options) > 0:
|
97
96
|
for setting_name, setting_val in session_options.items():
|
98
|
-
command = sql.SQL("SET {setting_name}
|
99
|
-
setting_name=sql.Identifier(setting_name),
|
100
|
-
setting_val=sql.Identifier(str(setting_val)),
|
97
|
+
command = sql.SQL("SET {setting_name} = {setting_val};").format(
|
98
|
+
setting_name=sql.Identifier(setting_name), setting_val=sql.Literal(setting_val)
|
101
99
|
)
|
102
100
|
log.debug(command.as_string(self.cursor))
|
103
101
|
self.cursor.execute(command)
|
104
102
|
self.conn.commit()
|
105
103
|
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
104
|
+
search_params = self.case_config.search_param()
|
105
|
+
|
106
|
+
if search_params.get("reranking"):
|
107
|
+
# Reranking-enabled queries
|
108
|
+
self._filtered_search = sql.SQL(
|
109
|
+
"""
|
110
|
+
SELECT i.id
|
111
|
+
FROM (
|
112
|
+
SELECT id, embedding
|
113
|
+
FROM public.{table_name}
|
114
|
+
WHERE id >= %s
|
115
|
+
ORDER BY embedding {metric_fun_op} %s::vector
|
116
|
+
LIMIT {quantized_fetch_limit}::int
|
117
|
+
) i
|
118
|
+
ORDER BY i.embedding {reranking_metric_fun_op} %s::vector
|
119
|
+
LIMIT %s::int
|
120
|
+
"""
|
121
|
+
).format(
|
122
|
+
table_name=sql.Identifier(self.table_name),
|
123
|
+
metric_fun_op=sql.SQL(search_params["metric_fun_op"]),
|
124
|
+
reranking_metric_fun_op=sql.SQL(search_params["reranking_metric_fun_op"]),
|
125
|
+
quantized_fetch_limit=sql.Literal(search_params["quantized_fetch_limit"]),
|
126
|
+
)
|
115
127
|
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
128
|
+
self._unfiltered_search = sql.SQL(
|
129
|
+
"""
|
130
|
+
SELECT i.id
|
131
|
+
FROM (
|
132
|
+
SELECT id, embedding
|
133
|
+
FROM public.{table_name}
|
134
|
+
ORDER BY embedding {metric_fun_op} %s::vector
|
135
|
+
LIMIT {quantized_fetch_limit}::int
|
136
|
+
) i
|
137
|
+
ORDER BY i.embedding {reranking_metric_fun_op} %s::vector
|
138
|
+
LIMIT %s::int
|
139
|
+
"""
|
140
|
+
).format(
|
141
|
+
table_name=sql.Identifier(self.table_name),
|
142
|
+
metric_fun_op=sql.SQL(search_params["metric_fun_op"]),
|
143
|
+
reranking_metric_fun_op=sql.SQL(search_params["reranking_metric_fun_op"]),
|
144
|
+
quantized_fetch_limit=sql.Literal(search_params["quantized_fetch_limit"]),
|
145
|
+
)
|
146
|
+
|
147
|
+
else:
|
148
|
+
self._filtered_search = sql.Composed(
|
149
|
+
[
|
150
|
+
sql.SQL(
|
151
|
+
"SELECT id FROM public.{table_name} WHERE id >= %s ORDER BY embedding ",
|
152
|
+
).format(table_name=sql.Identifier(self.table_name)),
|
153
|
+
sql.SQL(search_params["metric_fun_op"]),
|
154
|
+
sql.SQL(" %s::vector LIMIT %s::int"),
|
155
|
+
]
|
156
|
+
)
|
157
|
+
|
158
|
+
self._unfiltered_search = sql.Composed(
|
159
|
+
[
|
160
|
+
sql.SQL("SELECT id FROM public.{table_name} ORDER BY embedding ").format(
|
161
|
+
table_name=sql.Identifier(self.table_name)
|
162
|
+
),
|
163
|
+
sql.SQL(search_params["metric_fun_op"]),
|
164
|
+
sql.SQL(" %s::vector LIMIT %s::int"),
|
165
|
+
]
|
166
|
+
)
|
167
|
+
|
168
|
+
log.debug(f"Unfiltered search query={self._unfiltered_search.as_string(self.conn)}")
|
169
|
+
log.debug(f"Filtered search query={self._filtered_search.as_string(self.conn)}")
|
125
170
|
|
126
171
|
try:
|
127
172
|
yield
|
@@ -234,7 +279,7 @@ class PgDiskANN(VectorDB):
|
|
234
279
|
options.append(
|
235
280
|
sql.SQL("{option_name} = {val}").format(
|
236
281
|
option_name=sql.Identifier(option_name),
|
237
|
-
val=sql.
|
282
|
+
val=sql.Literal(option_val),
|
238
283
|
),
|
239
284
|
)
|
240
285
|
|
@@ -314,16 +359,39 @@ class PgDiskANN(VectorDB):
|
|
314
359
|
assert self.conn is not None, "Connection is not initialized"
|
315
360
|
assert self.cursor is not None, "Cursor is not initialized"
|
316
361
|
|
362
|
+
search_params = self.case_config.search_param()
|
363
|
+
is_reranking = search_params.get("reranking", False)
|
364
|
+
|
317
365
|
q = np.asarray(query)
|
318
366
|
if filters:
|
319
367
|
gt = filters.get("id")
|
368
|
+
if is_reranking:
|
369
|
+
result = self.cursor.execute(
|
370
|
+
self._filtered_search,
|
371
|
+
(gt, q, q, k),
|
372
|
+
prepare=True,
|
373
|
+
binary=True,
|
374
|
+
)
|
375
|
+
else:
|
376
|
+
result = self.cursor.execute(
|
377
|
+
self._filtered_search,
|
378
|
+
(gt, q, k),
|
379
|
+
prepare=True,
|
380
|
+
binary=True,
|
381
|
+
)
|
382
|
+
elif is_reranking:
|
320
383
|
result = self.cursor.execute(
|
321
|
-
self.
|
322
|
-
(
|
384
|
+
self._unfiltered_search,
|
385
|
+
(q, q, k),
|
323
386
|
prepare=True,
|
324
387
|
binary=True,
|
325
388
|
)
|
326
389
|
else:
|
327
|
-
result = self.cursor.execute(
|
390
|
+
result = self.cursor.execute(
|
391
|
+
self._unfiltered_search,
|
392
|
+
(q, k),
|
393
|
+
prepare=True,
|
394
|
+
binary=True,
|
395
|
+
)
|
328
396
|
|
329
397
|
return [int(i[0]) for i in result.fetchall()]
|
@@ -36,6 +36,17 @@ class ZillizTypedDict(CommonTypedDict):
|
|
36
36
|
str,
|
37
37
|
click.option("--level", type=str, help="Zilliz index level", required=False),
|
38
38
|
]
|
39
|
+
num_shards: Annotated[
|
40
|
+
int,
|
41
|
+
click.option(
|
42
|
+
"--num-shards",
|
43
|
+
type=int,
|
44
|
+
help="Number of shards",
|
45
|
+
required=False,
|
46
|
+
default=1,
|
47
|
+
show_default=True,
|
48
|
+
),
|
49
|
+
]
|
39
50
|
|
40
51
|
|
41
52
|
@cli.command()
|
@@ -50,9 +61,11 @@ def ZillizAutoIndex(**parameters: Unpack[ZillizTypedDict]):
|
|
50
61
|
uri=SecretStr(parameters["uri"]),
|
51
62
|
user=parameters["user_name"],
|
52
63
|
password=SecretStr(parameters["password"]),
|
64
|
+
num_shards=parameters["num_shards"],
|
53
65
|
),
|
54
66
|
db_case_config=AutoIndexConfig(
|
55
|
-
|
67
|
+
level=int(parameters["level"]) if parameters["level"] else 1,
|
68
|
+
num_shards=parameters["num_shards"],
|
56
69
|
),
|
57
70
|
**parameters,
|
58
71
|
)
|
@@ -8,24 +8,27 @@ class ZillizCloudConfig(DBConfig):
|
|
8
8
|
uri: SecretStr
|
9
9
|
user: str
|
10
10
|
password: SecretStr
|
11
|
+
num_shards: int = 1
|
11
12
|
|
12
13
|
def to_dict(self) -> dict:
|
13
14
|
return {
|
14
15
|
"uri": self.uri.get_secret_value(),
|
15
16
|
"user": self.user,
|
16
17
|
"password": self.password.get_secret_value(),
|
18
|
+
"num_shards": self.num_shards,
|
17
19
|
}
|
18
20
|
|
19
21
|
|
20
22
|
class AutoIndexConfig(MilvusIndexConfig, DBCaseConfig):
|
21
23
|
index: IndexType = IndexType.AUTOINDEX
|
22
24
|
level: int = 1
|
25
|
+
num_shards: int = 1
|
23
26
|
|
24
27
|
def index_param(self) -> dict:
|
25
28
|
return {
|
26
29
|
"metric_type": self.parse_metric(),
|
27
30
|
"index_type": self.index.value,
|
28
|
-
"params": {},
|
31
|
+
"params": {"shardsNum": self.num_shards},
|
29
32
|
}
|
30
33
|
|
31
34
|
def search_param(self) -> dict:
|
@@ -3,9 +3,11 @@ import logging
|
|
3
3
|
import multiprocessing as mp
|
4
4
|
import time
|
5
5
|
from concurrent.futures import ThreadPoolExecutor
|
6
|
+
from copy import deepcopy
|
6
7
|
|
7
8
|
from vectordb_bench import config
|
8
9
|
from vectordb_bench.backend.clients import api
|
10
|
+
from vectordb_bench.backend.clients.pgvector.pgvector import PgVector
|
9
11
|
from vectordb_bench.backend.dataset import DataSetIterator
|
10
12
|
from vectordb_bench.backend.utils import time_it
|
11
13
|
|
@@ -33,17 +35,27 @@ class RatedMultiThreadingInsertRunner:
|
|
33
35
|
self.executing_futures = []
|
34
36
|
self.sig_idx = 0
|
35
37
|
|
36
|
-
def send_insert_task(self, db: api.VectorDB, emb: list[list[float]], metadata: list[str]
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
38
|
+
def send_insert_task(self, db: api.VectorDB, emb: list[list[float]], metadata: list[str]):
|
39
|
+
def _insert_embeddings(db: api.VectorDB, emb: list[list[float]], metadata: list[str], retry_idx: int = 0):
|
40
|
+
_, error = db.insert_embeddings(emb, metadata)
|
41
|
+
if error is not None:
|
42
|
+
log.warning(f"Insert Failed, try_idx={retry_idx}, Exception: {error}")
|
43
|
+
retry_idx += 1
|
44
|
+
if retry_idx <= config.MAX_INSERT_RETRY:
|
45
|
+
time.sleep(retry_idx)
|
46
|
+
_insert_embeddings(db, emb=emb, metadata=metadata, retry_idx=retry_idx)
|
47
|
+
else:
|
48
|
+
msg = f"Insert failed and retried more than {config.MAX_INSERT_RETRY} times"
|
49
|
+
raise RuntimeError(msg) from None
|
50
|
+
|
51
|
+
if isinstance(db, PgVector):
|
52
|
+
# pgvector is not thread-safe for concurrent insert,
|
53
|
+
# so we need to copy the db object, make sure each thread has its own connection
|
54
|
+
db_copy = deepcopy(db)
|
55
|
+
with db_copy.init():
|
56
|
+
_insert_embeddings(db_copy, emb, metadata, retry_idx=0)
|
57
|
+
else:
|
58
|
+
_insert_embeddings(db, emb, metadata, retry_idx=0)
|
47
59
|
|
48
60
|
@time_it
|
49
61
|
def run_with_rate(self, q: mp.Queue):
|
vectordb_bench/cli/cli.py
CHANGED
@@ -471,6 +471,33 @@ class HNSWFlavor4(HNSWBaseRequiredTypedDict):
|
|
471
471
|
]
|
472
472
|
|
473
473
|
|
474
|
+
class HNSWFlavor5(HNSWBaseRequiredTypedDict):
|
475
|
+
ef_search: Annotated[
|
476
|
+
int | None,
|
477
|
+
click.option("--ef-search", type=int, help="hnsw ef-search", required=True),
|
478
|
+
]
|
479
|
+
index_type: Annotated[
|
480
|
+
str | None,
|
481
|
+
click.option(
|
482
|
+
"--index-type",
|
483
|
+
type=click.Choice(["HGraph"], case_sensitive=True),
|
484
|
+
help="Type of index to use. Supported values: HGraph",
|
485
|
+
required=True,
|
486
|
+
),
|
487
|
+
]
|
488
|
+
use_reorder: Annotated[
|
489
|
+
bool,
|
490
|
+
click.option(
|
491
|
+
"--use-reorder/--no-use-reorder",
|
492
|
+
is_flag=True,
|
493
|
+
type=bool,
|
494
|
+
help="use reorder index",
|
495
|
+
default=True,
|
496
|
+
show_default=True,
|
497
|
+
),
|
498
|
+
]
|
499
|
+
|
500
|
+
|
474
501
|
class IVFFlatTypedDict(TypedDict):
|
475
502
|
lists: Annotated[int | None, click.option("--lists", type=int, help="ivfflat lists")]
|
476
503
|
probes: Annotated[int | None, click.option("--probes", type=int, help="ivfflat probes")]
|
@@ -501,6 +528,15 @@ class OceanBaseIVFTypedDict(TypedDict):
|
|
501
528
|
int | None,
|
502
529
|
click.option("--nlist", "nlist", type=int, help="Number of cluster centers", required=True),
|
503
530
|
]
|
531
|
+
nbits: Annotated[
|
532
|
+
int | None,
|
533
|
+
click.option(
|
534
|
+
"--nbits",
|
535
|
+
"nbits",
|
536
|
+
type=int,
|
537
|
+
help="Number of bits used to encode the index of a sub-vector's centroid in the compressed representation",
|
538
|
+
),
|
539
|
+
]
|
504
540
|
sample_per_nlist: Annotated[
|
505
541
|
int | None,
|
506
542
|
click.option(
|
@@ -1,6 +1,7 @@
|
|
1
1
|
from ..backend.clients.alloydb.cli import AlloyDBScaNN
|
2
2
|
from ..backend.clients.aws_opensearch.cli import AWSOpenSearch
|
3
3
|
from ..backend.clients.clickhouse.cli import Clickhouse
|
4
|
+
from ..backend.clients.hologres.cli import HologresHGraph
|
4
5
|
from ..backend.clients.lancedb.cli import LanceDB
|
5
6
|
from ..backend.clients.mariadb.cli import MariaDBHNSW
|
6
7
|
from ..backend.clients.memorydb.cli import MemoryDB
|
@@ -43,6 +44,7 @@ cli.add_command(TiDB)
|
|
43
44
|
cli.add_command(Clickhouse)
|
44
45
|
cli.add_command(Vespa)
|
45
46
|
cli.add_command(LanceDB)
|
47
|
+
cli.add_command(HologresHGraph)
|
46
48
|
cli.add_command(QdrantCloud)
|
47
49
|
cli.add_command(QdrantLocal)
|
48
50
|
cli.add_command(BatchCli)
|
@@ -423,8 +423,58 @@ CaseConfigParamInput_storage_layout = CaseConfigInput(
|
|
423
423
|
},
|
424
424
|
)
|
425
425
|
|
426
|
-
|
426
|
+
CaseConfigParamInput_reranking_PgDiskANN = CaseConfigInput(
|
427
|
+
label=CaseConfigParamType.reranking,
|
428
|
+
inputType=InputType.Bool,
|
429
|
+
displayLabel="Enable Reranking",
|
430
|
+
inputHelp="Enable if you want to use reranking while performing \
|
431
|
+
similarity search with PQ",
|
432
|
+
inputConfig={
|
433
|
+
"value": False,
|
434
|
+
},
|
435
|
+
)
|
436
|
+
|
437
|
+
CaseConfigParamInput_quantized_fetch_limit_PgDiskANN = CaseConfigInput(
|
438
|
+
label=CaseConfigParamType.quantized_fetch_limit,
|
439
|
+
displayLabel="Quantized Fetch Limit",
|
440
|
+
inputHelp="Limit top-k vectors using the quantized vector comparison",
|
441
|
+
inputType=InputType.Number,
|
442
|
+
inputConfig={
|
443
|
+
"min": 20,
|
444
|
+
"max": 1000,
|
445
|
+
"value": 200,
|
446
|
+
},
|
447
|
+
isDisplayed=lambda config: config.get(CaseConfigParamType.reranking, False),
|
448
|
+
)
|
449
|
+
|
450
|
+
CaseConfigParamInput_pq_param_num_chunks_PgDiskANN = CaseConfigInput(
|
451
|
+
label=CaseConfigParamType.pq_param_num_chunks,
|
452
|
+
displayLabel="pq_param_num_chunks",
|
453
|
+
inputHelp="Number of chunks for product quantization (Defaults to 0). 0 means it is determined automatically, based on embedding dimensions.",
|
454
|
+
inputType=InputType.Number,
|
455
|
+
inputConfig={
|
456
|
+
"min": 0,
|
457
|
+
"max": 1028,
|
458
|
+
"value": 0,
|
459
|
+
},
|
460
|
+
isDisplayed=lambda config: config.get(CaseConfigParamType.reranking, False),
|
461
|
+
)
|
462
|
+
|
463
|
+
|
464
|
+
CaseConfigParamInput_reranking_metric_PgDiskANN = CaseConfigInput(
|
465
|
+
label=CaseConfigParamType.reranking_metric,
|
466
|
+
displayLabel="Reranking Metric",
|
467
|
+
inputType=InputType.Option,
|
468
|
+
inputConfig={
|
469
|
+
"options": [metric.value for metric in MetricType if metric.value not in ["HAMMING", "JACCARD", "DP"]],
|
470
|
+
},
|
471
|
+
isDisplayed=lambda config: config.get(CaseConfigParamType.reranking, False),
|
472
|
+
)
|
473
|
+
|
474
|
+
|
475
|
+
CaseConfigParamInput_max_neighbors_PgDiskANN = CaseConfigInput(
|
427
476
|
label=CaseConfigParamType.max_neighbors,
|
477
|
+
displayLabel="max_neighbors",
|
428
478
|
inputType=InputType.Number,
|
429
479
|
inputConfig={
|
430
480
|
"min": 10,
|
@@ -456,6 +506,29 @@ CaseConfigParamInput_l_value_is = CaseConfigInput(
|
|
456
506
|
isDisplayed=lambda config: config.get(CaseConfigParamType.IndexType, None) == IndexType.DISKANN.value,
|
457
507
|
)
|
458
508
|
|
509
|
+
CaseConfigParamInput_maintenance_work_mem_PgDiskANN = CaseConfigInput(
|
510
|
+
label=CaseConfigParamType.maintenance_work_mem,
|
511
|
+
inputHelp="Memory to use during index builds. Not to exceed the available free memory."
|
512
|
+
"Specify in gigabytes. e.g. 8GB",
|
513
|
+
inputType=InputType.Text,
|
514
|
+
inputConfig={
|
515
|
+
"value": "8GB",
|
516
|
+
},
|
517
|
+
)
|
518
|
+
|
519
|
+
CaseConfigParamInput_max_parallel_workers_PgDiskANN = CaseConfigInput(
|
520
|
+
label=CaseConfigParamType.max_parallel_workers,
|
521
|
+
displayLabel="Max parallel workers",
|
522
|
+
inputHelp="Recommended value: (cpu cores - 1). This will set the parameters: max_parallel_maintenance_workers,"
|
523
|
+
" max_parallel_workers & table(parallel_workers)",
|
524
|
+
inputType=InputType.Number,
|
525
|
+
inputConfig={
|
526
|
+
"min": 0,
|
527
|
+
"max": 1024,
|
528
|
+
"value": 16,
|
529
|
+
},
|
530
|
+
)
|
531
|
+
|
459
532
|
CaseConfigParamInput_num_neighbors = CaseConfigInput(
|
460
533
|
label=CaseConfigParamType.num_neighbors,
|
461
534
|
inputType=InputType.Number,
|
@@ -1796,15 +1869,21 @@ PgVectorScalePerformanceConfig = [
|
|
1796
1869
|
|
1797
1870
|
PgDiskANNLoadConfig = [
|
1798
1871
|
CaseConfigParamInput_IndexType_PgDiskANN,
|
1799
|
-
|
1872
|
+
CaseConfigParamInput_max_neighbors_PgDiskANN,
|
1800
1873
|
CaseConfigParamInput_l_value_ib,
|
1801
1874
|
]
|
1802
1875
|
|
1803
1876
|
PgDiskANNPerformanceConfig = [
|
1804
1877
|
CaseConfigParamInput_IndexType_PgDiskANN,
|
1805
|
-
|
1878
|
+
CaseConfigParamInput_reranking_PgDiskANN,
|
1879
|
+
CaseConfigParamInput_max_neighbors_PgDiskANN,
|
1806
1880
|
CaseConfigParamInput_l_value_ib,
|
1807
1881
|
CaseConfigParamInput_l_value_is,
|
1882
|
+
CaseConfigParamInput_maintenance_work_mem_PgDiskANN,
|
1883
|
+
CaseConfigParamInput_max_parallel_workers_PgDiskANN,
|
1884
|
+
CaseConfigParamInput_pq_param_num_chunks_PgDiskANN,
|
1885
|
+
CaseConfigParamInput_quantized_fetch_limit_PgDiskANN,
|
1886
|
+
CaseConfigParamInput_reranking_metric_PgDiskANN,
|
1808
1887
|
]
|
1809
1888
|
|
1810
1889
|
|
@@ -67,6 +67,7 @@ DB_TO_ICON = {
|
|
67
67
|
DB.LanceDB: "data:image/png;base64,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",
|
68
68
|
DB.OceanBase: "data:image/png;base64,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",
|
69
69
|
DB.S3Vectors: "https://assets.zilliz.com/s3_vectors_daf370b4e5.png",
|
70
|
+
DB.Hologres: "https://img.alicdn.com/imgextra/i3/O1CN01d9qrry1i6lTNa2BRa_!!6000000004364-2-tps-218-200.png",
|
70
71
|
}
|
71
72
|
|
72
73
|
# RedisCloud color: #0D6EFD
|
vectordb_bench/interface.py
CHANGED
@@ -43,7 +43,11 @@ class BenchMarkRunner:
|
|
43
43
|
self.running_task: TaskRunner | None = None
|
44
44
|
self.latest_error: str | None = None
|
45
45
|
self.drop_old: bool = True
|
46
|
-
|
46
|
+
# set default data source by ENV
|
47
|
+
if config.DATASET_SOURCE.upper() == "ALIYUNOSS":
|
48
|
+
self.dataset_source: DatasetSource = DatasetSource.AliyunOSS
|
49
|
+
else:
|
50
|
+
self.dataset_source: DatasetSource = DatasetSource.S3
|
47
51
|
|
48
52
|
def set_drop_old(self, drop_old: bool):
|
49
53
|
self.drop_old = drop_old
|
vectordb_bench/models.py
CHANGED
@@ -86,6 +86,9 @@ class CaseConfigParamType(Enum):
|
|
86
86
|
storage_layout = "storage_layout"
|
87
87
|
num_neighbors = "num_neighbors"
|
88
88
|
max_neighbors = "max_neighbors"
|
89
|
+
quantized_fetch_limit = "quantized_fetch_limit"
|
90
|
+
pq_param_num_chunks = "pq_param_num_chunks"
|
91
|
+
reranking_metric = "reranking_metric"
|
89
92
|
l_value_ib = "l_value_ib"
|
90
93
|
l_value_is = "l_value_is"
|
91
94
|
search_list_size = "search_list_size"
|
@@ -2,10 +2,11 @@ import json
|
|
2
2
|
import logging
|
3
3
|
|
4
4
|
|
5
|
-
from vectordb_bench.backend.cases import CaseType
|
5
|
+
from vectordb_bench.backend.cases import CaseType, StreamingPerformanceCase
|
6
6
|
from vectordb_bench.backend.clients import DB
|
7
7
|
from vectordb_bench.models import CaseResult
|
8
8
|
from vectordb_bench import config
|
9
|
+
import numpy as np
|
9
10
|
|
10
11
|
logging.basicConfig(level=logging.DEBUG, format="%(asctime)s - %(levelname)s - %(message)s")
|
11
12
|
|
@@ -29,9 +30,11 @@ def save_to_json(data: list[dict], file_name: str):
|
|
29
30
|
def main():
|
30
31
|
standard_2025_case_results = get_standard_2025_results()
|
31
32
|
data = []
|
33
|
+
streaming_data = []
|
32
34
|
for case_result in standard_2025_case_results:
|
33
35
|
db = case_result.task_config.db
|
34
36
|
label = case_result.task_config.db_config.db_label
|
37
|
+
db_name = f"{db.value}{f'-{label}' if label else ''}"
|
35
38
|
metrics = case_result.metrics
|
36
39
|
qps = metrics.qps
|
37
40
|
latency = metrics.serial_latency_p99
|
@@ -45,14 +48,32 @@ def main():
|
|
45
48
|
"dataset": dataset,
|
46
49
|
"db": db.value,
|
47
50
|
"label": label,
|
48
|
-
"db_name":
|
51
|
+
"db_name": db_name,
|
49
52
|
"qps": round(qps, 4),
|
50
53
|
"latency": round(latency, 4),
|
51
54
|
"recall": round(recall, 4),
|
52
55
|
"filter_ratio": round(filter_ratio, 3),
|
53
56
|
}
|
54
57
|
)
|
58
|
+
else:
|
59
|
+
case: StreamingPerformanceCase = case
|
60
|
+
# use 90p search stage results to represent streaming performance
|
61
|
+
qps_90p = metrics.st_max_qps_list_list[metrics.st_search_stage_list.index(90)]
|
62
|
+
latency_90p = metrics.st_serial_latency_p99_list[metrics.st_search_stage_list.index(90)]
|
63
|
+
insert_rate = case.insert_rate
|
64
|
+
streaming_data.append(
|
65
|
+
{
|
66
|
+
"dataset": dataset,
|
67
|
+
"db": db.value,
|
68
|
+
"label": label,
|
69
|
+
"db_name": db_name,
|
70
|
+
"insert_rate": insert_rate,
|
71
|
+
"streaming_qps": round(qps_90p, 4),
|
72
|
+
"streaming_latency": round(latency_90p, 4),
|
73
|
+
}
|
74
|
+
)
|
55
75
|
save_to_json(data, config.RESULTS_LOCAL_DIR / "leaderboard_v2.json")
|
76
|
+
save_to_json(streaming_data, config.RESULTS_LOCAL_DIR / "leaderboard_v2_streaming.json")
|
56
77
|
|
57
78
|
|
58
79
|
if __name__ == "__main__":
|