

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

# openCypher `explain` 特征
<a name="access-graph-opencypher-explain"></a>

openCypher `explain` 特征是 Amazon Neptune 中的一种自助式工具，可帮助您了解 Neptune 引擎所采用的执行方法。要调用 explain，您需要使用 `explain={{mode}}` 向 openCypher [HTTPS](access-graph-opencypher-queries.md) 请求传递一个参数，其中 `mode` 值可以是以下值之一：

****
+ **`static`** – 在 `static` 模式下，`explain` 仅输出查询计划的静态结构。它不实际运行查询。
+ **`dynamic`** – 在 `dynamic` 模式下，`explain` 还会运行查询，并包括查询计划的动态方面。这些方面可能包括流经运算符的中间绑定的数量、传入绑定与传出绑定的比率以及每个运算符使用的总时间。
+ **`details`** – 在 `details` 模式下，`explain` 输出动态模式中显示的信息以及其它详细信息，例如实际的 openCypher 查询字符串和某个连接运算符之下模式的估计范围计数。

  

例如，在`dynamic`模式下`POST`使用：

------
#### [ Amazon CLI ]

```
aws neptunedata execute-open-cypher-explain-query \
  --endpoint-url https://{{your-neptune-endpoint}}:{{port}} \
  --open-cypher-query "MATCH (n) RETURN n LIMIT 1" \
  --explain-mode dynamic
```

