

本文属于机器翻译版本。若本译文内容与英语原文存在差异，则一律以英文原文为准。

# 在 Neptune 中如何处理 Gremlin 查询
<a name="gremlin-explain-background-querying"></a>

在 Amazon Neptune 中，可以通过一系列模式来表示更复杂的遍历，这些模式基于命名变量的定义创建关系，而命名变量可以在模式之间共享以创建联接。如以下示例所示。

**问题：顶点 `v1` 有哪些两跳邻域？**

```
  Gremlin code:      g.V(‘v1’).out('knows').out('knows').path()
  Pattern:           (?1=<v1>, <knows>, ?2, ?) X Pattern(?2, <knows>, ?3, ?)

  The pattern produces a three-column relation (?1, ?2, ?3) like this:
                     ?1     ?2     ?3
                     ================
                     v1     v2     v3
                     v1     v2     v4
                     v1     v5     v6
```

通过在两个模式之间共享 `?2` 变量（在第一个模式的 O 位置和第二个模式的 S 位置），可以创建从一跳邻域到二跳邻域的联接。每个 Neptune 解都有三个命名变量的绑定，这些变量可用于重新创建 [TinkerPopTraverser](http://tinkerpop.apache.org/docs/current/reference/#_the_traverser)（包括路径信息）。

```
```

[Gremlin 查询处理的第一步是将查询解析为 TinkerPop [Traversal](http://tinkerpop.apache.org/docs/current/reference/#traversal) 对象，该对象由一系列步骤组成。 TinkerPop ](http://tinkerpop.apache.org/docs/current/reference/#graph-traversal-steps)这些步骤是开源 [Apache TinkerPop 项目](http://tinkerpop.apache.org/)的一部分，既是逻辑运算符，也是物理运算符，在参考实现中构成 Gremlin 遍历。它们都用于表示查询模型。它们是可执行的运算符，可以根据其代表的运算符的语义生成解决方案。例如，`.V()`既由表示又由执行 TinkerPop [GraphStep](http://tinkerpop.apache.org/docs/current/reference/#graph-step)。

由于这些 off-the-shelf TinkerPop 步骤是可执行的，因此这样的 TinkerPop Traversal 可以执行任何 Gremlin 查询并生成正确的答案。但是，当针对大型图表执行时， TinkerPop 步骤有时效率低下且速度很慢。Neptune 不使用这些步骤，而是尝试将该遍历转换为由模式组组成的声明形式（如前所述）。

当前，Neptune 的原生查询引擎仅支持部分 Gremlin 运算符（步骤）。因此，它尝试将尽可能多的步骤折叠为一个 `NeptuneGraphQueryStep`，其中包含已转换的所有步骤的声明性逻辑查询计划。理想情况下，所有步骤都将转换。但是，当遇到无法转换的步骤时，Neptune 会脱离原生执行，并将所有查询执行从该点推迟到这些步骤。 TinkerPop 它不会尝试穿插进行本机执行。

将步骤转换成逻辑查询计划后，Neptune 运行一系列查询优化器，以根据静态分析和估计基数来重写查询计划。优化器执行多种操作，例如根据范围计数对运算符进行重新排序、删除不必要或多余的运算符、重新排列筛选条件、将运算符推入不同的组等。

生成优化的查询计划后，Neptune 创建物理运算符的管道来执行查询。这包括从语句索引中读取数据、执行各种类型的联接、筛选、排序等。管道生成解流，然后将其转换回 TinkerPop Traverser 对象流。

## 查询结果的序列化
<a name="gremlin-explain-background-querying-serialization"></a>

Amazon Neptune 目前依靠 TinkerPop 响应消息序列化器将查询结果（TinkerPop Traversers）转换为序列化数据，然后通过电线发送回客户端。这些序列化格式往往很冗长。

例如，要序列化 `g.V().limit(1)` 等顶点查询的结果，Neptune 查询引擎必须执行一次搜索来生成查询结果。但是，`GraphSON` 序列化程序将执行大量额外的搜索，才能将顶点打包为序列化格式。它必须执行一次搜索来获取标签，执行一次搜索来获取属性键，并对顶点的每个属性键执行一次搜索来获取每个键的所有值。

某些序列化格式效率更高，但是所有序列化格式都需要进行额外的搜索。此外， TinkerPop 序列化程序不会尽量避免重复搜索，这通常会导致不必要地重复许多搜索。

因此，在编写查询时，只询问所需的信息极为重要。例如，`g.V().limit(1).id()` 将仅返回顶点 ID，并消除所有其他序列化程序搜索。[Neptune 中的 Gremlin `profile` API](gremlin-profile-api.md) 允许您查看在查询执行和序列化期间进行了多少次搜索调用。