View a markdown version of this page

在 Neptune 中使用 Gremlin 解释 API - Amazon Neptune

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

在 Neptune 中使用 Gremlin 解释 API

Amazon Neptune Gremlin explain API 返回将在运行指定查询时执行的查询计划。由于该 API 实际上并未运行查询,因此几乎可即时返回计划。

它与 TinkerPop .explain () 步骤的不同之处在于能够报告特定于 Neptune 引擎的信息。

Gremlin 解释报告中包含的信息

explain 报告包含以下信息:

  • 要求的查询字符串。

  • 原始遍历。这是通过将查询字符串解析为步骤而生成的 TinkerPop Traversal 对象。 TinkerPop 它等同于在针对的查询.explain()上运行所产生的原始查询 TinkerPop TinkerGraph。

  • 转换的遍历。这是通过将遍历转换为海王星逻辑查询计划表示形式而生成的 Neptune Trav TinkerPop ersal。在许多情况下,整个 TinkerPop 遍历会转换为两个 Neptune 步骤:一个执行整个查询 (NeptuneGraphQueryStep),另一个将海王星查询引擎的输出转换回 Traversers ()。 TinkerPop NeptuneTraverserConverterStep

  • 优化的遍历。这是 Neptune 查询计划的优化版本,已经通过一系列静态减负优化器运行它,这些优化器基于静态分析和估计基数重写查询。优化器执行多种操作,例如根据范围计数对运算符进行重新排序、删除不必要或多余的运算符、重新排列筛选条件、将运算符推入不同的组等。

  • 谓词计数。如前所述,出于 Neptune 索引策略的原因,具有大量不同谓词可能会导致性能问题。对于使用没有边缘标签(.in.both)的反向遍历运算符的查询,这一点尤为明显。如果使用了此类运算符并且谓词数量足够多,explain 报告将显示警告消息。

  • DFE 信息。启用 DFE 替代引擎后,以下遍历组件可能会出现在优化的遍历中:

    • DFEStep – 在包含子 DFENode 的遍历中,Neptune 优化的 DFE 步骤。DFEStep 表示查询计划中在 DFE 引擎中执行的部分。

    • DFENode – 包含中间表示(作为一个或多个子 DFEJoinGroupNodes)。

    • DFEJoinGroupNode – 表示一个或多个 DFENodeDFEJoinGroupNode 元素的联接。

    • NeptuneInterleavingStep – 在包含子 DFEStep 的遍历中,Neptune 优化的 DFE 步骤。

      还包含一个 stepInfo 元素,其中包含有关遍历的信息,例如边界元素、使用的路径元素等。此信息用于处理子 DFEStep

    要查明 DFE 是否正在计算您的查询,一种简单的方法是检查 explain 输出中是否包含 DFEStep。任何不属于的遍历部分都不会由 DFE 执行,而是由引擎执行。DFEStep TinkerPop

    有关示例报告,请参阅启用 DFE 的示例

Gremlin 解释语法

explainAPI 的语法与用于查询的 HTTP API 的语法相同,不同之处在于它/gremlin/explain用作终端节点/gremlin,而不是以下示例所示。

AWS CLI
aws neptunedata execute-gremlin-explain-query \ --endpoint-url https://your-neptune-endpoint:port \ --gremlin-query "g.V().limit(1)"

有关更多信息,请参阅《命令参考》中的 execute-gremlin-explain-query。 AWS CLI

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_gremlin_explain_query( gremlinQuery='g.V().limit(1)' ) print(response['output'])

有关其他语言(如 Java、.NET 等)的 AWS SDK 示例,请参阅AWS SDK

awscurl
awscurl https://your-neptune-endpoint:port/gremlin/explain \ --region us-east-1 \ --service neptune-db \ -X POST \ -d '{"gremlin":"g.V().limit(1)"}'
注意

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

有关awscurl与 IAM 身份验证配合使用的更多信息,请参阅使用带有临时证书的 awscurl 安全地连接到启用 IAM 身份验证的数据库集群

curl
curl -X POST https://your-neptune-endpoint:port/gremlin/explain \ -d '{"gremlin":"g.V().limit(1)"}'

前面的查询将产生以下输出。

******************************************************* Neptune Gremlin Explain ******************************************************* Query String ============ g.V().limit(1) Original Traversal ================== [GraphStep(vertex,[]), RangeGlobalStep(0,1)] Converted Traversal =================== Neptune steps: [ NeptuneGraphQueryStep(Vertex) { JoinGroupNode { PatternNode[(?1, <~label>, ?2, <~>) . project distinct ?1 .] }, finishers=[limit(1)], annotations={path=[Vertex(?1):GraphStep], maxVarId=3} }, NeptuneTraverserConverterStep ] Optimized Traversal =================== Neptune steps: [ NeptuneGraphQueryStep(Vertex) { JoinGroupNode { PatternNode[(?1, <~label>, ?2, <~>) . project distinct ?1 .], {estimatedCardinality=INFINITY} }, finishers=[limit(1)], annotations={path=[Vertex(?1):GraphStep], maxVarId=3} }, NeptuneTraverserConverterStep ] Predicates ========== # of predicates: 18