有关更多信息，请参阅《 Amazon CLI 命令参考》中的 [execute-open-cypher-explain-query](https://docs.amazonaws.cn/cli/latest/reference/neptunedata/execute-open-cypher-explain-query.html)。

------
#### [ SDK ]

```
import boto3
from botocore.config import Config

client = boto3.client(
    'neptunedata',
    endpoint_url='https://{{your-neptune-endpoint}}:{{port}}',
    config=Config(read_timeout=None, retries={'total_max_attempts': 1})
)

response = client.execute_open_cypher_explain_query(
    openCypherQuery='MATCH (n) RETURN n LIMIT 1',
    explainMode='dynamic'
)

print(response['results'].read().decode('utf-8'))
```

有关其他语言 Amazon 的 SDK 示例，请参阅[Amazon SDK](access-graph-opencypher-sdk.md)。

------
#### [ awscurl ]

```
awscurl https://{{your-neptune-endpoint}}:{{port}}/openCypher \
  --region {{us-east-1}} \
  --service neptune-db \
  -X POST \
  -d "query=MATCH (n) RETURN n LIMIT 1" \
  -d "explain=dynamic"
```

**注意**  
此示例假设您的 Amazon 证书是在您的环境中配置的。{{us-east-1}}替换为 Neptune 集群的区域。

------
#### [ curl ]

```
curl https://{{your-neptune-endpoint}}:{{port}}/openCypher \
  -d "query=MATCH (n) RETURN n LIMIT 1" \
  -d "explain=dynamic"
```

------

## Neptune 中 openCypher `explain` 的限制
<a name="access-graph-opencypher-explain-limitations"></a>

openCypher Explain 的当前版本存在以下限制：
+ Explain 计划目前仅适用于执行只读操作的查询。不支持执行任何类型的突变（例如 `CREATE`、`DELETE`、`MERGE`、`SET` 等）的查询。
+ 特定计划的运算符和输出可能会在将来版本中发生变化。

## openCypher `explain` 输出中的 DFE 运算符
<a name="access-graph-opencypher-dfe-operators"></a>

要使用 openCypher `explain` 特征提供的信息，您需要了解有关 [DFE 查询引擎](neptune-dfe-engine.md)工作原理的一些详细信息（DFE 是 Neptune 用来处理 openCypher 查询的引擎）。

DFE 引擎将每个查询转换到一个运算符管道中。从第一个运算符开始，中间解将通过这个运算符管道从一个运算符流到下一个运算符。Explain 表中的每一行表示一个结果（截至到评估点）。

可以出现在 DFE 查询计划中的运算符如下所示：

**DFEApply**— 对存储在指定变量中的值执行参数部分中指定的函数

**DFEBind关系**-将具有指定名称的变量绑定在一起

**DFEChunkLocalSubQuery**— 这是一种非阻塞操作，充当正在执行的子查询的封装器。

**DFEDistinct列**-根据指定的变量返回输入值的不同子集。

**DFEDistinct关系**-根据指定的变量返回输入解决方案的不同子集。

**DFEDrain**— 出现在子查询的末尾，用作该子查询的终止步骤。解的数量记录为 `Units In`。`Units Out` 始终为零。

**DFEForward值** — 将所有输入块直接复制为输出块，以传递给其下游运算符。

**DFEGroupByHashIndex**— 根据先前计算的哈希索引（使用运算）对输入解执行分组`DFEHashIndexBuild`运算。作为输出，给定输入通过包含每个输入解的组键的列进行扩展。

**DFEHashIndexBuild**— 在一组变量上建立哈希索引作为副作用。此哈希索引通常会在以后的操作中重复使用。有关此哈希索引可能用在何处，请参阅 `DFEHashIndexJoin` 或 `DFEGroupByHashIndex`。

**DFEHashIndexJoin**— 根据先前构建的哈希索引对传入的解决方案执行联接。有关此哈希索引可能在何处构建，请参阅 `DFEHashIndexBuild`。

DFEJoinE **x** ists — 采用左手和右手输入关系，并保留左侧关系中具有相应值的值，这些值由给定联接变量定义。

**** - 这是一种非阻塞操作，它充当子查询的包装器，允许重复运行子查询以在循环中使用。

**DFEMergeChunks** — 这是一种阻塞操作，它将来自其上游运算符的区块组合成单个解决方案块，然后传递给其下游运算符（相反）。`DFESplitChunks`

**DFEMinus**— 采用左手和右手输入关系，并保留左侧关系中在给定连接变量定义的右关系中没有相应值的值。如果两个关系中的变量没有重叠，则此运算符只返回左侧输入关系。

DFENotE **x** ists — 采用左手和右手输入关系，并保留左侧关系中在给定联接变量定义的右关系中没有相应值的值。如果两个关系中的变量没有重叠，则此运算符会返回空关系。

**DFEOptional联接**-执行左外联接（也称为可选联接）：左侧的解决方案如果右侧至少有一个加入伙伴，则按原样转发来自左侧的解决方案，而右侧没有加入伙伴的解决方案则按原样转发。这是一项阻止操作。

DFEPipelineJo **in** — 根据`pattern`参数定义的元组模式连接输入。

**DFEPipelineRangeCount**— 计算与给定模式匹配的解数，并返回包含计数值的单一单元解。

**DFEPipeline扫描**-扫描数据库中的给定`pattern`参数，无论是否对列使用给定过滤器。

**DFEProject**— 获取多个输入列并仅投影所需的列。

**DFEReduce**— 对指定变量执行指定的聚合函数。

DFERelationalJo **in** — 使用合并联接根据指定的模式键连接前一个运算符的输入。这是一项阻止操作。

**DFERouteChunks** — 从其单个传入边缘获取输入块，然后沿着其多个传出边缘路由这些块。

**DFESelect行**-此运算符有选择地从其左侧输入关系解中提取行，以转发到其下游运算符。根据运算符右侧输入关系中提供的行标识符选择的行。

**DFESerialize**— 将查询的最终结果序列化为 JSON 字符串序列化，将每个输入解决方案映射到相应的变量名称。对于节点和边缘结果，这些结果将序列化为实体属性和元数据的映射。

**DFESort**— 获取输入关系并根据提供的排序键生成排序关系。

**DFESplitByGroup**— 将来自一个传入边的每个输入块拆分为较小的输出块，这些块对应于行组，行组由 IDs 来自另一个传入边的相应输入块的行标识。

**DFESplitChunks** — 将每个输入块拆分为较小的输出块（相反）。`DFEMergeChunks`

**DFEStreamingHashIndexBuild**— 直播版本的`DFEHashIndexBuild`.

**DFEStreamingGroupByHashIndex**— 直播版本的`DFEGroupByHashIndex`.

**DFESubquery**— 该运算符出现在所有计划的开头，它封装了计划中在 [DFE 引擎](neptune-dfe-engine.md)上运行的部分，这是 OpenCypher 的整个计划。

**DFESymmetricHashJoin**— 使用哈希联接根据指定的模式键连接前一个运算符的输入。这是一个非阻止操作。

**DFESync**— 此运算符是支持非阻塞计划的同步运算符。它从两个传入边缘获取解，然后将这些解转发到相应的下游边缘。出于同步目的，可以对其中一个边缘的输入进行内部缓冲。

**DFETee**— 这是一个分支运算符，它向多个运算符发送相同的解决方案集。

**DFETerm分辨率**-对其输入执行本地化或全局化操作，生成分别包含本地化或全球化标识符的列。

**** - 将输入列中的值列表作为单个元素展开到输出列。

**DFEUnion**— 采用两个或多个输入关系，并使用所需的输出架构生成这些关系的并集。

**SolutionInjection**— 显示在 explain 输出中的其他所有内容之前，在 Units Out 列中的值为 1。但是，它不起作用，实际上并没有向 DFE 引擎注入任何解。

**TermResolution**— 出现在计划末尾，将海王星引擎中的对象转换为 OpenCypher 对象。

## openCypher `explain` 输出中的列
<a name="access-graph-opencypher-explain-columns"></a>

Neptune 作为 openCypher explain 输出生成的查询计划信息包含每行具有一个运算符的表。此表包含以下各列：

**ID** – 计划中此运算符的数字 ID。

**Out \#1**（和 **Out \#2**）– 此运算符下游的运算符的 ID。最多可以有两个下游运算符。

**Name** – 此运算符的名称。

**Arguments** – 运算符的任何相关详细信息。这包括如输入架构、输出架构、模式（对于 `PipelineScan` 和 `PipelineJoin`）等。

**Mode** – 描述基本运算符行为的标签。此列一般为空白 (`-`)。一个例外是 `TermResolution`，其中模式可以是 `id2value_opencypher`，表示从 ID 到 openCypher 值的解。

**Units In** – 作为输入传递给该运算符的解的数量。没有上游运算符的运算符（例如 `DFEPipelineScan`、`SolutionInjections` 和未注入静态值的 `DFESubquery`）的值为零。

**Units Out** – 作为该运算符的输出而生成的解的数量。`DFEDrain` 是一种特殊情况，其中被排除的解的数量记录在 `Units In` 中，并且 `Units Out` 始终为零。

**Ratio** – `Units Out` 与 `Units In` 的比率。

**Time (ms)** – 此运算符消耗的 CPU 时间，以毫秒为单位。

## openCypher explain 输出的一个基本示例
<a name="access-graph-opencypher-explain-basic-example"></a>

以下是 openCypher `explain` 输出的基本示例。该查询是空中航线数据集中的单节点查找，该节点的机场代码`ATL``explain`使用默认 ASCII 输出格式的`details`模式调用。

要调`explain`用此查询，请执行以下操作：

------
#### [ Amazon CLI ]

```
aws neptunedata execute-open-cypher-explain-query \
  --endpoint-url https://{{your-neptune-endpoint}}:{{port}} \
  --open-cypher-query "MATCH (n {code: 'ATL'}) RETURN n" \
  --explain-mode details
```

有关更多信息，请参阅《 Amazon CLI 命令参考》中的 [execute-open-cypher-explain-query](https://docs.amazonaws.cn/cli/latest/reference/neptunedata/execute-open-cypher-explain-query.html)。

------
#### [ SDK ]

```
import boto3
from botocore.config import Config

client = boto3.client(
    'neptunedata',
    endpoint_url='https://{{your-neptune-endpoint}}:{{port}}',
    config=Config(read_timeout=None, retries={'total_max_attempts': 1})
)

response = client.execute_open_cypher_explain_query(
    openCypherQuery="MATCH (n {code: 'ATL'}) RETURN n",
    explainMode='details'
)

print(response['results'].read().decode('utf-8'))
```

有关其他语言 Amazon 的 SDK 示例，请参阅[Amazon SDK](access-graph-opencypher-sdk.md)。

------
#### [ awscurl ]

```
awscurl https://{{your-neptune-endpoint}}:{{port}}/openCypher \
  --region {{us-east-1}} \
  --service neptune-db \
  -X POST \
  -d "query=MATCH (n {code: 'ATL'}) RETURN n" \
  -d "explain=details"
```

**注意**  
此示例假设您的 Amazon 证书是在您的环境中配置的。{{us-east-1}}替换为 Neptune 集群的区域。

------
#### [ curl ]

```
curl https://{{your-neptune-endpoint}}:{{port}}/openCypher \
  -d "query=MATCH (n {code: 'ATL'}) RETURN n" \
  -d "explain=details"
```

------

输`explain`出：

```
Query:
MATCH (n {code: 'ATL'}) RETURN n

╔════╤════════╤════════╤═══════════════════╤════════════════════╤═════════════════════╤══════════╤═══════════╤═══════╤═══════════╗
║ ID │ Out #1 │ Out #2 │ Name              │ Arguments          │ Mode                │ Units In │ Units Out │ Ratio │ Time (ms) ║
╠════╪════════╪════════╪═══════════════════╪════════════════════╪═════════════════════╪══════════╪═══════════╪═══════╪═══════════╣
║ 0  │ 1      │ -      │ SolutionInjection │ solutions=[{}]     │ -                   │ 0        │ 1         │ 0.00  │ 0         ║
╟────┼────────┼────────┼───────────────────┼────────────────────┼─────────────────────┼──────────┼───────────┼───────┼───────────╢
║ 1  │ 2      │ -      │ DFESubquery       │ subQuery=subQuery1 │ -                   │ 0        │ 1         │ 0.00  │ 4.00      ║
╟────┼────────┼────────┼───────────────────┼────────────────────┼─────────────────────┼──────────┼───────────┼───────┼───────────╢
║ 2  │ -      │ -      │ TermResolution    │ vars=[?n]          │ id2value_opencypher │ 1        │ 1         │ 1.00  │ 2.00      ║
╚════╧════════╧════════╧═══════════════════╧════════════════════╧═════════════════════╧══════════╧═══════════╧═══════╧═══════════╝


subQuery1
╔════╤════════╤════════╤═══════════════════════╤══════════════════════════════════════════════════════════════════════════════════════════════════════════════╤══════╤══════════╤═══════════╤═══════╤═══════════╗
║ ID │ Out #1 │ Out #2 │ Name                  │ Arguments                                                                                                    │ Mode │ Units In │ Units Out │ Ratio │ Time (ms) ║
╠════╪════════╪════════╪═══════════════════════╪══════════════════════════════════════════════════════════════════════════════════════════════════════════════╪══════╪══════════╪═══════════╪═══════╪═══════════╣
║ 0  │ 1      │ -      │ DFEPipelineScan       │ pattern=Node(?n) with property 'code' as ?n_code2 and label 'ALL'                                            │ -    │ 0        │ 1         │ 0.00  │ 0.21      ║
║    │        │        │                       │ inlineFilters=[(?n_code2 IN ["ATL"^^xsd:string])]                                                            │      │          │           │       │           ║
║    │        │        │                       │ patternEstimate=1                                                                                            │      │          │           │       │           ║
╟────┼────────┼────────┼───────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 1  │ 2      │ -      │ DFEChunkLocalSubQuery │ subQuery=http://aws.amazon.com/neptune/vocab/v01/dfe/past/graph#9d84f97c-c3b0-459a-98d5-955a8726b159/graph_1 │ -    │ 1        │ 1         │ 1.00  │ 0.04      ║
╟────┼────────┼────────┼───────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 2  │ 3      │ -      │ DFEProject            │ columns=[?n]                                                                                                 │ -    │ 1        │ 1         │ 1.00  │ 0.04      ║
╟────┼────────┼────────┼───────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 3  │ -      │ -      │ DFEDrain              │ -                                                                                                            │ -    │ 1        │ 0         │ 0.00  │ 0.03      ║
╚════╧════════╧════════╧═══════════════════════╧══════════════════════════════════════════════════════════════════════════════════════════════════════════════╧══════╧══════════╧═══════════╧═══════╧═══════════╝


subQuery=http://aws.amazon.com/neptune/vocab/v01/dfe/past/graph#9d84f97c-c3b0-459a-98d5-955a8726b159/graph_1
╔════╤════════╤════════╤══════════════════════╤════════════════════════════════════════════════════════════╤══════╤══════════╤═══════════╤═══════╤═══════════╗
║ ID │ Out #1 │ Out #2 │ Name                 │ Arguments                                                  │ Mode │ Units In │ Units Out │ Ratio │ Time (ms) ║
╠════╪════════╪════════╪══════════════════════╪════════════════════════════════════════════════════════════╪══════╪══════════╪═══════════╪═══════╪═══════════╣
║ 0  │ 1      │ -      │ DFESolutionInjection │ outSchema=[?n, ?n_code2]                                   │ -    │ 0        │ 1         │ 0.00  │ 0.02      ║
╟────┼────────┼────────┼──────────────────────┼────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 1  │ 2      │ 3      │ DFETee               │ -                                                          │ -    │ 1        │ 2         │ 2.00  │ 0.02      ║
╟────┼────────┼────────┼──────────────────────┼────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 2  │ 4      │ -      │ DFEDistinctColumn    │ column=?n                                                  │ -    │ 1        │ 1         │ 1.00  │ 0.20      ║
║    │        │        │                      │ ordered=false                                              │      │          │           │       │           ║
╟────┼────────┼────────┼──────────────────────┼────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 3  │ 5      │ -      │ DFEHashIndexBuild    │ vars=[?n]                                                  │ -    │ 1        │ 1         │ 1.00  │ 0.04      ║
╟────┼────────┼────────┼──────────────────────┼────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 4  │ 5      │ -      │ DFEPipelineJoin      │ pattern=Node(?n) with property 'ALL' and label '?n_label1' │ -    │ 1        │ 1         │ 1.00  │ 0.25      ║
║    │        │        │                      │ patternEstimate=3506                                       │      │          │           │       │           ║
╟────┼────────┼────────┼──────────────────────┼────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 5  │ 6      │ 7      │ DFESync              │ -                                                          │ -    │ 2        │ 2         │ 1.00  │ 0.02      ║
╟────┼────────┼────────┼──────────────────────┼────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 6  │ 8      │ -      │ DFEForwardValue      │ -                                                          │ -    │ 1        │ 1         │ 1.00  │ 0.01      ║
╟────┼────────┼────────┼──────────────────────┼────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 7  │ 8      │ -      │ DFEForwardValue      │ -                                                          │ -    │ 1        │ 1         │ 1.00  │ 0.01      ║
╟────┼────────┼────────┼──────────────────────┼────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 8  │ 9      │ -      │ DFEHashIndexJoin     │ -                                                          │ -    │ 2        │ 1         │ 0.50  │ 0.35      ║
╟────┼────────┼────────┼──────────────────────┼────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 9  │ -      │ -      │ DFEDrain             │ -                                                          │ -    │ 1        │ 0         │ 0.00  │ 0.02      ║
╚════╧════════╧════════╧══════════════════════╧════════════════════════════════════════════════════════════╧══════╧══════════╧═══════════╧═══════╧═══════════╝
```

在顶层，`SolutionInjection` 出现在其它所有内容之前，其 Units Out 为 1。请注意，它实际上并没有注入任何解。您可以看到下一个运算符 `DFESubquery` 的 Units In 为 0。

在顶层的 `SolutionInjection` 之后是 `DFESubquery` 和 `TermResolution` 运算符。`DFESubquery` 封装查询执行计划中正在推送到 [DFE 引擎](neptune-dfe-engine.md)的部分（对于 openCypher 查询，整个查询计划由 DFE 执行）。查询计划中的所有运算符都嵌套在由 `DFESubquery` 引用的 `subQuery1` 内部。唯一的例外是`TermResolution`，它在内部实现 IDs 为完全序列化的 OpenCypher 对象。

所有下推到 DFE 引擎的运算符的名称都以 `DFE` 前缀开头。如上所述，整个 openCypher 查询计划由 DFE 执行，因此，除最后一个 `TermResolution` 运算符之外的所有运算符都以 `DFE` 开头。

在 `subQuery1` 内部，可以有零个或多个 `DFEChunkLocalSubQuery` 或 `DFELoopSubQuery` 运算符来封装在内存受限机制中执行的推送执行计划的一部分。这里的 `DFEChunkLocalSubQuery` 包含一个 `SolutionInjection`，它用作子查询的输入。要在输出中查找该子查询的表，请在 `Arguments` 列中搜索为 `DFEChunkLocalSubQuery` 或 `DFELoopSubQuery` 运算符指定的 `subQuery={{graph URI}}`。

在 `subQuery1` 中，`ID` 为 0 的 `DFEPipelineScan` 扫描数据库以查找指定的 `pattern`。该模式在所有标签上扫描属性 `code` 保存为变量 `?n_code2` 的实体（可以通过将 `airport` 附加到 `n:airport` 来针对特定标签进行筛选）。`inlineFilters` 参数显示了针对等于 `ATL` 的 `code` 属性的筛选。

接下来，`DFEChunkLocalSubQuery` 运算符联接包含 `DFEPipelineJoin` 的子查询的中间结果。这可以确保 `?n` 实际上是一个节点，因为之前的 `DFEPipelineScan` 会扫描任何具有 `code` 属性的实体。