diff --git a/docs/interactive_engine/tinkerpop/supported_gremlin_steps.md b/docs/interactive_engine/tinkerpop/supported_gremlin_steps.md index 229f2f6aa207..895607d11ceb 100644 --- a/docs/interactive_engine/tinkerpop/supported_gremlin_steps.md +++ b/docs/interactive_engine/tinkerpop/supported_gremlin_steps.md @@ -586,6 +586,18 @@ lengthRange - the lower and the upper bounds of the path length,
edgeLabel Usages of the with()-step:
keyValuePair - the options to configure the corresponding behaviors of the `PathExpand`-step. + +Below are the supported values and descriptions for `PATH_OPT` and `RESULT_OPT` options. + + Parameter | Supported Values | Description +-----------|-------------------|------------------------------------------------ + PATH_OPT | ARBITRARY | Allow vertices or edges to be duplicated. + PATH_OPT | SIMPLE | No duplicated nodes. + PATH_OPT | TRAIL | No duplicated edges. + RESULT_OPT| END_V | Only keep the end vertex. + RESULT_OPT| ALL_V | Keep all vertices along the path. + RESULT_OPT| ALL_V_E | Keep all vertices and edges along the path. + ```bash # expand hops within the range of [1, 10) along the outgoing edges, # vertices can be duplicated and only the end vertex should be kept @@ -594,6 +606,9 @@ g.V().out("1..10").with('PATH_OPT', 'ARBITRARY').with('RESULT_OPT', 'END_V') # vertices and edges can be duplicated, and all vertices and edges along the path should be kept g.V().out("1..10").with('PATH_OPT', 'ARBITRARY').with('RESULT_OPT', 'ALL_V_E') # expand hops within the range of [1, 10) along the outgoing edges, +# edges cannot be duplicated, and all vertices and edges along the path should be kept +g.V().out("1..10").with('PATH_OPT', 'TRAIL').with('RESULT_OPT', 'ALL_V_E') +# expand hops within the range of [1, 10) along the outgoing edges, # vertices cannot be duplicated and all vertices should be kept g.V().out("1..10").with('PATH_OPT', 'SIMPLE').with('RESULT_OPT', 'ALL_V') # = g.V().out("1..10").with('PATH_OPT', 'ARBITRARY').with('RESULT_OPT', 'END_V') diff --git a/interactive_engine/compiler/ir_experimental_ci.sh b/interactive_engine/compiler/ir_experimental_ci.sh index ae3dd45b7c35..71d668c35d94 100755 --- a/interactive_engine/compiler/ir_experimental_ci.sh +++ b/interactive_engine/compiler/ir_experimental_ci.sh @@ -37,6 +37,7 @@ fi # Test3: run gremlin standard tests on distributed experimental store via calcite-based ir # start distributed engine service and load modern graph +export DISTRIBUTED_ENV=true cd ${base_dir}/../executor/ir/target/release && RUST_LOG=info DATA_PATH=/tmp/gstest/modern_graph_exp_bin PARTITION_ID=0 ./start_rpc_server --config ${base_dir}/../executor/ir/integrated/config/distributed/server_0 & cd ${base_dir}/../executor/ir/target/release && @@ -54,6 +55,7 @@ if [ $exit_code -ne 0 ]; then echo "ir\(calcite-based\) gremlin integration with proto physical test on distributed experimental store fail" exit 1 fi +unset DISTRIBUTED_ENV # Test4: run cypher movie tests on experimental store via ir-core cd ${base_dir}/../executor/ir/target/release && DATA_PATH=/tmp/gstest/movie_graph_exp_bin RUST_LOG=info ./start_rpc_server --config ${base_dir}/../executor/ir/integrated/config & diff --git a/interactive_engine/compiler/pom.xml b/interactive_engine/compiler/pom.xml index 2d368e12b8ec..db9c9b0ad2b4 100644 --- a/interactive_engine/compiler/pom.xml +++ b/interactive_engine/compiler/pom.xml @@ -234,6 +234,10 @@ + + org.apache.maven.plugins + maven-shade-plugin + org.apache.maven.plugins maven-clean-plugin diff --git a/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/common/ir/runtime/ffi/Utils.java b/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/common/ir/runtime/ffi/Utils.java index fa7655eea0a7..5154d1221531 100644 --- a/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/common/ir/runtime/ffi/Utils.java +++ b/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/common/ir/runtime/ffi/Utils.java @@ -117,6 +117,8 @@ public static final PathOpt ffiPathOpt(GraphOpt.PathExpandPath opt) { switch (opt) { case ARBITRARY: return PathOpt.Arbitrary; + case TRAIL: + return PathOpt.Trail; case SIMPLE: default: return PathOpt.Simple; diff --git a/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/common/ir/runtime/proto/Utils.java b/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/common/ir/runtime/proto/Utils.java index 86a354cd2e0f..41955150c9a6 100644 --- a/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/common/ir/runtime/proto/Utils.java +++ b/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/common/ir/runtime/proto/Utils.java @@ -562,6 +562,8 @@ public static final GraphAlgebraPhysical.PathExpand.PathOpt protoPathOpt( return GraphAlgebraPhysical.PathExpand.PathOpt.ARBITRARY; case SIMPLE: return GraphAlgebraPhysical.PathExpand.PathOpt.SIMPLE; + case TRAIL: + return GraphAlgebraPhysical.PathExpand.PathOpt.TRAIL; default: throw new UnsupportedOperationException( "opt " + opt + " in path is unsupported yet"); diff --git a/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/common/ir/tools/config/GraphOpt.java b/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/common/ir/tools/config/GraphOpt.java index 27f464dc85f1..ab4e34dd23c1 100644 --- a/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/common/ir/tools/config/GraphOpt.java +++ b/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/common/ir/tools/config/GraphOpt.java @@ -59,7 +59,8 @@ public enum Match { public enum PathExpandPath { ARBITRARY, - SIMPLE + SIMPLE, + TRAIL } public enum PathExpandResult { diff --git a/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/common/jna/type/PathOpt.java b/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/common/jna/type/PathOpt.java index 64ecc99ffe3d..788815cecbf6 100644 --- a/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/common/jna/type/PathOpt.java +++ b/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/common/jna/type/PathOpt.java @@ -20,7 +20,8 @@ public enum PathOpt implements IntEnum { Arbitrary, - Simple; + Simple, + Trail; @Override public int getInt() { 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 2a5631cb0ea4..f3bd48f94669 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 @@ -199,11 +199,36 @@ public abstract class IrGremlinQueryTest extends AbstractGremlinProcessTest { public abstract Traversal get_g_V_path_expand_until_age_gt_30_values_age(); + // g.V().has("id",2).both("1..5").with("PATH_OPT","ARBITRARY").with("RESULT_OPT","END_V").count() + public abstract Traversal get_g_VX2X_both_with_arbitrary_endv_count(); + + // g.V().has("id",2).both("1..5").with("PATH_OPT","SIMPLE").with("RESULT_OPT","END_V").count() + public abstract Traversal get_g_VX2X_both_with_simple_endv_count(); + + // g.V().has("id",2).both("1..5").with("PATH_OPT","TRAIL").with("RESULT_OPT","END_V").count() + public abstract Traversal get_g_VX2X_both_with_trail_endv_count(); + + // g.V().has("id",2).both("1..5").with("PATH_OPT","ARBITRARY").with("RESULT_OPT","ALL_V").count() + public abstract Traversal get_g_VX2X_both_with_arbitrary_allv_count(); + + // g.V().has("id",2).both("1..5").with("PATH_OPT","SIMPLE").with("RESULT_OPT","ALL_V").count() + public abstract Traversal get_g_VX2X_both_with_simple_allv_count(); + + // g.V().has("id",2).both("1..5").with("PATH_OPT","TRAIL").with("RESULT_OPT","ALL_V").count() + public abstract Traversal get_g_VX2X_both_with_trail_allv_count(); + + // g.V().has("id",2).both("1..5").with("PATH_OPT","ARBITRARY").with("RESULT_OPT","ALL_V_E").count() + public abstract Traversal get_g_VX2X_both_with_arbitrary_allve_count(); + + // g.V().has("id",2).both("1..5").with("PATH_OPT","SIMPLE").with("RESULT_OPT","ALL_V_E").count() + public abstract Traversal get_g_VX2X_both_with_simple_allve_count(); + + // g.V().has("id",2).both("1..5").with("PATH_OPT","TRAIL").with("RESULT_OPT","ALL_V_E").count() + public abstract Traversal get_g_VX2X_both_with_trail_allve_count(); + @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(); @@ -251,6 +276,96 @@ public void g_V_where_expr_name_equal_marko_and_age_gt_20_or_age_lt_10_name() { Assert.assertEquals("marko", traversal.next()); } + @Test + @LoadGraphWith(LoadGraphWith.GraphData.MODERN) + public void g_VX2X_both_with_arbitrary_endv_count() { + assumeFalse("hiactor".equals(System.getenv("ENGINE_TYPE"))); + final Traversal traversal = get_g_VX2X_both_with_arbitrary_endv_count(); + printTraversalForm(traversal); + Assert.assertEquals(28, traversal.next().intValue()); + } + + @Test + @LoadGraphWith(LoadGraphWith.GraphData.MODERN) + public void g_VX2X_both_with_simple_endv_count() { + assumeFalse("hiactor".equals(System.getenv("ENGINE_TYPE"))); + final Traversal traversal = get_g_VX2X_both_with_simple_endv_count(); + printTraversalForm(traversal); + Assert.assertEquals(9, traversal.next().intValue()); + } + + @Test + @LoadGraphWith(LoadGraphWith.GraphData.MODERN) + public void g_VX2X_both_with_trail_endv_count() { + // Skip this test in distributed settings because edge ids might differ + // across partitions in experimental store. + assumeFalse("hiactor".equals(System.getenv("ENGINE_TYPE"))); + assumeFalse("true".equals(System.getenv("DISTRIBUTED_ENV"))); + final Traversal traversal = get_g_VX2X_both_with_trail_endv_count(); + printTraversalForm(traversal); + Assert.assertEquals(11, traversal.next().intValue()); + } + + @Test + @LoadGraphWith(LoadGraphWith.GraphData.MODERN) + public void g_VX2X_both_with_arbitrary_allv_count() { + assumeFalse("hiactor".equals(System.getenv("ENGINE_TYPE"))); + final Traversal traversal = get_g_VX2X_both_with_arbitrary_allv_count(); + printTraversalForm(traversal); + Assert.assertEquals(28, traversal.next().intValue()); + } + + @Test + @LoadGraphWith(LoadGraphWith.GraphData.MODERN) + public void g_VX2X_both_with_simple_allv_count() { + assumeFalse("hiactor".equals(System.getenv("ENGINE_TYPE"))); + final Traversal traversal = get_g_VX2X_both_with_simple_allv_count(); + printTraversalForm(traversal); + Assert.assertEquals(9, traversal.next().intValue()); + } + + @Test + @LoadGraphWith(LoadGraphWith.GraphData.MODERN) + public void g_VX2X_both_with_trail_allv_count() { + // Skip this test in distributed settings because edge ids might differ + // across partitions in experimental store. + assumeFalse("hiactor".equals(System.getenv("ENGINE_TYPE"))); + assumeFalse("true".equals(System.getenv("DISTRIBUTED_ENV"))); + final Traversal traversal = get_g_VX2X_both_with_trail_allv_count(); + printTraversalForm(traversal); + Assert.assertEquals(11, traversal.next().intValue()); + } + + @Test + @LoadGraphWith(LoadGraphWith.GraphData.MODERN) + public void g_VX2X_both_with_arbitrary_allve_count() { + assumeFalse("hiactor".equals(System.getenv("ENGINE_TYPE"))); + final Traversal traversal = get_g_VX2X_both_with_arbitrary_allve_count(); + printTraversalForm(traversal); + Assert.assertEquals(28, traversal.next().intValue()); + } + + @Test + @LoadGraphWith(LoadGraphWith.GraphData.MODERN) + public void g_VX2X_both_with_simple_allve_count() { + assumeFalse("hiactor".equals(System.getenv("ENGINE_TYPE"))); + final Traversal traversal = get_g_VX2X_both_with_simple_allve_count(); + printTraversalForm(traversal); + Assert.assertEquals(9, traversal.next().intValue()); + } + + @Test + @LoadGraphWith(LoadGraphWith.GraphData.MODERN) + public void g_VX2X_both_with_trail_allve_count() { + // Skip this test in distributed settings because edge ids might differ + // across partitions in experimental store. + assumeFalse("hiactor".equals(System.getenv("ENGINE_TYPE"))); + assumeFalse("true".equals(System.getenv("DISTRIBUTED_ENV"))); + final Traversal traversal = get_g_VX2X_both_with_trail_allve_count(); + printTraversalForm(traversal); + Assert.assertEquals(11, traversal.next().intValue()); + } + @Test @LoadGraphWith(MODERN) public void g_V_both_both_dedup_byXoutE_countX_name() { @@ -1425,6 +1540,96 @@ public Traversal get_g_V_select_expr_2_xor_3_mult_2_limit_1() { .values("name"); } + @Override + public Traversal get_g_VX2X_both_with_arbitrary_endv_count() { + return ((IrCustomizedTraversal) + g.V().has("id", 2) + .both("1..5") + .with("PATH_OPT", "ARBITRARY") + .with("RESULT_OPT", "END_V") + .count()); + } + + @Override + public Traversal get_g_VX2X_both_with_simple_endv_count() { + return ((IrCustomizedTraversal) + g.V().has("id", 2) + .both("1..5") + .with("PATH_OPT", "SIMPLE") + .with("RESULT_OPT", "END_V") + .count()); + } + + @Override + public Traversal get_g_VX2X_both_with_trail_endv_count() { + return ((IrCustomizedTraversal) + g.V().has("id", 2) + .both("1..5") + .with("PATH_OPT", "TRAIL") + .with("RESULT_OPT", "END_V") + .count()); + } + + @Override + public Traversal get_g_VX2X_both_with_arbitrary_allv_count() { + return ((IrCustomizedTraversal) + g.V().has("id", 2) + .both("1..5") + .with("PATH_OPT", "ARBITRARY") + .with("RESULT_OPT", "ALL_V") + .count()); + } + + @Override + public Traversal get_g_VX2X_both_with_simple_allv_count() { + return ((IrCustomizedTraversal) + g.V().has("id", 2) + .both("1..5") + .with("PATH_OPT", "SIMPLE") + .with("RESULT_OPT", "ALL_V") + .count()); + } + + @Override + public Traversal get_g_VX2X_both_with_trail_allv_count() { + return ((IrCustomizedTraversal) + g.V().has("id", 2) + .both("1..5") + .with("PATH_OPT", "TRAIL") + .with("RESULT_OPT", "ALL_V") + .count()); + } + + @Override + public Traversal get_g_VX2X_both_with_arbitrary_allve_count() { + return ((IrCustomizedTraversal) + g.V().has("id", 2) + .both("1..5") + .with("PATH_OPT", "ARBITRARY") + .with("RESULT_OPT", "ALL_V_E") + .count()); + } + + @Override + public Traversal get_g_VX2X_both_with_simple_allve_count() { + return ((IrCustomizedTraversal) + g.V().has("id", 2) + .both("1..5") + .with("PATH_OPT", "SIMPLE") + .with("RESULT_OPT", "ALL_V_E") + .count()); + } + + @Override + public Traversal get_g_VX2X_both_with_trail_allve_count() { + return ((IrCustomizedTraversal) + g.V().has("id", 2) + .both("1..5") + .with("PATH_OPT", "TRAIL") + .with("RESULT_OPT", "ALL_V_E") + .count()); + } + @Override public Traversal get_g_V_path_expand_until_age_gt_30_values_age() { return ((IrCustomizedTraversal) diff --git a/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/gremlin/plugin/step/PathExpandStep.java b/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/gremlin/plugin/step/PathExpandStep.java index c51d5c10d8fe..d0dfc7f79e4a 100644 --- a/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/gremlin/plugin/step/PathExpandStep.java +++ b/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/gremlin/plugin/step/PathExpandStep.java @@ -87,13 +87,13 @@ public void configure(final Object... keyValues) { String key = toCamelCaseInsensitive(originalKey); String value = toCamelCaseInsensitive(originalVal); if (key.equals("PathOpt")) { - if (value.equals("Arbitrary") || value.equals("Simple")) { + if (value.equals("Arbitrary") || value.equals("Simple") || value.equals("Trail")) { this.pathOpt = PathOpt.valueOf(value); } else { throw new ExtendGremlinStepException( "value " + originalVal - + " is invalid, use ARBITRARY or SIMPLE instead (case" + + " is invalid, use ARBITRARY, SIMPLE or TRAIL instead (case" + " insensitive)"); } } else if (key.equals("ResultOpt")) { diff --git a/interactive_engine/executor/ir/core/src/plan/ffi.rs b/interactive_engine/executor/ir/core/src/plan/ffi.rs index f622220aa164..63063c37b886 100644 --- a/interactive_engine/executor/ir/core/src/plan/ffi.rs +++ b/interactive_engine/executor/ir/core/src/plan/ffi.rs @@ -2312,6 +2312,7 @@ mod graph { pub enum PathOpt { Arbitrary = 0, Simple = 1, + Trail = 2, } #[allow(dead_code)] diff --git a/interactive_engine/executor/ir/graph_proxy/src/apis/graph/element/path.rs b/interactive_engine/executor/ir/graph_proxy/src/apis/graph/element/path.rs index 326b17519c4b..5a2a55eb2653 100644 --- a/interactive_engine/executor/ir/graph_proxy/src/apis/graph/element/path.rs +++ b/interactive_engine/executor/ir/graph_proxy/src/apis/graph/element/path.rs @@ -85,9 +85,11 @@ pub enum GraphPath { AllPath(Vec), /// Simple path, which may contains both vertices and edges, or only vertices. SimpleAllPath(Vec), - /// Arbitrary path with only end vertices preserved, which may contain both vertices and edges, or only vertices. + /// Trail, which may contains both vertices and edges, or only vertices. + TrailAllPath(Vec), + /// Arbitrary path with only end vertices preserved. EndV((VertexOrEdge, usize)), - /// Simple path with only end vertex preserved, which may contains both vertices and edges, or only vertices. + /// Simple path with only end vertex preserved. SimpleEndV((VertexOrEdge, Vec, usize)), } @@ -102,11 +104,13 @@ impl GraphPath { let entry = entry.into(); let id = entry.id(); GraphPath::SimpleEndV((entry, vec![id], 1)) - } + }, + pb::path_expand::PathOpt::Trail => GraphPath::TrailAllPath(vec![entry.into()]), }, pb::path_expand::ResultOpt::AllV | pb::path_expand::ResultOpt::AllVE => match path_opt { pb::path_expand::PathOpt::Arbitrary => GraphPath::AllPath(vec![entry.into()]), pb::path_expand::PathOpt::Simple => GraphPath::SimpleAllPath(vec![entry.into()]), + pb::path_expand::PathOpt::Trail => GraphPath::TrailAllPath(vec![entry.into()]), }, } } @@ -120,7 +124,16 @@ impl GraphPath { } GraphPath::SimpleAllPath(ref mut path) => { let entry = entry.into(); - if path.contains(&entry) { + if entry.is_vertex() && path.contains(&entry) { + false + } else { + path.push(entry); + true + } + } + GraphPath::TrailAllPath(ref mut path) => { + let entry = entry.into(); + if entry.is_edge() && path.contains(&entry) { false } else { path.push(entry); @@ -137,7 +150,7 @@ impl GraphPath { } GraphPath::SimpleEndV((ref mut e, ref mut path, ref mut weight)) => { let entry = entry.into(); - if path.contains(&entry.id()) { + if entry.is_vertex() && path.contains(&entry.id()) { false } else { path.push(entry.id()); @@ -154,35 +167,35 @@ impl GraphPath { pub fn get_path_start(&self) -> Option<&VertexOrEdge> { match self { - GraphPath::AllPath(ref p) | GraphPath::SimpleAllPath(ref p) => p.first(), + GraphPath::AllPath(ref p) | GraphPath::SimpleAllPath(ref p) | GraphPath::TrailAllPath(ref p) => p.first(), GraphPath::EndV(_) | GraphPath::SimpleEndV(_) => None, } } pub fn get_path_end(&self) -> &VertexOrEdge { match self { - GraphPath::AllPath(ref p) | GraphPath::SimpleAllPath(ref p) => p.last().unwrap(), + GraphPath::AllPath(ref p) | GraphPath::SimpleAllPath(ref p) | GraphPath::TrailAllPath(ref p) => p.last().unwrap(), GraphPath::EndV((ref e, _)) | GraphPath::SimpleEndV((ref e, _, _)) => e, } } pub fn get_path_end_mut(&mut self) -> &mut VertexOrEdge { match self { - GraphPath::AllPath(ref mut p) | GraphPath::SimpleAllPath(ref mut p) => p.last_mut().unwrap(), + GraphPath::AllPath(ref mut p) | GraphPath::SimpleAllPath(ref mut p) | GraphPath::TrailAllPath(ref mut p) => p.last_mut().unwrap(), GraphPath::EndV((ref mut e, _)) | GraphPath::SimpleEndV((ref mut e, _, _)) => e, } } pub fn get_path(&self) -> Option<&Vec> { match self { - GraphPath::AllPath(p) | GraphPath::SimpleAllPath(p) => Some(p), + GraphPath::AllPath(p) | GraphPath::SimpleAllPath(p) | GraphPath::TrailAllPath(p) => Some(p), GraphPath::EndV(_) | GraphPath::SimpleEndV(_) => None, } } pub fn take_path(self) -> Option> { match self { - GraphPath::AllPath(p) | GraphPath::SimpleAllPath(p) => Some(p), + GraphPath::AllPath(p) | GraphPath::SimpleAllPath(p) | GraphPath::TrailAllPath(p) => Some(p), GraphPath::EndV(_) | GraphPath::SimpleEndV(_) => None, } } @@ -201,7 +214,7 @@ impl GraphPath { false } } - GraphPath::SimpleAllPath(_) => { + GraphPath::SimpleAllPath(_) | GraphPath::TrailAllPath(_) => { if let Some(other_path) = other.take_path() { for e in other_path { if !self.append(e) { @@ -220,7 +233,7 @@ impl GraphPath { // pop the last element from the path, and return the element. pub fn pop(&mut self) -> Option { match self { - GraphPath::AllPath(ref mut p) | GraphPath::SimpleAllPath(ref mut p) => p.pop(), + GraphPath::AllPath(ref mut p) | GraphPath::SimpleAllPath(ref mut p) | GraphPath::TrailAllPath(ref mut p) => p.pop(), GraphPath::EndV(_) | GraphPath::SimpleEndV(_) => None, } } @@ -228,7 +241,7 @@ impl GraphPath { // reverse the path. pub fn reverse(&mut self) { match self { - GraphPath::AllPath(ref mut p) | GraphPath::SimpleAllPath(ref mut p) => { + GraphPath::AllPath(ref mut p) | GraphPath::SimpleAllPath(ref mut p) | GraphPath::TrailAllPath(ref mut p) => { p.reverse(); } GraphPath::EndV(_) | GraphPath::SimpleEndV(_) => {} @@ -238,7 +251,7 @@ impl GraphPath { // get the element ids in the path, including both vertices and edges. pub fn get_elem_ids(&self) -> Vec { match self { - GraphPath::AllPath(p) | GraphPath::SimpleAllPath(p) => p.iter().map(|e| e.id()).collect(), + GraphPath::AllPath(p) | GraphPath::SimpleAllPath(p) | GraphPath::TrailAllPath(p) => p.iter().map(|e| e.id()).collect(), GraphPath::EndV((e, _)) | GraphPath::SimpleEndV((e, _, _)) => vec![e.id()], } } @@ -246,7 +259,7 @@ impl GraphPath { // get the element labels in the path, including both vertices and edges. pub fn get_elem_labels(&self) -> Vec> { match self { - GraphPath::AllPath(p) | GraphPath::SimpleAllPath(p) => p.iter().map(|e| e.label()).collect(), + GraphPath::AllPath(p) | GraphPath::SimpleAllPath(p) | GraphPath::TrailAllPath(p) => p.iter().map(|e| e.label()).collect(), GraphPath::EndV((e, _)) | GraphPath::SimpleEndV((e, _, _)) => vec![e.label()], } } @@ -319,7 +332,7 @@ impl Element for GraphPath { // the path len is the number of edges in the path; fn len(&self) -> usize { match self { - GraphPath::AllPath(p) | GraphPath::SimpleAllPath(p) => { + GraphPath::AllPath(p) | GraphPath::SimpleAllPath(p) | GraphPath::TrailAllPath(p) => { p.iter() .filter(|v_or_e| v_or_e.is_vertex()) .count() @@ -349,7 +362,7 @@ impl GraphElement for GraphPath { fn get_property(&self, key: &NameOrId) -> Option { match self { - GraphPath::AllPath(path) | GraphPath::SimpleAllPath(path) => { + GraphPath::AllPath(path) | GraphPath::SimpleAllPath(path) | GraphPath::TrailAllPath(path) => { let mut properties = vec![]; for v_or_e in path { if let Some(p) = v_or_e.get_property(key) { @@ -376,7 +389,7 @@ impl GraphElement for GraphPath { fn get_all_properties(&self) -> Option> { match self { - GraphPath::AllPath(_) | GraphPath::SimpleAllPath(_) => { + GraphPath::AllPath(_) | GraphPath::SimpleAllPath(_) | GraphPath::TrailAllPath(_) => { // not supported yet. None } @@ -394,8 +407,13 @@ impl PartialEq for GraphPath { match (self, other) { (GraphPath::AllPath(p1), GraphPath::AllPath(p2)) | (GraphPath::AllPath(p1), GraphPath::SimpleAllPath(p2)) + | (GraphPath::AllPath(p1), GraphPath::TrailAllPath(p2)) | (GraphPath::SimpleAllPath(p1), GraphPath::AllPath(p2)) - | (GraphPath::SimpleAllPath(p1), GraphPath::SimpleAllPath(p2)) => p1.eq(p2), + | (GraphPath::SimpleAllPath(p1), GraphPath::SimpleAllPath(p2)) + | (GraphPath::SimpleAllPath(p1), GraphPath::TrailAllPath(p2)) + | (GraphPath::TrailAllPath(p1), GraphPath::AllPath(p2)) + | (GraphPath::TrailAllPath(p1), GraphPath::SimpleAllPath(p2)) + | (GraphPath::TrailAllPath(p1), GraphPath::TrailAllPath(p2)) => p1.eq(p2), (GraphPath::EndV((p1, _)), GraphPath::EndV((p2, _))) | (GraphPath::EndV((p1, _)), GraphPath::SimpleEndV((p2, _, _))) | (GraphPath::SimpleEndV((p1, _, _)), GraphPath::EndV((p2, _))) @@ -478,6 +496,10 @@ impl Encode for GraphPath { path.write_to(writer)?; writer.write_u64(*weight as u64)?; } + GraphPath::TrailAllPath(path) => { + writer.write_u8(4)?; + path.write_to(writer)?; + } } Ok(()) } @@ -506,6 +528,10 @@ impl Decode for GraphPath { let weight = ::read_from(reader)? as usize; Ok(GraphPath::SimpleEndV((vertex_or_edge, path, weight))) } + 4 => { + let path = >::read_from(reader)?; + Ok(GraphPath::TrailAllPath(path)) + } _ => Err(std::io::Error::new(std::io::ErrorKind::Other, "unreachable")), } } @@ -545,7 +571,7 @@ impl TryFrom for GraphPath { impl Hash for GraphPath { fn hash(&self, state: &mut H) { match self { - GraphPath::AllPath(p) | GraphPath::SimpleAllPath(p) => p.hash(state), + GraphPath::AllPath(p) | GraphPath::SimpleAllPath(p) | GraphPath::TrailAllPath(p) => p.hash(state), GraphPath::EndV((e, _)) | GraphPath::SimpleEndV((e, _, _)) => e.hash(state), } } diff --git a/interactive_engine/executor/ir/proto/algebra.proto b/interactive_engine/executor/ir/proto/algebra.proto index 4a7dd61b7962..3587bb631270 100644 --- a/interactive_engine/executor/ir/proto/algebra.proto +++ b/interactive_engine/executor/ir/proto/algebra.proto @@ -323,6 +323,8 @@ message PathExpand { ARBITRARY = 0; // a path without vertex duplications SIMPLE = 1; + // a path without edge duplications + TRAIL = 2; } // Define what result is required for this path. We currently support `EndV` and `AllV`, while an option to // include all edges and vertices may be needed in the future. diff --git a/interactive_engine/executor/ir/proto/physical.proto b/interactive_engine/executor/ir/proto/physical.proto index 4a3983c55941..8e4f30d40ac4 100644 --- a/interactive_engine/executor/ir/proto/physical.proto +++ b/interactive_engine/executor/ir/proto/physical.proto @@ -221,6 +221,8 @@ message PathExpand { ARBITRARY = 0; // a path without vertex duplications SIMPLE = 1; + // a path without edge duplications + TRAIL = 2; } // Define what result is required for this path. We currently support `EndV` and `AllV`, while an option to // include all edges and vertices may be needed in the future. diff --git a/interactive_engine/executor/ir/runtime/src/assembly.rs b/interactive_engine/executor/ir/runtime/src/assembly.rs index 4f8c66926782..9cef1c501579 100644 --- a/interactive_engine/executor/ir/runtime/src/assembly.rs +++ b/interactive_engine/executor/ir/runtime/src/assembly.rs @@ -786,8 +786,7 @@ impl IRJobAssembly { base ))) })?; - - if pb::path_expand::ResultOpt::AllVE == unsafe { std::mem::transmute(path.result_opt) } + if (pb::path_expand::ResultOpt::AllVE == unsafe { std::mem::transmute(path.result_opt) } || pb::path_expand::PathOpt::Trail == unsafe { std::mem::transmute(path.path_opt) }) && pb::edge_expand::ExpandOpt::Vertex == unsafe { std::mem::transmute(edge_expand.expand_opt) } { diff --git a/interactive_engine/executor/ir/runtime/src/process/operator/sink/sink.rs b/interactive_engine/executor/ir/runtime/src/process/operator/sink/sink.rs index 93e61c09baae..426a2c2e782a 100644 --- a/interactive_engine/executor/ir/runtime/src/process/operator/sink/sink.rs +++ b/interactive_engine/executor/ir/runtime/src/process/operator/sink/sink.rs @@ -355,7 +355,7 @@ impl RecordSinkEncoder { fn path_to_pb(&self, p: &GraphPath) -> result_pb::GraphPath { let mut graph_path_pb = vec![]; match p { - GraphPath::AllPath(path) | GraphPath::SimpleAllPath(path) => { + GraphPath::AllPath(path) | GraphPath::SimpleAllPath(path) | GraphPath::TrailAllPath(path) => { for vertex_or_edge in path { let vertex_or_edge_pb = self.vertex_or_edge_to_pb(vertex_or_edge); graph_path_pb.push(vertex_or_edge_pb); diff --git a/interactive_engine/pom.xml b/interactive_engine/pom.xml index ebac47b2d6ec..f88742d73e9b 100644 --- a/interactive_engine/pom.xml +++ b/interactive_engine/pom.xml @@ -737,6 +737,32 @@ maven-shade-plugin ${maven.shade.version} + + + package + + shade + + + + + com.alibaba.graphscope:interactive + + com.alibaba.graphscope.gaia.proto.* + + + + *:* + + META-INF/*.SF + META-INF/*.DSA + META-INF/*.RSA + + + + + + maven-assembly-plugin