Skip to content

Commit a84deb9

Browse files
committed
remoe outdated readme
1 parent 61518f3 commit a84deb9

File tree

11 files changed

+68
-156
lines changed

11 files changed

+68
-156
lines changed

README.md

Lines changed: 8 additions & 125 deletions
Original file line numberDiff line numberDiff line change
@@ -12,138 +12,21 @@ scenario against which it should be tested. A specific scenario may assume
1212
running the server in a single or distributed mode, a different client
1313
implementation and the number of client instances.
1414

15-
## TL;DR
15+
## How to run a benchmark?
1616

17-
First, we need to run the server instance:
17+
Benchmarks are implemented in server-client mode, meaning that the server is
18+
running in a single machine, and the client is running on another.
1819

19-
```shell
20-
python main.py run-server qdrant-0.8.4
21-
```
20+
### Run the server
2221

23-
After launching it, we can configure the engine to accept loading the data:
2422

25-
```shell
26-
python main.py run-client qdrant-0.8.4 configure random-100
27-
```
23+
### Run the client
2824

29-
Then, a client instance may be launched, or even several ones:
3025

31-
```shell
32-
python main.py run-client qdrant-0.8.4 load random-100
33-
```
3426

35-
- `qdrant-0.8.4` is an engine to launch
36-
- `random-100` defines a dataset
27+
## How to update benchmark parameters?
3728

38-
Expected output should look like following:
29+
## How to register a dataset?
3930

40-
```text
41-
sum(load::time) = 0.22590500000000002
42-
count(load::time) = 100
43-
mean(load::time) = 0.0022590500000000003
44-
```
31+
## How to implement a new engine?
4532

46-
### Backend
47-
48-
A specific way of managing the containers. Right now only Docker, but might be
49-
Docker Swarm, SSH or Kubernetes, so the benchmark is not executed on a single
50-
machine, but on several servers.
51-
52-
### Engine
53-
54-
There are various vector search projects available. Some of them are just pure
55-
libraries (like FAISS or Annoy) and they offer great performance, but doesn't
56-
fit well any production systems. Those could be also benchmarked, however the
57-
primary focus is on vector databases using client-server architecture.
58-
59-
All the engine configurations are kept in `./engine` subdirectories.
60-
61-
Each engine has its own configuration defined in `config.json` file:
62-
63-
```json
64-
{
65-
"server": {
66-
"image": "qdrant/qdrant:v0.8.4",
67-
"hostname": "qdrant_server",
68-
"environment": {
69-
"DEBUG": true
70-
}
71-
},
72-
"client": {
73-
"dockerfile": "client.Dockerfile",
74-
"main": "python cmd.py"
75-
}
76-
}
77-
```
78-
79-
- Either `image` or `dockerfile` has to be defined, similar to
80-
`docker-compose.yaml` file. The `dockerfile` has a precedence over `image`
81-
- The `main` parameter points to a main client script which takes parameters.
82-
Those parameters define the operations to perform with a client library.
83-
84-
##### Supported engines:
85-
86-
- `qdrant-0.8.4`
87-
- `elasticsearch-8.3.1`
88-
89-
#### Server
90-
91-
The server is a process, or a bunch of processes, responsible for creating
92-
vector indexes and handling all the user requests. It may be run on a single
93-
machine, or in case of some engines using the distributed mode (**in the future**).
94-
95-
#### Client
96-
97-
A client process performing all the operations, as it would be typically done in
98-
any client-server based communication. There might be several clients launched
99-
in parallel and each of them might be using part of the data. The number of
100-
clients depends on the scenario.
101-
102-
Each client has to define a main script which takes some parameters and allow
103-
performing typical CRUD-like operations:
104-
105-
- `load [file]`
106-
- `search [file]`
107-
108-
If the scenario attempts to load the data from a given file, then it will call
109-
the following command:
110-
111-
`python cmd.py load vectors.jsonl`
112-
113-
The main script has to handle the conversion and load operations.
114-
115-
By introducing a main script, we can allow using different client libraries, if
116-
available, so there is no assumption about the language used, as long as it can
117-
accept parameters.
118-
119-
### Dataset
120-
121-
Consists of vectors and/or payloads. Scenario decides what to do with the data.
122-
123-
## Metrics
124-
125-
Metrics are being measured by the clients themselves and displayed on stdout.
126-
The benchmark will collect all the metrics and display some statistics at the
127-
end of each test.
128-
129-
All the displayed metrics should be printed in the following way:
130-
131-
```shell
132-
phase::kpi_name = 0.242142
133-
```
134-
135-
Where `0.242142` is a numerical value specific for the `kpi_name`. In the
136-
simplest case that might be a time spent in a specific operation, like:
137-
138-
```
139-
load::time = 0.0052424
140-
```
141-
142-
## Open topics
143-
144-
1. The list of supported KPIs should be still established and implemented by
145-
every single engine, so can be tracked in all the benchmark scenarios.
146-
2. What should be the format supported in the datasets? JSON lines are cross
147-
language and platform, what makes them easy to be parsed to whatever format
148-
a specific engine support.
149-
3. How do we handle engine errors?

