上下文加载 · Cypher 查询 API (0.1.4)

Download OpenAPI specification:

用只读 Cypher 查知识网络:标签是对象类,关系类型是关系类,属性是逻辑属性名。 本服务不自带查询语言实现——它把请求带着调用方身份转给 bkn-backend,由那边按 知识网络的模型把 Cypher 编译成一条 SQL 下发,再把行返回来。

与其他查询入口的分工:

  • object-instance.yaml 的 query_object_instance: 单个对象类的平面过滤,不跨关系。
  • instance-subgraph.yaml 的 query_instance_subgraph / explore_subgraph:要的是子图(节点 + 边的拓扑)。
  • 本接口:要的是表(按路径过滤后投影出的行,可聚合、可排序、可分页), 路径与条件写在一句 Cypher 里。
  • data-access.yaml 的 run_sql:绕开本体直查物理表。 本接口表达不了的口径(CTE、窗口函数)或资源没建成对象类时才落到那里。

不需要 resource_id,也不需要物理列名——名字全部取自 schema-search.yaml 的 search_schema 或 kn-explore.yaml 的 get_object_types / get_relation_types。

授权:由 bkn-backend 按调用方账户裁决——语句点名的每个对象类与关系类都要有 query_data(网络级授权会继承到其下的对象类与关系类),再往下 vega 对每个资源 校验读取权限。无权查询的概念在编译用的模型里直接不存在,写了只会报「未知标签」, 而不是「无权」,所以不能拿本接口探测模型里有什么。本服务只做转发,不放大调用方能 读的范围。

认证:Authorization: Bearer <token>(OAuth access token 或 bak_ AppKey)。

Cypher

对知识网络执行只读 Cypher

