Skip to content

Commit 34e8f25

Browse files
authored
Added Endee Client Support (#711)
* Added Endee Client Support * Reformatted 4 files with black * Validated linting with ruff
1 parent 5e92b4f commit 34e8f25

8 files changed

Lines changed: 429 additions & 0 deletions

File tree

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ All the database client supported
6464
| alisql | `pip install 'vectordb-bench[alisql]'` |
6565
| doris | `pip install vectordb-bench[doris]` |
6666
| zvec | `pip install vectordb-bench[zvec]` |
67+
| endee | `pip install vectordb-bench[endee]` |
6768

6869
### Run
6970

pyproject.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ all = [
7979
"mysql-connector-python",
8080
"turbopuffer[fast]",
8181
'zvec',
82+
"endee",
8283
]
8384

8485
qdrant = [ "qdrant-client" ]
@@ -108,6 +109,7 @@ alisql = [ "mysql-connector-python" ]
108109
doris = [ "doris-vector-search" ]
109110
turbopuffer = [ "turbopuffer" ]
110111
zvec = [ "zvec" ]
112+
endee = [ "endee" ]
111113

112114
[project.urls]
113115
Repository = "https://github.com/zilliztech/VectorDBBench"

vectordb_bench/backend/clients/__init__.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ class DB(Enum):
5757
Doris = "Doris"
5858
TurboPuffer = "TurboPuffer"
5959
Zvec = "Zvec"
60+
Endee = "Endee"
6061

6162
@property
6263
def init_cls(self) -> type[VectorDB]: # noqa: PLR0911, PLR0912, C901, PLR0915
@@ -229,6 +230,11 @@ def init_cls(self) -> type[VectorDB]: # noqa: PLR0911, PLR0912, C901, PLR0915
229230

230231
return AliSQL
231232

233+
if self == DB.Endee:
234+
from .endee.endee import Endee
235+
236+
return Endee
237+
232238
if self == DB.Zvec:
233239
from .zvec.zvec import Zvec
234240

@@ -408,6 +414,11 @@ def config_cls(self) -> type[DBConfig]: # noqa: PLR0911, PLR0912, C901, PLR0915
408414

409415
return AliSQLConfig
410416

417+
if self == DB.Endee:
418+
from .endee.config import EndeeConfig
419+
420+
return EndeeConfig
421+
411422
if self == DB.Zvec:
412423
from .zvec.config import ZvecConfig
413424

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
import logging
2+
import uuid
3+
from typing import Annotated
4+
5+
import click
6+
7+
from vectordb_bench.cli.cli import (
8+
CommonTypedDict,
9+
benchmark_runner,
10+
click_parameter_decorators_from_typed_dict,
11+
get_custom_case_config,
12+
parse_task_stages,
13+
)
14+
from vectordb_bench.models import (
15+
CaseConfig,
16+
CaseType,
17+
ConcurrencySearchConfig,
18+
TaskConfig,
19+
)
20+
21+
from .. import DB
22+
from ..api import EmptyDBCaseConfig
23+
from .config import EndeeConfig
24+
25+
log = logging.getLogger(__name__)
26+
27+
28+
class EndeeTypedDict(CommonTypedDict):
29+
token: Annotated[str, click.option("--token", type=str, required=True, default=None, help="Endee API token")]
30+
region: Annotated[str, click.option("--region", type=str, default=None, help="Endee region", show_default=True)]
31+
base_url: Annotated[
32+
str,
33+
click.option(
34+
"--base-url", type=str, default="http://127.0.0.1:8080/api/v1", help="API server URL", show_default=True
35+
),
36+
]
37+
space_type: Annotated[
38+
str,
39+
click.option(
40+
"--space-type",
41+
type=click.Choice(["cosine", "l2", "dot_product"]),
42+
default="cosine",
43+
help="Distance metric",
44+
show_default=True,
45+
),
46+
]
47+
precision: Annotated[
48+
str,
49+
click.option(
50+
"--precision",
51+
type=click.Choice(["binary", "int8d", "int16d", "float16", "float32"]),
52+
default="int8d",
53+
help="Quant Level",
54+
show_default=True,
55+
),
56+
]
57+
version: Annotated[int, click.option("--version", type=int, default=None, help="Index version", show_default=True)]
58+
m: Annotated[int, click.option("--m", type=int, default=None, help="HNSW M parameter", show_default=True)]
59+
ef_con: Annotated[
60+
int, click.option("--ef-con", type=int, default=None, help="HNSW construction parameter", show_default=True)
61+
]
62+
ef_search: Annotated[
63+
int, click.option("--ef-search", type=int, default=None, help="HNSW search parameter", show_default=True)
64+
]
65+
index_name: Annotated[
66+
str,
67+
click.option(
68+
"--index-name",
69+
type=str,
70+
required=True,
71+
help="Endee index name (will use a random name if not provided)",
72+
show_default=True,
73+
),
74+
]
75+
76+
77+
@click.command()
78+
@click_parameter_decorators_from_typed_dict(EndeeTypedDict)
79+
def Endee(**parameters):
80+
"""
81+
Run VectorDBBench against Endee VectorDB.
82+
"""
83+
stages = parse_task_stages(
84+
parameters["drop_old"],
85+
parameters["load"],
86+
parameters["search_serial"],
87+
parameters["search_concurrent"],
88+
)
89+
90+
# Generate a random collection name if not provided
91+
collection_name = parameters["index_name"]
92+
if not collection_name:
93+
collection_name = f"endee_bench_{uuid.uuid4().hex[:8]}"
94+
95+
# Filter out None values before creating config
96+
params_for_nd = {k: v for k, v in parameters.items() if v is not None}
97+
db_config = EndeeConfig(**params_for_nd)
98+
99+
custom_case_config = get_custom_case_config(parameters)
100+
101+
db_case_config = EmptyDBCaseConfig()
102+
103+
task = TaskConfig(
104+
db=DB.Endee,
105+
db_config=db_config,
106+
db_case_config=db_case_config,
107+
case_config=CaseConfig(
108+
case_id=CaseType[parameters["case_type"]],
109+
k=parameters["k"],
110+
concurrency_search_config=ConcurrencySearchConfig(
111+
concurrency_duration=parameters["concurrency_duration"],
112+
num_concurrency=[int(s) for s in parameters["num_concurrency"]],
113+
concurrency_timeout=parameters["concurrency_timeout"],
114+
),
115+
custom_case=custom_case_config,
116+
),
117+
stages=stages,
118+
)
119+
120+
# Use the run method of the benchmark_runner object
121+
if not parameters["dry_run"]:
122+
# Generate task label
123+
run_uuid = uuid.uuid4().hex
124+
base_name = parameters.get("task_label")
125+
if not base_name:
126+
base_name = parameters.get("index_name", "endee")
127+
128+
final_label = f"{base_name}_{run_uuid}"
129+
130+
# Run the benchmark
131+
benchmark_runner.run([task], final_label)
132+
133+
# Wait for task to complete
134+
import time
135+
from concurrent.futures import wait
136+
137+
from vectordb_bench.interface import global_result_future
138+
139+
time.sleep(5)
140+
if global_result_future:
141+
wait([global_result_future])
142+
143+
# Ensure CLI doesn't close while background processes are active
144+
while benchmark_runner.has_running():
145+
time.sleep(1)
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
from pydantic import SecretStr
2+
3+
from vectordb_bench.backend.clients.api import DBConfig
4+
5+
6+
class EndeeConfig(DBConfig):
7+
token: SecretStr | None = None
8+
region: str | None = "as1"
9+
base_url: str = "http://127.0.0.1:8080/api/v1"
10+
space_type: str = "cosine"
11+
precision: str = "int8d"
12+
version: int | None = 1
13+
m: int | None = 16
14+
ef_con: int | None = 128
15+
ef_search: int | None = 128
16+
index_name: str
17+
18+
def to_dict(self) -> dict:
19+
return {
20+
"token": self.token.get_secret_value() if self.token else None,
21+
"region": self.region,
22+
"base_url": self.base_url,
23+
"space_type": self.space_type,
24+
"precision": self.precision,
25+
"version": self.version,
26+
"m": self.m,
27+
"ef_con": self.ef_con,
28+
"ef_search": self.ef_search,
29+
"index_name": self.index_name,
30+
}

0 commit comments

Comments
 (0)