跳转到主要内容
Schema 说明是什么;路由决定放在哪里。

1. 路由做什么

路由将每个实体字段映射到一个或多个后端实例与存储策略。单个实体可把标量字段放在一个后端、向量放在另一个、可搜索文本放在第三个,而查询仍从 ws.query(Entity) 开始。 查询时,HeavenBase 为拥有该字段的后端编译每个 filter 或 near 子句,执行受支持的片段,再按 object_id 合并结果帧。
object_id 放置是固定的。HeavenBase 在需要处复制身份,使拆分字段仍能水合成一行逻辑行。

2. 从自动放置开始

工作区 preset 选择实用默认值。在 debug 中,普通行去 main,向量字段可路由到 vec,面向搜索的字段可路由到 search
import heavenbase as hb


class Document(hb.Entity):
    title = hb.field(hb.ShortText)
    body = hb.field(hb.LongText)
    embedding = hb.field(hb.Vector[2])


ws = hb.HeavenBase("core-routing-auto", preset="debug")
ws.register(Document)

ws.upsert_many(
    Document,
    [
        {"object_id": "d1", "name": "Agent routing", "title": "Agent routing", "body": "Agents query one surface.", "embedding": [1.0, 0.0]},
        {"object_id": "d2", "name": "Backend notes", "title": "Backend notes", "body": "Backends store fields.", "embedding": [0.0, 1.0]},
    ],
)

frame = ws.query(Document).near(Document.embedding, [1.0, 0.0], top_k=1).select("title", "score").execute()
print(frame.rows()[0]["title"])

3. 显式放置字段

字段必须落在特定后端时,使用 .store(to=..., strategy=...)
class RoutedDocument(hb.Entity):
    title = hb.field(hb.ShortText).store(to="main")
    body = hb.field(hb.LongText).store(to="main")
    embedding = hb.field(hb.Vector[2]).store(to="vec", strategy=hb.VectorIndex)


ws = hb.HeavenBase(
    "core-routing-explicit",
    backends={
        "main": {"type": "inmem"},
        "vec": {"type": "inmem"},
    },
)
ws.register(RoutedDocument)

routes = (
    ws.query(hb.MetaSchema)
    .where(hb.MetaSchema.kind == "storage")
    .where(hb.MetaSchema.subject_id == "routed-document")
    .select("field", "backend", "strategy")
    .execute()
    .rows()
)

print([(row["field"], row["backend"]) for row in routes])
存储策略是面向后端的提示,例如 InlineColumnSideTableVectorIndexInvertedIndexJsonFieldGraphEdgeExternalRef。多数用户只需显式指定 VectorIndex

4. 检查查询决策

需要查看查询将使用哪个后端与处理器时,用 explain()
plan = (
    ws.query(RoutedDocument)
    .near(RoutedDocument.embedding, [1.0, 0.0], top_k=3)
    .explain()
)

print(plan["steps"][0]["backend"])
每一步报告所选后端、存储策略、处理器种类、处理器模式,以及原生路径不可用时的 unsupported 原因。

5. 保持心智模型简单

对应用代码,按此顺序思考:
  1. 定义实体一次。
  2. 让 preset 自动路由字段。
  3. 仅对需要显式放置的字段添加 .store(...)
  4. 关心性能或后端选择时用 explain()
跨后端写入在多后端边界上是尽力而为。部署尚无清晰事务策略前,保持跨后端不变量简单。

进一步探索

相关资源:
  • 实体 - 声明类型化字段
  • 后端 - 了解后端选择
  • 查询 - 执行并解释路由后的查询
  • 架构 - 路由背后的系统结构