Skip to main content

A supabase-style embedded data port with semantic search as a first-class operator (single-engine DuckDB: vss + fts).

Project description

seekbase

一个 supabase 风格的数据端口,search() 做成一等算子——单引擎 DuckDB 一库通吃:结构化/分析、向量语义(vss/HNSW)、全文检索(fts/BM25),search() 是 hybrid(向量 + BM25 用 RRF 融合、中文用 jieba 分词);再加一份本地文件镜像用于审计。一个端口、一个文件、零运维。

两种使用形态,一套完全相同的 API:

形态 怎么拿到 db 跑在哪 什么时候用
嵌入(embedded) Seekbase.open(dir, schema=…) 进程内、DuckDB 单进程、本地优先、零运维
服务(server) Seekbase.connect(url) → 连一个运行中的 server HTTP 多客户端 / 多进程共享同一个实例

两种形态的调用代码逐字节相同——query(sql) / insert / delete 一个字都不用改,变的只有你怎么拿到 db 句柄。

状态:核心完整(单引擎 + 单表同步写)。 SQL query(结构化 + hybrid search() + ds 时间窗)、同步 ticket 写(insert/delete,主键写一次、重复报错)、文件镜像(每表 <表>.jsonl + rebuild)、检索侧(DuckDB vss+fts 就地长在业务表上,单引擎、无 LanceDB)、两种使用形态,今天都能跑。delete 只软删 deleted_ds 墓碑、历史永久保留,没有物理删/vacuum。完整设计见 DESIGN.md

安装

pip install seekbase   # 嵌入 + HTTP 客户端 + server(seekbase_server)+ ApiEmbedder,全部开箱即用

两种形态都是标配、无需任何 extra:嵌入、HTTP 客户端(Seekbase.connect)、以及把端口暴露成 HTTP 服务的 seekbase_server(db)——它是一个零依赖的手写 ASGI app。跑这个 app 的 ASGI runner 由你从外部注入(uvicorn / hypercorn / gunicorn,或挂进已有应用),seekbase 不绑定 runner。

嵌入形态(进程内)

from seekbase import Seekbase

SCHEMA = [
    {
        "table": "cards",
        "columns": [
            {"name": "card_id", "type": "str"},
            {"name": "issue",   "type": "str"},
            {"name": "kind",    "type": "str"},
        ],
        "primary": "card_id",
        "searchable": ["issue"],                 # 可 search() 的列(hybrid:vss 向量 + fts 全文)
    },
]

db = await Seekbase.open("./data", schema=SCHEMA)

# 写是同步的:返回 ticket(已落库),wait 立即返回
await db.wait(await db.insert("cards", {"card_id": "c1", "issue": "pty vs tmux", "kind": "issue"}))

# 读是 SQL:结构化 + 时光机(ds_start/ds_end)+ 语义 search() 都在这一个接口
rows = await db.query(
    "SELECT card_id, issue FROM cards WHERE kind = ? ORDER BY created_at DESC LIMIT 20",
    params=["issue"],
)

await db.delete("cards", where="card_id = ?", params=["c1"])   # 打墓碑,永不物理删

await db.close()

服务形态(HTTP)

起一个 server——它持有 schema(以及将来的 embedder),并拥有数据目录。seekbase_server(db) 给你一个裸 ASGI app,用你自己的 runner 跑:

# serve.py —— 用外部注入的 runner(这里是 uvicorn)
import uvicorn
from seekbase import Seekbase
from seekbase.server import seekbase_server

db = await Seekbase.open("./data", schema=SCHEMA)        # 就是上面那个嵌入 db
uvicorn.run(seekbase_server(db, api_key="secret"), host="0.0.0.0", port=8000)

也有个便捷函数 serve(db, host=…, port=…, api_key=…, runner=…):runner 是任意 runner(app, host=…, port=…) 可调用(默认用 uvicorn,前提是你装了它)。runner 始终由外部提供,seekbase 不把它作为依赖。

然后从任何地方连它——调用代码和嵌入形态一模一样,只有拿句柄这一步不同:

db = await Seekbase.connect("http://localhost:8000", api_key="secret")

await db.wait(await db.insert("cards", {"card_id": "c1", "issue": "pty vs tmux", "kind": "issue"}))
rows = await db.query("SELECT card_id, issue FROM cards WHERE kind = ?", params=["issue"])

await db.close()

读走 POST /v1/query、写走 POST /v1/insert(同步,返回已 done 的 ticket)。错误过线保型(server 侧抛的 ReadOnlyError,client 侧还是 ReadOnlyError)。鉴权是一个可选的 bearer token;时光机走 query(..., ds_end="20260601"),HTTP 上一样。

设计原则

  • 只增、引擎强制:没有 update/upsert;delete() 只写一列 deleted_at 墓碑。历史因此诚实——时光机对所有列都严谨。
  • 业务无关:不认识任何业务概念、不读任何 config——由你注入 data_dirschema,以及(要 search 时)一个 embedder
  • 调用方永远不见向量:声明 searchable 列;SQL 里 search(列, 'text') 自动 embed + jieba 分词 + hybrid 检索(每个可搜列各自一套 vss 向量 + fts 全文,RRF 融合)+ 在同一条 SQL 里和结构化过滤组合。

文档

  • DESIGN.md —— 整体设计
  • docs/api/ —— API 参考(query / insert / delete / admin / setup,每个接口的请求·响应·错误)
  • docs/works/ —— 专题设计:store.md(两层存储 files/DuckDB)、search.md(vss+fts hybrid 检索)

Apache-2.0。

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

seekbase-0.0.1.tar.gz (108.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

seekbase-0.0.1-py3-none-any.whl (49.2 kB view details)

Uploaded Python 3

File details

Details for the file seekbase-0.0.1.tar.gz.

File metadata

  • Download URL: seekbase-0.0.1.tar.gz
  • Upload date:
  • Size: 108.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.2

File hashes

Hashes for seekbase-0.0.1.tar.gz
Algorithm Hash digest
SHA256 7289fb5eaf031e82a8aa5378083cf15fbb8dd00499139c0635d62d384ccd1ea8
MD5 5e354cc98e8ca53fe74b700e38017d27
BLAKE2b-256 d4df84efcdcb71449013cbc8b9311d57fd96838545e946b20351a64849ca6d91

See more details on using hashes here.

File details

Details for the file seekbase-0.0.1-py3-none-any.whl.

File metadata

  • Download URL: seekbase-0.0.1-py3-none-any.whl
  • Upload date:
  • Size: 49.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.2

File hashes

Hashes for seekbase-0.0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 f69cf57e6e679699d225015159745be16d63e66483b3d4b07edc43be42f703db
MD5 48164638b1f42a4668eb47356ba9a21c
BLAKE2b-256 6ee0342c59d0fbe79da52c06413b4e0bcdcabd09c995376ee60c00030178de28

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page