vectordb-bench 0.0.16__py3-none-any.whl → 0.0.17__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.
@@ -17,7 +17,7 @@ class config:
17
17
 
18
18
  DEFAULT_DATASET_URL = env.str("DEFAULT_DATASET_URL", AWS_S3_URL)
19
19
  DATASET_LOCAL_DIR = env.path("DATASET_LOCAL_DIR", "/tmp/vectordb_bench/dataset")
20
- NUM_PER_BATCH = env.int("NUM_PER_BATCH", 5000)
20
+ NUM_PER_BATCH = env.int("NUM_PER_BATCH", 100)
21
21
 
22
22
  DROP_OLD = env.bool("DROP_OLD", True)
23
23
  USE_SHUFFLED_DATA = env.bool("USE_SHUFFLED_DATA", True)
@@ -66,7 +66,8 @@ class Milvus(VectorDB):
66
66
  self.case_config.index_param(),
67
67
  index_name=self._index_name,
68
68
  )
69
- # self._pre_load(coll)
69
+ if kwargs.get("pre_load") is True:
70
+ self._pre_load(col)
70
71
 
71
72
  connections.disconnect("default")
72
73
 
@@ -92,7 +93,7 @@ class Milvus(VectorDB):
92
93
  self._post_insert()
93
94
  log.info(f"{self.name} optimizing before search")
94
95
  try:
95
- self.col.load()
96
+ self.col.load(refresh=True)
96
97
  except Exception as e:
97
98
  log.warning(f"{self.name} optimize error: {e}")
98
99
  raise e from None
@@ -57,11 +57,11 @@ class CustomDataset(BaseDataset):
57
57
  dir: str
58
58
  file_num: int
59
59
  isCustom: bool = True
60
-
60
+
61
61
  @validator("size")
62
62
  def verify_size(cls, v):
63
63
  return v
64
-
64
+
65
65
  @property
66
66
  def label(self) -> str:
67
67
  return "Custom"
@@ -73,7 +73,8 @@ class CustomDataset(BaseDataset):
73
73
  @property
74
74
  def file_count(self) -> int:
75
75
  return self.file_num
76
-
76
+
77
+
77
78
  class LAION(BaseDataset):
78
79
  name: str = "LAION"
79
80
  dim: int = 768
@@ -242,13 +243,15 @@ class DataSetIterator:
242
243
  self._cur = None
243
244
  self._sub_idx = [0 for i in range(len(self._ds.train_files))] # iter num for each file
244
245
 
246
+ def __iter__(self):
247
+ return self
248
+
245
249
  def _get_iter(self, file_name: str):
246
250
  p = pathlib.Path(self._ds.data_dir, file_name)
247
251
  log.info(f"Get iterator for {p.name}")
248
252
  if not p.exists():
249
253
  raise IndexError(f"No such file {p}")
250
- log.warning(f"No such file: {p}")
251
- return ParquetFile(p).iter_batches(config.NUM_PER_BATCH)
254
+ return ParquetFile(p, memory_map=True, pre_buffer=True).iter_batches(config.NUM_PER_BATCH)
252
255
 
253
256
  def __next__(self) -> pd.DataFrame:
254
257
  """return the data in the next file of the training list"""
@@ -64,7 +64,7 @@ class MultiProcessingSearchRunner:
64
64
  log.warning(f"VectorDB search_embedding error: {e}")
65
65
  traceback.print_exc(chain=True)
66
66
  raise e from None
67
-
67
+
68
68
  latencies.append(time.perf_counter() - s)
69
69
  count += 1
70
70
  # loop through the test data
@@ -87,11 +87,14 @@ class MultiProcessingSearchRunner:
87
87
  log.debug(f"MultiProcessingSearchRunner get multiprocessing start method: {mp_start_method}")
88
88
  return mp.get_context(mp_start_method)
89
89
 
90
- def _run_all_concurrencies_mem_efficient(self) -> float:
90
+
91
+
92
+ def _run_all_concurrencies_mem_efficient(self):
91
93
  max_qps = 0
92
94
  conc_num_list = []
93
95
  conc_qps_list = []
94
96
  conc_latency_p99_list = []
97
+ conc_latency_avg_list = []
95
98
  try:
96
99
  for conc in self.concurrencies:
97
100
  with mp.Manager() as m:
@@ -111,13 +114,15 @@ class MultiProcessingSearchRunner:
111
114
  start = time.perf_counter()
112
115
  all_count = sum([r.result()[0] for r in future_iter])
113
116
  latencies = sum([r.result()[2] for r in future_iter], start=[])
114
- latency_p99 = np.percentile(latencies, 0.99)
117
+ latency_p99 = np.percentile(latencies, 99)
118
+ latency_avg = np.mean(latencies)
115
119
  cost = time.perf_counter() - start
116
120
 
117
121
  qps = round(all_count / cost, 4)
118
122
  conc_num_list.append(conc)
119
123
  conc_qps_list.append(qps)
120
124
  conc_latency_p99_list.append(latency_p99)
125
+ conc_latency_avg_list.append(latency_avg)
121
126
  log.info(f"End search in concurrency {conc}: dur={cost}s, total_count={all_count}, qps={qps}")
122
127
 
123
128
  if qps > max_qps:
@@ -134,7 +139,7 @@ class MultiProcessingSearchRunner:
134
139
  finally:
135
140
  self.stop()
136
141
 
137
- return max_qps, conc_num_list, conc_qps_list, conc_latency_p99_list
142
+ return max_qps, conc_num_list, conc_qps_list, conc_latency_p99_list, conc_latency_avg_list
138
143
 
139
144
  def run(self) -> float:
