openCypher explain 特征 - Amazon Neptune
Amazon Web Services 文档中描述的 Amazon Web Services 服务或功能可能因区域而异。要查看适用于中国区域的差异,请参阅 中国的 Amazon Web Services 服务入门 (PDF)

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

openCypher explain 特征

openCypher explain 特征是 Amazon Neptune 中的一种自助式工具,可帮助您了解 Neptune 引擎所采用的执行方法。要调用 explain,您需要使用 explain=mode 向 openCypher HTTPS 请求传递一个参数,其中 mode 值可以是以下值之一:

  • static – 在 static 模式下,explain 仅输出查询计划的静态结构。它不实际运行查询。

  • dynamic – 在 dynamic 模式下,explain 还会运行查询,并包括查询计划的动态方面。这些方面可能包括流经运算符的中间绑定的数量、传入绑定与传出绑定的比率以及每个运算符使用的总时间。

  • details – 在 details 模式下,explain 输出动态模式中显示的信息以及其它详细信息,例如实际的 openCypher 查询字符串和某个连接运算符之下模式的估计范围计数。

例如,使用 POST

curl HTTPS://server:port/openCypher \ -d "query=MATCH (n) RETURN n LIMIT 1;" \ -d "explain=dynamic"

或者,使用 GET

curl -X GET \ "HTTPS://server:port/openCypher?query=MATCH%20(n)%20RETURN%20n%20LIMIT%201&explain=dynamic"

Neptune 中 openCypher explain 的限制

openCypher Explain 的当前版本存在以下限制:

  • Explain 计划目前仅适用于执行只读操作的查询。不支持执行任何类型的突变(例如 CREATEDELETEMERGESET 等)的查询。

  • 特定计划的运算符和输出可能会在将来版本中发生变化。

openCypher explain 输出中的 DFE 运算符

要使用 openCypher explain 特征提供的信息,您需要了解有关 DFE 查询引擎工作原理的一些详细信息(DFE 是 Neptune 用来处理 openCypher 查询的引擎)。

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

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

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

DFE BindRelation-将具有指定名称的变量绑定在一起

DFE ChunkLocal SubQuery — 这是一种非阻塞操作,充当正在执行的子查询的封装器。

DFE DistinctColumn-根据指定的变量返回输入值的不同子集。

DFE DistinctRelation-根据指定的变量返回输入解决方案的不同子集。

DFEDrain – 出现在子查询的末尾,用作该子查询的终止步骤。解的数量记录为 Units InUnits Out 始终为零。

DFE ForwardValue — 将所有输入区块直接复制为输出块,然后传递给其下游运算符。

DFE GroupBy HashIndex — 根据先前计算的哈希索引(使用运算)对输入解执行分组运算。DFEHashIndexBuild作为输出,给定输入通过包含每个输入解的组键的列进行扩展。

DFE B HashIndex uild — 在一组变量上构建哈希索引作为副作用。此哈希索引通常会在以后的操作中重复使用。有关此哈希索引可能用在何处,请参阅 DFEHashIndexJoinDFEGroupByHashIndex

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

DFE JoinExists — 采用左手和右手输入关系,并保留左侧关系中具有相应值的值,这些值由给定连接变量定义。

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

DFE MergeChunks — 这是一种阻塞操作,它将来自上游运算符的区块组合成单个解决方案块,然后传递给其下游运算符(相反)。DFESplitChunks

DFEMinus - 获取左侧和右侧输入关系,并保留左侧输入关系中的值,这些值在由给定联接变量定义的右侧输入关系中不具有相应的值。如果两个关系中的变量没有重叠,则此运算符只返回左侧输入关系。

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

DFE OptionalJoin — 执行左外联接(也称为 OPTIONAL join):来自左侧的解决方案如果右侧至少有一个加入伙伴,则按原样转发来自左侧的解决方案,而右侧没有加入伙伴的解决方案则按原样转发。这是一项阻止操作。

DFE PipelineJoin — 根据参数定义的元组模式连接输入。pattern

DFE C PipelineRange ount — 计算与给定模式匹配的解的数量,并返回包含计数值的单个一元解。

DFE PipelineScan — 扫描数据库中的给定pattern参数,无论是否对列使用给定过滤器。

DFEProject – 采用多个输入列并仅投影所需的列。

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

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

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

DFE SelectRows — 此运算符有选择地从其左侧输入关系解中提取行,然后转发给其下游运算符。根据运算符右侧输入关系中提供的行标识符选择的行。

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

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

DFE SplitBy Grou p — 将来自一个传入边的每个输入块拆分为较小的输出块,这些块对应于行组,行组由来自另一个传入边的相应输入区块的行 ID 标识。

DFE SplitChunks — 将每个输入块拆分为较小的输出块(相反)。DFEMergeChunks

DFE StreamingHash IndexBuild —直播版本的. DFEHashIndexBuild

DFE StreamingGroup ByHash 索引 —直播版本. DFEGroupByHashIndex

DFESubquery – 此运算符出现在所有计划的开头,它封装计划中在 DFE 引擎上运行的部分,这是 openCypher 的整个计划。

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

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

DFETee – 这是一个分支运算符,它向多个运算符发送相同的解集。

DFE TermResolution — 对其输入执行本地化或全局化操作,生成分别包含本地化或全球化标识符的列。

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

DFEUnion - 获取两个或多个输入关系,并使用所需的输出架构生成这些关系的并集。

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

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

openCypher explain 输出中的列

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

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

Out #1(和 Out #2)– 此运算符下游的运算符的 ID。最多可以有两个下游运算符。

Name – 此运算符的名称。

Arguments – 运算符的任何相关详细信息。这包括如输入架构、输出架构、模式(对于 PipelineScanPipelineJoin)等。

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

Units In – 作为输入传递给该运算符的解的数量。没有上游运算符的运算符(例如 DFEPipelineScanSolutionInjections 和未注入静态值的 DFESubquery)的值为零。

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

RatioUnits OutUnits In 的比率。

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

openCypher explain 输出的一个基本示例

以下是 openCypher explain 输出的基本示例。该查询是在航线数据集中针对机场代码为 ATL 的节点执行的单节点查找,它使用默认 ASCII 输出格式的 details 模式调用 explain

curl -d "query=MATCH (n {code: 'ATL'}) RETURN n" -k https://localhost:8182/openCypher -d "explain=details" ~ 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 之后是 DFESubqueryTermResolution 运算符。DFESubquery 封装查询执行计划中正在推送到 DFE 引擎的部分(对于 openCypher 查询,整个查询计划由 DFE 执行)。查询计划中的所有运算符都嵌套在由 DFESubquery 引用的 subQuery1 内部。唯一的例外是 TermResolution,它将内部 ID 实体化为完全序列化的 openCypher 对象。

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

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

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

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