hasContainers = holder.getHasContainers();
+ // Keep pure label non-EQ/IN predicates on GraphStep for TinkerPop filtering.
+ if (hasContainers.size() == 1 &&
+ isOnlyNonEqInLabelPredicate(hasContainers.get(0))) {
+ return false;
+ }
for (HasContainer has : holder.getHasContainers()) {
if (!canExtractHasContainer(graph, has)) {
return false;
@@ -453,6 +459,22 @@ private static boolean canExtractHasContainers(HugeGraph graph,
return true;
}
+ private static boolean isOnlyNonEqInLabelPredicate(HasContainer has) {
+ if (!has.getKey().equals(T.label.getAccessor())) {
+ return false;
+ }
+
+ List> predicates = new ArrayList<>();
+ collectPredicates(predicates, ImmutableList.of(has.getPredicate()));
+ for (P predicate : predicates) {
+ BiPredicate, ?> bp = predicate.getBiPredicate();
+ if (bp == Compare.eq || bp == Contains.within) {
+ return false;
+ }
+ }
+ return true;
+ }
+
static boolean canExtractHasContainer(HugeGraph graph,
HasContainer has) {
if (isSysProp(has.getKey())) {
diff --git a/hugegraph-server/hugegraph-hstore/src/main/java/org/apache/hugegraph/backend/store/hstore/HstoreStore.java b/hugegraph-server/hugegraph-hstore/src/main/java/org/apache/hugegraph/backend/store/hstore/HstoreStore.java
index 6439096674..00bef521d0 100644
--- a/hugegraph-server/hugegraph-hstore/src/main/java/org/apache/hugegraph/backend/store/hstore/HstoreStore.java
+++ b/hugegraph-server/hugegraph-hstore/src/main/java/org/apache/hugegraph/backend/store/hstore/HstoreStore.java
@@ -402,8 +402,8 @@ public IdPrefixQuery next() {
List queryList = Lists.newArrayList();
if (hugeGraph != null) {
for (ConditionQuery conditionQuery :
- ConditionQueryFlatten.flatten(cq)) {
- Id label = conditionQuery.condition(HugeKeys.LABEL);
+ ConditionQueryFlatten.flatten(cq)) {
+ Id label = conditionQuery.uniqueConditionValue(HugeKeys.LABEL);
/* Parent type + sortKeys: g.V("V.id").outE("parentLabel")
.has("sortKey","value") converted to all subtypes + sortKeys */
if ((this.subEls == null ||
@@ -459,7 +459,7 @@ private boolean matchEdgeSortKeys(ConditionQuery query,
boolean matchAll,
HugeGraph graph) {
assert query.resultType().isEdge();
- Id label = query.condition(HugeKeys.LABEL);
+ Id label = query.uniqueConditionValue(HugeKeys.LABEL);
if (label == null) {
return false;
}
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 bbf7db6562..a683486e4c 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
@@ -3582,6 +3582,57 @@ public void testQueryOutEdgesOfVertexBySortkeyAndProps() {
Assert.assertEquals(0, edges.size());
}
+ @Test
+ public void testQueryOutEdgesBySingleResolvedLabelAndSortKey() {
+ HugeGraph graph = graph();
+ Vertex reader = initEdgeLabelQueryEdges();
+
+ List edges = graph.traversal().V(reader.id())
+ .outE("reviewed")
+ .has(T.label, P.within("reviewed",
+ "recommended"))
+ .has("time", "2026-1-1")
+ .toList();
+
+ Assert.assertEquals(1, edges.size());
+ Assert.assertEquals("reviewed", edges.get(0).label());
+ Assert.assertEquals("2026-1-1", edges.get(0).value("time"));
+ }
+
+ @Test
+ public void testQueryOutEdgesByMultiLabelsAndSortKey() {
+ HugeGraph graph = graph();
+ Vertex reader = initEdgeLabelQueryEdges();
+
+ List edges = graph.traversal().V(reader.id())
+ .outE("reviewed", "recommended")
+ .has("time", "2026-1-1")
+ .toList();
+
+ Set labels = new HashSet<>();
+ for (Edge edge : edges) {
+ labels.add(edge.label());
+ Assert.assertEquals("2026-1-1", edge.value("time"));
+ }
+ Assert.assertEquals(2, edges.size());
+ Assert.assertEquals(ImmutableSet.of("reviewed", "recommended"),
+ labels);
+ }
+
+ @Test
+ public void testQueryEdgesByNonEqLabel() {
+ HugeGraph graph = graph();
+ init18Edges();
+
+ List edges = graph.traversal().E()
+ .has(T.label, P.neq("created"))
+ .toList();
+ Assert.assertEquals(16, edges.size());
+ for (Edge edge : edges) {
+ Assert.assertNotEquals("created", edge.label());
+ }
+ }
+
@Test
public void testQueryOutEdgesOfVertexBySortkeyWithRange() {
// FIXME: skip this test for hstore
@@ -7691,6 +7742,40 @@ private void init18Edges(boolean commit) {
}
}
+ private Vertex initEdgeLabelQueryEdges() {
+ HugeGraph graph = graph();
+ SchemaManager schema = graph.schema();
+
+ schema.edgeLabel("reviewed").properties("time", "score")
+ .multiTimes().sortKeys("time")
+ .link("person", "book")
+ .enableLabelIndex(false)
+ .create();
+ schema.edgeLabel("recommended").properties("time", "score")
+ .multiTimes().sortKeys("time")
+ .link("person", "book")
+ .enableLabelIndex(false)
+ .create();
+
+ Vertex reader = graph.addVertex(T.label, "person",
+ "name", "edge-label-reader",
+ "city", "Beijing",
+ "age", 29);
+ Vertex book1 = graph.addVertex(T.label, "book",
+ "name", "edge-label-book-1");
+ Vertex book2 = graph.addVertex(T.label, "book",
+ "name", "edge-label-book-2");
+ Vertex book3 = graph.addVertex(T.label, "book",
+ "name", "edge-label-book-3");
+
+ reader.addEdge("reviewed", book1, "time", "2026-1-1", "score", 1);
+ reader.addEdge("recommended", book2, "time", "2026-1-1", "score", 2);
+ reader.addEdge("reviewed", book3, "time", "2026-1-2", "score", 3);
+
+ graph.tx().commit();
+ return reader;
+ }
+
private void init100LookEdges() {
HugeGraph graph = graph();
diff --git a/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/core/VertexCoreTest.java b/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/core/VertexCoreTest.java
index d33f9bb07d..68a1dd1547 100644
--- a/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/core/VertexCoreTest.java
+++ b/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/core/VertexCoreTest.java
@@ -54,6 +54,7 @@
import org.apache.hugegraph.exception.NotAllowException;
import org.apache.hugegraph.schema.PropertyKey;
import org.apache.hugegraph.schema.SchemaManager;
+import org.apache.hugegraph.schema.SchemaLabel;
import org.apache.hugegraph.schema.Userdata;
import org.apache.hugegraph.schema.VertexLabel;
import org.apache.hugegraph.structure.HugeElement;
@@ -9076,6 +9077,76 @@ public void testQueryByJointLabels() {
Assert.assertEquals(0, vertices.size());
}
+ @Test
+ public void testQueryByNonEqLabelAndIndexedProperty() {
+ HugeGraph graph = graph();
+ initPersonIndex(true);
+ init5Persons();
+
+ GraphTraversalSource g = graph.traversal();
+
+ List vertices = g.V().has(T.label, P.neq("author"))
+ .has("city", "Beijing").toList();
+ Assert.assertEquals(3, vertices.size());
+ for (Vertex vertex : vertices) {
+ Assert.assertEquals("person", vertex.label());
+ }
+ }
+
+ @Test
+ public void testQueryByNonEqLabel() {
+ HugeGraph graph = graph();
+ init10Vertices();
+
+ GraphTraversalSource g = graph.traversal();
+
+ List vertices = g.V().has(T.label, P.neq("author")).toList();
+ Assert.assertEquals(8, vertices.size());
+ for (Vertex vertex : vertices) {
+ Assert.assertNotEquals("author", vertex.label());
+ }
+ }
+
+ @Test
+ public void testCollectMatchedIndexesByJointLabelsWithIndexedProperties() {
+ HugeGraph graph = graph();
+ initPersonIndex(true);
+
+ VertexLabel person = graph.vertexLabel("person");
+ VertexLabel computer = graph.vertexLabel("computer");
+ PropertyKey city = graph.propertyKey("city");
+
+ ConditionQuery query = new ConditionQuery(HugeType.VERTEX);
+ query.query(Condition.in(HugeKeys.LABEL,
+ ImmutableList.of(person.id(), computer.id())));
+ query.query(Condition.eq(city.id(), "Beijing"));
+
+ Set> matchedIndexes = Whitebox.invoke(params().graphTransaction(),
+ "indexTx",
+ "collectMatchedIndexes",
+ query);
+ Assert.assertEquals(1, matchedIndexes.size());
+ Object matchedIndex = matchedIndexes.iterator().next();
+ SchemaLabel schemaLabel = Whitebox.getInternalState(matchedIndex,
+ "schemaLabel");
+ Assert.assertEquals("person", schemaLabel.name());
+
+ ConditionQuery conflicting = new ConditionQuery(HugeType.VERTEX);
+ conflicting.eq(HugeKeys.LABEL, person.id());
+ conflicting.eq(HugeKeys.LABEL, computer.id());
+ conflicting.query(Condition.eq(city.id(), "Beijing"));
+
+ Assert.assertTrue(conflicting.containsCondition(HugeKeys.LABEL));
+ Assert.assertEquals(ImmutableSet.of(),
+ conflicting.conditionValues(HugeKeys.LABEL));
+
+ matchedIndexes = Whitebox.invoke(params().graphTransaction(),
+ "indexTx",
+ "collectMatchedIndexes",
+ conflicting);
+ Assert.assertEquals(0, matchedIndexes.size());
+ }
+
@Test
public void testQueryByHasIdEmptyList() {
HugeGraph graph = graph();
diff --git a/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/unit/core/QueryTest.java b/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/unit/core/QueryTest.java
index 7d48084dbf..b8b505c3d8 100644
--- a/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/unit/core/QueryTest.java
+++ b/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/unit/core/QueryTest.java
@@ -48,6 +48,19 @@ public void testOrderBy() {
query.orders());
}
+ @Test
+ public void testConditionWithoutLabel() {
+ ConditionQuery query = new ConditionQuery(HugeType.EDGE);
+
+ Assert.assertFalse(query.containsCondition(HugeKeys.LABEL));
+ Assert.assertFalse(query.containsConditionValues(HugeKeys.LABEL));
+ Assert.assertEquals(ImmutableSet.of(),
+ query.conditionValues(HugeKeys.LABEL));
+ Assert.assertNull(query.uniqueConditionValue(HugeKeys.LABEL));
+ Assert.assertNull(query.conditionValue(HugeKeys.LABEL));
+ Assert.assertNull(query.condition(HugeKeys.LABEL));
+ }
+
@Test
public void testConditionWithEqAndIn() {
Id label1 = IdGenerator.of(1);
@@ -58,9 +71,37 @@ public void testConditionWithEqAndIn() {
query.query(Condition.in(HugeKeys.LABEL,
ImmutableList.of(label1, label2)));
+ Assert.assertTrue(query.containsCondition(HugeKeys.LABEL));
+ Assert.assertTrue(query.containsConditionValues(HugeKeys.LABEL));
+ Assert.assertEquals(ImmutableSet.of(label1),
+ query.conditionValues(HugeKeys.LABEL));
+ Assert.assertEquals(label1, query.uniqueConditionValue(HugeKeys.LABEL));
+ Assert.assertEquals(label1, query.conditionValue(HugeKeys.LABEL));
Assert.assertEquals(label1, query.condition(HugeKeys.LABEL));
}
+ @Test
+ public void testConditionWithSingleInValues() {
+ Id label1 = IdGenerator.of(1);
+ Id label2 = IdGenerator.of(2);
+
+ ConditionQuery query = new ConditionQuery(HugeType.EDGE);
+ query.query(Condition.in(HugeKeys.LABEL,
+ ImmutableList.of(label1, label2)));
+
+ Assert.assertTrue(query.containsCondition(HugeKeys.LABEL));
+ Assert.assertTrue(query.containsConditionValues(HugeKeys.LABEL));
+ Assert.assertEquals(ImmutableSet.of(label1, label2),
+ query.conditionValues(HugeKeys.LABEL));
+ Assert.assertNull(query.uniqueConditionValue(HugeKeys.LABEL));
+ Assert.assertThrows(IllegalStateException.class,
+ () -> query.conditionValue(HugeKeys.LABEL),
+ e -> Assert.assertContains("Illegal key 'LABEL'",
+ e.getMessage()));
+ Assert.assertEquals(ImmutableList.of(label1, label2),
+ query.condition(HugeKeys.LABEL));
+ }
+
@Test
public void testConditionWithConflictingEqAndIn() {
Id label1 = IdGenerator.of(1);
@@ -73,9 +114,44 @@ public void testConditionWithConflictingEqAndIn() {
query.query(Condition.in(HugeKeys.LABEL,
ImmutableList.of(label1, label3)));
+ Assert.assertTrue(query.containsCondition(HugeKeys.LABEL));
+ Assert.assertTrue(query.containsConditionValues(HugeKeys.LABEL));
+ Assert.assertEquals(ImmutableSet.of(),
+ query.conditionValues(HugeKeys.LABEL));
+ Assert.assertNull(query.uniqueConditionValue(HugeKeys.LABEL));
+ Assert.assertNull(query.conditionValue(HugeKeys.LABEL));
Assert.assertNull(query.condition(HugeKeys.LABEL));
}
+ @Test
+ public void testConditionWithNonEqInLabel() {
+ Id label = IdGenerator.of(1);
+
+ ConditionQuery query = new ConditionQuery(HugeType.EDGE);
+ query.neq(HugeKeys.LABEL, label);
+
+ Assert.assertTrue(query.containsCondition(HugeKeys.LABEL));
+ Assert.assertFalse(query.containsConditionValues(HugeKeys.LABEL));
+ Assert.assertTrue(query.hasNeqCondition());
+ Assert.assertFalse(query.hasUserpropNeqCondition());
+ Assert.assertEquals(ImmutableSet.of(),
+ query.conditionValues(HugeKeys.LABEL));
+ Assert.assertNull(query.uniqueConditionValue(HugeKeys.LABEL));
+ Assert.assertNull(query.conditionValue(HugeKeys.LABEL));
+ Assert.assertNull(query.condition(HugeKeys.LABEL));
+ }
+
+ @Test
+ public void testConditionWithUserpropNeq() {
+ Id prop = IdGenerator.of(1);
+
+ ConditionQuery query = new ConditionQuery(HugeType.EDGE);
+ query.query(Condition.neq(prop, "Beijing"));
+
+ Assert.assertTrue(query.hasNeqCondition());
+ Assert.assertTrue(query.hasUserpropNeqCondition());
+ }
+
@Test
public void testConditionWithMultipleMatchedInValues() {
Id label1 = IdGenerator.of(1);
@@ -89,6 +165,15 @@ public void testConditionWithMultipleMatchedInValues() {
query.query(Condition.in(HugeKeys.LABEL,
ImmutableList.of(label1, label2, label4)));
+ Assert.assertTrue(query.containsCondition(HugeKeys.LABEL));
+ Assert.assertTrue(query.containsConditionValues(HugeKeys.LABEL));
+ Assert.assertEquals(ImmutableSet.of(label1, label2),
+ query.conditionValues(HugeKeys.LABEL));
+ Assert.assertNull(query.uniqueConditionValue(HugeKeys.LABEL));
+ Assert.assertThrows(IllegalStateException.class,
+ () -> query.conditionValue(HugeKeys.LABEL),
+ e -> Assert.assertContains("Illegal key 'LABEL'",
+ e.getMessage()));
Assert.assertThrows(IllegalStateException.class,
() -> query.condition(HugeKeys.LABEL),
e -> Assert.assertContains("Illegal key 'LABEL'",