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 142c95620b..5077845aad 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
@@ -41,6 +41,7 @@
import org.apache.hugegraph.backend.query.Query;
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;
@@ -67,6 +68,7 @@
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;
@@ -166,11 +168,23 @@ public static void trySetGraph(Step, ?> step, HugeGraph graph) {
public static void extractHasContainer(HugeGraphStep, ?> newStep,
Traversal.Admin, ?> traversal) {
- Step, ?> step = newStep;
- do {
- step = step.getNextStep();
+ Step, ?> step = newStep.getNextStep();
+ while (step instanceof HasStep || step instanceof NoOpBarrierStep) {
+ 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)) {
+ extractUsableHasContainers(newStep, holder);
+ step = nextStep;
+ continue;
+ }
for (HasContainer has : holder.getHasContainers()) {
if (!GraphStep.processHasContainerIds(newStep, has)) {
newStep.addHasContainer(has);
@@ -179,7 +193,103 @@ public static void extractHasContainer(HugeGraphStep, ?> newStep,
TraversalHelper.copyLabels(step, step.getPreviousStep(), false);
traversal.removeStep(step);
}
- } while (step instanceof HasStep || step instanceof NoOpBarrierStep);
+ step = nextStep;
+ }
+ }
+
+ private static boolean followedByMatchStep(Step, ?> step) {
+ Step, ?> next = step.getNextStep();
+ while (next instanceof HasStep || next instanceof NoOpBarrierStep) {
+ 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 void extractUsableHasContainers(HugeGraphStep, ?> step,
+ HasContainerHolder holder) {
+ HugeGraph graph = tryGetGraph(step);
+ for (HasContainer has : holder.getHasContainers()) {
+ if (hasMatchIndexSensitivePredicate(has) &&
+ (graph == null || !hasUsableMatchIndex(graph, step, has))) {
+ continue;
+ }
+ if (!GraphStep.processHasContainerIds(step, has)) {
+ step.addHasContainer(has);
+ }
+ }
+ }
+
+ private static boolean hasMatchIndexSensitivePredicate(HasContainer has) {
+ List
> predicates = new ArrayList<>();
+ collectPredicates(predicates, ImmutableList.of(has.getPredicate()));
+ for (P