fix(server): handle repeated range predicates correctly (#3122)
diff --git a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/backend/query/ConditionQuery.java b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/backend/query/ConditionQuery.java
index 063d23a..097e98d 100644
--- a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/backend/query/ConditionQuery.java
+++ b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/backend/query/ConditionQuery.java
@@ -629,12 +629,18 @@
/*
* NOTE: seems need to keep call checkRangeIndex() for each condition,
* so don't break early even if test() return false.
- */
+ */
boolean valid = true;
+ Map<Id, Boolean> rangeIndexMatches = null;
+ if (this.element2IndexValueMap != null) {
+ rangeIndexMatches = new HashMap<>();
+ }
for (Condition cond : this.conditions) {
valid &= cond.test(element);
- valid &= this.element2IndexValueMap == null ||
- this.element2IndexValueMap.checkRangeIndex(element, cond);
+ if (this.element2IndexValueMap != null) {
+ valid &= this.element2IndexValueMap.checkRangeIndex(
+ element, cond, rangeIndexMatches);
+ }
}
return valid;
}
@@ -859,7 +865,8 @@
this.leftIndexMap.remove(elementId);
}
- public boolean checkRangeIndex(HugeElement element, Condition cond) {
+ public boolean checkRangeIndex(HugeElement element, Condition cond,
+ Map<Id, Boolean> rangeIndexMatches) {
// Not UserpropRelation
if (!(cond instanceof Condition.UserpropRelation)) {
return true;
@@ -875,11 +882,16 @@
return true;
}
+ if (rangeIndexMatches.containsKey(propId)) {
+ return rangeIndexMatches.get(propId);
+ }
+
HugeProperty<Object> property = element.getProperty(propId);
if (property == null) {
// Property value has been deleted, so it's not matched
this.addLeftIndex(element.id(), propId, fieldValues);
- return false;
+ return this.cacheRangeIndexMatch(rangeIndexMatches, propId,
+ false);
}
/*
@@ -900,10 +912,19 @@
* the element is valid or not.
*/
if (this.selectedIndexField != null) {
- return !propId.equals(this.selectedIndexField) || hasRightValue;
+ hasRightValue = !propId.equals(this.selectedIndexField) ||
+ hasRightValue;
}
- return hasRightValue;
+ return this.cacheRangeIndexMatch(rangeIndexMatches, propId,
+ hasRightValue);
+ }
+
+ private boolean cacheRangeIndexMatch(Map<Id, Boolean> rangeIndexMatches,
+ Id propertyId,
+ boolean matched) {
+ rangeIndexMatches.put(propertyId, matched);
+ return matched;
}
private static boolean removeFieldValue(Set<Object> values,
diff --git a/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/core/EdgeCoreTest.java b/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/core/EdgeCoreTest.java
index f74c5c1..cbb2b7d 100644
--- a/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/core/EdgeCoreTest.java
+++ b/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/core/EdgeCoreTest.java
@@ -4792,6 +4792,38 @@
}
@Test
+ public void testQueryByRepeatedRangePredicates() {
+ HugeGraph graph = graph();
+ SchemaManager schema = graph.schema();
+
+ schema.indexLabel("transferByTimestamp").onE("transfer").range()
+ .by("timestamp").create();
+
+ Vertex source = graph.addVertex(T.label, "person", "name", "source",
+ "city", "Beijing", "age", 20);
+ Vertex target = graph.addVertex(T.label, "person", "name", "target",
+ "city", "Beijing", "age", 21);
+ source.addEdge("transfer", target, "id", 1, "amount", 1.0F,
+ "timestamp", -4L, "message", "test");
+ graph.tx().commit();
+
+ List<Edge> edges = graph.traversal().E()
+ .has("timestamp", -4L)
+ .has("timestamp", P.lte(4L)).toList();
+ Assert.assertEquals(1, edges.size());
+
+ long count = graph.traversal().E()
+ .has("timestamp", -4L)
+ .has("timestamp", P.lte(4L)).count().next();
+ Assert.assertEquals(1L, count);
+
+ count = graph.traversal().E()
+ .has("timestamp", P.lte(4L))
+ .has("timestamp", -4L).count().next();
+ Assert.assertEquals(1L, count);
+ }
+
+ @Test
public void testQueryByNegativeFloatProperty() {
HugeGraph graph = graph();
SchemaManager schema = graph.schema();