Skip to content

Commit a795e4c

Browse files
Including QPS per precision chart on cli.
1 parent 6d6f2e6 commit a795e4c

File tree

3 files changed

+197
-2
lines changed

3 files changed

+197
-2
lines changed

DOCKER_README.md

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,47 @@
22

33
A comprehensive benchmarking tool for vector databases, including Redis (both RediSearch and Vector Sets), Weaviate, Milvus, Qdrant, OpenSearch, Postgres, and others...
44

5+
In a one-liner cli tool you can get this and much more:
6+
7+
```
8+
docker run --rm --network=host redis/vector-db-benchmark:latest run.py --host localhost --engines vectorsets-fp32-default --datasets glove-100-angular --parallels 100
9+
(...)
10+
================================================================================
11+
BENCHMARK RESULTS SUMMARY
12+
Experiment: vectorsets-fp32-default - glove-100-angular
13+
================================================================================
14+
15+
Precision vs Performance Trade-off:
16+
--------------------------------------------------
17+
Precision QPS P50 (ms) P95 (ms)
18+
--------------------------------------------------
19+
0.86 1408.3 61.877 107.548
20+
0.80 2136.3 38.722 69.102
21+
0.72 2954.3 25.820 48.072
22+
0.68 3566.5 20.229 38.581
23+
24+
QPS vs Precision Trade-off - vectorsets-fp32-default - glove-100-angular (up and to the right is better):
25+
26+
3566 │●
27+
│ ●
28+
29+
2594 │
30+
│ ●
31+
32+
1621 │ ●
33+
34+
35+
648 │
36+
37+
38+
0 │
39+
└────────────────────────────────────────────────────────────
40+
0.680 0.726 0.772 0.817
41+
Precision (0.0 = 0%, 1.0 = 100%)
42+
================================================================================
43+
44+
```
45+
546
## Quick Start
647

