This is an automated email from the ASF dual-hosted git repository.

jin pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-hugegraph.git


The following commit(s) were added to refs/heads/master by this push:
     new eb7a65c44 refact: fallback queryNumber() if there are uncommitted 
records (#2060)
eb7a65c44 is described below

commit eb7a65c44016cabbbd20a4bd85530d138c84b7e8
Author: Jermy Li <[email protected]>
AuthorDate: Thu Dec 29 15:26:53 2022 +0800

    refact: fallback queryNumber() if there are uncommitted records (#2060)
---
 .../org/apache/hugegraph/backend/query/Query.java  |  5 ++
 .../hugegraph/backend/tx/GraphTransaction.java     | 89 +++++++++++++---------
 .../org/apache/hugegraph/core/EdgeCoreTest.java    | 60 +++++++++------
 .../org/apache/hugegraph/core/VertexCoreTest.java  | 56 ++++++++------
 4 files changed, 127 insertions(+), 83 deletions(-)

diff --git 
a/hugegraph-core/src/main/java/org/apache/hugegraph/backend/query/Query.java 
b/hugegraph-core/src/main/java/org/apache/hugegraph/backend/query/Query.java
index 5c96297a9..6ac50df7d 100644
--- a/hugegraph-core/src/main/java/org/apache/hugegraph/backend/query/Query.java
+++ b/hugegraph-core/src/main/java/org/apache/hugegraph/backend/query/Query.java
@@ -37,6 +37,7 @@ import org.apache.hugegraph.util.CollectionUtil;
 import org.apache.hugegraph.util.E;
 import org.apache.hugegraph.util.InsertionOrderUtil;
 import org.apache.hugegraph.util.collection.IdSet;
+
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableSet;
 
@@ -421,6 +422,10 @@ public class Query implements Cloneable {
         this.aggregate = new Aggregate(func, property);
     }
 
+    public void aggregate(Aggregate aggregate) {
+        this.aggregate = aggregate;
+    }
+
     public boolean showHidden() {
         return this.showHidden;
     }
diff --git 
a/hugegraph-core/src/main/java/org/apache/hugegraph/backend/tx/GraphTransaction.java
 
b/hugegraph-core/src/main/java/org/apache/hugegraph/backend/tx/GraphTransaction.java
index 66986407c..3300d3777 100644
--- 
a/hugegraph-core/src/main/java/org/apache/hugegraph/backend/tx/GraphTransaction.java
+++ 
b/hugegraph-core/src/main/java/org/apache/hugegraph/backend/tx/GraphTransaction.java
@@ -32,19 +32,7 @@ import java.util.function.BiFunction;
 import java.util.function.Consumer;
 import java.util.function.Function;
 
-import jakarta.ws.rs.ForbiddenException;
 import org.apache.commons.collections.CollectionUtils;
-import org.apache.hugegraph.backend.store.BackendEntry;
-import org.apache.hugegraph.backend.store.BackendMutation;
-import org.apache.hugegraph.backend.store.BackendStore;
-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.Vertex;
-import org.apache.tinkerpop.gremlin.structure.util.CloseableIterator;
-import org.apache.tinkerpop.gremlin.structure.util.ElementHelper;
-import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils;
-
 import org.apache.hugegraph.HugeException;
 import org.apache.hugegraph.HugeGraph;
 import org.apache.hugegraph.HugeGraphParams;
@@ -64,6 +52,9 @@ import 
org.apache.hugegraph.backend.query.ConditionQueryFlatten;
 import org.apache.hugegraph.backend.query.IdQuery;
 import org.apache.hugegraph.backend.query.Query;
 import org.apache.hugegraph.backend.query.QueryResults;
+import org.apache.hugegraph.backend.store.BackendEntry;
+import org.apache.hugegraph.backend.store.BackendMutation;
+import org.apache.hugegraph.backend.store.BackendStore;
 import org.apache.hugegraph.config.CoreOptions;
 import org.apache.hugegraph.config.HugeConfig;
 import org.apache.hugegraph.exception.LimitExceedException;
@@ -98,8 +89,18 @@ import org.apache.hugegraph.type.define.IdStrategy;
 import org.apache.hugegraph.util.E;
 import org.apache.hugegraph.util.InsertionOrderUtil;
 import org.apache.hugegraph.util.LockUtil;
+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.Vertex;
+import org.apache.tinkerpop.gremlin.structure.util.CloseableIterator;
+import org.apache.tinkerpop.gremlin.structure.util.ElementHelper;
+import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils;
+
 import com.google.common.collect.ImmutableList;
 
+import jakarta.ws.rs.ForbiddenException;
+
 public class GraphTransaction extends IndexableTransaction {
 
     public static final int COMMIT_BATCH = (int) Query.COMMIT_BATCH;
@@ -528,12 +529,12 @@ public class GraphTransaction extends 
IndexableTransaction {
     @Override
     public QueryResults<BackendEntry> query(Query query) {
         if (!(query instanceof ConditionQuery)) {
+            // It's a sysprop-query, don't need to optimize
             LOG.debug("Query{final:{}}", query);
             return super.query(query);
         }
 
-        QueryList<BackendEntry> queries = this.optimizeQueries(query,
-                                                               super::query);
+        QueryList<BackendEntry> queries = this.optimizeQueries(query, 
super::query);
         LOG.debug("{}", queries);
         return queries.empty() ? QueryResults.empty() :
                                  queries.fetch(this.pageSize);
@@ -541,39 +542,51 @@ public class GraphTransaction extends 
IndexableTransaction {
 
     @Override
     public Number queryNumber(Query query) {
-        E.checkArgument(!this.hasUpdate(),
-                        "It's not allowed to query number when " +
-                        "there are uncommitted records.");
-
-        if (!(query instanceof ConditionQuery)) {
-            return super.queryNumber(query);
-        }
-
+        boolean hasUpdate = this.hasUpdate();
         Aggregate aggregate = query.aggregateNotNull();
 
         QueryList<Number> queries = this.optimizeQueries(query, q -> {
-            boolean indexQuery = q.getClass() == IdQuery.class;
-            OptimizedType optimized = ((ConditionQuery) query).optimized();
+            boolean isIndexQuery = q instanceof IdQuery;
+            boolean isConditionQuery = query instanceof ConditionQuery;
+            assert isIndexQuery || isConditionQuery || q == query;
+            // Need to fallback if there are uncommitted records
+            boolean fallback = hasUpdate;
             Number result;
-            if (!indexQuery) {
+
+            if (fallback) {
+                // Here just ignore it, and do fallback later
+                result = null;
+            } else if (!isIndexQuery || !isConditionQuery) {
+                // It's a sysprop-query, let parent tx do it
+                assert !fallback;
                 result = super.queryNumber(q);
             } else {
                 E.checkArgument(aggregate.func() == AggregateFunc.COUNT,
                                 "The %s operator on index is not supported 
now",
                                 aggregate.func().string());
-                if (this.optimizeAggrByIndex &&
-                    optimized == OptimizedType.INDEX) {
+                assert query instanceof ConditionQuery;
+                OptimizedType optimized = ((ConditionQuery) query).optimized();
+                if (this.optimizeAggrByIndex && optimized == 
OptimizedType.INDEX) {
                     // The ids size means results count (assume no left index)
                     result = q.idsSize();
                 } else {
-                    assert optimized == OptimizedType.INDEX_FILTER ||
-                           optimized == OptimizedType.INDEX;
-                    assert q.resultType().isVertex() || 
q.resultType().isEdge();
-                    result = IteratorUtils.count(q.resultType().isVertex() ?
-                                                 this.queryVertices(q) :
-                                                 this.queryEdges(q));
+                    assert !fallback;
+                    fallback = true;
+                    result = null;
                 }
             }
+
+            // Can't be optimized, then do fallback
+            if (fallback) {
+                assert result == null;
+                assert q.resultType().isVertex() || q.resultType().isEdge();
+                // Reset aggregate to fallback and scan
+                q.aggregate(null);
+                result = IteratorUtils.count(q.resultType().isVertex() ?
+                                             this.queryVertices(q) :
+                                             this.queryEdges(q));
+            }
+
             return new QueryResults<>(IteratorUtils.of(result), q);
         });
 
@@ -1335,14 +1348,20 @@ public class GraphTransaction extends 
IndexableTransaction {
 
     private <R> QueryList<R> optimizeQueries(Query query,
                                              QueryResults.Fetcher<R> fetcher) {
-        boolean supportIn = 
this.storeFeatures().supportsQueryWithInCondition();
         QueryList<R> queries = new QueryList<>(query, fetcher);
+        if (!(query instanceof ConditionQuery)) {
+            // It's a sysprop-query, add itself as subquery, don't need to 
flatten
+            queries.add(query);
+            return queries;
+        }
+
+        boolean supportIn = 
this.storeFeatures().supportsQueryWithInCondition();
         for (ConditionQuery cq: ConditionQueryFlatten.flatten(
                                 (ConditionQuery) query, supportIn)) {
             // Optimize by sysprop
             Query q = this.optimizeQuery(cq);
             /*
-             * NOTE: There are two possibilities for this query:
+             * NOTE: There are two possibilities for the returned q:
              * 1.sysprop-query, which would not be empty.
              * 2.index-query result(ids after optimization), which may be 
empty.
              */
diff --git 
a/hugegraph-test/src/main/java/org/apache/hugegraph/core/EdgeCoreTest.java 
b/hugegraph-test/src/main/java/org/apache/hugegraph/core/EdgeCoreTest.java
index 023fbcba4..119b85af1 100644
--- a/hugegraph-test/src/main/java/org/apache/hugegraph/core/EdgeCoreTest.java
+++ b/hugegraph-test/src/main/java/org/apache/hugegraph/core/EdgeCoreTest.java
@@ -31,23 +31,6 @@ import java.util.UUID;
 import java.util.concurrent.ExecutionException;
 import java.util.function.Function;
 
-import org.apache.tinkerpop.gremlin.process.traversal.Order;
-import org.apache.tinkerpop.gremlin.process.traversal.P;
-import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
-import 
org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
-import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
-import org.apache.tinkerpop.gremlin.structure.Direction;
-import org.apache.tinkerpop.gremlin.structure.Edge;
-import org.apache.tinkerpop.gremlin.structure.T;
-import org.apache.tinkerpop.gremlin.structure.Vertex;
-import org.apache.tinkerpop.gremlin.structure.util.CloseableIterator;
-import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils;
-import org.apache.hugegraph.testutil.FakeObjects;
-import org.apache.hugegraph.testutil.Utils;
-import org.junit.Assume;
-import org.junit.Before;
-import org.junit.Test;
-
 import org.apache.hugegraph.HugeException;
 import org.apache.hugegraph.HugeGraph;
 import org.apache.hugegraph.backend.BackendException;
@@ -69,6 +52,8 @@ import org.apache.hugegraph.schema.Userdata;
 import org.apache.hugegraph.structure.HugeEdge;
 import org.apache.hugegraph.structure.HugeVertex;
 import org.apache.hugegraph.testutil.Assert;
+import org.apache.hugegraph.testutil.FakeObjects;
+import org.apache.hugegraph.testutil.Utils;
 import org.apache.hugegraph.testutil.Whitebox;
 import org.apache.hugegraph.traversal.optimize.ConditionP;
 import org.apache.hugegraph.traversal.optimize.Text;
@@ -78,6 +63,21 @@ import org.apache.hugegraph.type.define.Directions;
 import org.apache.hugegraph.type.define.HugeKeys;
 import org.apache.hugegraph.util.Events;
 import org.apache.hugegraph.util.collection.CollectionFactory;
+import org.apache.tinkerpop.gremlin.process.traversal.Order;
+import org.apache.tinkerpop.gremlin.process.traversal.P;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
+import 
org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
+import org.apache.tinkerpop.gremlin.structure.Direction;
+import org.apache.tinkerpop.gremlin.structure.Edge;
+import org.apache.tinkerpop.gremlin.structure.T;
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+import org.apache.tinkerpop.gremlin.structure.util.CloseableIterator;
+import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils;
+import org.junit.Assume;
+import org.junit.Before;
+import org.junit.Test;
+
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableSet;
 
@@ -1835,19 +1835,20 @@ public class EdgeCoreTest extends BaseCoreTest {
         // Query all with limit after delete
         graph.traversal().E().limit(14).drop().iterate();
 
-        Assert.assertThrows(IllegalArgumentException.class, () -> {
-            // Query count with uncommitted records
-            graph.traversal().E().count().next();
-        });
+        // Query count with uncommitted records
+        Assert.assertEquals(4L, graph.traversal().E().count().next());
+
         Assert.assertThrows(IllegalArgumentException.class, () -> {
             // Query with limit
             graph.traversal().E().limit(3).toList();
         });
+
         Assert.assertThrows(IllegalArgumentException.class, () -> {
             // Query with offset
             graph.traversal().E().range(1, -1).toList();
         });
 
+        // Query all with limit after delete once
         graph.tx().commit();
         Assert.assertEquals(4L, graph.traversal().E().count().next());
         List<Edge> edges = graph.traversal().E().limit(3).toList();
@@ -1877,21 +1878,30 @@ public class EdgeCoreTest extends BaseCoreTest {
                       "comment", "good book!",
                       "comment", "good book too!");
 
-        Assert.assertThrows(IllegalArgumentException.class, () -> {
-            // Query count with uncommitted records
-            graph.traversal().E().count().next();
-        });
+        // Query count with uncommitted records
+        Assert.assertEquals(19L, graph.traversal().E().count().next());
+
         Assert.assertThrows(IllegalArgumentException.class, () -> {
             // Query with limit
             graph.traversal().E().limit(3).toList();
         });
+
         Assert.assertThrows(IllegalArgumentException.class, () -> {
             // Query with offset
             graph.traversal().E().range(1, -1).toList();
         });
 
+        // Do commit
         graph.tx().commit();
+
+        // Query count
         Assert.assertEquals(19L, graph.traversal().E().count().next());
+
+        // Query with limit
+        Assert.assertEquals(3L, 
graph.traversal().E().limit(3).toList().size());
+
+        // Query with offset
+        Assert.assertEquals(18L, graph.traversal().E().range(1, 
-1).toList().size());
     }
 
     @Test
diff --git 
a/hugegraph-test/src/main/java/org/apache/hugegraph/core/VertexCoreTest.java 
b/hugegraph-test/src/main/java/org/apache/hugegraph/core/VertexCoreTest.java
index 6cfce9a12..c2855bd9f 100644
--- a/hugegraph-test/src/main/java/org/apache/hugegraph/core/VertexCoreTest.java
+++ b/hugegraph-test/src/main/java/org/apache/hugegraph/core/VertexCoreTest.java
@@ -33,20 +33,6 @@ import java.util.Set;
 import java.util.UUID;
 import java.util.concurrent.atomic.AtomicInteger;
 
-import org.apache.tinkerpop.gremlin.process.traversal.P;
-import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
-import 
org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
-import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
-import org.apache.tinkerpop.gremlin.structure.T;
-import org.apache.tinkerpop.gremlin.structure.Vertex;
-import org.apache.tinkerpop.gremlin.structure.util.CloseableIterator;
-import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils;
-import org.apache.hugegraph.testutil.FakeObjects;
-import org.apache.hugegraph.testutil.Utils;
-import org.junit.Assume;
-import org.junit.Before;
-import org.junit.Test;
-
 import org.apache.hugegraph.HugeException;
 import org.apache.hugegraph.HugeGraph;
 import org.apache.hugegraph.backend.BackendException;
@@ -71,6 +57,8 @@ import org.apache.hugegraph.schema.Userdata;
 import org.apache.hugegraph.schema.VertexLabel;
 import org.apache.hugegraph.structure.HugeElement;
 import org.apache.hugegraph.testutil.Assert;
+import org.apache.hugegraph.testutil.FakeObjects;
+import org.apache.hugegraph.testutil.Utils;
 import org.apache.hugegraph.testutil.Whitebox;
 import org.apache.hugegraph.traversal.optimize.ConditionP;
 import org.apache.hugegraph.traversal.optimize.Text;
@@ -82,6 +70,18 @@ import org.apache.hugegraph.type.define.WriteType;
 import org.apache.hugegraph.util.Blob;
 import org.apache.hugegraph.util.CollectionUtil;
 import org.apache.hugegraph.util.LongEncoding;
+import org.apache.tinkerpop.gremlin.process.traversal.P;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
+import 
org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
+import org.apache.tinkerpop.gremlin.structure.T;
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+import org.apache.tinkerpop.gremlin.structure.util.CloseableIterator;
+import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils;
+import org.junit.Assume;
+import org.junit.Before;
+import org.junit.Test;
+
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableSet;
 
@@ -2778,19 +2778,20 @@ public class VertexCoreTest extends BaseCoreTest {
         // Query all with limit after delete
         graph.traversal().V().limit(6).drop().iterate();
 
-        Assert.assertThrows(IllegalArgumentException.class, () -> {
-            // Query count with uncommitted records
-            graph.traversal().V().count().next();
-        });
+        // Query count with uncommitted records
+        graph.traversal().V().count().next();
+
         Assert.assertThrows(IllegalArgumentException.class, () -> {
             // Query with limit
             graph.traversal().V().limit(3).toList();
         });
+
         Assert.assertThrows(IllegalArgumentException.class, () -> {
             // Query with offset
             graph.traversal().V().range(1, -1).toList();
         });
 
+        // Query all with limit after delete once
         this.commitTx();
         Assert.assertEquals(4L, graph.traversal().V().count().next());
         List<Vertex> vertices = graph.traversal().V().limit(3).toList();
@@ -2813,21 +2814,30 @@ public class VertexCoreTest extends BaseCoreTest {
                         "name", "test", "age", 88,
                         "lived", "California");
 
-        Assert.assertThrows(IllegalArgumentException.class, () -> {
-            // Query count with uncommitted records
-            graph.traversal().V().count().next();
-        });
+        // Query count with uncommitted records
+        Assert.assertEquals(11L, graph.traversal().V().count().next());
+
         Assert.assertThrows(IllegalArgumentException.class, () -> {
             // Query with limit
             graph.traversal().V().limit(3).toList();
         });
+
         Assert.assertThrows(IllegalArgumentException.class, () -> {
             // Query with offset
             graph.traversal().V().range(1, -1).toList();
         });
 
+        // Do commit
         this.commitTx();
+
+        // Query count
         Assert.assertEquals(11L, graph.traversal().V().count().next());
+
+        // Query with limit
+        Assert.assertEquals(3L, 
graph.traversal().V().limit(3).toList().size());
+
+        // Query with offset
+        Assert.assertEquals(10L, graph.traversal().V().range(1, 
-1).toList().size());
     }
 
     @Test
@@ -5968,7 +5978,7 @@ public class VertexCoreTest extends BaseCoreTest {
 
     @Test
     public void testQueryByUniqueIndex() {
-        HugeGraph graph = this.graph();
+        HugeGraph graph = graph();
         SchemaManager schema = graph.schema();
         schema.vertexLabel("node")
               .properties("name")

Reply via email to