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

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


The following commit(s) were added to refs/heads/master by this push:
     new 7f0a44adc fix(server): handle match() in no index case (#3039)
7f0a44adc is described below

commit 7f0a44adc0bd8f7445a4ac357633e967955c845c
Author: legendpei <[email protected]>
AuthorDate: Thu Jun 4 17:50:07 2026 +0800

    fix(server): handle match() in no index case (#3039)
---
 .../traversal/optimize/TraversalUtil.java          | 227 +++++++++++++++++
 .../hugegraph/core/CountStrategyCoreTest.java      | 283 +++++++++++++++++++++
 .../optimize/TraversalUtilOptimizeTest.java        |  24 ++
 3 files changed, 534 insertions(+)

diff --git 
a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/optimize/TraversalUtil.java
 
b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/optimize/TraversalUtil.java
index 8f4f7eb86..7b68f7177 100644
--- 
a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/optimize/TraversalUtil.java
+++ 
b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/optimize/TraversalUtil.java
@@ -42,6 +42,7 @@ import org.apache.hugegraph.backend.query.Query;
 import org.apache.hugegraph.exception.NotFoundException;
 import org.apache.hugegraph.exception.NotSupportException;
 import org.apache.hugegraph.iterator.FilterIterator;
+import org.apache.hugegraph.schema.IndexLabel;
 import org.apache.hugegraph.schema.PropertyKey;
 import org.apache.hugegraph.schema.SchemaLabel;
 import org.apache.hugegraph.structure.HugeElement;
@@ -68,6 +69,7 @@ import 
org.apache.tinkerpop.gremlin.process.traversal.step.filter.HasStep;
 import 
org.apache.tinkerpop.gremlin.process.traversal.step.filter.RangeGlobalStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.map.CountGlobalStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.map.GraphStep;
+import org.apache.tinkerpop.gremlin.process.traversal.step.map.MatchStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.map.MaxGlobalStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.map.MeanGlobalStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.map.MinGlobalStep;
@@ -172,6 +174,27 @@ public final class TraversalUtil {
             Step<?, ?> nextStep = step.getNextStep();
             if (step instanceof HasStep) {
                 HasContainerHolder holder = (HasContainerHolder) step;
+                /*
+                 * Range/neq predicates before match() may trigger a no-index
+                 * query after MatchStep reorders filters. Keep known-indexed
+                 * boolean predicates pushed down, and leave the rest for
+                 * TinkerPop to evaluate.
+                 */
+                if (followedByMatchStep(step) &&
+                    hasUnusableMatchPredicate(newStep, holder)) {
+                    List<HasContainer> extracted =
+                            extractUsableHasContainers(newStep, holder);
+                    for (HasContainer has : extracted) {
+                        holder.removeHasContainer(has);
+                    }
+                    if (holder.getHasContainers().isEmpty()) {
+                        TraversalHelper.copyLabels(step, 
step.getPreviousStep(),
+                                                   false);
+                        traversal.removeStep(step);
+                    }
+                    step = nextStep;
+                    continue;
+                }
                 if (extractHasContainers(newStep, holder)) {
                     TraversalHelper.copyLabels(step, step.getPreviousStep(), 
false);
                     traversal.removeStep(step);
@@ -181,6 +204,203 @@ public final class TraversalUtil {
         }
     }
 
+    private static boolean followedByMatchStep(Step<?, ?> step) {
+        Step<?, ?> next = step.getNextStep();
+        while (next instanceof HasStep ||
+               next instanceof NoOpBarrierStep ||
+               next instanceof IdentityStep) {
+            next = next.getNextStep();
+        }
+        return next instanceof MatchStep;
+    }
+
+    private static boolean hasUnusableMatchPredicate(HugeGraphStep<?, ?> step,
+                                                     HasContainerHolder 
holder) {
+        HugeGraph graph = tryGetGraph(step);
+        for (HasContainer has : holder.getHasContainers()) {
+            if (!hasMatchIndexSensitivePredicate(has)) {
+                continue;
+            }
+            if (graph == null || !hasUsableMatchIndex(graph, step, has)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private static List<HasContainer> extractUsableHasContainers(
+            HugeGraphStep<?, ?> step, HasContainerHolder holder) {
+        List<HasContainer> extracted = new ArrayList<>();
+        HugeGraph graph = tryGetGraph(step);
+        for (HasContainer has : holder.getHasContainers()) {
+            if (hasMatchIndexSensitivePredicate(has) &&
+                (graph == null || !hasUsableMatchIndex(graph, step, has))) {
+                continue;
+            }
+            if (!canExtractHasContainer(graph, has)) {
+                continue;
+            }
+            if (!GraphStep.processHasContainerIds(step, has)) {
+                step.addHasContainer(has);
+            }
+            extracted.add(has);
+        }
+        return extracted;
+    }
+
+    private static boolean hasMatchIndexSensitivePredicate(HasContainer has) {
+        if (hasNullPredicate(has)) {
+            return true;
+        }
+        List<P<Object>> predicates = new ArrayList<>();
+        collectPredicates(predicates, ImmutableList.of(has.getPredicate()));
+        for (P<Object> pred : predicates) {
+            BiPredicate<?, ?> bp = pred.getBiPredicate();
+            if (bp == Compare.neq ||
+                bp == Compare.gt || bp == Compare.gte ||
+                bp == Compare.lt || bp == Compare.lte) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private static boolean hasUsableMatchIndex(HugeGraph graph,
+                                               HugeGraphStep<?, ?> step,
+                                               HasContainer has) {
+        if (isSysProp(has.getKey())) {
+            return false;
+        }
+
+        PropertyKey pkey;
+        try {
+            pkey = graph.propertyKey(has.getKey());
+        } catch (NotFoundException e) {
+            return false;
+        }
+        if (!hasOnlyUsableNeqPredicates(pkey, has)) {
+            return false;
+        }
+        if (!canExtractHasContainer(graph, has)) {
+            return false;
+        }
+
+        Collection<? extends SchemaLabel> schemaLabels = step.returnsVertex() ?
+                                                         graph.vertexLabels() :
+                                                         graph.edgeLabels();
+        boolean seen = false;
+        for (SchemaLabel schemaLabel : schemaLabels) {
+            if (!schemaLabel.properties().contains(pkey.id())) {
+                continue;
+            }
+            seen = true;
+            if (pkey.dataType() == DataType.BOOLEAN &&
+                !hasBooleanIndex(graph, schemaLabel, pkey)) {
+                return false;
+            }
+            if (pkey.dataType().isNumber() &&
+                (!hasOnlyRangePredicates(has) ||
+                 !hasRangeIndex(graph, schemaLabel, pkey))) {
+                return false;
+            }
+            if (pkey.dataType() != DataType.BOOLEAN &&
+                !pkey.dataType().isNumber()) {
+                return false;
+            }
+        }
+        return seen;
+    }
+
+    private static boolean hasOnlyUsableNeqPredicates(PropertyKey pkey,
+                                                      HasContainer has) {
+        if (hasNullPredicate(has)) {
+            return false;
+        }
+        List<P<Object>> predicates = new ArrayList<>();
+        collectPredicates(predicates, ImmutableList.of(has.getPredicate()));
+        for (P<Object> pred : predicates) {
+            if (pred.getBiPredicate() != Compare.neq) {
+                continue;
+            }
+            if (pkey.dataType() == DataType.BOOLEAN &&
+                pred.getValue() instanceof Boolean) {
+                continue;
+            }
+            return false;
+        }
+        return true;
+    }
+
+    private static boolean hasNullPredicate(HasContainer has) {
+        List<P<Object>> predicates = new ArrayList<>();
+        collectPredicates(predicates, ImmutableList.of(has.getPredicate()));
+        for (P<Object> pred : predicates) {
+            if (pred.getValue() == null) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private static boolean hasBooleanIndex(HugeGraph graph,
+                                           SchemaLabel schemaLabel,
+                                           PropertyKey pkey) {
+        for (Id id : schemaLabel.indexLabels()) {
+            IndexLabel indexLabel = indexLabelOrNull(graph, id);
+            if (indexLabel == null ||
+                !matchSingleFieldIndex(indexLabel, pkey)) {
+                continue;
+            }
+            if (indexLabel.indexType().isSecondary()) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private static boolean hasRangeIndex(HugeGraph graph,
+                                         SchemaLabel schemaLabel,
+                                         PropertyKey pkey) {
+        for (Id id : schemaLabel.indexLabels()) {
+            IndexLabel indexLabel = indexLabelOrNull(graph, id);
+            if (indexLabel == null ||
+                !matchSingleFieldIndex(indexLabel, pkey)) {
+                continue;
+            }
+            if (indexLabel.indexType().isRange()) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    static IndexLabel indexLabelOrNull(HugeGraph graph, Id id) {
+        try {
+            return graph.indexLabel(id);
+        } catch (IllegalArgumentException e) {
+            return null;
+        }
+    }
+
+    private static boolean matchSingleFieldIndex(IndexLabel indexLabel,
+                                                 PropertyKey pkey) {
+        return indexLabel.indexFields().size() == 1 &&
+               indexLabel.indexField().equals(pkey.id());
+    }
+
+    private static boolean hasOnlyRangePredicates(HasContainer has) {
+        List<P<Object>> predicates = new ArrayList<>();
+        collectPredicates(predicates, ImmutableList.of(has.getPredicate()));
+        for (P<Object> pred : predicates) {
+            BiPredicate<?, ?> bp = pred.getBiPredicate();
+            if (bp != Compare.gt && bp != Compare.gte &&
+                bp != Compare.lt && bp != Compare.lte) {
+                return false;
+            }
+        }
+        return true;
+    }
+
     public static void extractHasContainer(HugeVertexStep<?> newStep,
                                            Traversal.Admin<?, ?> traversal) {
         Step<?, ?> step = newStep;
@@ -248,6 +468,9 @@ public final class TraversalUtil {
         } catch (NotFoundException e) {
             return false;
         }
+        if (hasNullPredicate(has)) {
+            return false;
+        }
         if (!pkey.dataType().isText()) {
             return true;
         }
@@ -775,6 +998,10 @@ public final class TraversalUtil {
         List<P<Object>> leafPredicates = new ArrayList<>();
         collectPredicates(leafPredicates, ImmutableList.of(predicate));
         for (P<Object> pred : leafPredicates) {
+            if (pred.getBiPredicate() == Compare.neq &&
+                pred.getValue() == null) {
+                continue;
+            }
             Object value = validPropertyValue(pred.getValue(), pkey);
             pred.setValue(value);
         }
diff --git 
a/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/core/CountStrategyCoreTest.java
 
b/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/core/CountStrategyCoreTest.java
index 212c2bc04..58a0d992f 100644
--- 
a/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/core/CountStrategyCoreTest.java
+++ 
b/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/core/CountStrategyCoreTest.java
@@ -19,8 +19,15 @@ package org.apache.hugegraph.core;
 
 import org.apache.hugegraph.schema.SchemaManager;
 import org.apache.hugegraph.testutil.Assert;
+import org.apache.hugegraph.traversal.optimize.HugeGraphStep;
 import org.apache.tinkerpop.gremlin.process.traversal.P;
+import org.apache.tinkerpop.gremlin.process.traversal.Step;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
+import org.apache.tinkerpop.gremlin.process.traversal.step.HasContainerHolder;
+import org.apache.tinkerpop.gremlin.process.traversal.step.filter.HasStep;
+import org.apache.tinkerpop.gremlin.process.traversal.step.util.HasContainer;
+import org.apache.tinkerpop.gremlin.structure.Edge;
 import org.apache.tinkerpop.gremlin.structure.T;
 import org.apache.tinkerpop.gremlin.structure.Vertex;
 import org.junit.Test;
@@ -48,6 +55,57 @@ public class CountStrategyCoreTest extends BaseCoreTest {
         commitTx();
     }
 
+    private void initMatchNoIndexSchema() {
+        SchemaManager schema = graph().schema();
+        schema.propertyKey("vp2").asBoolean().create();
+        schema.propertyKey("vp3").asLong().create();
+        schema.propertyKey("vp4").asText().create();
+        schema.propertyKey("ep2").asBoolean().create();
+        schema.vertexLabel("vl1").properties("vp2", "vp4")
+              .nullableKeys("vp2", "vp4").create();
+        schema.vertexLabel("vl0").properties("vp3")
+              .nullableKeys("vp3").create();
+        schema.edgeLabel("el1").link("vl1", "vl0")
+              .properties("ep2").nullableKeys("ep2").create();
+    }
+
+    private void initMatchNoIndexGraph() {
+        Vertex v1 = graph().addVertex(T.label, "vl1", "vp2", true,
+                                      "vp4", "foo");
+        Vertex v2 = graph().addVertex(T.label, "vl1", "vp2", false,
+                                      "vp4", "J2O");
+        Vertex v3 = graph().addVertex(T.label, "vl0",
+                                      "vp3", 4592737712018141719L);
+        Vertex v4 = graph().addVertex(T.label, "vl0",
+                                      "vp3", 4592737712018141717L);
+
+        v1.addEdge("el1", v3, "ep2", true);
+        v2.addEdge("el1", v4, "ep2", false);
+        commitTx();
+    }
+
+    private static HugeGraphStep<?, ?> applyAndGetGraphStep(
+            GraphTraversal<?, ?> traversal) {
+        traversal.asAdmin().applyStrategies();
+        return (HugeGraphStep<?, ?>) traversal.asAdmin().getStartStep();
+    }
+
+    private static boolean hasRemainingHasStep(GraphTraversal<?, ?> traversal,
+                                               String key) {
+        for (Step<?, ?> step : traversal.asAdmin().getSteps()) {
+            if (!(step instanceof HasStep)) {
+                continue;
+            }
+            HasContainerHolder holder = (HasContainerHolder) step;
+            for (HasContainer has : holder.getHasContainers()) {
+                if (key.equals(has.getKey())) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
     private void initTextRangeSchema(boolean withEdge) {
         SchemaManager schema = graph().schema();
         schema.propertyKey("vp4").asText().create();
@@ -227,4 +285,229 @@ public class CountStrategyCoreTest extends BaseCoreTest {
         Assert.assertEquals(direct, viaMatch);
     }
 
+    @Test
+    public void testMatchWithNoIndexConditionMatchesDirectTraversal() {
+        this.initMatchNoIndexSchema();
+        this.initMatchNoIndexGraph();
+
+        long direct = graph().traversal().V()
+                           .has("vp4", P.neq("J2O"))
+                           .has("vl1", "vp2", P.gte(false))
+                           .has("vp2")
+                           .has("vl0", "vp3", P.gt(4592737712018141718L))
+                           .out("el1")
+                           .count().next();
+        long viaMatch = graph().traversal().V()
+                             .has("vp4", P.neq("J2O"))
+                             .has("vl1", "vp2", P.gte(false))
+                             .match(__.<Vertex>as("start0")
+                                      .has("vp2")
+                                      .has("vl0", "vp3",
+                                           P.gt(4592737712018141718L))
+                                      .repeat(__.out("el1"))
+                                      .times(1)
+                                      .as("m0"))
+                             .<Vertex>select("m0").count().next();
+
+        Assert.assertEquals(0L, direct);
+        Assert.assertEquals(direct, viaMatch);
+    }
+
+    @Test
+    public void testMatchWithIndexedRangeConditionStillExtractsHas() {
+        this.initMatchNoIndexSchema();
+        graph().schema().indexLabel("vl1ByVp2").onV("vl1")
+               .by("vp2").secondary().create();
+        this.initMatchNoIndexGraph();
+
+        GraphTraversal<Vertex, Long> traversal = graph().traversal().V()
+                                                        .has("vp2", P.lt(true))
+                                                        
.match(__.<Vertex>as("s")
+                                                                 .has("vp2")
+                                                                 .as("m"))
+                                                        .<Vertex>select("m")
+                                                        .count();
+
+        HugeGraphStep<?, ?> graphStep = applyAndGetGraphStep(traversal);
+        Assert.assertEquals(1, graphStep.getHasContainers().size());
+        Assert.assertEquals("vp2", 
graphStep.getHasContainers().get(0).getKey());
+        Assert.assertEquals(1L, traversal.next());
+    }
+
+    @Test
+    public void testMatchWithNoIndexConditionKeepsExtractingNextHas() {
+        this.initMatchNoIndexSchema();
+        graph().schema().indexLabel("vl1ByVp2").onV("vl1")
+               .by("vp2").secondary().create();
+        this.initMatchNoIndexGraph();
+
+        GraphTraversal<Vertex, Long> traversal = graph().traversal().V()
+                                                        .has("vp4", 
P.neq("J2O"))
+                                                        .has("vp2", true)
+                                                        
.match(__.<Vertex>as("s")
+                                                                 .has("vp2")
+                                                                 .as("m"))
+                                                        .<Vertex>select("m")
+                                                        .count();
+
+        HugeGraphStep<?, ?> graphStep = applyAndGetGraphStep(traversal);
+        Assert.assertEquals(1, graphStep.getHasContainers().size());
+        Assert.assertEquals("vp2", 
graphStep.getHasContainers().get(0).getKey());
+        Assert.assertTrue(hasRemainingHasStep(traversal, "vp4"));
+        Assert.assertFalse(hasRemainingHasStep(traversal, "vp2"));
+        Assert.assertEquals(1L, traversal.next());
+    }
+
+    @Test
+    public void testMatchWithBooleanExistsConditionKeepsHas() {
+        this.initMatchNoIndexSchema();
+        graph().schema().indexLabel("vl1ByVp2").onV("vl1")
+               .by("vp2").secondary().create();
+        this.initMatchNoIndexGraph();
+
+        GraphTraversal<Vertex, Long> traversal = graph().traversal().V()
+                                                        .has("vp2", 
P.neq(null))
+                                                        
.match(__.<Vertex>as("s")
+                                                                 .has("vp2", 
true)
+                                                                 .as("m"))
+                                                        .<Vertex>select("m")
+                                                        .count();
+
+        HugeGraphStep<?, ?> graphStep = applyAndGetGraphStep(traversal);
+        Assert.assertEquals(0, graphStep.getHasContainers().size());
+        Assert.assertEquals(1L, traversal.next());
+    }
+
+    @Test
+    public void testMatchWithIdentityKeepsNoIndexConditionLocal() {
+        this.initMatchNoIndexSchema();
+        this.initMatchNoIndexGraph();
+
+        GraphTraversal<Vertex, Long> traversal = graph().traversal().V()
+                                                        .has("vp4", 
P.neq("J2O"))
+                                                        .identity()
+                                                        
.match(__.<Vertex>as("s")
+                                                                 .has("vp2")
+                                                                 .as("m"))
+                                                        .<Vertex>select("m")
+                                                        .count();
+
+        HugeGraphStep<?, ?> graphStep = applyAndGetGraphStep(traversal);
+        Assert.assertEquals(0, graphStep.getHasContainers().size());
+        Assert.assertTrue(hasRemainingHasStep(traversal, "vp4"));
+        Assert.assertEquals(1L, traversal.next());
+    }
+
+    @Test
+    public void testMatchWithIndexedEdgeRangeConditionStillExtractsHas() {
+        this.initMatchNoIndexSchema();
+        graph().schema().indexLabel("el1ByEp2").onE("el1")
+               .by("ep2").secondary().create();
+        this.initMatchNoIndexGraph();
+
+        GraphTraversal<Edge, Long> traversal = graph().traversal().E()
+                                                      .has("ep2", P.lt(true))
+                                                      .match(__.<Edge>as("s")
+                                                               .has("ep2")
+                                                               .as("m"))
+                                                      .<Edge>select("m")
+                                                      .count();
+
+        HugeGraphStep<?, ?> graphStep = applyAndGetGraphStep(traversal);
+        Assert.assertEquals(1, graphStep.getHasContainers().size());
+        Assert.assertEquals("ep2", 
graphStep.getHasContainers().get(0).getKey());
+        Assert.assertEquals(1L, traversal.next());
+    }
+
+    @Test
+    public void testMatchWithIndexedNumericRangeConditionStillExtractsHas() {
+        this.initMatchNoIndexSchema();
+        graph().schema().indexLabel("vl0ByVp3").onV("vl0")
+               .by("vp3").range().create();
+        this.initMatchNoIndexGraph();
+
+        GraphTraversal<Vertex, Long> traversal = graph().traversal().V()
+                                                        .has("vp3",
+                                                             
P.gt(4592737712018141718L))
+                                                        
.match(__.<Vertex>as("s")
+                                                                 .has("vp3")
+                                                                 .as("m"))
+                                                        .<Vertex>select("m")
+                                                        .count();
+
+        HugeGraphStep<?, ?> graphStep = applyAndGetGraphStep(traversal);
+        Assert.assertEquals(1, graphStep.getHasContainers().size());
+        Assert.assertEquals("vp3", 
graphStep.getHasContainers().get(0).getKey());
+        Assert.assertFalse(hasRemainingHasStep(traversal, "vp3"));
+        Assert.assertEquals(1L, traversal.next());
+    }
+
+    @Test
+    public void testMatchWithIndexedNumericNeqConditionKeepsHas() {
+        this.initMatchNoIndexSchema();
+        graph().schema().indexLabel("vl0ByVp3").onV("vl0")
+               .by("vp3").range().create();
+        graph().schema().indexLabel("vl1ByVp2").onV("vl1")
+               .by("vp2").secondary().create();
+        this.initMatchNoIndexGraph();
+
+        GraphTraversal<Vertex, Long> traversal = graph().traversal().V()
+                                                        .has("vp3",
+                                                             
P.neq(4592737712018141719L))
+                                                        .has("vp2", true)
+                                                        
.match(__.<Vertex>as("s")
+                                                                 .has("vp2")
+                                                                 .as("m"))
+                                                        .<Vertex>select("m")
+                                                        .count();
+
+        HugeGraphStep<?, ?> graphStep = applyAndGetGraphStep(traversal);
+        Assert.assertEquals(1, graphStep.getHasContainers().size());
+        Assert.assertEquals("vp2", 
graphStep.getHasContainers().get(0).getKey());
+        Assert.assertTrue(hasRemainingHasStep(traversal, "vp3"));
+        Assert.assertEquals(0L, traversal.next());
+    }
+
+    @Test
+    public void testMatchWithSystemRangeConditionMatchesDirectTraversal() {
+        this.initMatchNoIndexSchema();
+        this.initMatchNoIndexGraph();
+
+        long direct = graph().traversal().V()
+                           .hasLabel("vl1")
+                           .has("vp2")
+                           .count().next();
+        GraphTraversal<Vertex, Long> traversal = graph().traversal().V()
+                                                        .hasLabel(P.neq("vl0"))
+                                                        
.match(__.<Vertex>as("s")
+                                                                 .has("vp2")
+                                                                 .as("m"))
+                                                        .<Vertex>select("m")
+                                                        .count();
+
+        HugeGraphStep<?, ?> graphStep = applyAndGetGraphStep(traversal);
+        Assert.assertTrue(hasRemainingHasStep(traversal, 
T.label.getAccessor()));
+        Assert.assertEquals(direct, traversal.next().longValue());
+    }
+
+    @Test
+    public void testMatchWithUniqueBooleanRangeConditionKeepsHas() {
+        this.initMatchNoIndexSchema();
+        graph().schema().indexLabel("vl1ByUniqueVp2").onV("vl1")
+               .by("vp2").unique().create();
+        this.initMatchNoIndexGraph();
+
+        GraphTraversal<Vertex, Long> traversal = graph().traversal().V()
+                                                        .has("vp2", P.lt(true))
+                                                        
.match(__.<Vertex>as("s")
+                                                                 .has("vp2")
+                                                                 .as("m"))
+                                                        .<Vertex>select("m")
+                                                        .count();
+
+        HugeGraphStep<?, ?> graphStep = applyAndGetGraphStep(traversal);
+        Assert.assertEquals(0, graphStep.getHasContainers().size());
+        Assert.assertTrue(hasRemainingHasStep(traversal, "vp2"));
+        Assert.assertEquals(1L, traversal.next());
+    }
 }
diff --git 
a/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/traversal/optimize/TraversalUtilOptimizeTest.java
 
b/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/traversal/optimize/TraversalUtilOptimizeTest.java
index cdf6addfc..c3208a0b9 100644
--- 
a/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/traversal/optimize/TraversalUtilOptimizeTest.java
+++ 
b/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/traversal/optimize/TraversalUtilOptimizeTest.java
@@ -60,6 +60,16 @@ public class TraversalUtilOptimizeTest {
                 graph, new HasContainer("missing", P.eq("marko"))));
     }
 
+    @Test
+    public void testIndexLabelOrNullWithMissingIndexLabel() {
+        HugeGraph graph = Mockito.mock(HugeGraph.class);
+        Id id = IdGenerator.of(1L);
+        Mockito.when(graph.indexLabel(id))
+               .thenThrow(new IllegalArgumentException("missing"));
+
+        Assert.assertNull(TraversalUtil.indexLabelOrNull(graph, id));
+    }
+
     @Test
     public void testCanExtractHasContainerWithNonTextProperty() {
         HugeGraph graph = Mockito.mock(HugeGraph.class);
@@ -116,6 +126,20 @@ public class TraversalUtilOptimizeTest {
         Assert.assertTrue(hasStepExists(traversal));
     }
 
+    @Test
+    public void testExtractHasContainerKeepsMatchRangeWithoutGraph() {
+        Traversal.Admin<?, ?> traversal = __.V()
+                                           .has("age", P.gt(18))
+                                           
.match(__.as("v").identity().as("m"))
+                                           .asAdmin();
+        HugeGraphStep<?, ?> newStep = replaceGraphStep(traversal);
+
+        TraversalUtil.extractHasContainer(newStep, traversal);
+
+        Assert.assertTrue(newStep.getHasContainers().isEmpty());
+        Assert.assertTrue(hasStepExists(traversal));
+    }
+
     @Test
     public void testExtractHasContainerKeepsTextBetweenGraphHasStep() {
         HugeGraph graph = Mockito.mock(HugeGraph.class);

Reply via email to