未转换的步骤 TinkerPop

理想情况下,遍历中的所有 TinkerPop 步骤都具有原生 Neptune 运算符覆盖范围。如果不是这种情况,Neptune会因为操作员覆盖范围存在差距而退回 TinkerPop 分步执行。如果遍历使用 Neptune 尚无原生运算符的步骤,explain 报告将显示一条警告,指出缺失运算符的位置。

当遇到没有相应原生 Neptune 运算符的步骤时,即使后续步骤确实有原生 Neptune 运算符,也将使用 TinkerPop 步骤运行从该点开始的整个遍历。

这种情况的例外是调用 Neptune 全文搜索时。 NeptuneSearchStep 实现了没有原生等效项的步骤作为全文搜索步骤。

expl a in 输出示例,其中查询中的所有步骤都具有本机等效项

下面是一个示例查询 explain 报告,其中所有步骤都有原生等效运算符:

******************************************************* Neptune Gremlin Explain ******************************************************* Query String ============ g.V().out() Original Traversal ================== [GraphStep(vertex,[]), VertexStep(OUT,vertex)] Converted Traversal =================== Neptune steps: [ NeptuneGraphQueryStep(Vertex) { JoinGroupNode { PatternNode[(?1, <~label>, ?2, <~>) . project distinct ?1 .] PatternNode[(?1, ?5, ?3, ?6) . project ?1,?3 . IsEdgeIdFilter(?6) .] PatternNode[(?3, <~label>, ?4, <~>) . project ask .] }, annotations={path=[Vertex(?1):GraphStep, Vertex(?3):VertexStep], maxVarId=7} }, NeptuneTraverserConverterStep ] Optimized Traversal =================== Neptune steps: [ NeptuneGraphQueryStep(Vertex) { JoinGroupNode { PatternNode[(?1, ?5, ?3, ?6) . project ?1,?3 . IsEdgeIdFilter(?6) .], {estimatedCardinality=INFINITY} }, annotations={path=[Vertex(?1):GraphStep, Vertex(?3):VertexStep], maxVarId=7} }, NeptuneTraverserConverterStep ] Predicates ========== # of predicates: 18

查询中的部分步骤没有本机等效运算符的示例

Neptune 原生处理 GraphStepVertexStep,但如果引入 FoldStepUnfoldStep,则结果 explain 输出会有所不同:

******************************************************* Neptune Gremlin Explain ******************************************************* Query String ============ g.V().fold().unfold().out() Original Traversal ================== [GraphStep(vertex,[]), FoldStep, UnfoldStep, VertexStep(OUT,vertex)] Converted Traversal =================== Neptune steps: [ NeptuneGraphQueryStep(Vertex) { JoinGroupNode { PatternNode[(?1, <~label>, ?2, <~>) . project distinct ?1 .] }, annotations={path=[Vertex(?1):GraphStep], maxVarId=3} }, NeptuneTraverserConverterStep ] + not converted into Neptune steps: [FoldStep, UnfoldStep, VertexStep(OUT,vertex)] Optimized Traversal =================== Neptune steps: [ NeptuneGraphQueryStep(Vertex) { JoinGroupNode { PatternNode[(?1, <~label>, ?2, <~>) . project distinct ?1 .], {estimatedCardinality=INFINITY} }, annotations={path=[Vertex(?1):GraphStep], maxVarId=3} }, NeptuneTraverserConverterStep, NeptuneMemoryTrackerStep ] + not converted into Neptune steps: [FoldStep, UnfoldStep, VertexStep(OUT,vertex)] WARNING: >> FoldStep << is not supported natively yet

在这种情况下,FoldStep 将使遍历跳出本机执行。同时,后续的 VertexStep 也不再在本机处理,因为它出现在 Fold/Unfold 步骤之后。

为了提高性能和节省成本,请务必尝试制定遍历公式,以便在 Neptune 查询引擎中以本机方式完成尽可能多的工作,而不是通过分步实现。 TinkerPop

使用 Neptune 全文搜索的查询示例

以下查询使用 Neptune 全文搜索:

g.withSideEffect("Neptune#fts.endpoint", "some_endpoint") .V() .tail(100) .has("Neptune#fts mark*") ------- .has("name", "Neptune#fts mark*") .has("Person", "name", "Neptune#fts mark*")

.has("name", "Neptune#fts mark*") 部分将搜索限制为带有 name 的顶点,而 .has("Person", "name", "Neptune#fts mark*") 将搜索限制为带有 name 和标签 Person 的顶点。这将导致 explain 报告中出现以下遍历:

