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.
Files changed (37) hide show
  1. vectordb_bench/__init__.py +1 -0
  2. vectordb_bench/backend/clients/__init__.py +15 -0
  3. vectordb_bench/backend/clients/api.py +2 -0
  4. vectordb_bench/backend/clients/aws_opensearch/aws_opensearch.py +104 -40
  5. vectordb_bench/backend/clients/aws_opensearch/cli.py +52 -15
  6. vectordb_bench/backend/clients/aws_opensearch/config.py +27 -7
  7. vectordb_bench/backend/clients/hologres/cli.py +50 -0
  8. vectordb_bench/backend/clients/hologres/config.py +121 -0
  9. vectordb_bench/backend/clients/hologres/hologres.py +365 -0
  10. vectordb_bench/backend/clients/lancedb/lancedb.py +1 -0
  11. vectordb_bench/backend/clients/milvus/cli.py +25 -0
  12. vectordb_bench/backend/clients/milvus/config.py +2 -0
  13. vectordb_bench/backend/clients/milvus/milvus.py +1 -1
  14. vectordb_bench/backend/clients/oceanbase/cli.py +1 -0
  15. vectordb_bench/backend/clients/oceanbase/config.py +3 -1
  16. vectordb_bench/backend/clients/oceanbase/oceanbase.py +20 -4
  17. vectordb_bench/backend/clients/pgdiskann/cli.py +45 -0
  18. vectordb_bench/backend/clients/pgdiskann/config.py +16 -0
  19. vectordb_bench/backend/clients/pgdiskann/pgdiskann.py +94 -26
  20. vectordb_bench/backend/clients/zilliz_cloud/cli.py +14 -1
  21. vectordb_bench/backend/clients/zilliz_cloud/config.py +4 -1
  22. vectordb_bench/backend/runner/rate_runner.py +23 -11
  23. vectordb_bench/cli/cli.py +36 -0
  24. vectordb_bench/cli/vectordbbench.py +2 -0
  25. vectordb_bench/frontend/config/dbCaseConfigs.py +82 -3
  26. vectordb_bench/frontend/config/styles.py +1 -0
  27. vectordb_bench/interface.py +5 -1
  28. vectordb_bench/models.py +3 -0
  29. vectordb_bench/results/getLeaderboardDataV2.py +23 -2
  30. vectordb_bench/results/leaderboard_v2.json +200 -0
  31. vectordb_bench/results/leaderboard_v2_streaming.json +128 -0
  32. {vectordb_bench-1.0.5.dist-info → vectordb_bench-1.0.7.dist-info}/METADATA +40 -8
  33. {vectordb_bench-1.0.5.dist-info → vectordb_bench-1.0.7.dist-info}/RECORD +37 -33
  34. {vectordb_bench-1.0.5.dist-info → vectordb_bench-1.0.7.dist-info}/WHEEL +0 -0
  35. {vectordb_bench-1.0.5.dist-info → vectordb_bench-1.0.7.dist-info}/entry_points.txt +0 -0
  36. {vectordb_bench-1.0.5.dist-info → vectordb_bench-1.0.7.dist-info}/licenses/LICENSE +0 -0
  37. {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} " + "= {setting_val};").format(
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
- self._filtered_search = sql.Composed(
107
- [
108
- sql.SQL(
109
- "SELECT id FROM public.{table_name} WHERE id >= %s ORDER BY embedding ",
110
- ).format(table_name=sql.Identifier(self.table_name)),
111
- sql.SQL(self.case_config.search_param()["metric_fun_op"]),
112
- sql.SQL(" %s::vector LIMIT %s::int"),
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
- self._unfiltered_search = sql.Composed(
117
- [
118
- sql.SQL("SELECT id FROM public.{} ORDER BY embedding ").format(
119
- sql.Identifier(self.table_name),
120
- ),
121
- sql.SQL(self.case_config.search_param()["metric_fun_op"]),
122
- sql.SQL(" %s::vector LIMIT %s::int"),
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.Identifier(str(option_val)),
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._filtered_search,
322
- (gt, q, k),
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(self._unfiltered_search, (q, k), prepare=True, binary=True)
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
- params={parameters["level"]},
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], retry_idx: int = 0):
37
- _, error = db.insert_embeddings(emb, metadata)
38
- if error is not None:
39
- log.warning(f"Insert Failed, try_idx={retry_idx}, Exception: {error}")
40
- retry_idx += 1
41
- if retry_idx <= config.MAX_INSERT_RETRY:
42
- time.sleep(retry_idx)
43
- self.send_insert_task(db, emb=emb, metadata=metadata, retry_idx=retry_idx)
44
- else:
45
- msg = f"Insert failed and retried more than {config.MAX_INSERT_RETRY} times"
46
- raise RuntimeError(msg) from None
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
- CaseConfigParamInput_max_neighbors = CaseConfigInput(
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
- CaseConfigParamInput_max_neighbors,
1872
+ CaseConfigParamInput_max_neighbors_PgDiskANN,
1800
1873
  CaseConfigParamInput_l_value_ib,
1801
1874
  ]
1802
1875
 
1803
1876
  PgDiskANNPerformanceConfig = [
1804
1877
  CaseConfigParamInput_IndexType_PgDiskANN,
1805
- CaseConfigParamInput_max_neighbors,
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
@@ -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
- self.dataset_source: DatasetSource = DatasetSource.S3
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": f"{db.value}-{label}",
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__":