140
145
  """
@@ -145,3 +150,88 @@ class MultiProcessingSearchRunner:
145
150
 
146
151
  def stop(self) -> None:
147
152
  pass
153
+
154
+ def run_by_dur(self, duration: int) -> float:
155
+ return self._run_by_dur(duration)
156
+
157
+ def _run_by_dur(self, duration: int) -> float:
158
+ max_qps = 0
159
+ try:
160
+ for conc in self.concurrencies:
161
+ with mp.Manager() as m:
162
+ q, cond = m.Queue(), m.Condition()
163
+ with concurrent.futures.ProcessPoolExecutor(mp_context=self.get_mp_context(), max_workers=conc) as executor:
164
+ log.info(f"Start search_by_dur {duration}s in concurrency {conc}, filters: {self.filters}")
165
+ future_iter = [executor.submit(self.search_by_dur, duration, self.test_data, q, cond) for i in range(conc)]
166
+ # Sync all processes
167
+ while q.qsize() < conc:
168
+ sleep_t = conc if conc < 10 else 10
169
+ time.sleep(sleep_t)
170
+
171
+ with cond:
172
+ cond.notify_all()
173
+ log.info(f"Syncing all process and start concurrency search, concurrency={conc}")
174
+
175
+ start = time.perf_counter()
176
+ all_count = sum([r.result() for r in future_iter])
177
+ cost = time.perf_counter() - start
178
+
179
+ qps = round(all_count / cost, 4)
180
+ log.info(f"End search in concurrency {conc}: dur={cost}s, total_count={all_count}, qps={qps}")
181
+
182
+ if qps > max_qps:
183
+ max_qps = qps
184
+ log.info(f"Update largest qps with concurrency {conc}: current max_qps={max_qps}")
185
+ except Exception as e:
186
+ log.warning(f"Fail to search all concurrencies: {self.concurrencies}, max_qps before failure={max_qps}, reason={e}")
187
+ traceback.print_exc()
188
+
189
+ # No results available, raise exception
190
+ if max_qps == 0.0:
191
+ raise e from None
192
+
193
+ finally:
194
+ self.stop()
195
+
196
+ return max_qps
197
+
198
+
199
+ def search_by_dur(self, dur: int, test_data: list[list[float]], q: mp.Queue, cond: mp.Condition) -> int:
200
+ # sync all process
201
+ q.put(1)
202
+ with cond:
203
+ cond.wait()
204
+
205
+ with self.db.init():
206
+ num, idx = len(test_data), random.randint(0, len(test_data) - 1)
207
+
208
+ start_time = time.perf_counter()
209
+ count = 0
210
+ while time.perf_counter() < start_time + dur:
211
+ s = time.perf_counter()
212
+ try:
213
+ self.db.search_embedding(
214
+ test_data[idx],
215
+ self.k,
216
+ self.filters,
217
+ )
218
+ except Exception as e:
219
+ log.warning(f"VectorDB search_embedding error: {e}")
220
+ traceback.print_exc(chain=True)
221
+ raise e from None
222
+
223
+ count += 1
224
+ # loop through the test data
225
+ idx = idx + 1 if idx < num - 1 else 0
226
+
227
+ if count % 500 == 0:
228
+ log.debug(f"({mp.current_process().name:16}) search_count: {count}, latest_latency={time.perf_counter()-s}")
229
+
230
+ total_dur = round(time.perf_counter() - start_time, 4)
231
+ log.debug(
232
+ f"{mp.current_process().name:16} search {self.duration}s: "
233
+ f"actual_dur={total_dur}s, count={count}, qps in this process: {round(count / total_dur, 4):3}"
234
+ )
235
+
236
+ return count
237
+
@@ -0,0 +1,79 @@
1
+ import logging
2
+ import time
3
+ from concurrent.futures import ThreadPoolExecutor
4
+ import multiprocessing as mp
5
+
6
+
7
+ from vectordb_bench.backend.clients import api
8
+ from vectordb_bench.backend.dataset import DataSetIterator
9
+ from vectordb_bench.backend.utils import time_it
10
+ from vectordb_bench import config
11
+
12
+ from .util import get_data, is_futures_completed, get_future_exceptions
13
+ log = logging.getLogger(__name__)
14
+
15
+
16
+ class RatedMultiThreadingInsertRunner:
17
+ def __init__(
18
+ self,
19
+ rate: int, # numRows per second
20
+ db: api.VectorDB,
21
+ dataset_iter: DataSetIterator,
22
+ normalize: bool = False,
23
+ timeout: float | None = None,
24
+ ):
25
+ self.timeout = timeout if isinstance(timeout, (int, float)) else None
26
+ self.dataset = dataset_iter
27
+ self.db = db
28
+ self.normalize = normalize
29
+ self.insert_rate = rate
30
+ self.batch_rate = rate // config.NUM_PER_BATCH
31
+
32
+ def send_insert_task(self, db, emb: list[list[float]], metadata: list[str]):
33
+ db.insert_embeddings(emb, metadata)
34
+
35
+ @time_it
36
+ def run_with_rate(self, q: mp.Queue):
37
+ with ThreadPoolExecutor(max_workers=mp.cpu_count()) as executor:
38
+ executing_futures = []
39
+
40
+ @time_it
41
+ def submit_by_rate() -> bool:
42
+ rate = self.batch_rate
43
+ for data in self.dataset:
44
+ emb, metadata = get_data(data, self.normalize)
45
+ executing_futures.append(executor.submit(self.send_insert_task, self.db, emb, metadata))
46
+ rate -= 1
47
+
48
+ if rate == 0:
49
+ return False
50
+ return rate == self.batch_rate
51
+
52
+ with self.db.init():
53
+ while True:
54
+ start_time = time.perf_counter()
55
+ finished, elapsed_time = submit_by_rate()
56
+ if finished is True:
57
+ q.put(None, block=True)
58
+ log.info(f"End of dataset, left unfinished={len(executing_futures)}")
59
+ return
60
+
61
+ q.put(True, block=False)
62
+ wait_interval = 1 - elapsed_time if elapsed_time < 1 else 0.001
63
+
64
+ e, completed = is_futures_completed(executing_futures, wait_interval)
65
+ if completed is True:
66
+ ex = get_future_exceptions(executing_futures)
67
+ if ex is not None:
68
+ log.warn(f"task error, terminating, err={ex}")
69
+ q.put(None)
70
+ executor.shutdown(wait=True, cancel_futures=True)
71
+ raise ex
72
+ else:
73
+ log.debug(f"Finished {len(executing_futures)} insert-{config.NUM_PER_BATCH} task in 1s, wait_interval={wait_interval:.2f}")
74
+ executing_futures = []
75
+ else:
76
+ log.warning(f"Failed to finish tasks in 1s, {e}, waited={wait_interval:.2f}, try to check the next round")
77
+ dur = time.perf_counter() - start_time
78
+ if dur < 1:
79
+ time.sleep(1 - dur)
@@ -0,0 +1,112 @@
1
+ import logging
2
+ from typing import Iterable
3
+ import multiprocessing as mp
4
+ import concurrent
5
+ import numpy as np
6
+ import math
7
+
8
+ from .mp_runner import MultiProcessingSearchRunner
9
+ from .serial_runner import SerialSearchRunner
10
+ from .rate_runner import RatedMultiThreadingInsertRunner
11
+ from vectordb_bench.backend.clients import api
12
+ from vectordb_bench.backend.dataset import DatasetManager
13
+
14
+ log = logging.getLogger(__name__)
15
+
16
+
17
+ class ReadWriteRunner(MultiProcessingSearchRunner, RatedMultiThreadingInsertRunner):
18
+ def __init__(
19
+ self,
20
+ db: api.VectorDB,
21
+ dataset: DatasetManager,
22
+ insert_rate: int = 1000,
23
+ normalize: bool = False,
24
+ k: int = 100,
25
+ filters: dict | None = None,
26
+ concurrencies: Iterable[int] = (1, 15, 50),
27
+ search_stage: Iterable[float] = (0.5, 0.6, 0.7, 0.8, 0.9, 1.0), # search in any insert portion, 0.0 means search from the start
28
+ read_dur_after_write: int = 300, # seconds, search duration when insertion is done
29
+ timeout: float | None = None,
30
+ ):
31
+ self.insert_rate = insert_rate
32
+ self.data_volume = dataset.data.size
33
+
34
+ for stage in search_stage:
35
+ assert 0.0 <= stage <= 1.0, "each search stage should be in [0.0, 1.0]"
36
+ self.search_stage = sorted(search_stage)
37
+ self.read_dur_after_write = read_dur_after_write
38
+
39
+ log.info(f"Init runner, concurencys={concurrencies}, search_stage={search_stage}, stage_search_dur={read_dur_after_write}")
40
+
41
+ test_emb = np.stack(dataset.test_data["emb"])
42
+ if normalize:
43
+ test_emb = test_emb / np.linalg.norm(test_emb, axis=1)[:, np.newaxis]
44
+ test_emb = test_emb.tolist()
45
+
46
+ MultiProcessingSearchRunner.__init__(
47
+ self,
48
+ db=db,
49
+ test_data=test_emb,
50
+ k=k,
51
+ filters=filters,
52
+ concurrencies=concurrencies,
53
+ )
54
+ RatedMultiThreadingInsertRunner.__init__(
55
+ self,
56
+ rate=insert_rate,
57
+ db=db,
58
+ dataset_iter=iter(dataset),
59
+ normalize=normalize,
60
+ )
61
+ self.serial_search_runner = SerialSearchRunner(
62
+ db=db,
63
+ test_data=test_emb,
64
+ ground_truth=dataset.gt_data,
65
+ k=k,
66
+ )
67
+
68
+ def run_read_write(self):
69
+ futures = []
70
+ with mp.Manager() as m:
71
+ q = m.Queue()
72
+ with concurrent.futures.ProcessPoolExecutor(mp_context=mp.get_context("spawn"), max_workers=2) as executor:
73
+ futures.append(executor.submit(self.run_with_rate, q))
74
+ futures.append(executor.submit(self.run_search_by_sig, q))
75
+
76
+ for future in concurrent.futures.as_completed(futures):
77
+ res = future.result()
78
+ log.info(f"Result = {res}")
79
+
80
+ log.info("Concurrent read write all done")
81
+
82
+
83
+ def run_search_by_sig(self, q):
84
+ res = []
85
+ total_batch = math.ceil(self.data_volume / self.insert_rate)
86
+ batch = 0
87
+ recall = 'x'
88
+
89
+ for idx, stage in enumerate(self.search_stage):
90
+ target_batch = int(total_batch * stage)
91
+ while q.get(block=True):
92
+ batch += 1
93
+ if batch >= target_batch:
94
+ perc = int(stage * 100)
95
+ log.info(f"Insert {perc}% done, total batch={total_batch}")
96
+ log.info(f"[{batch}/{total_batch}] Serial search - {perc}% start")
97
+ recall, ndcg, p99 =self.serial_search_runner.run()
98
+
99
+ if idx < len(self.search_stage) - 1:
100
+ stage_search_dur = (self.data_volume * (self.search_stage[idx + 1] - stage) // self.insert_rate) // len(self.concurrencies)
101
+ if stage_search_dur < 30:
102
+ log.warning(f"Search duration too short, please reduce concurrency count or insert rate, or increase dataset volume: dur={stage_search_dur}, concurrencies={len(self.concurrencies)}, insert_rate={self.insert_rate}")
103
+ log.info(f"[{batch}/{total_batch}] Conc search - {perc}% start, dur for each conc={stage_search_dur}s")
104
+ else:
105
+ last_search_dur = self.data_volume * (1.0 - stage) // self.insert_rate
106
+ stage_search_dur = last_search_dur + self.read_dur_after_write
107
+ log.info(f"[{batch}/{total_batch}] Last conc search - {perc}% start, [read_until_write|read_after_write|total] =[{last_search_dur}s|{self.read_dur_after_write}s|{stage_search_dur}s]")
108
+
109
+ max_qps = self.run_by_dur(stage_search_dur)
110
+ res.append((perc, max_qps, recall))
111
+ break
112
+ return res
@@ -0,0 +1,32 @@
1
+ import logging
2
+ import concurrent
3
+ from typing import Iterable
4
+
5
+ from pandas import DataFrame
6
+ import numpy as np
7
+
8
+ log = logging.getLogger(__name__)
9
+
10
+ def get_data(data_df: DataFrame, normalize: bool) -> tuple[list[list[float]], list[str]]:
11
+ all_metadata = data_df['id'].tolist()
12
+ emb_np = np.stack(data_df['emb'])
13
+ if normalize:
14
+ log.debug("normalize the 100k train data")
15
+ all_embeddings = (emb_np / np.linalg.norm(emb_np, axis=1)[:, np.newaxis]).tolist()
16
+ else:
17
+ all_embeddings = emb_np.tolist()
18
+ return all_embeddings, all_metadata
19
+
20
+ def is_futures_completed(futures: Iterable[concurrent.futures.Future], interval) -> (Exception, bool):
21
+ try:
22
+ list(concurrent.futures.as_completed(futures, timeout=interval))
23
+ except TimeoutError as e:
24
+ return e, False
25
+ return None, True
26
+
27
+
28
+ def get_future_exceptions(futures: Iterable[concurrent.futures.Future]) -> BaseException | None:
29
+ for f in futures:
30
+ if f.exception() is not None:
31
+ return f.exception()
32
+ return
@@ -150,7 +150,7 @@ class CaseRunner(BaseModel):
150
150
  )
151
151
 
152
152
  self._init_search_runner()
153
-
153
+
154
154
  m.qps, m.conc_num_list, m.conc_qps_list, m.conc_latency_p99_list = self._conc_search()
155
155
  m.recall, m.serial_latency_p99 = self._serial_search()
156
156
  '''
@@ -176,6 +176,9 @@ class CaseRunner(BaseModel):
176
176
  or TaskStage.SEARCH_CONCURRENT in self.config.stages
177
177
  ):
178
178
  self._init_search_runner()
179
+ if TaskStage.SEARCH_CONCURRENT in self.config.stages:
180
+ search_results = self._conc_search()
181
+ m.qps, m.conc_num_list, m.conc_qps_list, m.conc_latency_p99_list, m.conc_latency_avg_list = search_results
179
182
  if TaskStage.SEARCH_SERIAL in self.config.stages:
180
183
  search_results = self._serial_search()
181
184
  '''
@@ -183,10 +186,7 @@ class CaseRunner(BaseModel):
183
186
  m.serial_latencies = search_results.serial_latencies
184
187
  '''
185
188
  m.recall, m.ndcg, m.serial_latency_p99 = search_results
186
- if TaskStage.SEARCH_CONCURRENT in self.config.stages:
187
- search_results = self._conc_search()
188
- m.qps, m.conc_num_list, m.conc_qps_list, m.conc_latency_p99_list = search_results
189
-
189
+
190
190
  except Exception as e:
191
191
  log.warning(f"Failed to run performance case, reason = {e}")
192
192
  traceback.print_exc()
@@ -6,7 +6,7 @@ import plotly.express as px
6
6
  from vectordb_bench.frontend.config.styles import COLOR_MAP
7
7
 
8
8
 
9
- def drawChartsByCase(allData, showCaseNames: list[str], st):
9
+ def drawChartsByCase(allData, showCaseNames: list[str], st, latency_type: str):
10
10
  initMainExpanderStyle(st)
11
11
  for caseName in showCaseNames:
12
12
  chartContainer = st.expander(caseName, True)
@@ -14,15 +14,24 @@ def drawChartsByCase(allData, showCaseNames: list[str], st):
14
14
  data = [
15
15
  {
16
16
  "conc_num": caseData["conc_num_list"][i],
17
- "qps": caseData["conc_qps_list"][i],
18
- "latency_p99": caseData["conc_latency_p99_list"][i] * 1000,
17
+ "qps": caseData["conc_qps_list"][i]
18
+ if 0 <= i < len(caseData["conc_qps_list"])
19
+ else 0,
20
+ "latency_p99": caseData["conc_latency_p99_list"][i] * 1000
21
+ if 0 <= i < len(caseData["conc_latency_p99_list"])
22
+ else 0,
23
+ "latency_avg": caseData["conc_latency_avg_list"][i] * 1000
24
+ if 0 <= i < len(caseData["conc_latency_avg_list"])
25
+ else 0,
19
26
  "db_name": caseData["db_name"],
20
27
  "db": caseData["db"],
21
28
  }
22
29
  for caseData in caseDataList
23
30
  for i in range(len(caseData["conc_num_list"]))
24
31
  ]
25
- drawChart(data, chartContainer, key=f"{caseName}-qps-p99")
32
+ drawChart(
33
+ data, chartContainer, key=f"{caseName}-qps-p99", x_metric=latency_type
34
+ )
26
35
 
27
36
 
28
37
  def getRange(metric, data, padding_multipliers):
@@ -36,14 +45,21 @@ def getRange(metric, data, padding_multipliers):
36
45
  return rangeV
37
46
 
38
47
 
39
- def drawChart(data, st, key: str):
48
+ def gen_title(s: str) -> str:
49
+ if "latency" in s:
50
+ return f'{s.replace("_", " ").title()} (ms)'
51
+ else:
52
+ return s.upper()
53
+
54
+
55
+ def drawChart(data, st, key: str, x_metric: str = "latency_p99", y_metric: str = "qps"):
40
56
  if len(data) == 0:
41
57
  return
42
58
 
43
- x = "latency_p99"
59
+ x = x_metric
44
60
  xrange = getRange(x, data, [0.05, 0.1])
45
61
 
46
- y = "qps"
62
+ y = y_metric
47
63
  yrange = getRange(y, data, [0.2, 0.1])
48
64
 
49
65
  color = "db"
@@ -69,8 +85,8 @@ def drawChart(data, st, key: str):
69
85
  },
70
86
  height=720,
71
87
  )
72
- fig.update_xaxes(range=xrange, title_text="Latency P99 (ms)")
73
- fig.update_yaxes(range=yrange, title_text="QPS")
88
+ fig.update_xaxes(range=xrange, title_text=gen_title(x_metric))
89
+ fig.update_yaxes(range=yrange, title_text=gen_title(y_metric))
74
90
  fig.update_traces(textposition="bottom right", texttemplate="conc-%{text:,.4~r}")
75
91
 
76
92
  st.plotly_chart(fig, use_container_width=True, key=key)
@@ -55,7 +55,11 @@ def main():
55
55
  resultesContainer = st.sidebar.container()
56
56
  getResults(resultesContainer, "vectordb_bench_concurrent")
57
57
 
58
- drawChartsByCase(shownData, showCaseNames, st.container())
58
+ # main
59
+ latency_type = st.radio("Latency Type", options=["latency_p99", "latency_avg"])
60
+ drawChartsByCase(
61
+ shownData, showCaseNames, st.container(), latency_type=latency_type
62
+ )
59
63
 
60
64
  # footer
61
65
  footer(st.container())
vectordb_bench/metric.py CHANGED
@@ -23,6 +23,7 @@ class Metric:
23
23
  conc_num_list: list[int] = field(default_factory=list)
24
24
  conc_qps_list: list[float] = field(default_factory=list)
25
25
  conc_latency_p99_list: list[float] = field(default_factory=list)
26
+ conc_latency_avg_list: list[float] = field(default_factory=list)
26
27
 
27
28
 
28
29
  QURIES_PER_DOLLAR_METRIC = "QP$ (Quries per Dollar)"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: vectordb-bench
3
- Version: 0.0.16
3
+ Version: 0.0.17
4
4
  Summary: VectorDBBench is not just an offering of benchmark results for mainstream vector databases and cloud services, it's your go-to tool for the ultimate performance and cost-effectiveness comparison. Designed with ease-of-use in mind, VectorDBBench is devised to help users, even non-professionals, reproduce results or test new systems, making the hunt for the optimal choice amongst a plethora of cloud services and open-source vector databases a breeze.
5
5
  Author-email: XuanYang-cn <xuan.yang@zilliz.com>
6
6
  Project-URL: repository, https://github.com/zilliztech/VectorDBBench
@@ -14,7 +14,7 @@ Requires-Dist: click
14
14
  Requires-Dist: pytz
15
15
  Requires-Dist: streamlit-autorefresh
16
16
  Requires-Dist: streamlit!=1.34.0
17
- Requires-Dist: streamlit-extras
17
+ Requires-Dist: streamlit_extras
18
18
  Requires-Dist: tqdm
19
19
  Requires-Dist: s3fs
20
20
  Requires-Dist: oss2
@@ -25,6 +25,9 @@ Requires-Dist: environs
25
25
  Requires-Dist: pydantic<v2
26
26
  Requires-Dist: scikit-learn
27
27
  Requires-Dist: pymilvus
28
+ Provides-Extra: test
29
+ Requires-Dist: ruff; extra == "test"
30
+ Requires-Dist: pytest; extra == "test"
28
31
  Provides-Extra: all
29
32
  Requires-Dist: grpcio==1.53.0; extra == "all"
30
33
  Requires-Dist: grpcio-tools==1.53.0; extra == "all"
@@ -33,7 +36,7 @@ Requires-Dist: pinecone-client; extra == "all"
33
36
  Requires-Dist: weaviate-client; extra == "all"
34
37
  Requires-Dist: elasticsearch; extra == "all"
35
38
  Requires-Dist: pgvector; extra == "all"
36
- Requires-Dist: pgvecto-rs[psycopg3]>=0.2.2; extra == "all"
39
+ Requires-Dist: pgvecto_rs[psycopg3]>=0.2.2; extra == "all"
37
40
  Requires-Dist: sqlalchemy; extra == "all"
38
41
  Requires-Dist: redis; extra == "all"
39
42
  Requires-Dist: chromadb; extra == "all"
@@ -41,20 +44,14 @@ Requires-Dist: psycopg; extra == "all"
41
44
  Requires-Dist: psycopg-binary; extra == "all"
42
45
  Requires-Dist: opensearch-dsl==2.1.0; extra == "all"
43
46
  Requires-Dist: opensearch-py==2.6.0; extra == "all"
44
- Provides-Extra: awsopensearch
45
- Requires-Dist: awsopensearch; extra == "awsopensearch"
46
- Provides-Extra: chromadb
47
- Requires-Dist: chromadb; extra == "chromadb"
47
+ Provides-Extra: qdrant
48
+ Requires-Dist: qdrant-client; extra == "qdrant"
49
+ Provides-Extra: pinecone
50
+ Requires-Dist: pinecone-client; extra == "pinecone"
51
+ Provides-Extra: weaviate
52
+ Requires-Dist: weaviate-client; extra == "weaviate"
48
53
  Provides-Extra: elastic
49
54
  Requires-Dist: elasticsearch; extra == "elastic"
50
- Provides-Extra: memorydb
51
- Requires-Dist: memorydb; extra == "memorydb"
52
- Provides-Extra: pgdiskann
53
- Requires-Dist: psycopg; extra == "pgdiskann"
54
- Requires-Dist: psycopg-binary; extra == "pgdiskann"
55
- Requires-Dist: pgvector; extra == "pgdiskann"
56
- Provides-Extra: pgvecto_rs
57
- Requires-Dist: pgvecto-rs[psycopg3]>=0.2.2; extra == "pgvecto-rs"
58
55
  Provides-Extra: pgvector
59
56
  Requires-Dist: psycopg; extra == "pgvector"
60
57
  Requires-Dist: psycopg-binary; extra == "pgvector"
@@ -63,18 +60,21 @@ Provides-Extra: pgvectorscale
63
60
  Requires-Dist: psycopg; extra == "pgvectorscale"
64
61
  Requires-Dist: psycopg-binary; extra == "pgvectorscale"
65
62
  Requires-Dist: pgvector; extra == "pgvectorscale"
66
- Provides-Extra: pinecone
67
- Requires-Dist: pinecone-client; extra == "pinecone"
68
- Provides-Extra: qdrant
69
- Requires-Dist: qdrant-client; extra == "qdrant"
63
+ Provides-Extra: pgdiskann
64
+ Requires-Dist: psycopg; extra == "pgdiskann"
65
+ Requires-Dist: psycopg-binary; extra == "pgdiskann"
66
+ Requires-Dist: pgvector; extra == "pgdiskann"
67
+ Provides-Extra: pgvecto-rs
68
+ Requires-Dist: pgvecto_rs[psycopg3]>=0.2.2; extra == "pgvecto-rs"
70
69
  Provides-Extra: redis
71
70
  Requires-Dist: redis; extra == "redis"
72
- Provides-Extra: test
73
- Requires-Dist: ruff; extra == "test"
74
- Requires-Dist: pytest; extra == "test"
75
- Provides-Extra: weaviate
76
- Requires-Dist: weaviate-client; extra == "weaviate"
77
- Provides-Extra: zilliz_cloud
71
+ Provides-Extra: memorydb
72
+ Requires-Dist: memorydb; extra == "memorydb"
73
+ Provides-Extra: chromadb
74
+ Requires-Dist: chromadb; extra == "chromadb"
75
+ Provides-Extra: awsopensearch
76
+ Requires-Dist: awsopensearch; extra == "awsopensearch"
77
+ Provides-Extra: zilliz-cloud
78
78
 
79
79
  # VectorDBBench: A Benchmark Tool for VectorDB
80
80
 
@@ -1,17 +1,17 @@
1
- vectordb_bench/__init__.py,sha256=6eCX-hQJJtc97zlz6qcwJHrdwfAtkkwMSZEYeK9RRN0,2152
1
+ vectordb_bench/__init__.py,sha256=sma1LoKYvRHXYmNKHgz1TT3oy-65scS9ZoF5o5b30SM,2151
2
2
  vectordb_bench/__main__.py,sha256=YJOTn5MlbmLyr3PRsecY6fj7igHLB6_D3y1HwF_sO20,848
3
3
  vectordb_bench/base.py,sha256=d34WCGXZI1u5RGQtqrPHd3HbOF5AmioFrM2j30Aj1sY,130
4
4
  vectordb_bench/interface.py,sha256=ZT3pseyq--TuxtopdP2hRut-6vIInKo62pvAl2zBD10,9708
5
5
  vectordb_bench/log_util.py,sha256=nMnW-sN24WyURcI07t-WA3q2N5R-YIvFgboRsSrNJDg,2906
6
- vectordb_bench/metric.py,sha256=osb58NvGGmqs3EKTfFujO7Qq5fAhGO9AOkCsziKgEUs,1976
6
+ vectordb_bench/metric.py,sha256=c-LAxCtb55txnsfd3FN4gRpRif8RREhKRF0eg2JmHGc,2045
7
7
  vectordb_bench/models.py,sha256=jAY60QFq3Uhq0YPIQOGYBU1JspOz8D0XJEXSlEBT7cs,10645
8
8
  vectordb_bench/backend/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
9
  vectordb_bench/backend/assembler.py,sha256=mmoLzWXFSlrpWvaVY41wiRNWNv2IR-LzlANX55MJbYI,2028
10
10
  vectordb_bench/backend/cases.py,sha256=lQ9jgKaJGunj-mJXR3cgGt16wCsrDrvs-GS3ycTDk0U,16169
11
11
  vectordb_bench/backend/data_source.py,sha256=j4-eD0nIe7Y6fSM5WKEij3GfhyU_YOQ3L5Tyl-1GxX0,5446
12
- vectordb_bench/backend/dataset.py,sha256=WHHNDIOrO6eyU3LsW4SxDeZT-_u0dMFwKigNB5kWMk0,8764
12
+ vectordb_bench/backend/dataset.py,sha256=MZSu0Q3AkK9gxiuLKNTMH6hhucKK668j4G1-8emhS18,8786
13
13
  vectordb_bench/backend/result_collector.py,sha256=jdQf5-q1z5y07SKy9Sig1wFROmm-p9x_Y81fId0sjaU,807
14
- vectordb_bench/backend/task_runner.py,sha256=Y1HYWvWlIo_4pe0EMLuAN8bWj2xhqfbw59afbCmZeAI,11855
14
+ vectordb_bench/backend/task_runner.py,sha256=cn_RRDyFfNSLlTT84W-ZaXvdl54pK6Cxcsp9ucNRcCs,11864
15
15
  vectordb_bench/backend/utils.py,sha256=2UixYyfKvl8zRiashywB1l6hTI3jMtiZhiVm_bXHV1Y,1811
16
16
  vectordb_bench/backend/clients/__init__.py,sha256=vl-ldJCTAm6aXUNZS4xE5M2zbiWSz9-rua_9PcOj7ZA,6277
17
17
  vectordb_bench/backend/clients/api.py,sha256=KGHdn8gewGm_HbsF7qfn3ibep4AoMXUzaoTjLpF98NE,6176
@@ -28,7 +28,7 @@ vectordb_bench/backend/clients/memorydb/config.py,sha256=PjhLMMr_LdJ8O91JpHNCCT6
28
28
  vectordb_bench/backend/clients/memorydb/memorydb.py,sha256=XIqtXpY-2lJohIuImFDsRO3c_upn04eCplIOlaLxFo4,10114
29
29
  vectordb_bench/backend/clients/milvus/cli.py,sha256=QqzYIOeUSXEvdLH0_YUMhwDHUDJirTNKeUxrJQIqSdw,8506
30
30
  vectordb_bench/backend/clients/milvus/config.py,sha256=AZ4QHoufRIjsX2eVrtnug8SeYnuHeBMna_34OQNFxz0,6847
31
- vectordb_bench/backend/clients/milvus/milvus.py,sha256=BzOySmlYCQnNScazK9XBjKPh3X99jZSm0W3-IigRAYY,7653
31
+ vectordb_bench/backend/clients/milvus/milvus.py,sha256=BhEkJr8ZQuiFqYd1sQYhKd8YXHS9vlaqOv36zlHI6xc,7712
32
32
  vectordb_bench/backend/clients/pgdiskann/cli.py,sha256=ued1DyufltataIk6KcmBkNp8PdB9Aj65nVJ6WhrD_VI,3130
33
33
  vectordb_bench/backend/clients/pgdiskann/config.py,sha256=8E0GLgUxa5LlJ_eXCugbbO08qdbCVqc1wtdsoOsKEW4,4444
34
34
  vectordb_bench/backend/clients/pgdiskann/pgdiskann.py,sha256=bEcbpTVSFxRJ5HiJTX77cgu6NqTMPs8qiGeMF7jBC30,12628
@@ -58,8 +58,11 @@ vectordb_bench/backend/clients/zilliz_cloud/cli.py,sha256=V8XnjrM4IOexqJksQCBgEY
58
58
  vectordb_bench/backend/clients/zilliz_cloud/config.py,sha256=3Tk7X4r0n2SLzan110xlF63otVGjCKe28CVDfCEI04c,910
59
59
  vectordb_bench/backend/clients/zilliz_cloud/zilliz_cloud.py,sha256=4JcwiVEJcdEykW6n471nfHeIlmhIDa-gOZ7G5H_4krY,681
60
60
  vectordb_bench/backend/runner/__init__.py,sha256=5dZfPky8pY9Bi9HD5GZ3Fge8V2FJWrkGkQUkNL2v1t0,230
61
- vectordb_bench/backend/runner/mp_runner.py,sha256=u8UqIp44fSIEhT5M9-RQEiaFwOlxLA0L5n989hCv3hY,5456
61
+ vectordb_bench/backend/runner/mp_runner.py,sha256=sPJJWg6bKSQYsyWEe5y_j8i_Cf9l5buhtyY-wZxXDAI,9080
62
+ vectordb_bench/backend/runner/rate_runner.py,sha256=qLfirLmS9tR0-3jljaWD_AMw_gt6nwhAVVkxhoo4F4A,3195
63
+ vectordb_bench/backend/runner/read_write_runner.py,sha256=B8PD_gRS5K1nFH5004x6ON1Z8TulK7c4QepW3Glltd8,4732
62
64
  vectordb_bench/backend/runner/serial_runner.py,sha256=ku1Dtps9JcmwCwZq7eDw0pcP9IN2Zjjg-1VJumXYJpA,9414
65
+ vectordb_bench/backend/runner/util.py,sha256=pGJn-qXWwGXVlmsMulaqH0zXcasDWjsVwwOJeDFWXhc,1032
63
66
  vectordb_bench/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
64
67
  vectordb_bench/cli/cli.py,sha256=Z2-vLwvnnZFsVAPyjFK557cZZYWX_q60XVJP-aYUGdc,15416
65
68
  vectordb_bench/cli/vectordbbench.py,sha256=QOKwURuiaxsQ-vf7ji-qHEug5j1y_j1xSeykSsENz30,1055
@@ -76,7 +79,7 @@ vectordb_bench/frontend/components/check_results/headerIcon.py,sha256=0uvvSe-oro
76
79
  vectordb_bench/frontend/components/check_results/nav.py,sha256=DQl74rujw70ayh37PQaiO4AdtVZ95-OtTMEtw_Ui7hE,685
77
80
  vectordb_bench/frontend/components/check_results/priceTable.py,sha256=n7OLXfG95CECPR9lQuK_7HXd3jjprmuk8EHgJ8hcth4,1309
78
81
  vectordb_bench/frontend/components/check_results/stPageConfig.py,sha256=vHDHS3qwAbOAQ-Zvz3DftUiKJS4Xs109172aWUmzOt0,430
79
- vectordb_bench/frontend/components/concurrent/charts.py,sha256=_fredxaByBkzEe_2NDX31yNxwi_EnReknUm1nqCcgbs,2218
82
+ vectordb_bench/frontend/components/concurrent/charts.py,sha256=H1FSMrnwzmqUInJoHGLVceqLm0-CJ66ujbSNVQJ_SBg,2830
80
83
  vectordb_bench/frontend/components/custom/displayCustomCase.py,sha256=oZfvtiCWr3VnHdvXgcf5YoqvtPWsfMN-YOT7KKoIxp4,1613
81
84
  vectordb_bench/frontend/components/custom/displaypPrams.py,sha256=pxpHgnyGItxkwbajI8qIun0YBY23ZZAvsnK5z7_g5p4,1321
82
85
  vectordb_bench/frontend/components/custom/getCustomConfig.py,sha256=P0WCMla2hmzeDcsHju6gFMQrugsBzajAVSYtBZTEwWg,1050
@@ -94,7 +97,7 @@ vectordb_bench/frontend/components/tables/data.py,sha256=pVG_hb4bTMLfUt10NUCJSqc
94
97
  vectordb_bench/frontend/config/dbCaseConfigs.py,sha256=Sl6sPTtUJki8uRu5wgPynKcR4OdaDwIgnmzCVVX9gQ0,31070
95
98
  vectordb_bench/frontend/config/dbPrices.py,sha256=10aBKjVcEg8y7TPSda28opmBM1KmXNrvbU9WM_BsZcE,176
96
99
  vectordb_bench/frontend/config/styles.py,sha256=E2PmwmiewxBKJJ59hQ4ZXatqg8QTN-Z53JlsvWMHM2M,2291
97
- vectordb_bench/frontend/pages/concurrent.py,sha256=yK62Tjto8G9ObvLy0JSVLq9fqDMy_D3oAEGZw2Te4gU,1958
100
+ vectordb_bench/frontend/pages/concurrent.py,sha256=z2izkQ0suO5mZ8PpVY2jypZkF5VT8xUkQQEkwd6C-ww,2094
98
101
  vectordb_bench/frontend/pages/custom.py,sha256=BYQuWa7_OQz0wnDvh0LiXzjevmDpO2BbSIuF1_Z_39M,2234
99
102
  vectordb_bench/frontend/pages/quries_per_dollar.py,sha256=SRLPjGfXwZOIrLeDLgVNg1kE6xjAu-QfmXoa3Sfiqi8,2510
100
103
  vectordb_bench/frontend/pages/run_test.py,sha256=b1NoMhFA3MmUyItkofh3xozvo1vAqywXKOsoWdIWmRU,2161
@@ -117,9 +120,9 @@ vectordb_bench/results/WeaviateCloud/result_20230808_standard_weaviatecloud.json
117
120
  vectordb_bench/results/ZillizCloud/result_20230727_standard_zillizcloud.json,sha256=-Mdm4By65XDRCrmVOCF8yQXjcZtH4Xo4shcjoDoBUKU,18293
118
121
  vectordb_bench/results/ZillizCloud/result_20230808_standard_zillizcloud.json,sha256=77XlHT5zM_K7mG5HfDQKwXZnSCuR37VUbt6-P3J_amI,15737
119
122
  vectordb_bench/results/ZillizCloud/result_20240105_standard_202401_zillizcloud.json,sha256=TualfJ0664Hs-vdIW68bdkqAEYyzotXmu2P0yIN-GHk,42526
120
- vectordb_bench-0.0.16.dist-info/LICENSE,sha256=HXbxhrb5u5SegVzeLNF_voVgRsJMavcLaOmD1N0lZkM,1067
121
- vectordb_bench-0.0.16.dist-info/METADATA,sha256=CpbILuoA-dYaH1oQs0Bm08mExmD0kx5wfk8UbXPRIzc,34643
122
- vectordb_bench-0.0.16.dist-info/WHEEL,sha256=P9jw-gEje8ByB7_hXoICnHtVCrEwMQh-630tKvQWehc,91
123
- vectordb_bench-0.0.16.dist-info/entry_points.txt,sha256=Qzw6gVx96ui8esG21H6yHsI6nboEohRmV424TYhQNrA,113
124
- vectordb_bench-0.0.16.dist-info/top_level.txt,sha256=jnhZFZAuKX1J60yt-XOeBZ__ctiZMvoC_s0RFq29lpM,15
125
- vectordb_bench-0.0.16.dist-info/RECORD,,
123
+ vectordb_bench-0.0.17.dist-info/LICENSE,sha256=HXbxhrb5u5SegVzeLNF_voVgRsJMavcLaOmD1N0lZkM,1067
124
+ vectordb_bench-0.0.17.dist-info/METADATA,sha256=SreMZtCcdr-dKZrwyLXuVHX-WinJe9uLTvV9_NtIXgY,34643
125
+ vectordb_bench-0.0.17.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
126
+ vectordb_bench-0.0.17.dist-info/entry_points.txt,sha256=Qzw6gVx96ui8esG21H6yHsI6nboEohRmV424TYhQNrA,113
127
+ vectordb_bench-0.0.17.dist-info/top_level.txt,sha256=jnhZFZAuKX1J60yt-XOeBZ__ctiZMvoC_s0RFq29lpM,15
128
+ vectordb_bench-0.0.17.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (75.3.0)
2
+ Generator: setuptools (75.6.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5