Final Traversal [NeptuneGraphQueryStep(Vertex) { JoinGroupNode { PatternNode[(?1, termid(1,URI), ?2, termid(0,URI)) . project distinct ?1 .], {estimatedCardinality=INFINITY} }, annotations={path=[Vertex(?1):GraphStep], maxVarId=4} }, NeptuneTraverserConverterStep, NeptuneTailGlobalStep(10), NeptuneTinkerpopTraverserConverterStep, NeptuneSearchStep { JoinGroupNode { SearchNode[(idVar=?3, query=mark*, field=name) . project ask .], {endpoint=some_endpoint} } JoinGroupNode { SearchNode[(idVar=?3, query=mark*, field=name) . project ask .], {endpoint=some_endpoint} } }]

启用 DFE 时使用解释的示例

以下是启用 DFE 备用查询引擎时 explain 报告的示例:

******************************************************* Neptune Gremlin Explain ******************************************************* Query String ============ g.V().as("a").out().has("name", "josh").out().in().where(eq("a")) Original Traversal ================== [GraphStep(vertex,[])@[a], VertexStep(OUT,vertex), HasStep([name.eq(josh)]), VertexStep(OUT,vertex), VertexStep(IN,vertex), WherePredicateStep(eq(a))] Converted Traversal =================== Neptune steps: [ DFEStep(Vertex) { DFENode { DFEJoinGroupNode[ children={ DFEPatternNode[(?1, <http://www.w3.org/1999/02/22-rdf-syntax-ns#type>, ?2, <http://aws.amazon.com/neptune/vocab/v01/DefaultNamedGraph>) . project DISTINCT[?1] {rangeCountEstimate=unknown}], DFEPatternNode[(?1, ?3, ?4, ?5) . project ALL[?1, ?4] graphFilters=(!= <http://aws.amazon.com/neptune/vocab/v01/DefaultNamedGraph> . ), {rangeCountEstimate=unknown}] }, {rangeCountEstimate=unknown} ] } [Vertex(?1):GraphStep@[a], Vertex(?4):VertexStep] } , NeptuneTraverserConverterDFEStep ] + not converted into Neptune steps: HasStep([name.eq(josh)]), Neptune steps: [ NeptuneInterleavingStep { StepInfo[joinVars=[?7, ?1], frontierElement=Vertex(?7):HasStep, pathElements={a=(last,Vertex(?1):GraphStep@[a])}, listPathElement={}, indexTime=0ms], DFEStep(Vertex) { DFENode { DFEJoinGroupNode[ children={ DFEPatternNode[(?7, ?8, ?9, ?10) . project ALL[?7, ?9] graphFilters=(!= <http://aws.amazon.com/neptune/vocab/v01/DefaultNamedGraph> . ), {rangeCountEstimate=unknown}], DFEPatternNode[(?12, ?11, ?9, ?13) . project ALL[?9, ?12] graphFilters=(!= <http://aws.amazon.com/neptune/vocab/v01/DefaultNamedGraph> . ), {rangeCountEstimate=unknown}] }, {rangeCountEstimate=unknown} ] } [Vertex(?9):VertexStep, Vertex(?12):VertexStep] } } ] + not converted into Neptune steps: WherePredicateStep(eq(a)), Neptune steps: [ DFECleanupStep ] Optimized Traversal =================== Neptune steps: [ DFEStep(Vertex) { DFENode { DFEJoinGroupNode[ children={ DFEPatternNode[(?1, ?3, ?4, ?5) . project ALL[?1, ?4] graphFilters=(!= defaultGraph[526] . ), {rangeCountEstimate=9223372036854775807}] }, {rangeCountEstimate=unknown} ] } [Vertex(?1):GraphStep@[a], Vertex(?4):VertexStep] } , NeptuneTraverserConverterDFEStep ] + not converted into Neptune steps: NeptuneHasStep([name.eq(josh)]), Neptune steps: [ NeptuneMemoryTrackerStep, NeptuneInterleavingStep { StepInfo[joinVars=[?7, ?1], frontierElement=Vertex(?7):HasStep, pathElements={a=(last,Vertex(?1):GraphStep@[a])}, listPathElement={}, indexTime=0ms], DFEStep(Vertex) { DFENode { DFEJoinGroupNode[ children={ DFEPatternNode[(?7, ?8, ?9, ?10) . project ALL[?7, ?9] graphFilters=(!= defaultGraph[526] . ), {rangeCountEstimate=9223372036854775807}], DFEPatternNode[(?12, ?11, ?9, ?13) . project ALL[?9, ?12] graphFilters=(!= defaultGraph[526] . ), {rangeCountEstimate=9223372036854775807}] }, {rangeCountEstimate=unknown} ] } [Vertex(?9):VertexStep, Vertex(?12):VertexStep] } } ] + not converted into Neptune steps: WherePredicateStep(eq(a)), Neptune steps: [ DFECleanupStep ] WARNING: >> [NeptuneHasStep([name.eq(josh)]), WherePredicateStep(eq(a))] << (or one of the children for each step) is not supported natively yet Predicates ========== # of predicates: 8

explain 中的信息有关报告中 DFE-specific 各部分的说明,请参阅。