编译并执行一条只读 Cypher 语句。支持的子集:

  • MATCH:一个或多个 MATCH 子句;一个 MATCH 里可以写逗号分隔的多条路径。 同名变量指同一个节点;不共享变量的部分两两组合,但有两部分既没连起来、又都没有任何条件时, 查询会被拒(400 Unsupported)。
  • 节点:变量首次出现时必须带标签(对象类 id 或名称),可带内联属性 {prop: value}。
  • 关系:-[:R]->、<-[:R]-、无向 -[:R]-,每条必须指名一个关系类; 一条查询的模式最多 8 条关系、9 个节点(不与其他节点相连的节点也各算一张表)。 关系可以带变量(-[r:R]->),用于在 RETURN 里返回关系本身;关系没有自己的属性,r.x 会被拒绝。
  • OPTIONAL MATCH:写一条关系,把一个新节点挂到前面子句已经找到的节点上。 匹配不到时该行保留,新节点的列为 NULL,所以 count(可选侧的属性) 得 0 而不是整行 消失(count(*) 仍然算 1 行)——按邻居数排序又不丢零度邻居,用的就是这一点。 它自带的 WHERE 与内联属性决定这条关系匹配到什么,不决定哪些行留下。 限制:首个子句必须是 MATCH;一条 OPTIONAL MATCH 只能写一条关系、只能引入一个 新节点(两端都已匹配或两端都是新节点都会被拒);它引入的节点不能被后面的 MATCH 或查询的 WHERE 再要求,否则留下来的行会被重新删掉,这类查询一律拒绝而不是照做。
  • WHERE:= <> < > <= >=(不等于写 <>,!= 也接受,按 <> 处理), 两边可以都是属性(o.shipped < o.ordered、a.code = b.code;模型声明为字符串和数字的属性不能互比), 日期写 date('2026-08-13') / datetime(...),只能和日期类属性比较;IN [...]、IS NULL / IS NOT NULL, STARTS WITH / ENDS WITH / CONTAINS,用 AND / OR / NOT 组合,可加括号。 值可写 $name 参数;IN $list 可把整个列表作为一个参数传入。字符串谓词左侧须为 变量.属性,右侧须为字符串字面量或取值为字符串的参数;按 openCypher 语义做字面 子串匹配(%、_ 等不是通配符),属性为 null 时不匹配;大小写是否敏感取决于 数据源列的排序规则(collation)。只能用于字符串属性,用在数值、日期等属性上返回 400。
  • RETURN:属性、AS 别名、DISTINCT,以及 count / sum / avg / min / max(含 count(*) 与 DISTINCT 形式)。count(n) 统计节点 n 存在的行, count(DISTINCT n) 按主键统计不同对象(多个主键属性按组合区分,没有主键的对象类不能用)。有聚合时按 RETURN 中其余 列自动分组——这是 Cypher 的隐式 GROUP BY,无需也不能自己写 GROUP BY(写了会报语法错误并提示)。 RETURN 也可以返回条件,写法与 WHERE 相同,如 g.tournament_name CONTAINS 'Men' AS mens: 值为 true / false,无法判定时(属性为 null,或 OPTIONAL MATCH 没匹配到节点)为 null;它和其他返回值一样参与分组。要按条件排序,请先起别名再按别名排序。
  • 图值:RETURN 可以直接返回节点 t 与关系 r。节点返回对象类和完整主键(主键值按声明类型 以精确文本给出),再加上 object_properties 里点名的属性;关系返回关系类、两端节点的标识和 连接两端的键值对。collect(x) 把每组的 x 收成列表(保留重复、跳过 null),{k: x} 构造映射。 节点和关系按标识分组,所以 RETURN t AS team, count(*) AS n 按每个对象计数,一次调用就拿到 对象和计数。这类查询总是作为一条 SQL 执行;带 collect 时每个结果行是一个结论(collect 以外的 返回值),LIMIT 按结论计数,保留下来的结论带全部证据。证据达到 10000 行时返回 400 BknBackend.Cypher.ReadBudgetExceeded,不会返回部分证据。图值不能用于 ORDER BY 或 DISTINCT, collect 不能和其他聚合混用,collect 旁只能返回节点、关系、属性或常量,并只能按返回属性的别名排序。
  • 算术:+ - * / % 与取负,可加括号,可写在 RETURN(含聚合的参数)、 WHERE 比较的两侧和 ORDER BY 里,如 count(*) * 2、sum(o.price * o.qty)、 count(o.x) * 1.0 / count(*)、WHERE o.amount * o.rate > $floor、 ORDER BY count(g.id) * 0.5 + p.rank * 0.3 DESC。操作数是数值属性、聚合、数字或 取值为数字的参数;字符串、布尔、null 与非数值属性返回 400。与 openCypher 语义不一致的 写法一律拒绝而不是照做:两个整数相除(Cypher 丢余数,各 SQL 库不一致),要小数结果把 一边乘 1.0;% 只用于整数;除以字面量 0;^ 乘方。聚合只能出现在 RETURN 与 ORDER BY 里,不能写在 WHERE 中。一个列或排序键既有聚合又在聚合外直接读属性(如 o.x - avg(o.x))时,该属性须同时作为单独的列返回,结果按它分组;DISTINCT 结果要按 算出来的值排序,请在 RETURN 里给它起别名再按别名排序。没有声明类型的属性交给数据源决定。 IN 列表、内联属性、SKIP / LIMIT 里仍不能写算术。
  • CASE 与 coalesce:CASE WHEN … THEN … ELSE … END、CASE x WHEN v THEN … END 与 coalesce(a, b, …) 能写在算术能写的地方:RETURN、WITH、ORDER BY、比较两侧和聚合参数,如 sum(CASE WHEN g.penalty = '1' THEN 1 ELSE 0 END)、count(CASE WHEN … THEN 1 END)。没有 ELSE 且没命中时为 null。 各分支(或参数)须都是数字或都不是数字(null 字面量可搭配任一种),不能返回布尔;字符串结果不能参与算术或 sum / avg;分支条件里的聚合要先在 WITH 里命名再用;简单形式不能写 WHEN null。这类查询总走 SQL 路径。
  • ORDER BY / SKIP / LIMIT:ORDER BY 可用属性、返回列名或聚合。结果被聚合 或 DISTINCT 折叠后,只能按返回的值排序。
  • 比较两组对象:如「两个产品共用哪些物料」,在一个 MATCH 里让两条路径共享节点即可,不需要 WITH: MATCH (p1:产品 {material_number: $a})-[:产品关联产品bom]->(b1:产品BOM)-[:产品bom关联物料]->(m:物料)<-[:产品bom关联物料]-(b2:产品BOM)<-[:产品关联产品bom]-(p2:产品 {material_number: $b}) RETURN DISTINCT m.material_code。
  • 比较两个列表:两段各自 collect([DISTINCT] x.p),第二个 WITH 把第一个列表传下去,RETURN 只写大小: MATCH … WITH collect(DISTINCT a.p) AS l1 MATCH … WITH l1, collect(DISTINCT b.q) AS l2 RETURN size([x IN l1 WHERE x IN l2]) AS common, size(l1) AS n1, size(l2) AS n2,返回一行; 第二段没匹配到时没有行。不能直接返回列表,要列出共有的值用上面的共享节点写法;不支持 UNWIND。
  • WITH:一条查询可以在所有 MATCH 之后写一个 WITH,用于先聚合再过滤,如 MATCH (g:goal)-[:rel_goal_team]->(t:team) WITH t, count(*) AS n WHERE n > 100 RETURN t.name AS team, n ORDER BY n DESC。 WITH 里的值须用 AS 命名,节点可直接传下去(WITH t,按对象的主键分组,同名对象不会合并)。 WITH 的 WHERE 用 WITH 传下来的名字、节点的属性、由它们算出的值、字面量或参数比较:只涉及分组键的条件在分组前过滤, 涉及聚合的条件对每个分组判断。可以连写多个 WITH:只有第一个能聚合,后面的用前面的名字算新值并各自过滤, 如 WITH code, stock - usage * 50 AS gap WHERE gap < 0。第一个 WITH 里的 collect(x.p) AS s 只能写成 size(s),即收集到的个数(如 WHERE size(s) = 3)。RETURN 取 WITH 的名字、传下来节点的属性或由它们算出的值; 不聚合的 WITH 之后可以再写 count(*);聚合的 WITH 之后,RETURN 也可以只写聚合(如 RETURN count(*) AS n、 max(n)),对分组再统计,返回一行。以下仍拒绝:第二个 WITH 之后再写 MATCH、第二段 MATCH 之后再接 WITH(比较两个列表除外)、WITH DISTINCT、WITH *、WITH 上的 ORDER BY / SKIP / LIMIT、WITH 的 WHERE 里写 IN / 字符串谓词、第一个之后的 WITH 再聚合。
  • 开头定义常量:查询可以用只含字面量、字面量列表或参数的 WITH 开头,如 WITH ['382-000005', 'P61-000351'] AS products MATCH (p:产品) WHERE p.material_number IN products …, 后面 MATCH 的条件按名字使用这些值。
  • 按上一段的值过滤:MATCH … WITH DISTINCT x.p AS v MATCH … WHERE y.q = v RETURN …,或 WITH collect(x.p) AS s MATCH … WHERE y.q IN s;v 也可以写在内联属性里({q: v})。第二段的每一行 只要值在第一段的值里就保留一次,不随第一段的重复而重复(半连接)。第一段的属性和行范围与查询中其他部分一样 受授权约束。WITH 只能有一项;不写 DISTINCT 时,RETURN 须写 DISTINCT 且不聚合;v 只能在 WHERE 顶层以 = 使用、s 只能以 IN 使用,不能放在 OR / NOT 下;第二段之后不能再接 WITH。
  • 把节点传给下一个 MATCH:WITH p, count(g) AS total WHERE total >= 10 MATCH (p)<-[:R]-(g2)-[:S]->(t) RETURN p, t, count(g2) AS n, total。WITH 传下来的每一行按主键和下一段 匹配到的行连接,下一段里节点可不写标签;total 可在 RETURN / ORDER BY 中使用和计算,用在含聚合的表达式里 时要同时单独返回;不能写在下一段的 WHERE 里。每个传下来的节点都要在下一段用到,下一段不能是 OPTIONAL MATCH, 之后不能再接 WITH。任何 WITH 之后,RETURN 都可以直接返回传下来的节点。这类查询总走 SQL 路径。