engine/base_client/client.py

Lines changed: 26 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -14,19 +14,19 @@
1414

1515
class BaseClient:
1616
def __init__(
17-
self,
18-
name: str, # name of the experiment
19-
configurator: BaseConfigurator,
20-
uploader: BaseUploader,
21-
searchers: List[BaseSearcher],
17+
self,
18+
name: str, # name of the experiment
19+
configurator: BaseConfigurator,
20+
uploader: BaseUploader,
21+
searchers: List[BaseSearcher],
2222
):
2323
self.name = name
2424
self.configurator = configurator
2525
self.uploader = uploader
2626
self.searchers = searchers
2727

2828
def save_search_results(
29-
self, dataset_name: str, results: dict, search_id: int, search_params: dict
29+
self, dataset_name: str, results: dict, search_id: int, search_params: dict
3030
):
3131
now = datetime.now()
3232
timestamp = now.strftime("%Y-%m-%d-%H-%M-%S")
@@ -49,23 +49,29 @@ def save_upload_results(self, dataset_name: str, results: dict, upload_params: d
4949
}
5050
out.write(json.dumps(upload_stats, indent=2))
5151

52-
def run_experiment(self, dataset: Dataset):
53-
print("Experiment stage: Configure")
54-
execution_params = self.configurator.configure(
52+
def run_experiment(self, dataset: Dataset, skip_upload: bool = False):
53+
execution_params = self.configurator.execution_params(
5554
distance=dataset.config.distance,
56-
vector_size=dataset.config.vector_size,
57-
)
55+
vector_size=dataset.config.vector_size)
5856

5957
reader = dataset.get_reader(execution_params.get("normalize", False))
60-
print("Experiment stage: Upload")
61-
upload_stats = self.uploader.upload(
62-
distance=dataset.config.distance,
63-
records=reader.read_data()
64-
)
65-
self.save_upload_results(dataset.config.name, upload_stats, upload_params={
66-
**self.uploader.upload_params,
67-
**self.configurator.collection_params
68-
})
58+
59+
if not skip_upload:
60+
print("Experiment stage: Configure")
61+
self.configurator.configure(
62+
distance=dataset.config.distance,
63+
vector_size=dataset.config.vector_size,
64+
)
65+
66+
print("Experiment stage: Upload")
67+
upload_stats = self.uploader.upload(
68+
distance=dataset.config.distance,
69+
records=reader.read_data()
70+
)
71+
self.save_upload_results(dataset.config.name, upload_stats, upload_params={
72+
**self.uploader.upload_params,
73+
**self.configurator.collection_params
74+
})
6975

7076
print("Experiment stage: Search")
7177
for search_id, searcher in enumerate(self.searchers):

engine/base_client/configure.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,6 @@ def recreate(self, distance, vector_size, collection_params):
1818
def configure(self, distance, vector_size) -> Optional[dict]:
1919
self.clean()
2020
return self.recreate(distance, vector_size, self.collection_params) or {}
21+
22+
def execution_params(self, distance, vector_size) -> dict:
23+
return {}

engine/clients/milvus/configure.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,4 +65,5 @@ def recreate(
6565
for index in collection.indexes:
6666
index.drop()
6767

68+
def execution_params(self, distance, vector_size):
6869
return {"normalize": distance == Distance.COSINE}

engine/clients/qdrant/search.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
1+
import multiprocessing
12
from typing import List, Optional, Tuple
23

4+
import httpx
35
from qdrant_client import QdrantClient
46
from qdrant_client.http import models as rest
7+
from qdrant_client import grpc
58

69
from engine.base_client.search import BaseSearcher
710
from engine.clients.qdrant.config import QDRANT_COLLECTION_NAME
@@ -28,7 +31,7 @@ def search_one(cls, vector, meta_conditions, top) -> List[Tuple[int, float]]:
2831
query_vector=vector,
2932
query_filter=cls.conditions_to_filter(meta_conditions),
3033
limit=top,
31-
**cls.search_params
34+
search_params=rest.SearchParams(**cls.search_params.get("search_params", {})),
3235
)
33-
3436
return [(hit.id, hit.score) for hit in res]
37+

