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

Lines changed: 28 additions & 0 deletions
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

Lines changed: 2 additions & 2 deletions
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

Lines changed: 6 additions & 0 deletions
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

Lines changed: 8 additions & 5 deletions
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.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
REDIS_INDEX_NAME = "benchmark"
Lines changed: 50 additions & 0 deletions
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
Lines changed: 34 additions & 0 deletions
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]
Lines changed: 39 additions & 0 deletions
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

Lines changed: 4 additions & 0 deletions
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

0 commit comments

Comments
 (0)