From c2e35fdbdbb0ede8067ff97b6c8084bc2dc4e8ad Mon Sep 17 00:00:00 2001 From: Xiaoli Zhou Date: Thu, 6 Jun 2024 20:03:46 +0800 Subject: [PATCH] fix(interactive): Support Path Expand Until Condition in Gremlin-Calcite (#3878) ## What do these changes do? as titled. ## Related issue number Fixes --------- Co-authored-by: Zhang Lei --- .../compiler/src/main/antlr4/GremlinGS.g4 | 1 + .../common/ir/planner/GraphFieldTrimmer.java | 1 + .../common/ir/planner/GraphIOProcessor.java | 9 +- .../planner/rules/ExpandGetVFusionRule.java | 1 + .../ir/rel/graph/GraphLogicalPathExpand.java | 21 ++++ .../proto/GraphRelToProtoConverter.java | 6 + .../common/ir/tools/GraphBuilder.java | 3 +- .../ir/tools/config/PathExpandConfig.java | 117 +++++++----------- .../common/ir/type/GraphTypeInference.java | 1 + .../antlr4/visitor/GraphBuilderVisitor.java | 4 +- .../visitor/PathExpandBuilderVisitor.java | 9 +- .../antlr4x/visitor/GraphBuilderVisitor.java | 12 +- .../visitor/PathExpandBuilderVisitor.java | 16 ++- .../suite/standard/IrGremlinQueryTest.java | 27 ++++ .../graphscope/common/ir/ExpandTest.java | 18 ++- .../ir/planner/rbo/ExpandGetVFusionTest.java | 27 +++- .../ir/planner/rbo/FilterPushDownTest.java | 20 ++- .../common/ir/runtime/FfiLogicalPlanTest.java | 9 +- .../ir/runtime/GraphRelToProtoTest.java | 18 ++- .../gremlin/antlr4x/GraphBuilderTest.java | 21 ++++ 20 files changed, 227 insertions(+), 114 deletions(-) diff --git a/interactive_engine/compiler/src/main/antlr4/GremlinGS.g4 b/interactive_engine/compiler/src/main/antlr4/GremlinGS.g4 index 9f9dbc10894c..3d400f0b84f1 100644 --- a/interactive_engine/compiler/src/main/antlr4/GremlinGS.g4 +++ b/interactive_engine/compiler/src/main/antlr4/GremlinGS.g4 @@ -189,6 +189,7 @@ traversalMethod_bothE traversalMethod_with : 'with' LPAREN StringLiteral COMMA oC_Literal RPAREN | 'with' LPAREN evaluationTimeoutKey COMMA evaluationTimeoutValue RPAREN + | 'with' LPAREN StringLiteral COMMA (ANON_TRAVERSAL_ROOT DOT)? traversalMethod_expr RPAREN // to support path until condition in gremlin-calcite, i.e. with('UNTIL', expr(_.age > 20)) ; evaluationTimeoutKey diff --git a/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/common/ir/planner/GraphFieldTrimmer.java b/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/common/ir/planner/GraphFieldTrimmer.java index 151ee0c617b9..0a535bca43b3 100644 --- a/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/common/ir/planner/GraphFieldTrimmer.java +++ b/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/common/ir/planner/GraphFieldTrimmer.java @@ -450,6 +450,7 @@ public TrimResult trimFields(GraphLogicalPathExpand pathExpand, UsedFields field pathExpand.getFetch(), pathExpand.getResultOpt(), pathExpand.getPathOpt(), + pathExpand.getUntilCondition(), pathExpand.getAliasName(), pathExpand.getStartAlias()); return result(newPathExpand, mapping, pathExpand); diff --git a/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/common/ir/planner/GraphIOProcessor.java b/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/common/ir/planner/GraphIOProcessor.java index 557ff6d10361..bf241e1f5e79 100644 --- a/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/common/ir/planner/GraphIOProcessor.java +++ b/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/common/ir/planner/GraphIOProcessor.java @@ -213,6 +213,10 @@ public void visit(RelNode node, int ordinal, @Nullable RelNode parent) { parent instanceof GraphLogicalGetV, "there should be a getV operator after path expand since" + " edge in patten should have two endpoints"); + Preconditions.checkArgument( + ((GraphLogicalPathExpand) node).getUntilCondition() == null, + "cannot apply optimization if path expand has until" + + " conditions"); PatternVertex vertex = visitAndAddVertex((GraphLogicalGetV) parent); visitAndAddPxdEdge( (GraphLogicalPathExpand) node, lastVisited, vertex); @@ -809,7 +813,8 @@ private RelNode createExpandGetV( edge.getElementDetails().getRange().getOffset(), edge.getElementDetails().getRange().getFetch()); GraphLogicalPathExpand pxd = - (GraphLogicalPathExpand) builder.pathExpand(pxdBuilder.build()).build(); + (GraphLogicalPathExpand) + builder.pathExpand(pxdBuilder.buildConfig()).build(); GraphLogicalExpand expand = (GraphLogicalExpand) pxd.getExpand(); GraphSchemaType edgeType = (GraphSchemaType) expand.getRowType().getFieldList().get(0).getType(); @@ -858,6 +863,7 @@ private GraphLogicalPathExpand createPathExpandWithOptional( pxd.getFetch(), pxd.getResultOpt(), pxd.getPathOpt(), + pxd.getUntilCondition(), pxd.getAliasName(), pxd.getStartAlias(), optional); @@ -872,6 +878,7 @@ private GraphLogicalPathExpand createPathExpandWithOptional( pxd.getFetch(), pxd.getResultOpt(), pxd.getPathOpt(), + pxd.getUntilCondition(), pxd.getAliasName(), pxd.getStartAlias(), optional); diff --git a/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/common/ir/planner/rules/ExpandGetVFusionRule.java b/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/common/ir/planner/rules/ExpandGetVFusionRule.java index 5ba60dee80ca..551492ce773c 100644 --- a/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/common/ir/planner/rules/ExpandGetVFusionRule.java +++ b/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/common/ir/planner/rules/ExpandGetVFusionRule.java @@ -308,6 +308,7 @@ public void onMatch(RelOptRuleCall call) { pathExpand.getFetch(), pathExpand.getResultOpt(), pathExpand.getPathOpt(), + pathExpand.getUntilCondition(), pathExpand.getAliasName(), pathExpand.getStartAlias(), pathExpand.isOptional()); diff --git a/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/common/ir/rel/graph/GraphLogicalPathExpand.java b/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/common/ir/rel/graph/GraphLogicalPathExpand.java index 68fed08477f5..f7deb4f67bba 100644 --- a/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/common/ir/rel/graph/GraphLogicalPathExpand.java +++ b/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/common/ir/rel/graph/GraphLogicalPathExpand.java @@ -63,6 +63,8 @@ public class GraphLogicalPathExpand extends SingleRel { private final boolean optional; + private final @Nullable RexNode untilCondition; + protected GraphLogicalPathExpand( GraphOptCluster cluster, @Nullable List hints, @@ -73,6 +75,7 @@ protected GraphLogicalPathExpand( @Nullable RexNode fetch, GraphOpt.PathExpandResult resultOpt, GraphOpt.PathExpandPath pathOpt, + @Nullable RexNode untilCondition, @Nullable String aliasName, AliasNameWithId startAlias, boolean optional) { @@ -97,6 +100,7 @@ protected GraphLogicalPathExpand( (this.aliasId == AliasInference.DEFAULT_ID) ? resultOpt : GraphOpt.PathExpandResult.ALL_V_E; + this.untilCondition = untilCondition; } protected GraphLogicalPathExpand( @@ -108,6 +112,7 @@ protected GraphLogicalPathExpand( @Nullable RexNode fetch, GraphOpt.PathExpandResult resultOpt, GraphOpt.PathExpandPath pathOpt, + @Nullable RexNode untilCondition, @Nullable String aliasName, AliasNameWithId startAlias, boolean optional) { @@ -125,6 +130,7 @@ protected GraphLogicalPathExpand( this.aliasId = cluster.getIdGenerator().generate(this.aliasName); this.startAlias = Objects.requireNonNull(startAlias); this.optional = optional; + this.untilCondition = untilCondition; } public static GraphLogicalPathExpand create( @@ -137,6 +143,7 @@ public static GraphLogicalPathExpand create( @Nullable RexNode fetch, GraphOpt.PathExpandResult resultOpt, GraphOpt.PathExpandPath pathOpt, + @Nullable RexNode untilCondition, String aliasName, AliasNameWithId startAlias, boolean optional) { @@ -150,6 +157,7 @@ public static GraphLogicalPathExpand create( fetch, resultOpt, pathOpt, + untilCondition, aliasName, startAlias, optional); @@ -165,6 +173,7 @@ public static GraphLogicalPathExpand create( @Nullable RexNode fetch, GraphOpt.PathExpandResult resultOpt, GraphOpt.PathExpandPath pathOpt, + @Nullable RexNode untilCondition, String aliasName, AliasNameWithId startAlias) { return create( @@ -177,6 +186,7 @@ public static GraphLogicalPathExpand create( fetch, resultOpt, pathOpt, + untilCondition, aliasName, startAlias, false); @@ -191,6 +201,7 @@ public static GraphLogicalPathExpand create( @Nullable RexNode fetch, GraphOpt.PathExpandResult resultOpt, GraphOpt.PathExpandPath pathOpt, + @Nullable RexNode untilCondition, String aliasName, AliasNameWithId startAlias) { return create( @@ -202,6 +213,7 @@ public static GraphLogicalPathExpand create( fetch, resultOpt, pathOpt, + untilCondition, aliasName, startAlias, false); @@ -216,6 +228,7 @@ public static GraphLogicalPathExpand create( @Nullable RexNode fetch, GraphOpt.PathExpandResult resultOpt, GraphOpt.PathExpandPath pathOpt, + @Nullable RexNode untilCondition, String aliasName, AliasNameWithId startAlias, boolean optional) { @@ -231,6 +244,7 @@ public static GraphLogicalPathExpand create( fetch, resultOpt, pathOpt, + untilCondition, aliasName, startAlias, optional); @@ -246,6 +260,7 @@ public RelWriter explainTerms(RelWriter pw) { .itemIf("fetch", fetch, fetch != null) .item("path_opt", getPathOpt()) .item("result_opt", getResultOpt()) + .itemIf("until_condition", untilCondition, untilCondition != null) .item("alias", AliasInference.SIMPLE_NAME(getAliasName())) .itemIf( "aliasId", @@ -306,6 +321,10 @@ public boolean isOptional() { return optional; } + public @Nullable RexNode getUntilCondition() { + return untilCondition; + } + @Override protected RelDataType deriveRowType() { return new RelRecordType( @@ -352,6 +371,7 @@ public GraphLogicalPathExpand copy(RelTraitSet traitSet, List inputs) { getFetch(), getResultOpt(), getPathOpt(), + getUntilCondition(), getAliasName(), getStartAlias(), isOptional()); @@ -366,6 +386,7 @@ public GraphLogicalPathExpand copy(RelTraitSet traitSet, List inputs) { getFetch(), getResultOpt(), getPathOpt(), + getUntilCondition(), getAliasName(), getStartAlias(), isOptional()); diff --git a/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/common/ir/runtime/proto/GraphRelToProtoConverter.java b/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/common/ir/runtime/proto/GraphRelToProtoConverter.java index 53e920b3a355..a642987e10cc 100644 --- a/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/common/ir/runtime/proto/GraphRelToProtoConverter.java +++ b/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/common/ir/runtime/proto/GraphRelToProtoConverter.java @@ -260,6 +260,12 @@ public RelNode visit(GraphLogicalPathExpand pxd) { pathExpandBuilder.setResultOpt(Utils.protoPathResultOpt(pxd.getResultOpt())); GraphAlgebra.Range range = buildRange(pxd.getOffset(), pxd.getFetch()); pathExpandBuilder.setHopRange(range); + if (pxd.getUntilCondition() != null) { + OuterExpression.Expression untilCondition = + pxd.getUntilCondition() + .accept(new RexToProtoConverter(true, isColumnId, this.rexBuilder)); + pathExpandBuilder.setCondition(untilCondition); + } if (pxd.getAliasId() != AliasInference.DEFAULT_ID) { pathExpandBuilder.setAlias(Utils.asAliasId(pxd.getAliasId())); } diff --git a/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/common/ir/tools/GraphBuilder.java b/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/common/ir/tools/GraphBuilder.java index 56b68bacd9ce..8c7485178992 100644 --- a/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/common/ir/tools/GraphBuilder.java +++ b/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/common/ir/tools/GraphBuilder.java @@ -217,6 +217,7 @@ public GraphBuilder pathExpand(PathExpandConfig pxdConfig) { fetchNode, pxdConfig.getResultOpt(), pxdConfig.getPathOpt(), + pxdConfig.getUntilCondition(), pxdConfig.getAlias(), getAliasNameWithId( pxdConfig.getStartAlias(), @@ -1817,7 +1818,7 @@ public GraphBuilder as(String alias) { fetch == null ? -1 : ((RexLiteral) fetch).getValueAs(Integer.class)) .startAlias(pxdExpand.getStartAlias().getAliasName()) .alias(alias); - pathExpand(pxdBuilder.build()); + pathExpand(pxdBuilder.buildConfig()); } else if (top instanceof GraphLogicalProject) { GraphLogicalProject project = (GraphLogicalProject) top; project(project.getProjects(), Lists.newArrayList(alias), project.isAppend()); diff --git a/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/common/ir/tools/config/PathExpandConfig.java b/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/common/ir/tools/config/PathExpandConfig.java index 10a1c5ae26d6..469dd5b06129 100644 --- a/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/common/ir/tools/config/PathExpandConfig.java +++ b/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/common/ir/tools/config/PathExpandConfig.java @@ -19,20 +19,15 @@ import com.alibaba.graphscope.common.ir.rel.graph.GraphLogicalExpand; import com.alibaba.graphscope.common.ir.rel.graph.GraphLogicalGetV; import com.alibaba.graphscope.common.ir.rel.type.AliasNameWithId; -import com.alibaba.graphscope.common.ir.rex.RexGraphVariable; import com.alibaba.graphscope.common.ir.tools.AliasInference; import com.alibaba.graphscope.common.ir.tools.GraphBuilder; -import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import org.apache.calcite.plan.GraphOptCluster; import org.apache.calcite.rel.RelNode; -import org.apache.calcite.rex.RexLiteral; import org.apache.calcite.rex.RexNode; -import org.apache.calcite.sql.SqlOperator; import org.checkerframework.checker.nullness.qual.Nullable; -import java.util.List; import java.util.Objects; /** @@ -47,6 +42,7 @@ public class PathExpandConfig { private final GraphOpt.PathExpandPath pathOpt; private final GraphOpt.PathExpandResult resultOpt; + private final @Nullable RexNode untilCondition; @Nullable private final String alias; @Nullable private final String startAlias; @@ -58,17 +54,7 @@ protected PathExpandConfig( int fetch, GraphOpt.PathExpandResult resultOpt, GraphOpt.PathExpandPath pathOpt, - @Nullable String alias) { - this(expand, getV, offset, fetch, resultOpt, pathOpt, alias, null); - } - - protected PathExpandConfig( - RelNode expand, - RelNode getV, - int offset, - int fetch, - GraphOpt.PathExpandResult resultOpt, - GraphOpt.PathExpandPath pathOpt, + @Nullable RexNode untilCondition, @Nullable String alias, @Nullable String startAlias) { this.expand = Objects.requireNonNull(expand); @@ -77,6 +63,7 @@ protected PathExpandConfig( this.fetch = fetch; this.resultOpt = resultOpt; this.pathOpt = pathOpt; + this.untilCondition = untilCondition; this.alias = alias; this.startAlias = startAlias; } @@ -117,6 +104,10 @@ public RelNode getGetV() { return getV; } + public @Nullable RexNode getUntilCondition() { + return untilCondition; + } + @Override public String toString() { StringBuilder builder = new StringBuilder(); @@ -127,14 +118,15 @@ public String toString() { builder.append(", fetch=" + fetch); builder.append(", pathOpt=" + pathOpt); builder.append(", resultOpt=" + resultOpt); + if (untilCondition != null) { + builder.append(", untilCondition=" + untilCondition); + } builder.append(", alias='" + alias + '\''); builder.append("}"); return builder.toString(); } - public static final class Builder { - private final GraphBuilder innerBuilder; - + public static final class Builder extends GraphBuilder { private RelNode expand; private RelNode getV; @@ -144,91 +136,66 @@ public static final class Builder { private GraphOpt.PathExpandPath pathOpt; private GraphOpt.PathExpandResult resultOpt; + private @Nullable RexNode untilCondition; + @Nullable private String alias; @Nullable private String startAlias; - protected Builder(GraphBuilder innerBuilder) { - this.innerBuilder = - GraphBuilder.create( - innerBuilder.getContext(), - (GraphOptCluster) innerBuilder.getCluster(), - innerBuilder.getRelOptSchema()); + protected Builder(GraphBuilder parentBuilder) { + super( + parentBuilder.getContext(), + (GraphOptCluster) parentBuilder.getCluster(), + parentBuilder.getRelOptSchema()); + if (parentBuilder.size() > 0) { + this.push(parentBuilder.peek()); + } this.pathOpt = GraphOpt.PathExpandPath.ARBITRARY; this.resultOpt = GraphOpt.PathExpandResult.END_V; } public Builder expand(ExpandConfig config) { if (this.getV == null && this.expand == null) { + GraphLogicalExpand expandRel = (GraphLogicalExpand) super.expand(config).build(); this.expand = GraphLogicalExpand.create( - (GraphOptCluster) innerBuilder.getCluster(), + (GraphOptCluster) expandRel.getCluster(), ImmutableList.of(), null, - config.getOpt(), - innerBuilder.getTableConfig( - config.getLabels(), GraphOpt.Source.EDGE), + expandRel.getOpt(), + expandRel.getTableConfig(), AliasInference.DEFAULT_NAME, AliasNameWithId.DEFAULT); - innerBuilder.push(this.expand); + push(this.expand); } return this; } public Builder getV(GetVConfig config) { if (this.expand != null && this.getV == null) { + GraphLogicalGetV getVRel = (GraphLogicalGetV) super.getV(config).build(); this.getV = GraphLogicalGetV.create( - (GraphOptCluster) innerBuilder.getCluster(), + (GraphOptCluster) getVRel.getCluster(), ImmutableList.of(), null, - config.getOpt(), - innerBuilder.getTableConfig( - config.getLabels(), GraphOpt.Source.VERTEX), + getVRel.getOpt(), + getVRel.getTableConfig(), AliasInference.DEFAULT_NAME, AliasNameWithId.DEFAULT); - // (the alias of endV is given in the getV - // base) - innerBuilder.push(this.getV); + push(this.getV); } return this; } public Builder filter(RexNode... conjunctions) { - Preconditions.checkArgument( - this.getV != null || this.expand != null, - "expand and getV are all null in path_expand"); - innerBuilder.filter(conjunctions); - return this; + return (Builder) super.filter(conjunctions); } - public Builder filter(List conjunctions) { - Preconditions.checkArgument( - this.getV != null || this.expand != null, - "expand and getV are all null in path_expand"); - innerBuilder.filter(conjunctions); + public Builder untilCondition(@Nullable RexNode untilCondition) { + this.untilCondition = untilCondition; return this; } - public RexGraphVariable variable(@Nullable String alias) { - return innerBuilder.variable(alias); - } - - public RexGraphVariable variable(@Nullable String alias, String property) { - return innerBuilder.variable(alias, property); - } - - public RexLiteral literal(@Nullable Object value) { - return innerBuilder.literal(value); - } - - public RexNode call(SqlOperator operator, RexNode... operands) { - return innerBuilder.call(operator, operands); - } - - public RexNode call(SqlOperator operator, Iterable operands) { - return innerBuilder.call(operator, operands); - } - public Builder range(int offset, int fetch) { this.offset = offset; this.fetch = fetch; @@ -255,13 +222,17 @@ public Builder startAlias(@Nullable String startAlias) { return this; } - public PathExpandConfig build() { + public PathExpandConfig buildConfig() { return new PathExpandConfig( - expand, getV, offset, fetch, resultOpt, pathOpt, alias, startAlias); - } - - public GraphBuilder getInnerBuilder() { - return innerBuilder; + expand, + getV, + offset, + fetch, + resultOpt, + pathOpt, + untilCondition, + alias, + startAlias); } } } diff --git a/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/common/ir/type/GraphTypeInference.java b/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/common/ir/type/GraphTypeInference.java index 083257b6b6b6..5efd51bc12c7 100644 --- a/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/common/ir/type/GraphTypeInference.java +++ b/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/common/ir/type/GraphTypeInference.java @@ -658,6 +658,7 @@ private RelNode newRel(RelNode rel, RelDataType newType) { pxd.getFetch(), pxd.getResultOpt(), pxd.getPathOpt(), + pxd.getUntilCondition(), pxd.getAliasName(), pxd.getStartAlias()); } diff --git a/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/cypher/antlr4/visitor/GraphBuilderVisitor.java b/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/cypher/antlr4/visitor/GraphBuilderVisitor.java index 4c01a27c8510..936f21ad321c 100644 --- a/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/cypher/antlr4/visitor/GraphBuilderVisitor.java +++ b/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/cypher/antlr4/visitor/GraphBuilderVisitor.java @@ -95,7 +95,9 @@ public GraphBuilder visitOC_PatternElementChain( // path_expand if (literalCtx != null && literalCtx.oC_IntegerLiteral().size() > 1) { builder.pathExpand( - new PathExpandBuilderVisitor(this).visitOC_PatternElementChain(ctx).build()); + new PathExpandBuilderVisitor(this) + .visitOC_PatternElementChain(ctx) + .buildConfig()); // extract the end vertex from path_expand results if (ctx.oC_NodePattern() != null) { builder.getV(Utils.getVConfig(ctx.oC_NodePattern())); diff --git a/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/cypher/antlr4/visitor/PathExpandBuilderVisitor.java b/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/cypher/antlr4/visitor/PathExpandBuilderVisitor.java index 3794010fab37..4f2c376f7764 100644 --- a/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/cypher/antlr4/visitor/PathExpandBuilderVisitor.java +++ b/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/cypher/antlr4/visitor/PathExpandBuilderVisitor.java @@ -64,11 +64,10 @@ public PathExpandConfig.Builder visitOC_NodePattern(CypherGSParser.OC_NodePatter public PathExpandConfig.Builder visitOC_Properties(CypherGSParser.OC_PropertiesContext ctx) { return (ctx == null) ? builder - : builder.filter( - Utils.propertyFilters( - this.builder.getInnerBuilder(), - this.parent.getExpressionVisitor(), - ctx)); + : (PathExpandConfig.Builder) + builder.filter( + Utils.propertyFilters( + this.builder, this.parent.getExpressionVisitor(), ctx)); } @Override diff --git a/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/gremlin/antlr4x/visitor/GraphBuilderVisitor.java b/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/gremlin/antlr4x/visitor/GraphBuilderVisitor.java index 816513273e60..a8fb65ab15d3 100644 --- a/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/gremlin/antlr4x/visitor/GraphBuilderVisitor.java +++ b/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/gremlin/antlr4x/visitor/GraphBuilderVisitor.java @@ -355,7 +355,7 @@ public GraphBuilder visitTraversalMethod_endV(GremlinGSParser.TraversalMethod_en public GraphBuilder visitTraversalMethod_out(GremlinGSParser.TraversalMethod_outContext ctx) { if (pathExpandPattern(ctx.oC_ListLiteral(), ctx.oC_Expression())) { return builder.pathExpand( - new PathExpandBuilderVisitor(this).visitTraversalMethod_out(ctx).build()); + new PathExpandBuilderVisitor(this).visitTraversalMethod_out(ctx).buildConfig()); } else { return builder.expand( new ExpandConfig( @@ -369,7 +369,7 @@ public GraphBuilder visitTraversalMethod_out(GremlinGSParser.TraversalMethod_out public GraphBuilder visitTraversalMethod_in(GremlinGSParser.TraversalMethod_inContext ctx) { if (pathExpandPattern(ctx.oC_ListLiteral(), ctx.oC_Expression())) { return builder.pathExpand( - new PathExpandBuilderVisitor(this).visitTraversalMethod_in(ctx).build()); + new PathExpandBuilderVisitor(this).visitTraversalMethod_in(ctx).buildConfig()); } else { return builder.expand( new ExpandConfig( @@ -383,7 +383,9 @@ public GraphBuilder visitTraversalMethod_in(GremlinGSParser.TraversalMethod_inCo public GraphBuilder visitTraversalMethod_both(GremlinGSParser.TraversalMethod_bothContext ctx) { if (pathExpandPattern(ctx.oC_ListLiteral(), ctx.oC_Expression())) { return builder.pathExpand( - new PathExpandBuilderVisitor(this).visitTraversalMethod_both(ctx).build()); + new PathExpandBuilderVisitor(this) + .visitTraversalMethod_both(ctx) + .buildConfig()); } else { return builder.expand( new ExpandConfig( @@ -791,6 +793,10 @@ public GraphBuilder getGraphBuilder() { return this.builder; } + public ExprUniqueAliasInfer getAliasInfer() { + return this.aliasInfer; + } + private RelBuilder.GroupKey convertGroupKeyBy( GremlinGSParser.TraversalMethod_group_keybyContext keyCtx) { String defaultAlias = Column.keys.name(); diff --git a/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/gremlin/antlr4x/visitor/PathExpandBuilderVisitor.java b/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/gremlin/antlr4x/visitor/PathExpandBuilderVisitor.java index 1d90c1726955..d986e58a3bfb 100644 --- a/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/gremlin/antlr4x/visitor/PathExpandBuilderVisitor.java +++ b/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/gremlin/antlr4x/visitor/PathExpandBuilderVisitor.java @@ -16,6 +16,7 @@ package com.alibaba.graphscope.gremlin.antlr4x.visitor; +import com.alibaba.graphscope.common.antlr4.ExprVisitorResult; import com.alibaba.graphscope.common.ir.tools.config.*; import com.alibaba.graphscope.grammar.GremlinGSBaseVisitor; import com.alibaba.graphscope.grammar.GremlinGSParser; @@ -26,10 +27,12 @@ public class PathExpandBuilderVisitor extends GremlinGSBaseVisitor { private final PathExpandConfig.Builder builder; + private final GraphBuilderVisitor parent; public PathExpandBuilderVisitor(GraphBuilderVisitor parent) { // PATH_OPT = ARBITRARY and RESULT_OPT = END_V are set by default this.builder = PathExpandConfig.newBuilder(parent.getGraphBuilder()); + this.parent = parent; } @Override @@ -93,14 +96,21 @@ public PathExpandConfig.Builder visitTraversalMethod_both( public PathExpandConfig.Builder visitTraversalMethod_with( GremlinGSParser.TraversalMethod_withContext ctx) { String optKey = (String) LiteralVisitor.INSTANCE.visit(ctx.StringLiteral()); - Object optValue = LiteralVisitor.INSTANCE.visit(ctx.oC_Literal()); switch (optKey.toUpperCase()) { case "PATH_OPT": + Object pathValue = LiteralVisitor.INSTANCE.visit(ctx.oC_Literal()); return builder.pathOpt( - GraphOpt.PathExpandPath.valueOf(String.valueOf(optValue).toUpperCase())); + GraphOpt.PathExpandPath.valueOf(String.valueOf(pathValue).toUpperCase())); case "RESULT_OPT": + Object resultValue = LiteralVisitor.INSTANCE.visit(ctx.oC_Literal()); return builder.resultOpt( - GraphOpt.PathExpandResult.valueOf(String.valueOf(optValue).toUpperCase())); + GraphOpt.PathExpandResult.valueOf( + String.valueOf(resultValue).toUpperCase())); + case "UNTIL": + ExprVisitorResult exprRes = + new ExtExpressionVisitor(builder, parent.getAliasInfer()) + .visitTraversalMethod_expr(ctx.traversalMethod_expr()); + return builder.untilCondition(exprRes.getExpr()); default: return builder; } diff --git a/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/gremlin/integration/suite/standard/IrGremlinQueryTest.java b/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/gremlin/integration/suite/standard/IrGremlinQueryTest.java index c82bea1a7b10..1e6c346c0bbc 100644 --- a/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/gremlin/integration/suite/standard/IrGremlinQueryTest.java +++ b/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/gremlin/integration/suite/standard/IrGremlinQueryTest.java @@ -171,6 +171,21 @@ public abstract class IrGremlinQueryTest extends AbstractGremlinProcessTest { public abstract Traversal get_g_V_where_expr_name_equal_marko_and_age_gt_20_or_age_lt_10_name(); + public abstract Traversal get_g_V_path_expand_until_age_gt_30_values_age(); + + @LoadGraphWith(LoadGraphWith.GraphData.MODERN) + @Test + public void g_V_path_expand_until_age_gt_30_values_age() { + // the until condition follows a sql-like expression syntax, which can only be opened when + // language type is antlr_gremlin_calcite + assumeTrue("antlr_gremlin_calcite".equals(System.getenv("GREMLIN_SCRIPT_LANGUAGE_NAME"))); + final Traversal traversal = + get_g_V_path_expand_until_age_gt_30_values_age(); + printTraversalForm(traversal); + Assert.assertEquals(32, traversal.next()); + Assert.assertFalse(traversal.hasNext()); + } + @LoadGraphWith(LoadGraphWith.GraphData.MODERN) @Test public void g_V_select_expr_power_age_by_2() { @@ -1213,6 +1228,18 @@ public Traversal get_g_V_select_expr_2_xor_3_mult_2_limit_1() { .values("name"); } + @Override + public Traversal get_g_V_path_expand_until_age_gt_30_values_age() { + return ((IrCustomizedTraversal) + g.V().out("1..100", "knows") + .with( + "UNTIL", + com.alibaba.graphscope.gremlin.integration.suite.utils + .__.expr("_.age > 30", ExprStep.Type.FILTER))) + .endV() + .values("age"); + } + @Override public Traversal get_g_V_where_out_out_count() { return g.V().where(__.out().out()).count(); diff --git a/interactive_engine/compiler/src/test/java/com/alibaba/graphscope/common/ir/ExpandTest.java b/interactive_engine/compiler/src/test/java/com/alibaba/graphscope/common/ir/ExpandTest.java index dd6ec127c8c5..989ba93b32cf 100644 --- a/interactive_engine/compiler/src/test/java/com/alibaba/graphscope/common/ir/ExpandTest.java +++ b/interactive_engine/compiler/src/test/java/com/alibaba/graphscope/common/ir/ExpandTest.java @@ -75,7 +75,12 @@ public void expand_2_test() { // SIMPLE).with('RESULT_OPT', ALL_V) @Test public void expand_3_test() { - GraphBuilder builder = Utils.mockGraphBuilder(); + GraphBuilder builder = + Utils.mockGraphBuilder() + .source( + new SourceConfig( + GraphOpt.Source.VERTEX, + new LabelConfig(false).addLabel("person"))); PathExpandConfig.Builder pxdBuilder = PathExpandConfig.newBuilder(builder); PathExpandConfig pxdConfig = pxdBuilder @@ -95,7 +100,7 @@ public void expand_3_test() { .range(1, 3) .pathOpt(GraphOpt.PathExpandPath.SIMPLE) .resultOpt(GraphOpt.PathExpandResult.ALL_V) - .build(); + .buildConfig(); RelNode pathExpand = builder.source( new SourceConfig( @@ -149,7 +154,12 @@ public void expand_4_test() { // g.V().hasLabel("person").as("a").outE("knows").select("a").out("1..3", "knows") @Test public void expand_5_test() { - GraphBuilder builder = Utils.mockGraphBuilder(); + GraphBuilder builder = + Utils.mockGraphBuilder() + .source( + new SourceConfig( + GraphOpt.Source.VERTEX, + new LabelConfig(false).addLabel("person"))); PathExpandConfig.Builder pxdBuilder = PathExpandConfig.newBuilder(builder); PathExpandConfig pxdConfig = pxdBuilder @@ -163,7 +173,7 @@ public void expand_5_test() { new LabelConfig(false).addLabel("person"))) .range(1, 3) .startAlias("a") - .build(); + .buildConfig(); RelNode expand = builder.source( new SourceConfig( diff --git a/interactive_engine/compiler/src/test/java/com/alibaba/graphscope/common/ir/planner/rbo/ExpandGetVFusionTest.java b/interactive_engine/compiler/src/test/java/com/alibaba/graphscope/common/ir/planner/rbo/ExpandGetVFusionTest.java index cd71d1a92696..a840b51464ff 100644 --- a/interactive_engine/compiler/src/test/java/com/alibaba/graphscope/common/ir/planner/rbo/ExpandGetVFusionTest.java +++ b/interactive_engine/compiler/src/test/java/com/alibaba/graphscope/common/ir/planner/rbo/ExpandGetVFusionTest.java @@ -413,7 +413,12 @@ public void expand_getv_fusion_8_test() { // SIMPLE).with('RESULT_OPT', ALL_V) @Test public void path_expand_getv_fusion_0_test() { - GraphBuilder builder = Utils.mockGraphBuilder(); + GraphBuilder builder = + Utils.mockGraphBuilder() + .source( + new SourceConfig( + GraphOpt.Source.VERTEX, + new LabelConfig(false).addLabel("person"))); PathExpandConfig.Builder pxdBuilder = PathExpandConfig.newBuilder(builder); PathExpandConfig pxdConfig = pxdBuilder @@ -428,7 +433,7 @@ public void path_expand_getv_fusion_0_test() { .range(1, 3) .pathOpt(GraphOpt.PathExpandPath.SIMPLE) .resultOpt(GraphOpt.PathExpandResult.ALL_V) - .build(); + .buildConfig(); RelNode before = builder.source( new SourceConfig( @@ -465,7 +470,12 @@ public void path_expand_getv_fusion_0_test() { // eq(10)).with('PATH_OPT', SIMPLE).with('RESULT_OPT', ALL_V) @Test public void path_expand_getv_fusion_1_test() { - GraphBuilder builder = Utils.mockGraphBuilder(); + GraphBuilder builder = + Utils.mockGraphBuilder() + .source( + new SourceConfig( + GraphOpt.Source.VERTEX, + new LabelConfig(false).addLabel("person"))); PathExpandConfig.Builder pxdBuilder = PathExpandConfig.newBuilder(builder); PathExpandConfig pxdConfig = pxdBuilder @@ -485,7 +495,7 @@ public void path_expand_getv_fusion_1_test() { .range(1, 3) .pathOpt(GraphOpt.PathExpandPath.SIMPLE) .resultOpt(GraphOpt.PathExpandResult.ALL_V) - .build(); + .buildConfig(); RelNode before = builder.source( new SourceConfig( @@ -524,7 +534,12 @@ public void path_expand_getv_fusion_1_test() { // path expand with edge filters @Test public void path_expand_getv_fusion_2_test() { - GraphBuilder builder = Utils.mockGraphBuilder(); + GraphBuilder builder = + Utils.mockGraphBuilder() + .source( + new SourceConfig( + GraphOpt.Source.VERTEX, + new LabelConfig(false).addLabel("person"))); PathExpandConfig.Builder pxdBuilder = PathExpandConfig.newBuilder(builder); PathExpandConfig pxdConfig = pxdBuilder @@ -544,7 +559,7 @@ public void path_expand_getv_fusion_2_test() { .range(1, 3) .pathOpt(GraphOpt.PathExpandPath.SIMPLE) .resultOpt(GraphOpt.PathExpandResult.ALL_V) - .build(); + .buildConfig(); RelNode before = builder.source( new SourceConfig( diff --git a/interactive_engine/compiler/src/test/java/com/alibaba/graphscope/common/ir/planner/rbo/FilterPushDownTest.java b/interactive_engine/compiler/src/test/java/com/alibaba/graphscope/common/ir/planner/rbo/FilterPushDownTest.java index c988bcc56ab9..be3036e1af52 100644 --- a/interactive_engine/compiler/src/test/java/com/alibaba/graphscope/common/ir/planner/rbo/FilterPushDownTest.java +++ b/interactive_engine/compiler/src/test/java/com/alibaba/graphscope/common/ir/planner/rbo/FilterPushDownTest.java @@ -54,7 +54,13 @@ public void push_filter_1_test() { // Match(x:person)-[:knows*1..3]->(z:person {age: 10}) @Test public void push_filter_2_test() { - GraphBuilder builder = Utils.mockGraphBuilder(); + GraphBuilder builder = + Utils.mockGraphBuilder() + .source( + new SourceConfig( + GraphOpt.Source.VERTEX, + new LabelConfig(false).addLabel("person"), + "x")); PathExpandConfig.Builder pxdBuilder = PathExpandConfig.newBuilder(builder); GetVConfig getVConfig = new GetVConfig(GraphOpt.GetV.END, new LabelConfig(false).addLabel("person"), "z"); @@ -68,16 +74,8 @@ public void push_filter_2_test() { .range(1, 3) .pathOpt(GraphOpt.PathExpandPath.SIMPLE) .resultOpt(GraphOpt.PathExpandResult.ALL_V) - .build(); - RelNode sentence = - builder.source( - new SourceConfig( - GraphOpt.Source.VERTEX, - new LabelConfig(false).addLabel("person"), - "x")) - .pathExpand(pxdConfig) - .getV(getVConfig) - .build(); + .buildConfig(); + RelNode sentence = builder.pathExpand(pxdConfig).getV(getVConfig).build(); RelNode before = builder.match(sentence, GraphOpt.Match.INNER) .filter( diff --git a/interactive_engine/compiler/src/test/java/com/alibaba/graphscope/common/ir/runtime/FfiLogicalPlanTest.java b/interactive_engine/compiler/src/test/java/com/alibaba/graphscope/common/ir/runtime/FfiLogicalPlanTest.java index da6232246bec..fa2cc42c35e1 100644 --- a/interactive_engine/compiler/src/test/java/com/alibaba/graphscope/common/ir/runtime/FfiLogicalPlanTest.java +++ b/interactive_engine/compiler/src/test/java/com/alibaba/graphscope/common/ir/runtime/FfiLogicalPlanTest.java @@ -40,7 +40,12 @@ public class FfiLogicalPlanTest { // Return count(*) @Test public void logical_plan_1_test() throws Exception { - GraphBuilder builder = Utils.mockGraphBuilder(); + GraphBuilder builder = + Utils.mockGraphBuilder() + .source( + new SourceConfig( + GraphOpt.Source.VERTEX, + new LabelConfig(false).addLabel("person"))); PathExpandConfig.Builder pxdBuilder = PathExpandConfig.newBuilder(builder); GetVConfig getVConfig = new GetVConfig(GraphOpt.GetV.END, new LabelConfig(false).addLabel("person")); @@ -54,7 +59,7 @@ public void logical_plan_1_test() throws Exception { .range(1, 3) .pathOpt(GraphOpt.PathExpandPath.SIMPLE) .resultOpt(GraphOpt.PathExpandResult.ALL_V) - .build(); + .buildConfig(); RelNode aggregate = builder.source( new SourceConfig( diff --git a/interactive_engine/compiler/src/test/java/com/alibaba/graphscope/common/ir/runtime/GraphRelToProtoTest.java b/interactive_engine/compiler/src/test/java/com/alibaba/graphscope/common/ir/runtime/GraphRelToProtoTest.java index cf3734a0b750..e86f4dfc1426 100644 --- a/interactive_engine/compiler/src/test/java/com/alibaba/graphscope/common/ir/runtime/GraphRelToProtoTest.java +++ b/interactive_engine/compiler/src/test/java/com/alibaba/graphscope/common/ir/runtime/GraphRelToProtoTest.java @@ -252,7 +252,12 @@ public void get_v_with_filter_test() throws Exception { @Test public void path_expand_test() throws Exception { - GraphBuilder builder = Utils.mockGraphBuilder(); + GraphBuilder builder = + Utils.mockGraphBuilder() + .source( + new SourceConfig( + GraphOpt.Source.VERTEX, + new LabelConfig(false).addLabel("person"))); PathExpandConfig.Builder pxdBuilder = PathExpandConfig.newBuilder(builder); PathExpandConfig pxdConfig = pxdBuilder @@ -267,7 +272,7 @@ public void path_expand_test() throws Exception { .range(1, 3) .pathOpt(GraphOpt.PathExpandPath.SIMPLE) .resultOpt(GraphOpt.PathExpandResult.ALL_V) - .build(); + .buildConfig(); RelNode pxd = builder.source( new SourceConfig( @@ -1031,7 +1036,12 @@ public void expand_vertex_with_filters_test() throws Exception { @Test public void path_expand_fused_test() throws Exception { - GraphBuilder builder = Utils.mockGraphBuilder(); + GraphBuilder builder = + Utils.mockGraphBuilder() + .source( + new SourceConfig( + GraphOpt.Source.VERTEX, + new LabelConfig(false).addLabel("person"))); PathExpandConfig.Builder pxdBuilder = PathExpandConfig.newBuilder(builder); PathExpandConfig pxdConfig = pxdBuilder @@ -1046,7 +1056,7 @@ public void path_expand_fused_test() throws Exception { .range(1, 3) .pathOpt(GraphOpt.PathExpandPath.SIMPLE) .resultOpt(GraphOpt.PathExpandResult.ALL_V) - .build(); + .buildConfig(); RelNode pxd = builder.source( new SourceConfig( diff --git a/interactive_engine/compiler/src/test/java/com/alibaba/graphscope/gremlin/antlr4x/GraphBuilderTest.java b/interactive_engine/compiler/src/test/java/com/alibaba/graphscope/gremlin/antlr4x/GraphBuilderTest.java index d05deac5538c..26f5a7d6bb1e 100644 --- a/interactive_engine/compiler/src/test/java/com/alibaba/graphscope/gremlin/antlr4x/GraphBuilderTest.java +++ b/interactive_engine/compiler/src/test/java/com/alibaba/graphscope/gremlin/antlr4x/GraphBuilderTest.java @@ -1680,4 +1680,25 @@ public void g_V_has_label_software_id_test() { + " alias=[_], fusedFilter=[[=(_.id, 1)]], opt=[VERTEX])", node.explain().trim()); } + + @Test + public void g_V_path_expand_until_age_gt_30_values_age() { + RelNode node = + eval("g.V().out('1..3').with('UNTIL', expr(_.age > 30)).endV().values('age')"); + Assert.assertEquals( + "GraphLogicalProject(age=[age], isAppend=[false])\n" + + " GraphLogicalProject(age=[_.age], isAppend=[true])\n" + + " GraphLogicalGetV(tableConfig=[{isAll=true, tables=[software, person]}]," + + " alias=[_], opt=[END])\n" + + " " + + " GraphLogicalPathExpand(expand=[GraphLogicalExpand(tableConfig=[{isAll=true," + + " tables=[created, knows]}], alias=[_], opt=[OUT])\n" + + "], getV=[GraphLogicalGetV(tableConfig=[{isAll=true, tables=[software," + + " person]}], alias=[_], opt=[END])\n" + + "], offset=[1], fetch=[2], path_opt=[ARBITRARY], result_opt=[END_V]," + + " until_condition=[>(_.age, 30)], alias=[_])\n" + + " GraphLogicalSource(tableConfig=[{isAll=true, tables=[software," + + " person]}], alias=[_], opt=[VERTEX])", + node.explain().trim()); + } }