数据集和索引:对象类绑定数据集或索引(不是 SQL 数据源),或一条查询跨多个数据源时,改为通过资源数据接口 逐表读取再关联,只支持基础写法;CASE、coalesce、对分组再统计、比较两个列表、把节点传给下一个 MATCH、 collect 会返回 400,读取量过大或超时也返回 400;返回节点、关系和虚拟边与 SQL 数据源上相同;UNION 也可用,每段各自读取。

不支持(会被拒绝,报错指名是哪个语法与位置): 变长路径 [:R*1..3]、XOR、date() / datetime() / localdatetime()、coalesce()、size()(只用于 WITH 收集的列表)和聚合以外的函数调用、^ 乘方、写操作(CREATE / MERGE / DELETE / SET / REMOVE)。

行数:不写 LIMIT 默认返回 1000 行;LIMIT 不得超过 10000。

关系唯一性:按 openCypher 语义,同一条路径里共用同一关系类的多跳互不相同, 编译器会自动补上主键不等的条件,调用方不必自己写。该规则按子句划分,因此 OPTIONAL MATCH 的那一跳不参与——它补出的条件会落在 WHERE 里,正好删掉外连接 保住的行。

Authorizations:
OAuth2AppKey
query Parameters
response_format
string
Default: "json"
Enum: "json" "toon"

