Skip to content

Commit 5cfca2e

Browse files
committed
add redis
1 parent de415eb commit 5cfca2e

File tree

23 files changed

+504
-59
lines changed

23 files changed

+504
-59
lines changed

benchmark/config_read.py

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import glob
2+
import json
3+
import os
4+
5+
from benchmark import ROOT_DIR, DATASETS_DIR
6+
7+
8+
def read_engine_configs() -> dict:
9+
all_configs = {}
10+
engines_config_dir = os.path.join(ROOT_DIR, "experiments", "configurations")
11+
config_files = glob.glob(os.path.join(engines_config_dir, "*.json"))
12+
for config_file in config_files:
13+
with open(config_file, "r") as fd:
14+
configs = json.load(fd)
15+
for config in configs:
16+
all_configs[config["name"]] = config
17+
18+
return all_configs
19+
20+
21+
def read_dataset_config():
22+
all_configs = {}
23+
datasets_config_path = DATASETS_DIR / "datasets.json"
24+
with open(datasets_config_path, "r") as fd:
25+
configs = json.load(fd)
26+
for config in configs:
27+
all_configs[config["name"]] = config
28+
return all_configs

engine/base_client/search.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -85,9 +85,9 @@ def search_all(
8585
total_time = time.perf_counter() - start
8686
return {
8787
"total_time": total_time,
88-
"mean_time": np.std(latencies),
88+
"mean_time": np.mean(latencies),
8989
"mean_precisions": np.mean(precisions),
90-
"std_time": np.mean(latencies),
90+
"std_time": np.std(latencies),
9191
"min_time": np.min(latencies),
9292
"max_time": np.max(latencies),
9393
"rps": len(latencies) / total_time,

engine/clients/client_factory.py

+6
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@
1212
from engine.clients.elasticsearch.upload import ElasticUploader
1313
from engine.clients.milvus import MilvusConfigurator, MilvusSearcher, MilvusUploader
1414
from engine.clients.qdrant import QdrantConfigurator, QdrantSearcher, QdrantUploader
15+
from engine.clients.redis_single_node.configure import RedisConfigurator
16+
from engine.clients.redis_single_node.search import RedisSearcher
17+
from engine.clients.redis_single_node.upload import RedisUploader
1518
from engine.clients.weaviate import (
1619
WeaviateConfigurator,
1720
WeaviateSearcher,
@@ -23,20 +26,23 @@
2326
"weaviate": WeaviateConfigurator,
2427
"milvus": MilvusConfigurator,
2528
"elastic": ElasticConfigurator,
29+
"redis": RedisConfigurator,
2630
}
2731

2832
ENGINE_UPLOADERS = {
2933
"qdrant": QdrantUploader,
3034
"weaviate": WeaviateUploader,
3135
"milvus": MilvusUploader,
3236
"elastic": ElasticUploader,
37+
"redis": RedisUploader,
3338
}
3439

3540
ENGINE_SEARCHERS = {
3641
"qdrant": QdrantSearcher,
3742
"weaviate": WeaviateSearcher,
3843
"milvus": MilvusSearcher,
3944
"elastic": ElasticSearcher,
45+
"redis": RedisSearcher,
4046
}
4147

4248

engine/clients/qdrant/upload.py

+8-5
Original file line numberDiff line numberDiff line change
@@ -32,18 +32,21 @@ def upload_batch(
3232

3333
@classmethod
3434
def post_upload(cls, _distance):
35-
cls.wait_collection_green()
36-
time.sleep(1.0)
3735
cls.wait_collection_green()
3836
return {}
3937

4038
@classmethod
4139
def wait_collection_green(cls):
42-
wait_time = 1.0
40+
wait_time = 5.0
4341
total = 0
44-
collection_info = cls.client.get_collection(QDRANT_COLLECTION_NAME)
45-
while collection_info.status != CollectionStatus.GREEN:
42+
while True:
4643
time.sleep(wait_time)
4744
total += wait_time
4845
collection_info = cls.client.get_collection(QDRANT_COLLECTION_NAME)
46+
if collection_info.status != CollectionStatus.GREEN:
47+
continue
48+
time.sleep(wait_time)
49+
collection_info = cls.client.get_collection(QDRANT_COLLECTION_NAME)
50+
if collection_info.status == CollectionStatus.GREEN:
51+
break
4952
return total

engine/clients/redis_single_node/__init__.py

Whitespace-only changes.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
REDIS_INDEX_NAME = "benchmark"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import redis
2+
from redis.commands.search.field import VectorField
3+
4+
from engine.base_client.configure import BaseConfigurator
5+
from engine.base_client.distances import Distance
6+
7+
8+
class RedisConfigurator(BaseConfigurator):
9+
DISTANCE_MAPPING = {
10+
Distance.L2: "L2",
11+
Distance.COSINE: "COSINE",
12+
Distance.DOT: "IP",
13+
}
14+
15+
def __init__(self, host, collection_params: dict, connection_params: dict):
16+
super().__init__(host, collection_params, connection_params)
17+
18+
self.client = redis.Redis(host=host, port=6379, db=0)
19+
20+
def clean(self):
21+
index = self.client.ft()
22+
try:
23+
index.dropindex(delete_documents=True)
24+
except redis.ResponseError as e:
25+
print(e)
26+
27+
def recreate(
28+
self,
29+
distance,
30+
vector_size,
31+
collection_params,
32+
):
33+
self.clean()
34+
index = self.client.ft()
35+
index.create_index(
36+
fields=[VectorField(
37+
name="vector",
38+
algorithm="HNSW",
39+
attributes={
40+
"TYPE": "FLOAT32",
41+
"DIM": vector_size,
42+
"DISTANCE_METRIC": self.DISTANCE_MAPPING[distance],
43+
**self.collection_params.get('hnsw_config', {}),
44+
}
45+
)]
46+
)
47+
48+
49+
if __name__ == '__main__':
50+
pass
+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
from typing import List, Tuple
2+
3+
import numpy as np
4+
import redis
5+
from redis.commands.search.query import Query
6+
7+
from engine.base_client.search import BaseSearcher
8+
9+
10+
class RedisSearcher(BaseSearcher):
11+
search_params = {}
12+
client = None
13+
14+
@classmethod
15+
def init_client(cls, host, distance, connection_params: dict, search_params: dict):
16+
cls.client = redis.Redis(host=host, port=6379, db=0)
17+
cls.search_params = search_params
18+
19+
@classmethod
20+
def search_one(cls, vector, meta_conditions, top) -> List[Tuple[int, float]]:
21+
q = Query(f'*=>[KNN $K @vector $vec_param EF_RUNTIME $EF AS vector_score]') \
22+
.sort_by('vector_score') \
23+
.paging(0, top) \
24+
.return_fields('vector_score') \
25+
.dialect(2)
26+
params_dict = {
27+
"vec_param": np.array(vector).astype(np.float32).tobytes(),
28+
"K": top,
29+
"EF": cls.search_params['search_params']["ef"],
30+
}
31+
32+
results = cls.client.ft().search(q, query_params=params_dict)
33+
34+
return [(int(result.id), float(result.vector_score)) for result in results.docs]
+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
from typing import List, Optional
2+
3+
import numpy as np
4+
import redis
5+
6+
from engine.base_client.upload import BaseUploader
7+
8+
9+
class RedisUploader(BaseUploader):
10+
client = None
11+
upload_params = {}
12+
13+
@classmethod
14+
def init_client(cls, host, distance, connection_params, upload_params):
15+
cls.client = redis.Redis(host=host, port=6379, db=0)
16+
cls.upload_params = upload_params
17+
18+
@classmethod
19+
def upload_batch(
20+
cls, ids: List[int], vectors: List[list], metadata: Optional[List[dict]]
21+
):
22+
23+
p = cls.client.pipeline(transaction=False)
24+
for i in range(len(ids)):
25+
idx = ids[i]
26+
vec = vectors[i]
27+
meta = metadata[i] if metadata else {}
28+
meta = meta or {}
29+
cls.client.hset(str(idx), mapping={
30+
"vector": np.array(vec).astype(np.float32).tobytes(),
31+
**meta
32+
})
33+
p.execute()
34+
35+
@classmethod
36+
def post_upload(cls, _distance):
37+
return {}
38+
39+

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

+4
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,7 @@ services:
1212
ports:
1313
- "9200:9200"
1414
- "9300:9300"
15+
deploy:
16+
resources:
17+
limits:
18+
memory: 25Gb

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

+4-2
Original file line numberDiff line numberDiff line change
@@ -34,13 +34,15 @@ services:
3434
environment:
3535
ETCD_ENDPOINTS: etcd:2379
3636
MINIO_ADDRESS: minio:9000
37-
volumes:
38-
- ${DOCKER_VOLUME_DIRECTORY:-.}/volumes/milvus:/var/lib/milvus
3937
ports:
4038
- "19530:19530"
4139
depends_on:
4240
- "etcd"
4341
- "minio"
42+
deploy:
43+
resources:
44+
limits:
45+
memory: 25Gb
4446

4547
networks:
4648
default:

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

+5-1
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,8 @@ version: '3.7'
33
services:
44
qdrant_bench:
55
image: qdrant/qdrant:v0.8.6
6-
network_mode: host
6+
network_mode: host
7+
deploy:
8+
resources:
9+
limits:
10+
memory: 25Gb
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
version: "3.7"
2+
3+
services:
4+
redis:
5+
image: redislabs/redisearch:2.4.13
6+
ports:
7+
- '6379:6379'

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

+5-3
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,14 @@ services:
1111
image: semitechnologies/weaviate:1.14.1
1212
ports:
1313
- "8090:8090"
14-
volumes:
15-
- ./data/storage:/var/lib/weaviate
1614
environment:
1715
QUERY_DEFAULTS_LIMIT: 10
1816
AUTHENTICATION_ANONYMOUS_ACCESS_ENABLED: 'true'
1917
PERSISTENCE_DATA_PATH: '/var/lib/weaviate'
2018
DEFAULT_VECTORIZER_MODULE: 'none'
2119
ENABLE_MODULES: ''
22-
CLUSTER_HOSTNAME: 'node1'
20+
CLUSTER_HOSTNAME: 'node1'
21+
deploy:
22+
resources:
23+
limits:
24+
memory: 25Gb

experiments/configurations/elastic-single-node.json

+7-7
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"name": "elastic-default",
44
"engine": "elastic",
55
"connection_params": {
6-
"request_timeout": 1000
6+
"request_timeout": 10000
77
},
88
"collection_params": { "index_options": { "m": 16, "ef_construction": 100 } },
99
"search_params": [
@@ -19,7 +19,7 @@
1919
"name": "elastic-m-16-ef-128",
2020
"engine": "elastic",
2121
"connection_params": {
22-
"request_timeout": 1000
22+
"request_timeout": 10000
2323
},
2424
"collection_params": { "index_options": { "m": 16, "ef_construction": 128 } },
2525
"search_params": [
@@ -35,7 +35,7 @@
3535
"name": "elastic-m-32-ef-128",
3636
"engine": "elastic",
3737
"connection_params": {
38-
"request_timeout": 1000
38+
"request_timeout": 10000
3939
},
4040
"collection_params": { "index_options": { "m": 32, "ef_construction": 128 } },
4141
"search_params": [
@@ -51,7 +51,7 @@
5151
"name": "elastic-m-32-ef-256",
5252
"engine": "elastic",
5353
"connection_params": {
54-
"request_timeout": 1000
54+
"request_timeout": 10000
5555
},
5656
"collection_params": { "index_options": { "m": 32, "ef_construction": 256 } },
5757
"search_params": [
@@ -67,7 +67,7 @@
6767
"name": "elastic-m-32-ef-512",
6868
"engine": "elastic",
6969
"connection_params": {
70-
"request_timeout": 1000
70+
"request_timeout": 10000
7171
},
7272
"collection_params": { "index_options": { "m": 32, "ef_construction": 512 } },
7373
"search_params": [
@@ -83,7 +83,7 @@
8383
"name": "elastic-m-64-ef-256",
8484
"engine": "elastic",
8585
"connection_params": {
86-
"request_timeout": 1000
86+
"request_timeout": 10000
8787
},
8888
"collection_params": { "index_options": { "m": 64, "ef_construction": 256 } },
8989
"search_params": [
@@ -99,7 +99,7 @@
9999
"name": "elastic-m-64-ef-512",
100100
"engine": "elastic",
101101
"connection_params": {
102-
"request_timeout": 1000
102+
"request_timeout": 10000
103103
},
104104
"collection_params": { "index_options": { "m": 64, "ef_construction": 512 } },
105105
"search_params": [

0 commit comments

Comments
 (0)