engine/servers/weaviate-single-node/docker-compose.yaml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@ services:
1818
DEFAULT_VECTORIZER_MODULE: 'none'
1919
ENABLE_MODULES: ''
2020
CLUSTER_HOSTNAME: 'node1'
21+
GOMEMLIMIT: 25GiB
22+
GOGC: 50
2123
deploy:
2224
resources:
2325
limits:
24-
memory: 25Gb
26+
memory: 27Gb

experiments/configurations/qdrant-single-node-rps.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
"hnsw_config": { "m": 16, "ef_construct": 128 }
99
},
1010
"search_params": [
11+
{ "parallel": 1, "search_params": { "hnsw_ef": 64 } }, { "parallel": 1, "search_params": { "hnsw_ef": 128 } }, { "parallel": 1, "search_params": { "hnsw_ef": 256 } }, { "parallel": 1, "search_params": { "hnsw_ef": 512 } },
1112
{ "parallel": 2, "search_params": { "hnsw_ef": 64 } }, { "parallel": 2, "search_params": { "hnsw_ef": 128 } }, { "parallel": 2, "search_params": { "hnsw_ef": 256 } }, { "parallel": 2, "search_params": { "hnsw_ef": 512 } },
1213
{ "parallel": 4, "search_params": { "hnsw_ef": 64 } }, { "parallel": 4, "search_params": { "hnsw_ef": 128 } }, { "parallel": 4, "search_params": { "hnsw_ef": 256 } }, { "parallel": 4, "search_params": { "hnsw_ef": 512 } },
1314
{ "parallel": 8, "search_params": { "hnsw_ef": 64 } }, { "parallel": 8, "search_params": { "hnsw_ef": 128 } }, { "parallel": 8, "search_params": { "hnsw_ef": 256 } }, { "parallel": 8, "search_params": { "hnsw_ef": 512 } },
@@ -24,6 +25,7 @@
2425
"hnsw_config": { "m": 32, "ef_construct": 128 }
2526
},
2627
"search_params": [
28+
{ "parallel": 1, "search_params": { "hnsw_ef": 64 } }, { "parallel": 1, "search_params": { "hnsw_ef": 128 } }, { "parallel": 1, "search_params": { "hnsw_ef": 256 } }, { "parallel": 1, "search_params": { "hnsw_ef": 512 } },
2729
{ "parallel": 2, "search_params": { "hnsw_ef": 64 } }, { "parallel": 2, "search_params": { "hnsw_ef": 128 } }, { "parallel": 2, "search_params": { "hnsw_ef": 256 } }, { "parallel": 2, "search_params": { "hnsw_ef": 512 } },
2830
{ "parallel": 4, "search_params": { "hnsw_ef": 64 } }, { "parallel": 4, "search_params": { "hnsw_ef": 128 } }, { "parallel": 4, "search_params": { "hnsw_ef": 256 } }, { "parallel": 4, "search_params": { "hnsw_ef": 512 } },
2931
{ "parallel": 8, "search_params": { "hnsw_ef": 64 } }, { "parallel": 8, "search_params": { "hnsw_ef": 128 } }, { "parallel": 8, "search_params": { "hnsw_ef": 256 } }, { "parallel": 8, "search_params": { "hnsw_ef": 512 } },
@@ -40,6 +42,7 @@
4042
"hnsw_config": { "m": 32, "ef_construct": 256 }
4143
},
4244
"search_params": [
45+
{ "parallel": 1, "search_params": { "hnsw_ef": 64 } }, { "parallel": 1, "search_params": { "hnsw_ef": 128 } }, { "parallel": 1, "search_params": { "hnsw_ef": 256 } }, { "parallel": 1, "search_params": { "hnsw_ef": 512 } },
4346
{ "parallel": 2, "search_params": { "hnsw_ef": 64 } }, { "parallel": 2, "search_params": { "hnsw_ef": 128 } }, { "parallel": 2, "search_params": { "hnsw_ef": 256 } }, { "parallel": 2, "search_params": { "hnsw_ef": 512 } },
4447
{ "parallel": 4, "search_params": { "hnsw_ef": 64 } }, { "parallel": 4, "search_params": { "hnsw_ef": 128 } }, { "parallel": 4, "search_params": { "hnsw_ef": 256 } }, { "parallel": 4, "search_params": { "hnsw_ef": 512 } },
4548
{ "parallel": 8, "search_params": { "hnsw_ef": 64 } }, { "parallel": 8, "search_params": { "hnsw_ef": 128 } }, { "parallel": 8, "search_params": { "hnsw_ef": 256 } }, { "parallel": 8, "search_params": { "hnsw_ef": 512 } },
@@ -56,6 +59,7 @@
5659
"hnsw_config": { "m": 32, "ef_construct": 512 }
5760
},
5861
"search_params": [
62+
{ "parallel": 1, "search_params": { "hnsw_ef": 64 } }, { "parallel": 1, "search_params": { "hnsw_ef": 128 } }, { "parallel": 1, "search_params": { "hnsw_ef": 256 } }, { "parallel": 1, "search_params": { "hnsw_ef": 512 } },
5963
{ "parallel": 2, "search_params": { "hnsw_ef": 64 } }, { "parallel": 2, "search_params": { "hnsw_ef": 128 } }, { "parallel": 2, "search_params": { "hnsw_ef": 256 } }, { "parallel": 2, "search_params": { "hnsw_ef": 512 } },
6064
{ "parallel": 4, "search_params": { "hnsw_ef": 64 } }, { "parallel": 4, "search_params": { "hnsw_ef": 128 } }, { "parallel": 4, "search_params": { "hnsw_ef": 256 } }, { "parallel": 4, "search_params": { "hnsw_ef": 512 } },
6165
{ "parallel": 8, "search_params": { "hnsw_ef": 64 } }, { "parallel": 8, "search_params": { "hnsw_ef": 128 } }, { "parallel": 8, "search_params": { "hnsw_ef": 256 } }, { "parallel": 8, "search_params": { "hnsw_ef": 512 } },
@@ -72,6 +76,7 @@
7276
"hnsw_config": { "m": 64, "ef_construct": 256 }
7377
},
7478
"search_params": [
79+
{ "parallel": 1, "search_params": { "hnsw_ef": 64 } }, { "parallel": 1, "search_params": { "hnsw_ef": 128 } }, { "parallel": 1, "search_params": { "hnsw_ef": 256 } }, { "parallel": 1, "search_params": { "hnsw_ef": 512 } },
7580
{ "parallel": 2, "search_params": { "hnsw_ef": 64 } }, { "parallel": 2, "search_params": { "hnsw_ef": 128 } }, { "parallel": 2, "search_params": { "hnsw_ef": 256 } }, { "parallel": 2, "search_params": { "hnsw_ef": 512 } },
7681
{ "parallel": 4, "search_params": { "hnsw_ef": 64 } }, { "parallel": 4, "search_params": { "hnsw_ef": 128 } }, { "parallel": 4, "search_params": { "hnsw_ef": 256 } }, { "parallel": 4, "search_params": { "hnsw_ef": 512 } },
7782
{ "parallel": 8, "search_params": { "hnsw_ef": 64 } }, { "parallel": 8, "search_params": { "hnsw_ef": 128 } }, { "parallel": 8, "search_params": { "hnsw_ef": 256 } }, { "parallel": 8, "search_params": { "hnsw_ef": 512 } },
@@ -88,6 +93,7 @@
8893
"hnsw_config": { "m": 64, "ef_construct": 512 }
8994
},
9095
"search_params": [
96+
{ "parallel": 1, "search_params": { "hnsw_ef": 64 } }, { "parallel": 1, "search_params": { "hnsw_ef": 128 } }, { "parallel": 1, "search_params": { "hnsw_ef": 256 } }, { "parallel": 1, "search_params": { "hnsw_ef": 512 } },
9197
{ "parallel": 2, "search_params": { "hnsw_ef": 64 } }, { "parallel": 2, "search_params": { "hnsw_ef": 128 } }, { "parallel": 2, "search_params": { "hnsw_ef": 256 } }, { "parallel": 2, "search_params": { "hnsw_ef": 512 } },
9298
{ "parallel": 4, "search_params": { "hnsw_ef": 64 } }, { "parallel": 4, "search_params": { "hnsw_ef": 128 } }, { "parallel": 4, "search_params": { "hnsw_ef": 256 } }, { "parallel": 4, "search_params": { "hnsw_ef": 512 } },
9399
{ "parallel": 8, "search_params": { "hnsw_ef": 64 } }, { "parallel": 8, "search_params": { "hnsw_ef": 128 } }, { "parallel": 8, "search_params": { "hnsw_ef": 256 } }, { "parallel": 8, "search_params": { "hnsw_ef": 512 } },

0 commit comments

Comments
 (0)