响应格式。toon 返回 application/toon,同构数组压成表格,省 token。

Request Body schema: application/json
required
object (BKNContext)

BKN Trace business-provenance context identifying the business conversation and interaction to which this call belongs. Required on MCP business tools and REST execution APIs while capture is enabled and Trace Core is available; optional on REST reads and /mcp/proxy/.../call. A verified disabled capture policy admits business calls without this context because no Conversation or Interaction IDs are issued. A verified Trace Core infrastructure outage also admits unrecorded REST execution after a bounded, read-only availability probe.

Naming it makes the call managed: the service records an Operation under that interaction and attempts to return a receipt and capture evidence. Omitting it entirely, or sending an empty object, makes an eligible REST read or proxy call ad hoc. Only those two shapes are ad hoc — one id without the other, or a misspelt field, is refused rather than quietly downgraded.

Both required child fields are server-issued handles and must not be invented by the caller:

  • conversation_id: obtained from the Context Loader MCP tool bkn_start_interaction on the first turn
  • interaction_id: obtained from the Context Loader MCP tool bkn_start_interaction

These handles are available only through the provenance MCP tool above. The BKN Trace Core session APIs under /api/agent-observability/v1 accept gateway credentials only from trusted in-cluster services. They do not accept OAuth tokens or bak_ AppKeys; direct external calls receive 401 permission_denied. Context Loader derives the Operation idempotency identity on the server from request correlation, tool name, and normalized input. Callers must not submit operation_key. Network retries should reuse bkn-request-id or provide a stable X-OpenBKN-Client-Invocation-Id for the same logical call. This hint is used only for idempotency and has no role in identity, authorization, or data-isolation decisions.

kn_id
required
string

知识网络 ID,来自 list_knowledge_networks。

branch
string

分支名。不传按主分支查。

query
required
string

只读 Cypher 语句,语法子集见端点说明。

object

语句里 $name 的取值。只能是字符串、数字或布尔值——参数是值,不会变成 表名或列名,因此不能用来拼标签、关系类型或属性名。null 会被拒绝: 判空写 IS NULL。用在 IN $name 右侧的参数须为非空数组,元素为同一类标量 (整数与小数都算数字),不能含 null,最多 500 个,如 {"keys": [6, 7, 8]}。 一条查询里多个长列表合计过大时会返回 400,需拆成多次查询。

object

返回的节点除标识外还要带哪些属性,按节点变量给出,如 {"t": ["team_name"]}。 变量必须是 RETURN 里返回的节点,所有变量合计最多 128 个属性;这些属性和查询里其他属性一样 受授权约束。不传时节点只带标识。

explain
boolean

为 true 时不执行查询、不读数据,只返回 plan(此时 entries 为空):查询形状、对象和关系、条件、 分组、返回列及类型、行数上限、会读的属性、行范围被收窄的对象类和提醒。查询的解析、授权和编译与执行时 完全相同,所以会被拒的写法返回与执行时相同的错误和改写提示。不返回 SQL。例外:explain 看不出数据存在哪里, 对象类绑定数据集、索引或跨多个数据源时才被拒的写法(CASE、coalesce 等),explain 照样通过,执行时才被拒。

timeout_sec
integer >= 1

查询在数据源上的执行时限(秒),查询执行的所有语句(UNION 的各分支、bind-join 及其 SQL 回退)共用这一个时限。不传则使用 bkn-backend 配置的时限(默认 55 秒,部署可通过 BKN_CYPHER_QUERY_TIMEOUT_SEC 调整)。只能比配置值更短:超过配置值或小于 1 返回 BknBackend.Cypher.InvalidParameter。仅本 REST 接口接受;MCP 工具 run_cypher 不接受此参数,传了也会被忽略。

Responses

Request samples

Content type
application/json
Example
{
  • "kn_id": "kn_retail",
  • "query": "MATCH (c:customer)<-[:rel_order_customer]-(o:order)-[:rel_order_item_order]->(i:order_item) WHERE c.city = 'Shanghai' AND o.status IN ['paid', 'shipped'] RETURN c.name AS customer, o.order_no AS order_no, i.sku AS sku LIMIT 100"
}

Response samples

Content type
{
  • "plan": { },
  • "limited": true,
  • "columns": [
    ],
  • "entries": [
    ],
  • "value_types": { },
  • "execution": {
    }
}