From 4910d9d022bb9996453fb29224ace9cfdc54b806 Mon Sep 17 00:00:00 2001 From: Zhangmei Li Date: Tue, 14 Jun 2022 00:03:32 +0800 Subject: [PATCH 1/2] fix: Traversal.graph is empty in StepStrategy.apply() with `count().is(0)` Change-Id: I0ca670a1df852504dcc8e8d0cfd8c0de39987e60 --- .../hugegraph/auth/HugeGraphAuthProxy.java | 25 +++++++++-------- .../optimize/HugeVertexStepStrategy.java | 23 +++++++++++---- .../traversal/optimize/TraversalUtil.java | 28 +++++++++++++------ 3 files changed, 50 insertions(+), 26 deletions(-) diff --git a/hugegraph-api/src/main/java/com/baidu/hugegraph/auth/HugeGraphAuthProxy.java b/hugegraph-api/src/main/java/com/baidu/hugegraph/auth/HugeGraphAuthProxy.java index d3efb5aa35..8d7515c2b2 100644 --- a/hugegraph-api/src/main/java/com/baidu/hugegraph/auth/HugeGraphAuthProxy.java +++ b/hugegraph-api/src/main/java/com/baidu/hugegraph/auth/HugeGraphAuthProxy.java @@ -38,11 +38,6 @@ import javax.security.sasl.AuthenticationException; -import com.baidu.hugegraph.iterator.MapperIterator; -import com.baidu.hugegraph.traversal.optimize.HugeScriptTraversal; -import jakarta.ws.rs.ForbiddenException; -import jakarta.ws.rs.NotAuthorizedException; - import org.apache.commons.configuration2.Configuration; import org.apache.tinkerpop.gremlin.process.computer.GraphComputer; import org.apache.tinkerpop.gremlin.process.traversal.Bytecode; @@ -81,6 +76,7 @@ import com.baidu.hugegraph.config.TypedOption; import com.baidu.hugegraph.exception.NotSupportException; import com.baidu.hugegraph.iterator.FilterIterator; +import com.baidu.hugegraph.iterator.MapperIterator; import com.baidu.hugegraph.rpc.RpcServiceConfig4Client; import com.baidu.hugegraph.rpc.RpcServiceConfig4Server; import com.baidu.hugegraph.schema.EdgeLabel; @@ -98,6 +94,7 @@ import com.baidu.hugegraph.task.TaskManager; import com.baidu.hugegraph.task.TaskScheduler; import com.baidu.hugegraph.task.TaskStatus; +import com.baidu.hugegraph.traversal.optimize.HugeScriptTraversal; import com.baidu.hugegraph.type.HugeType; import com.baidu.hugegraph.type.Nameable; import com.baidu.hugegraph.type.define.GraphMode; @@ -107,6 +104,9 @@ import com.baidu.hugegraph.util.Log; import com.baidu.hugegraph.util.RateLimiter; +import jakarta.ws.rs.ForbiddenException; +import jakarta.ws.rs.NotAuthorizedException; + public final class HugeGraphAuthProxy implements HugeGraph { static { @@ -1638,7 +1638,7 @@ public Iterator> iterator() { return new MapperIterator, TraversalStrategy>( this.strategies.iterator(), (strategy) -> { - return new TraversalStrategyProxy(strategy); + return new TraversalStrategyProxy<>(strategy); }); } @@ -1678,8 +1678,11 @@ private String translate(Bytecode bytecode) { } } - private final class TraversalStrategyProxy + private final class TraversalStrategyProxy> implements TraversalStrategy { + + private static final long serialVersionUID = 2071829024642435735L; + private final TraversalStrategy origin; public TraversalStrategyProxy(TraversalStrategy origin) { @@ -1687,7 +1690,7 @@ public TraversalStrategyProxy(TraversalStrategy origin) { } @Override - public void apply(Traversal.Admin traversal) { + public void apply(Traversal.Admin traversal) { String script; if (traversal instanceof HugeScriptTraversal) { script = ((HugeScriptTraversal) traversal).script(); @@ -1740,9 +1743,9 @@ public Configuration getConfiguration() { } @Override - public int compareTo(Class - otherTraversalCategory) { - return this.origin.compareTo(otherTraversalCategory); + public int compareTo(@SuppressWarnings("rawtypes") + Class otherCategory) { + return this.origin.compareTo(otherCategory); } @Override diff --git a/hugegraph-core/src/main/java/com/baidu/hugegraph/traversal/optimize/HugeVertexStepStrategy.java b/hugegraph-core/src/main/java/com/baidu/hugegraph/traversal/optimize/HugeVertexStepStrategy.java index 6931bb0a31..9321db7036 100644 --- a/hugegraph-core/src/main/java/com/baidu/hugegraph/traversal/optimize/HugeVertexStepStrategy.java +++ b/hugegraph-core/src/main/java/com/baidu/hugegraph/traversal/optimize/HugeVertexStepStrategy.java @@ -31,6 +31,8 @@ import org.apache.tinkerpop.gremlin.process.traversal.util.EmptyTraversal; import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalHelper; +import com.baidu.hugegraph.HugeGraph; + public final class HugeVertexStepStrategy extends AbstractTraversalStrategy implements ProviderOptimizationStrategy { @@ -59,16 +61,25 @@ public void apply(final Traversal.Admin traversal) { if (!steps.isEmpty()) { boolean withPath = HugeVertexStepStrategy.containsPath(traversal); boolean withTree = HugeVertexStepStrategy.containsTree(traversal); - boolean supportIn = TraversalUtil.getGraph(steps.get(0)) - .backendStoreFeatures() - .supportsQueryWithInCondition(); + /* + * The graph of traversal may be null when `__` step is followed + * by `count().is(0)` step, like the following gremlin: + * `g.V(id).repeat(in()).until(or(inE().count().is(0), loops().is(2)))` + * TODO: remove this `graph!=null` check after fixed the bug #1699 + */ + boolean supportIn = false; + HugeGraph graph = TraversalUtil.tryGetGraph(steps.get(0)); + if (graph != null) { + supportIn = graph.backendStoreFeatures() + .supportsQueryWithInCondition(); + } batchOptimize = !withTree && !withPath && supportIn; } for (VertexStep originStep : steps) { HugeVertexStep newStep = batchOptimize ? - new HugeVertexStepByBatch<>(originStep) : - new HugeVertexStep<>(originStep); + new HugeVertexStepByBatch<>(originStep) : + new HugeVertexStep<>(originStep); TraversalHelper.replaceStep(originStep, newStep, traversal); TraversalUtil.extractHasContainer(newStep, traversal); @@ -107,7 +118,7 @@ protected static boolean containsPath(Traversal.Admin traversal) { */ protected static boolean containsTree(Traversal.Admin traversal) { boolean hasTree = TraversalHelper.getStepsOfClass( - TreeStep.class, traversal).size() > 0; + TreeStep.class, traversal).size() > 0; if (hasTree) { return true; } else if (traversal instanceof EmptyTraversal) { diff --git a/hugegraph-core/src/main/java/com/baidu/hugegraph/traversal/optimize/TraversalUtil.java b/hugegraph-core/src/main/java/com/baidu/hugegraph/traversal/optimize/TraversalUtil.java index 15e7629065..ae2c333e82 100644 --- a/hugegraph-core/src/main/java/com/baidu/hugegraph/traversal/optimize/TraversalUtil.java +++ b/hugegraph-core/src/main/java/com/baidu/hugegraph/traversal/optimize/TraversalUtil.java @@ -60,11 +60,12 @@ import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalHelper; import org.apache.tinkerpop.gremlin.structure.Edge; import org.apache.tinkerpop.gremlin.structure.Element; +import org.apache.tinkerpop.gremlin.structure.Graph; import org.apache.tinkerpop.gremlin.structure.Property; import org.apache.tinkerpop.gremlin.structure.PropertyType; import org.apache.tinkerpop.gremlin.structure.T; import org.apache.tinkerpop.gremlin.structure.Vertex; -import org.slf4j.Logger; +import org.apache.tinkerpop.gremlin.structure.util.empty.EmptyGraph; import com.baidu.hugegraph.HugeException; import com.baidu.hugegraph.HugeGraph; @@ -91,17 +92,27 @@ import com.baidu.hugegraph.util.DateUtil; import com.baidu.hugegraph.util.E; import com.baidu.hugegraph.util.JsonUtil; -import com.baidu.hugegraph.util.Log; import com.google.common.collect.ImmutableList; public final class TraversalUtil { - private static final Logger LOG = Log.logger(HugeGraph.class); - public static final String P_CALL = "P."; public static HugeGraph getGraph(Step step) { - return (HugeGraph) step.getTraversal().getGraph().get(); + HugeGraph graph = tryGetGraph(step); + if (graph != null) { + return graph; + } + throw new IllegalArgumentException("There is no graph in step: " + step); + } + + public static HugeGraph tryGetGraph(Step step) { + Graph graph = step.getTraversal().getGraph().get(); + if (graph instanceof HugeGraph) { + return (HugeGraph) graph; + } + assert graph == null || graph instanceof EmptyGraph; + return null; } public static void extractHasContainer(HugeGraphStep newStep, @@ -572,10 +583,9 @@ public static void convAllHasSteps(Traversal.Admin traversal) { TraversalHelper.getStepsOfAssignableClassRecursively( HasStep.class, traversal); /* - * The graph may be null. - * For example: - * g.V().hasLabel('person').union(__.has("birth", dates[0])) - * Here "__.has" will create a new traversal, but the graph is null + * The graph in traversal may be null, for example: + * `g.V().hasLabel('person').union(__.has('name', 'tom'))` + * Here `__.has()` will create a new traversal, but the graph is null */ if (steps.isEmpty() || !traversal.getGraph().isPresent()) { return; From 64f030049b6bef2305eaa29b7680cd4fde93ab7d Mon Sep 17 00:00:00 2001 From: Zhangmei Li Date: Tue, 14 Jun 2022 14:46:43 +0800 Subject: [PATCH 2/2] add test cases for count().is(0) and outE()/inE()/bothE().count() Change-Id: Ifd20c613f6ff63ac9e7609347fb4b770740367de --- .../baidu/hugegraph/core/EdgeCoreTest.java | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/hugegraph-test/src/main/java/com/baidu/hugegraph/core/EdgeCoreTest.java b/hugegraph-test/src/main/java/com/baidu/hugegraph/core/EdgeCoreTest.java index ddd6841b5b..5bfed17e4c 100644 --- a/hugegraph-test/src/main/java/com/baidu/hugegraph/core/EdgeCoreTest.java +++ b/hugegraph-test/src/main/java/com/baidu/hugegraph/core/EdgeCoreTest.java @@ -5354,6 +5354,52 @@ public void testQueryCount() { .values().count().next()); } + @Test + public void testQueryCountOfAdjacentEdges() { + HugeGraph graph = graph(); + GraphTraversalSource g = graph.traversal(); + init18Edges(); + + Vertex james = vertex("author", "id", 1); + + Assert.assertEquals(18L, g.E().count().next()); + + Assert.assertEquals(6L, g.V(james).bothE().count().next()); + + Assert.assertEquals(4L, g.V(james).outE().count().next()); + Assert.assertEquals(1L, g.V(james).outE("created").count().next()); + Assert.assertEquals(3L, g.V(james).outE("authored").count().next()); + Assert.assertEquals(1L, g.V(james).outE("authored") + .has("score", 3).count().next()); + + Assert.assertEquals(2L, g.V(james).inE().count().next()); + Assert.assertEquals(1L, g.V(james).inE("know").count().next()); + Assert.assertEquals(1L, g.V(james).inE("follow").count().next()); + } + + @Test + public void testQueryCountAsCondition() { + HugeGraph graph = graph(); + GraphTraversalSource g = graph.traversal(); + init18Edges(); + + Vertex java1 = vertex("book", "name", "java-1"); + Vertex java3 = vertex("book", "name", "java-3"); + + long paths; + paths = g.V(java1) + .repeat(__.inE().outV().simplePath()) + .until(__.or(__.inE().count().is(0), __.loops().is(3))) + .path().count().next(); + Assert.assertEquals(4L, paths); + + paths = g.V(java3) + .repeat(__.inE().outV().simplePath()) + .until(__.or(__.inE().count().is(0), __.loops().is(3))) + .path().count().next(); + Assert.assertEquals(7L, paths); + } + @Test public void testRemoveEdge() { HugeGraph graph = graph();