Skip to content

Commit c2f1c51

Browse files
expose turbopuffer through CLI and make compatible with latest sdk (#667)
1 parent 45d1ff5 commit c2f1c51

5 files changed

Lines changed: 79 additions & 13 deletions

File tree

pyproject.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ all = [
7575
"pyvespa",
7676
"lancedb",
7777
"mysql-connector-python",
78+
"turbopuffer[fast]",
7879
]
7980

8081
qdrant = [ "qdrant-client" ]
@@ -102,6 +103,7 @@ lancedb = [ "lancedb" ]
102103
oceanbase = [ "mysql-connector-python" ]
103104
alisql = [ "mysql-connector-python" ]
104105
doris = [ "doris-vector-search" ]
106+
turbopuffer = [ "turbopuffer" ]
105107

106108
[project.urls]
107109
"repository" = "https://github.com/zilliztech/VectorDBBench"

vectordb_bench/backend/clients/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ class DB(Enum):
5555
TencentElasticsearch = "TencentElasticsearch"
5656
AliSQL = "AlibabaCloudRDSMySQL"
5757
Doris = "Doris"
58-
TurboPuffer = "TurpoBuffer"
58+
TurboPuffer = "TurboPuffer"
5959

6060
@property
6161
def init_cls(self) -> type[VectorDB]: # noqa: PLR0911, PLR0912, C901, PLR0915
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
from typing import Annotated, TypedDict, Unpack
2+
3+
import click
4+
from pydantic import SecretStr
5+
6+
from ....cli.cli import (
7+
CommonTypedDict,
8+
cli,
9+
click_parameter_decorators_from_typed_dict,
10+
run,
11+
)
12+
from .. import DB
13+
14+
15+
class TurboPufferTypedDict(TypedDict):
16+
api_key: Annotated[
17+
str,
18+
click.option("--api-key", type=str, help="TurboPuffer API key", required=True),
19+
]
20+
api_base_url: Annotated[
21+
str,
22+
click.option(
23+
"--api-base-url",
24+
type=str,
25+
help="TurboPuffer API base URL",
26+
required=False,
27+
default="https://api.turbopuffer.com",
28+
show_default=True,
29+
),
30+
]
31+
namespace: Annotated[
32+
str,
33+
click.option(
34+
"--namespace",
35+
type=str,
36+
help="TurboPuffer namespace",
37+
required=False,
38+
default="vdbbench_test",
39+
show_default=True,
40+
),
41+
]
42+
43+
44+
class TurboPufferIndexTypedDict(CommonTypedDict, TurboPufferTypedDict): ...
45+
46+
47+
@cli.command()
48+
@click_parameter_decorators_from_typed_dict(TurboPufferIndexTypedDict)
49+
def TurboPuffer(**parameters: Unpack[TurboPufferIndexTypedDict]):
50+
from .config import TurboPufferConfig, TurboPufferIndexConfig
51+
52+
run(
53+
db=DB.TurboPuffer,
54+
db_config=TurboPufferConfig(
55+
db_label=parameters["db_label"],
56+
api_key=SecretStr(parameters["api_key"]),
57+
api_base_url=parameters["api_base_url"],
58+
namespace=parameters["namespace"],
59+
),
60+
db_case_config=TurboPufferIndexConfig(),
61+
**parameters,
62+
)

vectordb_bench/backend/clients/turbopuffer/turbopuffer.py

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -42,21 +42,21 @@ def __init__(
4242
self._scalar_label_field = "label"
4343

4444
self.with_scalar_labels = with_scalar_labels
45+
46+
# Initialize client with new SDK pattern
47+
self.client = tpuf.Turbopuffer(api_key=self.api_key, base_url=self.api_base_url)
48+
4549
if drop_old:
4650
log.info(f"Drop old. delete the namespace: {self.namespace}")
47-
tpuf.api_key = self.api_key
48-
tpuf.api_base_url = self.api_base_url
49-
ns = tpuf.Namespace(self.namespace)
51+
ns = self.client.namespace(self.namespace)
5052
try:
5153
ns.delete_all()
5254
except Exception as e:
5355
log.warning(f"Failed to delete all. Error: {e}")
5456

5557
@contextmanager
5658
def init(self):
57-
tpuf.api_key = self.api_key
58-
tpuf.api_base_url = self.api_base_url
59-
self.ns = tpuf.Namespace(self.namespace)
59+
self.ns = self.client.namespace(self.namespace)
6060
yield
6161

6262
def optimize(self, data_size: int | None = None):
@@ -78,7 +78,7 @@ def insert_embeddings(
7878
try:
7979
if self.with_scalar_labels:
8080
self.ns.write(
81-
upsert_columns={
81+
columns={
8282
self._scalar_id_field: metadata,
8383
self._vector_field: embeddings,
8484
self._scalar_label_field: labels_data,
@@ -87,7 +87,7 @@ def insert_embeddings(
8787
)
8888
else:
8989
self.ns.write(
90-
upsert_columns={
90+
columns={
9191
self._scalar_id_field: metadata,
9292
self._vector_field: embeddings,
9393
},
@@ -104,19 +104,19 @@ def search_embedding(
104104
timeout: int | None = None,
105105
) -> list[int]:
106106
res = self.ns.query(
107-
rank_by=["vector", "ANN", query],
107+
rank_by=("vector", "ANN", query),
108108
top_k=k,
109109
filters=self.expr,
110110
)
111-
return [row.id for row in res.rows]
111+
return [row.id for row in res.rows] if res.rows is not None else []
112112

113113
def prepare_filter(self, filters: Filter):
114114
if filters.type == FilterOp.NonFilter:
115115
self.expr = None
116116
elif filters.type == FilterOp.NumGE:
117-
self.expr = [self._scalar_id_field, "Gte", filters.int_value]
117+
self.expr = (self._scalar_id_field, "Gte", filters.int_value)
118118
elif filters.type == FilterOp.StrEqual:
119-
self.expr = [self._scalar_label_field, "Eq", filters.label_value]
119+
self.expr = (self._scalar_label_field, "Eq", filters.label_value)
120120
else:
121121
msg = f"Not support Filter for TurboPuffer - {filters}"
122122
raise ValueError(msg)

vectordb_bench/cli/vectordbbench.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
from ..backend.clients.tencent_elasticsearch.cli import TencentElasticsearch
2929
from ..backend.clients.test.cli import Test
3030
from ..backend.clients.tidb.cli import TiDB
31+
from ..backend.clients.turbopuffer.cli import TurboPuffer
3132
from ..backend.clients.vespa.cli import Vespa
3233
from ..backend.clients.weaviate_cloud.cli import Weaviate
3334
from ..backend.clients.zilliz_cloud.cli import ZillizAutoIndex
@@ -68,6 +69,7 @@
6869
cli.add_command(TencentElasticsearch)
6970
cli.add_command(AliSQLHNSW)
7071
cli.add_command(Doris)
72+
cli.add_command(TurboPuffer)
7173

7274

7375
if __name__ == "__main__":

0 commit comments

Comments
 (0)