Neptune에서 Gremlin explain API 사용 - Amazon Neptune

기계 번역으로 제공되는 번역입니다. 제공된 번역과 원본 영어의 내용이 상충하는 경우에는 영어 버전이 우선합니다.

Neptune에서 Gremlin explain API 사용

Amazon Neptune Gremlin explain API는 지정된 쿼리가 실행된 경우에 실행할 쿼리 계획을 반환합니다. API가 실제로 쿼리를 실행하는 것은 아니기 때문에 계획은 거의 동시에 반환됩니다.

이는 Neptune 엔진 고유의 정보를 보고할 수 있다는 점에서 TinkerPop .explain() 단계와 다릅니다.

Gremlin explain 보고서에 포함된 정보

explain 보고서에는 다음 정보가 포함됩니다.

  • 요청에 따른 쿼리 문자열.

  • 원래 순회. 이는 TinkerPop 단계로 쿼리 문자열을 구문 분석하여 생성한 TinkerPop 순회 객체입니다. 이는 TinkerPop TinkerGraph를 토대로 쿼리에서 .explain()을 실행하여 생성한 원래 쿼리와 동등합니다.

  • 변환된 순회. TinkerPop 순회를 Neptune 논리적 쿼리 계획 표현으로 변환하여 생성한 Neptune 순회입니다. 많은 경우에 전체 TinkerPop 순회는 2개의 Neptune 단계로 변환되는데, 하나는 전체 쿼리(NeptuneGraphQueryStep)를 실행하는 단계이고 다른 하나는 Neptune 쿼리 엔진 출력을 TinkerPop Traversers(NeptuneTraverserConverterStep)로 다시 변환하는 단계입니다.

  • 최적화된 순회. 일련의 정적 작업 감소 옵티마이저를 통해 실행된 이후에 최적화된 버전의 Neptune 쿼리 계획입니다. 이 옵티마이저는 정적 분석 및 예상 카디널리티를 토대로 쿼리를 재작성합니다. 이러한 옵티마이저는 범위 수에 따라 재정렬 연산자와 비슷한 기능을 수행하고, 불필요하거나 중복된 연산자를 제거하고, 필터를 재배열하고, 연산자를 서로 다른 그룹에 배치합니다.

  • 조건자 수. 앞서 설명한 Neptune 인덱싱 전략으로 인해 서로 다른 조건자를 다수 가지고 있으면 성능 문제가 발생할 수 있습니다. 엣지 레이블(.in 또는 .both)과 함께 역 순회 연산자를 사용하는 쿼리의 경우에는 특히 그렇습니다. 이러한 연산자를 사용하고 조건자 수가 충분히 많은 경우에는 explain 보고서에 경고 메시지가 표시됩니다.

  • DFE 정보. DFE 대체 엔진이 활성화되면 최적화된 순회에 다음과 같은 순회 구성 요소가 표시될 수 있습니다.

    • DFEStep   –   하위 DFENode가 포함된 순회 시 Neptune에 최적화된 DFE 단계입니다. DFEStep은 DFE 엔진에서 실행되는 쿼리 계획의 일부를 나타냅니다.

    • DFENode   –   하나 이상의 하위 DFEJoinGroupNodes로 표현된 중간 표현을 포함합니다.

    • DFEJoinGroupNode   –   하나 이상의 DFENode 또는 DFEJoinGroupNode 요소의 조인을 나타냅니다.

    • NeptuneInterleavingStep   –   하위 DFEStep이 포함된 순회 시 Neptune에 최적화된 DFE 단계입니다.

      프론티어 요소, 사용된 경로 요소 등과 같은 순회 관련 정보가 들어 있는 stepInfo 요소도 포함되어 있습니다. 이 정보는 하위 DFEStep을 처리하는 데 사용됩니다.

    DFE에서 쿼리를 평가하고 있는지 쉽게 확인할 수 있는 방법은 explain 출력에 DFEStep이 포함되어 있는지 확인하는 것입니다. DFEStep의 일부가 아닌 순회에 속하지 않은 부분은 DFE에 의해 실행되지 않으며 TinkerPop 엔진에 의해 실행됩니다.

    샘플 보고서는 DFE가 활성화된 경우의 예제 섹션을 참조하세요.

Gremlin explain 구문

explain API의 구문은 쿼리용 HTTP API의 구문과 동일합니다. 단, 다음 예제와 같이 /gremlin 대신 /gremlin/explain를 엔드포인트로 사용하는 경우는 예외입니다.

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

변환되지 않은 Unconverted TinkerPop 단계

순회의 모든 TinkerPop 단계가 네이티브 Neptune 연산자 범위를 가지고 있는 것이 가장 이상적입니다. 그렇지 않은 경우에는 Neptune이 연산자 범위의 격차에 대해 TinkerPop 단계 실행을 폴백합니다. 순회에서 Neptune이 아직 네이티브 범위를 가지고 있지 않은 단계를 사용하는 경우에는 explain 보고서에 격차가 발생했음을 알리는 경고가 표시됩니다.

해당되는 네이티브 Neptune 연산자가 없는 단계가 나타나면 해당 시점부터는 후속 단계에 네이티브 Neptune 연산자가 있는 경우라도 전체 순회가 TinkerPop 단계를 사용하여 실행됩니다.

단, Neptune 전체 텍스트 검색이 호출되는 경우는 예외입니다. NepTuneSearchStep은 네이티브에 상당하는 항목이 없는 단계를 전체 텍스트 검색 단계로 구현합니다.

쿼리의 모든 단계에 네이티브에 상당하는 항목이 있는 explain 출력 예제

다음은 모든 단계에 네이티브에 상당하는 항목이 있는 쿼리에 대한 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 단계의 다운스트림에 나타나기 때문입니다.

성능 및 비용 절감을 위해서는 TinkerPop 단계를 구현하는 대신에 Neptune 쿼리 엔진 내에서 기본적으로 최대한 많은 양의 작업이 처리되도록 순회를 구성하려고 해야 합니다.

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가 활성화된 경우의 explain 사용 예제

다음은 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

보고서의 DFE 관련 섹션에 대한 설명은 explain의 정보 섹션을 참조하세요.