748
```bash

README.md

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,49 @@
11
# vector-db-benchmark
22

3-
![Screenshot from 2022-08-23 14-10-01](https://user-images.githubusercontent.com/1935623/186516524-a61098d4-bca6-4aeb-acbe-d969cf30674e.png)
3+
A comprehensive benchmarking tool for vector databases, including Redis (both RediSearch and Vector Sets), Weaviate, Milvus, Qdrant, OpenSearch, Postgres, and others...
44

5-
> [View results](https://qdrant.tech/benchmarks/)
5+
In a one-liner cli tool you can get this and much more:
6+
7+
```
8+
docker run --rm --network=host redis/vector-db-benchmark:latest run.py --host localhost --engines vectorsets-fp32-default --datasets glove-100-angular --parallels 100
9+
(...)
10+
================================================================================
11+
BENCHMARK RESULTS SUMMARY
12+
Experiment: vectorsets-fp32-default - glove-100-angular
13+
================================================================================
14+
15+
Precision vs Performance Trade-off:
16+
--------------------------------------------------
17+
Precision QPS P50 (ms) P95 (ms)
18+
--------------------------------------------------
19+
0.86 1408.3 61.877 107.548
20+
0.80 2136.3 38.722 69.102
21+
0.72 2954.3 25.820 48.072
22+
0.68 3566.5 20.229 38.581
23+
24+
QPS vs Precision Trade-off - vectorsets-fp32-default - glove-100-angular (up and to the right is better):
25+
26+
3566 │●
27+
│ ●
28+
29+
2594 │
30+
│ ●
31+
32+
1621 │ ●
33+
34+
35+
648 │
36+
37+
38+
0 │
39+
└────────────────────────────────────────────────────────────
40+
0.680 0.726 0.772 0.817
41+
Precision (0.0 = 0%, 1.0 = 100%)
42+
================================================================================
43+
44+
```
45+
46+
> [View results](https://redis.io/blog/benchmarking-results-for-vector-databases/)
647
748
There are various vector search engines available, and each of them may offer
849
a different set of features and efficiency. But how do we measure the

engine/base_client/client.py

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,9 @@ def run_experiment(
311311
print(f"Added precision analysis with {len(precision_analysis)} precision thresholds")
312312
print(f"Added precision summary with {len(precision_summary)} precision levels")
313313

314+
# Display results table and chart
315+
self._display_results_summary(precision_summary, dataset.config.name)
316+
314317
summary_file = f"{self.name}-{dataset.config.name}-summary.json"
315318
summary_path = RESULTS_DIR / summary_file
316319
with open(summary_path, "w") as out:
@@ -323,6 +326,116 @@ def run_experiment(
323326
print("Results saved to: ", RESULTS_DIR)
324327
print("Summary saved to: ", summary_path)
325328

329+
def _display_results_summary(self, precision_summary: Dict[str, Dict[str, float]], dataset_name: str = ""):
330+
"""Display results table and ASCII chart after benchmark completion."""
331+
if not precision_summary:
332+
return
333+
334+
print("\n" + "="*80)
335+
print("BENCHMARK RESULTS SUMMARY")
336+
if dataset_name:
337+
print(f"Experiment: {self.name} - {dataset_name}")
338+
print("="*80)
339+
340+
# Results table
341+
print("\nPrecision vs Performance Trade-off:")
342+
print("-" * 50)
343+
print(f"{'Precision':<10} {'QPS':<8} {'P50 (ms)':<10} {'P95 (ms)':<10}")
344+
print("-" * 50)
345+
346+
# Sort by precision (descending for better readability)
347+
sorted_data = sorted(precision_summary.items(), key=lambda x: float(x[0]), reverse=True)
348+
349+
for precision, metrics in sorted_data:
350+
qps = metrics.get('qps', 0)
351+
p50 = metrics.get('p50', 0)
352+
p95 = metrics.get('p95', 0)
353+
print(f"{precision:<10} {qps:<8.1f} {p50:<10.3f} {p95:<10.3f}")
354+
355+
# ASCII scatter plot
356+
print(f"\n{self._create_ascii_scatter_plot(precision_summary, dataset_name)}")
357+
print("="*80 + "\n")
358+
359+
def _create_ascii_scatter_plot(self, precision_summary: Dict[str, Dict[str, float]], dataset_name: str = "") -> str:
360+
"""Create simple ASCII scatter plot with precision on X-axis and QPS on Y-axis."""
361+
if not precision_summary:
362+
return "No data available for chart."
363+
364+
# Sort by precision
365+
sorted_data = sorted(precision_summary.items(), key=lambda x: float(x[0]))
366+
367+
# Extract data
368+
precisions = [float(data[0]) for data in sorted_data]
369+
qps_values = [data[1].get('qps', 0) for data in sorted_data]
370+
371+
if not precisions or not qps_values:
372+
return "No valid data for chart."
373+
374+
# Chart dimensions
375+
width = 60
376+
height = 12
377+
378+
# Calculate scales
379+
min_precision = min(precisions)
380+
max_precision = max(precisions)
381+
min_qps = 0 # Always start from 0 for proper perspective
382+
max_qps = max(qps_values)
383+
384+
precision_range = max_precision - min_precision
385+
qps_range = max_qps - min_qps
386+
387+
if precision_range == 0:
388+
precision_range = 0.1
389+
if qps_range == 0:
390+
qps_range = 100
391+
392+
# Create grid
393+
grid = [[' ' for _ in range(width)] for _ in range(height)]
394+
395+
# Plot points
396+
for precision, qps in zip(precisions, qps_values):
397+
# Convert to grid coordinates
398+
x = int((precision - min_precision) / precision_range * (width - 1))
399+
y = int((max_qps - qps) / qps_range * (height - 1)) # Flip Y axis
400+
401+
# Ensure within bounds
402+
x = max(0, min(width - 1, x))
403+
y = max(0, min(height - 1, y))
404+
405+
grid[y][x] = '●'
406+
407+
# Build chart
408+
experiment_info = f" - {self.name}"
409+
if dataset_name:
410+
experiment_info += f" - {dataset_name}"
411+
chart = f"QPS vs Precision Trade-off{experiment_info} (up and to the right is better):\n\n"
412+
413+
# Y-axis labels and grid
414+
for i, row in enumerate(grid):
415+
if i % 3 == 0: # Show Y labels every 3 rows
416+
qps_val = max_qps - (i / (height - 1)) * qps_range
417+
chart += f"{qps_val:>6.0f} │"
418+
else:
419+
chart += " │"
420+
421+
chart += "".join(row) + "\n"
422+
423+
# Add 0 line at the bottom
424+
chart += f" 0 │" + " " * width + "\n"
425+
426+
# X-axis
427+
chart += " └" + "─" * width + "\n"
428+
chart += " "
429+
430+
# X-axis labels
431+
for i in range(0, width, 15): # Show X labels every 15 chars
432+
precision_val = min_precision + (i / (width - 1)) * precision_range
433+
chart += f"{precision_val:.3f}".ljust(15)
434+
435+
chart += "\n Precision (0.0 = 0%, 1.0 = 100%)"
436+
437+
return chart
438+
326439
def delete_client(self):
327440
self.uploader.delete_client()
328441
self.configurator.delete_client()

0 commit comments

Comments
 (0)