Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion content/cn/docs/language/_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@ linkTitle: "查询语言"
weight: 7
---

HugeGraph 支持 Gremlin 和 Cypher。这里主要介绍 Gremlin 用法;Cypher HTTP 接口见 [Cypher API](/cn/docs/clients/restful-api/cypher/)。
HugeGraph 支持 Gremlin 和 Cypher。本节涵盖两种语言;Cypher HTTP 接口见 [Cypher API](/cn/docs/clients/restful-api/cypher/)。
136 changes: 136 additions & 0 deletions content/cn/docs/language/cypher-compatibility.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
---
title: "Cypher 兼容性"
linkTitle: "Cypher 兼容性"
weight: 3
---

### 范围

**下文验证结果描述的是 `master`,不能直接套用于已发布版本。** HugeGraph 1.7.0 在
`/graphspaces/{graphspace}/graphs/{graph}/cypher` 上只提供两种请求形式:`GET ?cypher=<URL 编码的语句>`
和 `POST application/json`(请求体为原始 Cypher 文本)。1.7.0 之前的版本在 `/graphs/{graph}/cypher` 下
提供同样的两种形式。已发布版本不接受绑定参数,引用 `$param` 的语句
不会报错,缺失的绑定会被内联为 `null`(基于它的谓词匹配不到行,而 `RETURN $value AS value` 仍会返回一行)——参见[已知限制](/cn/docs/language/hugegraph-cypher/#已知限制)。

本页记录当前 Cypher 开发改动实际验证过的用例,不代表完整支持 openCypher 或 Neo4j,也不代表所有已发布
版本的 HugeGraph 都具备相同行为。测试代码基于当前 Apache `master` 的
[`5039e5b`](https://github.com/apache/hugegraph/commit/5039e5b67d26ea305b8509d3a414877749baaebb),
该提交声明 HugeGraph `1.8.0`,使用 Java 17 和 TinkerPop `3.8.1`,且 Cypher 改动
([ASF PR #3289](https://github.com/apache/hugegraph/pull/3289))已合入。运行栈使用 Java `17.0.20.1`(Temurin)、
TinkerPop `3.8.1`、`org.opencypher.gremlin:translation:1.0.4` 和 RocksDB。合入前在
[`af3c686`](https://github.com/apache/hugegraph/commit/af3c6867f4bfa3f95e63ad472c12a88c63529c1b)
上的验证仍见下文。

接口路径为 `/graphspaces/{graphspace}/graphs/{graph}/cypher`。一般用法见
[HugeGraph Cypher 指南](/cn/docs/language/hugegraph-cypher/)。

### 请求形式与参数

| 请求 | 是否存在于已发布版本 | 测试栈上已验证行为 | 测试方法 |
|---|---|---|---|
| `GET ?cypher=<URL 编码的语句>` | 是 | 保留原有查询参数形式 | `testGet` |
| `POST application/json`,请求体为原始 Cypher 文本 | 是 | 保留旧的原始文本请求形式 | `testPost` |
| `POST text/plain`,任意请求体 | 否 | 返回 HTTP 415 | `testRejectPlainTextPost` |
| `POST application/json`,请求体为 JSON 对象 | 否 — 由 [#3289](https://github.com/apache/hugegraph/pull/3289) 引入 | 查询语句与参数分开传入 | `testParameters` |

因此下面的 JSON 对象形式**在任何已发布的 HugeGraph 版本中都不可用**,它描述已合入 `master`(1.8.0 开发线)的改动。
在已发布版本上,引用 `$param` 的语句会把缺失的绑定内联为 `null`,是否返回行取决于表达式(`WHERE n.name = $name` 匹配不到行,`RETURN $value AS value` 会返回一行 `null`)——参见
[已知限制](/cn/docs/language/hugegraph-cypher/#已知限制)。

```json
{
"cypher": "MATCH (n:cypher_person) WHERE n.name = $name RETURN n.name",
"parameters": {"name": "marko"}
}
```

JSON 数组、字符串、数字、布尔值或 null 请求体会返回 HTTP 400。
格式错误的 JSON 对象和尾随内容也会产生请求错误,不会回退为原始 Cypher 文本。

JSON 对象中的 `cypher` 必须是非空白字符串;`parameters` 若提供,必须是对象。省略 `parameters` 表示空参数表。
语句引用了未提供的参数时会报执行错误;显式传入 `null` 是有效值。在测试栈上,该执行错误适用于所有请求形式,
包括 `GET ?cypher=` 和原始文本 `POST`:[#3289](https://github.com/apache/hugegraph/pull/3289) 总是附带
参数表并拒绝未解析的 `$param` 引用,取代了上文描述的已发布版本“缺失绑定按 `null` 处理”行为。测试覆盖字符串、数字、布尔值、引号和换行,
参数名 `id` 与 `label`。当前实现的 `parameters` 最多接受 16 个顶层条目,该上限固定。
该上限只统计顶层 `parameters` 对象中的键。Cypher 不支持在 Gremlin Server 的处理器配置中设置
`maxParameters`。参数值会作为绑定值传递,不会改写查询文本。

一个 Map 只计为一个顶层参数。可以将相关值放入一个 Map,并显式引用各字段;顶点标签和必需属性必须匹配图中已有的 Schema:

```json
{
"cypher": "CREATE (n:cypher_person {name:$props.name, age:$props.age, city:$props.city}) RETURN n.name",
"parameters": {"props": {"name": "new-person", "age": 20, "city": "Beijing"}}
}
```

实际 REST 验证确认,一个包含 17 个条目的 Map 可以通过显式属性引用完成写入,并通过原生 REST 核对全部 17 个持久化值。
返回包含 17 个条目的 Map 也成功,而 17 个顶层绑定参数会产生执行错误。请使用上述显式属性引用;
固定版本的转译库不会通过 CREATE 的简写形式赋予绑定 Map 中的属性。

转译库将精确字符串 `" cypher.null"`(开头有两个空格)保留为 null 标记,因此绑定值会拒绝该字符串,
包括列表和嵌套 Map 中的值。显式 null 仍受支持。语句字面量及存储属性等于该字符串的情况仍受转译库限制,
本次改动未验证这些值能够保真。

同时检查 HTTP 状态和响应体的 `status.code`:执行错误可能仍返回 HTTP 200,但 `status.code` 为 400,结果数据为 null。

### 已验证行为

API 测试夹具使用强类型 Schema,并为 `city` 建立 `SECONDARY` 索引、为 `age` 建立 `RANGE` 索引。验收结论仅限于下列用例:

| 范围 | 测试用例 | 测试方法 |
|---|---|---|
| 查询 | 标签扫描、相等和范围条件、布尔组合、有向一跳和两跳关系、空结果、计算字符串的正则全字符串匹配 | `testGet`、`testExactReadsAndPredicates`、`testRelationQuery`、`testComputedRegexExecutesExtensionPredicate`、`testComputedRegexRequiresWholeStringMatch` |
| 结果 | 别名、标量和节点值、嵌套值、关系 ID、路径结构、null 与缺失属性 | `testReturnNodeIdAsPrimitiveValue`、`testReturnNodeDoesNotLeakInternalIdTypes`、`testReturnNestedIdDoesNotLeakInternalIdTypes`、`testReturnRelationIdDoesNotLeakInternalIdTypes`、`testReturnPathShape`、`testNullAndMissingProperty` |
| 聚合和分页 | `DISTINCT`、`count`/`sum`/`min`/`max`/`avg`、`ORDER BY`、`SKIP`、`LIMIT` | `testDuplicatesDistinctAndPagination`、`testAggregates` |
| 写入 | 创建顶点和边、修改属性、删除边和顶点;通过原生 REST 读取检查状态 | `testCreate`、`testCreateSetAndDeleteWithNativeReadback` |
| 失败写入 | 拒绝双顶点 `CREATE` 后,连续 32 次查询和原生读取均未发现残留 | `testFailedWriteDoesNotLeakIntoLaterRequests` |
| 错误与路由 | 非法语法和请求结构、内容类型、参数键与保留的 null 标记、Schema 值、认证及图路由 | `testInvalidRequests`、`testRejectPlainTextPost`、`testRejectInvalidQuery`、`testRejectInvalidBindingShapeAndKeys`、`testRejectTranslatorNullMarker`、`testRejectTranslatorNullSentinelInBindings`、`testAuthenticationAndGraphRouting`、`testSpecifiedGraphRouting` |

合入后在 `5039e5b` 上的补充 REST 验证对全新 RocksDB 图重新执行了文档示例:查询、带排序和 LIMIT 的投影、聚合、
单顶点 `CREATE`、`SET`/`REMOVE`、边 `DELETE`、`DETACH DELETE`,以及上表全部请求形式约定均与文档一致,
包括三种请求形式下缺失绑定的执行错误。双顶点简写 `CREATE (a)-[:knows]->(b)` 在同一运行中于 `person` 标签使用
`AUTOMATIC` id 策略的图上验证通过;在 `PRIMARY_KEY` 标签上,同一语句会被拒绝并返回执行错误(提示必须设置主键),
而同一标签上的单顶点 `CREATE` 成功。在 `PRIMARY_KEY` Schema 上,请将两条 `CREATE` 语句分开执行,或对该形式使用
`AUTOMATIC` id 策略。

独立代码改动位于 [ASF PR #3289](https://github.com/apache/hugegraph/pull/3289),该 PR 已于 2026-10-08 合入 Apache `master`,合入提交为
[`5039e5b`](https://github.com/apache/hugegraph/commit/5039e5b67d26ea305b8509d3a414877749baaebb);上文的验证记录直接描述该合入后的提交,
合入前验证的基线为
[`af3c686`](https://github.com/apache/hugegraph/commit/af3c6867f4bfa3f95e63ad472c12a88c63529c1b)。
原始开发改动仍关联 [PR #238](https://github.com/hugegraph/hugegraph/pull/238)。
在固定源码提交
[`8d06ad3`](https://github.com/apache/hugegraph/blob/8d06ad3b18fbd18807cf545184d07e6fec0c55b4/docs/cypher-compatibility.md) 上,`CypherApiTest` 通过 23/23,
`CypherClientTest` 通过 7/7,`CypherOpProcessorTest` 通过 8/8,均无跳过。新增的谓词、执行上下文和请求资源所有权
回归测试均通过;`AbstractRestClientTest` 的九项测试也全部通过,包括 ASCII 请求体、UTF-16 Map 请求体及 gzip。
Login 测试通过 3/3;相关 Gremlin 测试通过 10 项,保留一项因后端不共享而不适用的 `testClearAndInit` 跳过。
EditorConfig 格式检查、仓库根目录 clean compile 和完整 install 均通过。在实际服务测试前,分发包内的 API JAR 与编译目标 JAR 一致。

该固定提交中的兼容性说明包含验证记录和逐方法映射。测试源码:
[`CypherApiTest`](https://github.com/apache/hugegraph/blob/8d06ad3b18fbd18807cf545184d07e6fec0c55b4/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/api/CypherApiTest.java)、
[`CypherClientTest`](https://github.com/apache/hugegraph/blob/8d06ad3b18fbd18807cf545184d07e6fec0c55b4/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/api/cypher/CypherClientTest.java)
和
[`CypherOpProcessorTest`](https://github.com/apache/hugegraph/blob/8d06ad3b18fbd18807cf545184d07e6fec0c55b4/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/opencypher/CypherOpProcessorTest.java)。
此前在
[`e62c961`](https://github.com/apache/hugegraph/commit/e62c961e00221569d4f955abbadf60faee45b283)
基线上的验证仍保留在
[`fd8f4a6`](https://github.com/apache/hugegraph/blob/fd8f4a626b9e899663d3114035e2967e421b3e55/docs/cypher-compatibility.md)。
此前变基前的验证记录仍保留在
[`c3b2f3e`](https://github.com/hugegraph/hugegraph/blob/c3b2f3e3b9ff1de0495260d6eec0b16816d7f095/docs/cypher-compatibility.md)。

### 基线故障与当前修复

在此前的基线
[`27a7c9b`](https://github.com/apache/hugegraph/commit/27a7c9b42274d6d4f95eabed6d2051d393ae0eaf)
中,失败的双顶点 `CREATE` 在两次观察中都留下了延迟可见的残留。第一次运行中,即时原生读取未发现前缀,
但后续聚合/排序查询暴露了前缀,原生全量列表也确认了它。第二次复现时,即时原生读取和之后 7 次 count/原生读取均未见前缀;
第 8 次 count 后才出现。原始基线证据保留在
[基线报告](https://github.com/apache/hugegraph-doc/pull/499#issuecomment-5826172378)。

当前开发改动通过了 `testFailedWriteDoesNotLeakIntoLaterRequests`:针对该夹具,原生读取和后续 32 轮查询/原生读取均确认无残留。
这只验证了已报告的失败场景及当前测试栈,不能据此推断所有回滚路径、跨请求事务语义、所有语句或后端的写原子性。

### 本次未验证

本次测试范围之外的高级语法和行为仍未验证,包括 `MERGE`、`OPTIONAL MATCH`、`WITH`、`UNWIND`、`UNION`、变长路径、
广泛的函数覆盖、过程调用、Cypher Schema DDL、`EXPLAIN`/`PROFILE`、HStore、Bolt、跨请求事务和性能。
165 changes: 165 additions & 0 deletions content/cn/docs/language/hugegraph-cypher.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
---
title: "HugeGraph Cypher"
linkTitle: "Cypher 查询语言"
weight: 2
---

### 概述

HugeGraph 支持 [Cypher](https://opencypher.org/) —— 最初由 Neo4j 创建、并由 [openCypher](https://github.com/opencypher/openCypher) 标准化的声明式图查询语言。Gremlin 是命令式的遍历语言,而 Cypher 只需描述想要的图模式(`MATCH`、`WHERE`、`RETURN`),由引擎决定如何执行。

HugeGraph 通过 [cypher-for-gremlin](https://github.com/opencypher/cypher-for-gremlin) 转译器将 Cypher 语句翻译为 Gremlin,再在 TinkerPop 技术栈上执行。因此 HugeGraph 的 Cypher 能力覆盖转译器所实现的 openCypher 9 语法面 —— 详见下文[已知限制](#已知限制)。

### 何时用 Cypher、何时用 Gremlin

| 适合用 Cypher | 适合用 Gremlin |
|---|---|
| 正在从 Neo4j 迁移,或已熟悉 Cypher | 需要 HugeGraph 的完整功能面 |
| 需要声明式模式匹配(`MATCH (a)-[:KNOWS]->(b)`) | 需要精细的遍历控制、自定义步骤或 lambda |
| 查询以读模式和投影为主 | 需要图算法、OLAP 或 Cypher 未暴露的功能 |

凡是 Cypher 表达不了的,等价的 Gremlin 查询总是可用 —— 下文示例同时给出两种写法。

### 调用 Cypher API

Cypher 语句通过 HugeGraph Server 的 REST 端点提交:

```http
GET /graphspaces/{graphspace}/graphs/{graph}/cypher?cypher={statement}
POST /graphspaces/{graphspace}/graphs/{graph}/cypher
```

该端点始终要求 `Authorization` 头(`Basic` 或 `Bearer`),即使服务端未开启认证 —— 凭据会被转发给 Gremlin Server。`Basic` 凭据必须使用 URL 安全的 Base64 编码(用 `-` 和 `_` 代替 `+` 和 `/`),且密码不能包含 `:`;无法满足这两个条件的账号请改用 `Bearer`。完整的请求/响应格式见 [Cypher REST API 参考](/cn/docs/clients/restful-api/cypher/)。

示例:

```bash
curl -H "Authorization: Bearer $TOKEN" \
"http://localhost:8080/graphspaces/DEFAULT/graphs/hugegraph/cypher?cypher=MATCH%20(n:person)%20RETURN%20n.name%20LIMIT%2010"
```

Java 客户端使用 `CypherManager`(见 [hugegraph-client](/cn/docs/clients/hugegraph-client/)):

```java
ResultSet resultSet = hugeClient.cypher().execute("MATCH (n:person) RETURN n.name LIMIT 10");
```

### 基础示例

以下示例假设图中存在 `person` 顶点(`name`、`age`、`city` 属性)和 `knows` 边,并假设标签
声明了 `person` 上的 `nullableKeys("age", "city")` 以及 `knows` 上的可空属性——例如在
`scripts/example.groovy` 的 Schema 上补充这些可空键。若 Schema 未声明(已发布的默认 Schema 把
`person` 的 `age`、`city` 标记为非空),下面的创建与更新示例会触发非空属性校验失败:请在每条语句中
为所有非空属性赋值,或先以 `nullableKeys` 声明标签。若 `person` 标签使用 `PRIMARY_KEY` id 策略(`scripts/example.groovy` 即如此),双顶点简写
`CREATE (a)-[:knows]->(b)` 会被拒绝并返回执行错误(提示必须设置主键;在已合入
[#3289](https://github.com/apache/hugegraph/pull/3289) 的 `master` 上验证),因此下面的边示例先分别创建顶点再匹配它们;
该简写在 `AUTOMATIC` id 策略下可用。

#### 查询 — MATCH / WHERE / RETURN

```cypher
// 所有名为 "marko" 的 person
MATCH (n:person) WHERE n.name = 'marko' RETURN n
```

```cypher
// 投影 + 排序 + 限制条数
MATCH (n:person)
WHERE n.age > 30
RETURN n.name AS name, n.age AS age
ORDER BY age DESC
LIMIT 10
```

```cypher
// 关系模式
MATCH (a:person)-[:knows]->(b:person)
WHERE a.name = 'marko'
RETURN b.name AS friend
```

#### 创建 — CREATE

```cypher
// 创建顶点
CREATE (n:person {name: 'josh', age: 32, city: 'beijing'})
```

```cypher
// 先创建两个顶点,再创建它们之间的边(每条语句单独作为一次请求发送)
CREATE (:person {name: 'peter'})
CREATE (:person {name: 'lop'})
MATCH (a:person), (b:person)
WHERE a.name = 'peter' AND b.name = 'lop'
CREATE (a)-[:knows]->(b)
```

#### 更新 — SET / REMOVE

```cypher
MATCH (n:person) WHERE n.name = 'josh'
SET n.age = 33
REMOVE n.city
```

#### 删除 — DELETE / DETACH DELETE

```cypher
// 删除边
MATCH (a:person)-[r:knows]->(b:person)
WHERE a.name = 'peter' AND b.name = 'lop'
DELETE r
```

```cypher
// 删除顶点及其所有边
MATCH (n:person) WHERE n.name = 'josh'
DETACH DELETE n
```

#### 聚合

```cypher
// 总数
MATCH (n:person) RETURN count(n) AS total
```

```cypher
// 按城市分组计数
MATCH (n:person) RETURN n.city AS city, count(*) AS cnt ORDER BY cnt DESC
```

### 等价的 Gremlin 写法

每条 Cypher 语句在内部都会被翻译为 Gremlin。当某个 Cypher 特性不受支持时,可直接编写遍历:

| Cypher | 等价 Gremlin |
|---|---|
| `MATCH (n:person) WHERE n.name='marko' RETURN n` | `g.V().hasLabel('person').has('name','marko')` |
| `MATCH (a)-[:knows]->(b) RETURN b` | `g.V().out('knows')` |
| `CREATE (n:person {name:'x'})` | `g.addV('person').property('name','x')` |
| `MATCH (n) DETACH DELETE n` | `g.V().drop()` |
| `MATCH (n:person) RETURN count(n)` | `g.V().hasLabel('person').count()` |

提示:`EXPLAIN MATCH (n:person) RETURN n` 会以 `EXPLAIN` 选项解析,翻译后的 Gremlin 预期出现在 `result.data[0].translation` 中 —— 这是转译层行为,尚未在服务器上端到端验证(见[兼容性说明](/cn/docs/language/cypher-compatibility/))。它仍是起草上表等价写法的最快方式。`PROFILE` 不受支持。

### 已知限制

HugeGraph 的 Cypher 能力受转译层约束,该层基于 openCypher 9 时代的工具链。已知缺口:

- **已发布版本不支持参数化查询** —— API 只接受原始语句字符串。使用 `$param` 的语句不会报错:缺失的绑定会被内联为 `null`,结果取决于表达式:`WHERE n.name = $name` 这类谓词匹配不到行,`RETURN $value AS value` 仍会返回一行 `null`,写入时则会写入 null 值。请在客户端先对值做转义/净化再拼接到语句中。在合入 [#3289](https://github.com/apache/hugegraph/pull/3289) 后的
测试栈上情况改变:缺失的绑定对所有请求形式都是执行错误,包括 `GET ?cypher=` 与原始文本
`POST`——服务器总是附带参数表并拒绝未解析的 `$param` 引用。JSON 绑定参数(`{"cypher": ..., "parameters": {...}}`)已通过合入 `master` 的 [ASF PR #3289](https://github.com/apache/hugegraph/pull/3289) 引入,承接原 [PR #238](https://github.com/hugegraph/hugegraph/pull/238);已验证的请求契约见[开发版兼容性记录](/cn/docs/language/cypher-compatibility/)。
- **子句覆盖不完整** —— 部分 openCypher 结构无法翻译(例如 map projection、部分 `datetime()` 函数)。不支持的结构会在翻译阶段报错。`MERGE ... ON CREATE SET`、`NOT ... IN` 等结构可以翻译,但尚未在 HugeGraph 上端到端验证。开发改动验证了计算字符串上的两个 `=~` 全字符串匹配用例,更广泛的正则覆盖仍未验证 —— 见[兼容性说明](/cn/docs/language/cypher-compatibility/)。
- **不支持 `CALL` 过程** —— HugeGraph 的图算法(最短路径、k-out、personalrank 等)未暴露为 Cypher 过程;请改用 [traverser REST API](/cn/docs/clients/restful-api/traverser/) 或 Gremlin。
- **每次请求仅一条语句** —— 不支持多语句脚本,请每次调用发送一条语句。

当语句翻译失败时,响应的 `status.message` 会包含转译器错误信息。遇到缺口时,等价的 Gremlin 写法是受支持的回退方案。

### 延伸阅读

- [Cypher REST API 参考](/cn/docs/clients/restful-api/cypher/)
- [Gremlin 查询语言](/cn/docs/language/hugegraph-gremlin/)
- [openCypher 项目](https://opencypher.org/) —— 语言规范与资源

转译库历史 TCK 通过比例不等于 HugeGraph 端到端兼容率;本页没有给出经测量的 HugeGraph Cypher 总体兼容百分比。
Loading