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

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

commit 3f415e0591d1bd81d8c8faf573265f9c6b29f20e
Author: Zhangmei Li <lizhang...@baidu.com>
AuthorDate: Fri Dec 17 01:39:19 2021 +0800

    add AdjacentEdgesQuery
    
    Change-Id: Ie7169fdb707495ff0a298ea97fa4d105117a132d
---
 .../backend/query/AdjacentEdgesQuery.java          | 396 +++++++++++++++++++++
 .../apache/hugegraph/backend/query/Condition.java  |  14 +-
 .../hugegraph/backend/query/ConditionQuery.java    |  34 +-
 .../backend/query/ConditionQueryFlatten.java       |  19 +-
 .../backend/query/EdgesQueryIterator.java          |   4 +-
 .../hugegraph/backend/tx/GraphTransaction.java     |  81 ++---
 .../traversal/algorithm/HugeTraverser.java         |   2 +-
 .../traversal/optimize/HugeVertexStep.java         |   2 +-
 .../apache/hugegraph/example/PerfExampleBase.java  |  11 +-
 9 files changed, 472 insertions(+), 91 deletions(-)

diff --git 
a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/backend/query/AdjacentEdgesQuery.java
 
b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/backend/query/AdjacentEdgesQuery.java
new file mode 100644
index 000000000..b1d3c1e41
--- /dev/null
+++ 
b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/backend/query/AdjacentEdgesQuery.java
@@ -0,0 +1,396 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.hugegraph.backend.query;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+
+import org.apache.hugegraph.backend.id.Id;
+import org.apache.hugegraph.backend.query.Condition.Relation;
+import org.apache.hugegraph.backend.query.Condition.RelationType;
+import org.apache.hugegraph.structure.HugeEdge;
+import org.apache.hugegraph.structure.HugeElement;
+import org.apache.hugegraph.type.HugeType;
+import org.apache.hugegraph.type.define.Directions;
+import org.apache.hugegraph.type.define.HugeKeys;
+import org.apache.hugegraph.util.CollectionUtil;
+import org.apache.hugegraph.util.E;
+import org.apache.hugegraph.util.InsertionOrderUtil;
+
+import com.google.common.collect.ImmutableList;
+
+public class AdjacentEdgesQuery extends ConditionQuery {
+
+    private Id ownerVertex;
+    private Directions direction;
+    private Id[] edgeLabels;
+
+    private List<Condition> selfConditions;
+
+    private static final Id[] EMPTY = new Id[0];
+
+    public AdjacentEdgesQuery(Id ownerVertex, Directions direction) {
+        this(ownerVertex, direction, EMPTY);
+    }
+
+    public AdjacentEdgesQuery(Id ownerVertex, Directions direction,
+                              Id[] edgeLabels) {
+        super(HugeType.EDGE);
+        E.checkArgument(ownerVertex != null,
+                        "The edge query must contain source vertex");
+        E.checkArgument(direction != null,
+                        "The edge query must contain direction");
+        this.ownerVertex = ownerVertex;
+        this.direction = direction;
+        this.edgeLabels = edgeLabels;
+        this.selfConditions = null;
+    }
+
+    @Override
+    public int conditionsSize() {
+        int size = super.conditionsSize() + 2;
+        if (this.edgeLabels.length > 0) {
+            size += 1;
+        }
+        return size;
+    }
+
+    @Override
+    public ConditionQuery query(Condition condition) {
+        if (!condition.isRelation()) {
+            return super.query(condition);
+        }
+
+        // Reset this.selfConditions cache
+        this.selfConditions = null;
+
+        // Update condition fields
+        Relation relation = ((Condition.Relation) condition);
+        Object key = relation.key();
+        RelationType relationType = relation.relation();
+
+        if (key == HugeKeys.OWNER_VERTEX) {
+            this.ownerVertex = (Id) relation.value();
+            return this;
+        }
+        if (key == HugeKeys.DIRECTION) {
+            this.direction = (Directions) relation.value();
+            return this;
+        }
+        if (key == HugeKeys.LABEL) {
+            Collection<Id> labels = null;
+            if (relationType == RelationType.EQ) {
+                labels = ImmutableList.of((Id) relation.value());
+            } else if (relationType == RelationType.IN) {
+                @SuppressWarnings("unchecked")
+                Collection<Id> value = (Collection<Id>) relation.value();
+                labels = value;
+            } else {
+                E.checkArgument(false,
+                                "Unexpected relation type '%s' for '%s'",
+                                relationType, key);
+            }
+
+            if (this.edgeLabels.length == 0) {
+                this.edgeLabels = labels.toArray(new Id[0]);
+            } else {
+                Collection<Id> edgeLabels = CollectionUtil.intersect(
+                                            Arrays.asList(this.edgeLabels),
+                                            labels);
+                if (edgeLabels.isEmpty()) {
+                    // Returns empty result if conditions are conflicting
+                    this.limit(0L);
+                }
+                this.edgeLabels = edgeLabels.toArray(new Id[0]);
+            }
+            return this;
+        }
+
+        return super.query(condition);
+    }
+
+    @Override
+    public Collection<Condition> conditions() {
+        List<Condition> conds = this.selfConditions();
+        if (super.conditionsSize() > 0) {
+            conds.addAll(super.conditions());
+        }
+        return conds;
+    }
+
+    private List<Condition> selfConditions() {
+        if (this.selfConditions != null) {
+            /*
+             * Return selfConditions cache if it has been collected before
+             * NOTE: it's also to keep the serialized condition value
+             */
+            return this.selfConditions;
+        }
+
+        List<Condition> conds = InsertionOrderUtil.newList();
+
+        conds.add(Condition.eq(HugeKeys.OWNER_VERTEX, this.ownerVertex));
+
+        if (this.direction == Directions.BOTH) {
+            conds.add(Condition.in(HugeKeys.DIRECTION, ImmutableList.of(
+                                                       Directions.OUT,
+                                                       Directions.IN)));
+        } else {
+            conds.add(Condition.eq(HugeKeys.DIRECTION, this.direction));
+        }
+
+        if (this.edgeLabels.length == 1) {
+            conds.add(Condition.eq(HugeKeys.LABEL, this.edgeLabels[0]));
+        } else if (this.edgeLabels.length > 1) {
+            conds.add(Condition.in(HugeKeys.LABEL,
+                                   Arrays.asList(this.edgeLabels)));
+        }
+
+        this.selfConditions = conds;
+        return conds;
+    }
+
+    @Override
+    public <T> T condition(Object key) {
+        T cond = this.selfCondition(key);
+        if (cond != null) {
+            return cond;
+        }
+        return super.condition(key);
+    }
+
+    @SuppressWarnings("unchecked")
+    private <T> T selfCondition(Object key) {
+        if (key == HugeKeys.OWNER_VERTEX) {
+            return (T) this.ownerVertex;
+        }
+        if (key == HugeKeys.DIRECTION) {
+            return (T) this.direction;
+        }
+        if (key == HugeKeys.LABEL) {
+            if (this.edgeLabels.length == 0) {
+                return null;
+            }
+            if (this.edgeLabels.length == 1) {
+                return (T) this.edgeLabels[0];
+            }
+            E.checkState(false,
+                         "Illegal key '%s' with more than one value", key);
+        }
+        return null;
+    }
+
+    private Condition.Relation selfRelation(Object key) {
+        if (key == HugeKeys.OWNER_VERTEX) {
+            return Condition.eq(HugeKeys.OWNER_VERTEX, this.ownerVertex);
+        }
+        if (key == HugeKeys.DIRECTION) {
+            if (this.direction == Directions.BOTH) {
+                return Condition.in(HugeKeys.DIRECTION, ImmutableList.of(
+                                                        Directions.OUT,
+                                                        Directions.IN));
+            } else {
+                return Condition.eq(HugeKeys.DIRECTION, this.direction);
+            }
+        }
+        if (key == HugeKeys.LABEL) {
+            if (this.edgeLabels.length == 0) {
+                return null;
+            }
+            if (this.edgeLabels.length == 1) {
+                return Condition.eq(HugeKeys.LABEL, this.edgeLabels[0]);
+            }
+            return Condition.in(HugeKeys.LABEL, 
Arrays.asList(this.edgeLabels));
+        }
+        return null;
+    }
+
+    @Override
+    public boolean containsCondition(HugeKeys key) {
+        if (key == HugeKeys.OWNER_VERTEX) {
+            return true;
+        }
+        if (key == HugeKeys.DIRECTION) {
+            return true;
+        }
+        if (key == HugeKeys.LABEL) {
+            if (this.edgeLabels.length == 0) {
+                return false;
+            }
+            return true;
+        }
+        return super.containsCondition(key);
+    }
+
+    @Override
+    public void unsetCondition(Object key) {
+        if (key == HugeKeys.OWNER_VERTEX ||
+            key == HugeKeys.DIRECTION ||
+            key == HugeKeys.LABEL) {
+            E.checkArgument(false, "Can't unset condition '%s'", key);
+        }
+        super.unsetCondition(key);
+    }
+
+    @Override
+    public List<Condition> syspropConditions() {
+        List<Condition> conds = this.selfConditions();
+        if (super.conditionsSize() > 0) {
+            conds.addAll(super.syspropConditions());
+        }
+        return conds;
+    }
+
+    @Override
+    public List<Condition> syspropConditions(HugeKeys key) {
+        Condition cond = this.selfRelation(key);
+        if (cond != null) {
+            return ImmutableList.of(cond);
+        }
+        return super.syspropConditions(key);
+    }
+
+    @Override
+    public List<Condition.Relation> relations() {
+        // NOTE: selfConditions() actually return a list of Relation
+        @SuppressWarnings({ "rawtypes", "unchecked" })
+        List<Condition.Relation> relations = (List) this.selfConditions();
+        if (super.conditionsSize() > 0) {
+            relations.addAll(super.relations());
+        }
+        return relations;
+    }
+
+    @Override
+    public Relation relation(Id key){
+        Relation relation = this.selfRelation(key);
+        if (relation != null) {
+            return relation;
+        }
+        return super.relation(key);
+    }
+
+    @Override
+    public boolean allSysprop() {
+        return super.allSysprop();
+    }
+
+    @Override
+    public boolean allRelation() {
+        if (!this.isFlattened()) {
+            return false;
+        }
+        return super.allRelation();
+    }
+
+    @Override
+    public AdjacentEdgesQuery copy() {
+        return (AdjacentEdgesQuery) super.copy();
+    }
+
+    @Override
+    public AdjacentEdgesQuery copyAndResetUnshared() {
+        return (AdjacentEdgesQuery) super.copyAndResetUnshared();
+    }
+
+    @Override
+    public boolean isFlattened() {
+        if (this.direction == Directions.BOTH) {
+            return false;
+        }
+        if (this.edgeLabels.length > 1) {
+            return false;
+        }
+        return super.isFlattened();
+    }
+
+    @Override
+    public boolean canFlatten() {
+        return super.conditionsSize() == 0;
+    }
+
+    @Override
+    public List<ConditionQuery> flatten() {
+        int labels = this.edgeLabels.length;
+        int directions = this.direction == Directions.BOTH ? 2 : 1;
+        int size = labels * directions;
+        List<ConditionQuery> queries = new ArrayList<>(size);
+        if (labels == 0) {
+            Id label = null;
+            if (this.direction == Directions.BOTH) {
+                queries.add(this.copyQuery(Directions.OUT, label));
+                queries.add(this.copyQuery(Directions.IN, label));
+            } else {
+                queries.add(this.copyQuery(this.direction, label));
+            }
+        } else {
+            for (Id label : this.edgeLabels) {
+                if (this.direction == Directions.BOTH) {
+                    queries.add(this.copyQuery(Directions.OUT, label));
+                    queries.add(this.copyQuery(Directions.IN, label));
+                } else {
+                    queries.add(this.copyQuery(this.direction, label));
+                }
+            }
+        }
+        E.checkState(super.conditionsSize() == 0,
+                     "Can't flatten query: %s", this);
+        return queries;
+    }
+
+    private AdjacentEdgesQuery copyQuery(Directions direction,
+                                         Id edgeLabel) {
+        AdjacentEdgesQuery query = this.copy();
+        query.direction = direction;
+        if (edgeLabel != null) {
+            query.edgeLabels = new Id[]{edgeLabel};
+        } else {
+            query.edgeLabels = EMPTY;
+        }
+        query.selfConditions = null;
+        return query;
+    }
+
+    @Override
+    public boolean test(HugeElement element) {
+        if (!super.test(element)) {
+            return false;
+        }
+        HugeEdge edge = (HugeEdge) element;
+        if (!edge.ownerVertex().id().equals(this.ownerVertex)) {
+            return false;
+        }
+        if (!edge.matchDirection(this.direction)) {
+            return false;
+        }
+
+        boolean matchedLabel = false;
+        if (this.edgeLabels.length == 0) {
+            matchedLabel = true;
+        } else {
+            for (Id label : this.edgeLabels) {
+                if (edge.schemaLabel().id().equals(label)) {
+                    matchedLabel = true;
+                }
+            }
+        }
+        return matchedLabel;
+    }
+}
diff --git 
a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/backend/query/Condition.java
 
b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/backend/query/Condition.java
index 3ef9cd5fa..19d759c0b 100644
--- 
a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/backend/query/Condition.java
+++ 
b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/backend/query/Condition.java
@@ -345,31 +345,31 @@ public abstract class Condition {
         return new SyspropRelation(key, RelationType.NEQ, value);
     }
 
-    public static Condition in(HugeKeys key, List<?> value) {
+    public static Relation in(HugeKeys key, List<?> value) {
         return new SyspropRelation(key, RelationType.IN, value);
     }
 
-    public static Condition nin(HugeKeys key, List<?> value) {
+    public static Relation nin(HugeKeys key, List<?> value) {
         return new SyspropRelation(key, RelationType.NOT_IN, value);
     }
 
-    public static Condition prefix(HugeKeys key, Id value) {
+    public static Relation prefix(HugeKeys key, Id value) {
         return new SyspropRelation(key, RelationType.PREFIX, value);
     }
 
-    public static Condition containsValue(HugeKeys key, Object value) {
+    public static Relation containsValue(HugeKeys key, Object value) {
         return new SyspropRelation(key, RelationType.CONTAINS_VALUE, value);
     }
 
-    public static Condition containsKey(HugeKeys key, Object value) {
+    public static Relation containsKey(HugeKeys key, Object value) {
         return new SyspropRelation(key, RelationType.CONTAINS_KEY, value);
     }
 
-    public static Condition contains(HugeKeys key, Object value) {
+    public static Relation contains(HugeKeys key, Object value) {
         return new SyspropRelation(key, RelationType.CONTAINS, value);
     }
 
-    public static Condition scan(String start, String end) {
+    public static Relation scan(String start, String end) {
         Shard value = new Shard(start, end, 0);
         return new SyspropRelation(HugeKeys.ID, RelationType.SCAN, value);
     }
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 8a5706a77..dfbfe75eb 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
@@ -37,6 +37,7 @@ import org.apache.hugegraph.backend.query.Condition.Relation;
 import org.apache.hugegraph.backend.query.Condition.RelationType;
 import org.apache.hugegraph.backend.query.serializer.QueryAdapter;
 import org.apache.hugegraph.backend.query.serializer.QueryIdAdapter;
+import org.apache.hugegraph.exception.NotSupportException;
 import org.apache.hugegraph.perf.PerfUtil.Watched;
 import org.apache.hugegraph.structure.HugeElement;
 import org.apache.hugegraph.structure.HugeProperty;
@@ -215,6 +216,10 @@ public class ConditionQuery extends IdQuery {
     }
 
     public List<Condition.Relation> relations() {
+        return this.selfRelations();
+    }
+
+    private List<Condition.Relation> selfRelations() {
         List<Condition.Relation> relations = new ArrayList<>();
         for (Condition c : this.conditions) {
             relations.addAll(c.relations());
@@ -447,7 +452,7 @@ public class ConditionQuery extends IdQuery {
 
     public List<Relation> userpropRelations() {
         List<Relation> relations = new ArrayList<>();
-        for (Relation r : this.relations()) {
+        for (Relation r : this.selfRelations()) {
             if (!r.isSysprop()) {
                 relations.add(r);
             }
@@ -456,12 +461,16 @@ public class ConditionQuery extends IdQuery {
     }
 
     public void resetUserpropConditions() {
+        if (this.conditions.isEmpty()) {
+            // UnsupprotedOperationException when ImmutableList.removeIf()
+            return;
+        }
         this.conditions.removeIf(condition -> !condition.isSysprop());
     }
 
     public Set<Id> userpropKeys() {
         Set<Id> keys = new LinkedHashSet<>();
-        for (Relation r : this.relations()) {
+        for (Relation r : this.selfRelations()) {
             if (!r.isSysprop()) {
                 Condition.UserpropRelation ur = (Condition.UserpropRelation) r;
                 keys.add(ur.key());
@@ -525,7 +534,7 @@ public class ConditionQuery extends IdQuery {
 
     public boolean hasRangeCondition() {
         // NOTE: we need to judge all the conditions, including the nested
-        for (Condition.Relation r : this.relations()) {
+        for (Condition.Relation r : this.selfRelations()) {
             if (r.relation().isRangeType()) {
                 return true;
             }
@@ -535,7 +544,7 @@ public class ConditionQuery extends IdQuery {
 
     public boolean hasSearchCondition() {
         // NOTE: we need to judge all the conditions, including the nested
-        for (Condition.Relation r : this.relations()) {
+        for (Condition.Relation r : this.selfRelations()) {
             if (r.relation().isSearchType()) {
                 return true;
             }
@@ -545,7 +554,7 @@ public class ConditionQuery extends IdQuery {
 
     public boolean hasSecondaryCondition() {
         // NOTE: we need to judge all the conditions, including the nested
-        for (Condition.Relation r : this.relations()) {
+        for (Condition.Relation r : this.selfRelations()) {
             if (r.relation().isSecondaryType()) {
                 return true;
             }
@@ -555,7 +564,7 @@ public class ConditionQuery extends IdQuery {
 
     public boolean hasNeqCondition() {
         // NOTE: we need to judge all the conditions, including the nested
-        for (Condition.Relation r : this.relations()) {
+        for (Condition.Relation r : this.selfRelations()) {
             if (r.relation() == RelationType.NEQ) {
                 return true;
             }
@@ -647,10 +656,19 @@ public class ConditionQuery extends IdQuery {
                 return false;
             }
         }
-        return true;
+
+        return !this.mayHasDupKeys(ImmutableSet.of(HugeKeys.LABEL));
+    }
+
+    public boolean canFlatten() {
+        return false;
+    }
+
+    public List<ConditionQuery> flatten() {
+        throw new NotSupportException("ConditionQuery.flatten()");
     }
 
-    public boolean mayHasDupKeys(Set<HugeKeys> keys) {
+    private boolean mayHasDupKeys(Set<HugeKeys> keys) {
         Map<HugeKeys, Integer> keyCounts = new HashMap<>();
         for (Condition condition : this.conditions) {
             if (!condition.isRelation()) {
diff --git 
a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/backend/query/ConditionQueryFlatten.java
 
b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/backend/query/ConditionQueryFlatten.java
index 83af41b00..f4fd383ea 100644
--- 
a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/backend/query/ConditionQueryFlatten.java
+++ 
b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/backend/query/ConditionQueryFlatten.java
@@ -21,10 +21,10 @@ import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Date;
+import java.util.HashSet;
 import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Set;
-import java.util.stream.Collectors;
 
 import org.apache.hugegraph.backend.id.Id;
 import org.apache.hugegraph.backend.query.Condition.Relation;
@@ -35,24 +35,23 @@ import org.apache.hugegraph.util.InsertionOrderUtil;
 import org.apache.hugegraph.util.NumericUtil;
 
 import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
 
 public final class ConditionQueryFlatten {
 
-    private static final Set<HugeKeys> SPECIAL_KEYS = ImmutableSet.of(
-            HugeKeys.LABEL
-    );
-
     public static List<ConditionQuery> flatten(ConditionQuery query) {
         return flatten(query, false);
     }
 
     public static List<ConditionQuery> flatten(ConditionQuery query,
                                                boolean supportIn) {
-        if (query.isFlattened() && !query.mayHasDupKeys(SPECIAL_KEYS)) {
+        if (query.isFlattened()) {
             return flattenRelations(query);
         }
 
+        if (query.canFlatten()) {
+            return query.flatten();
+        }
+
         List<ConditionQuery> queries = new ArrayList<>();
 
         // Flatten IN/NOT_IN if needed
@@ -271,8 +270,10 @@ public final class ConditionQueryFlatten {
     private static Relations optimizeRelations(Relations relations) {
         // Optimize and-relations in one query
         // e.g. (age>1 and age>2) -> (age>2)
-        Set<Object> keys = relations.stream().map(Relation::key)
-                                    .collect(Collectors.toSet());
+        Set<Object> keys = new HashSet<>(relations.size());
+        for (Relation r : relations) {
+            keys.add(r.key());
+        }
 
         // No duplicated keys
         if (keys.size() == relations.size()) {
diff --git 
a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/backend/query/EdgesQueryIterator.java
 
b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/backend/query/EdgesQueryIterator.java
index d8bce082c..963f9f3f8 100644
--- 
a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/backend/query/EdgesQueryIterator.java
+++ 
b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/backend/query/EdgesQueryIterator.java
@@ -44,7 +44,7 @@ public class EdgesQueryIterator implements Iterator<Query> {
 
     @Override
     public boolean hasNext() {
-        return sources.hasNext();
+        return this.sources.hasNext();
     }
 
     @Override
@@ -52,7 +52,7 @@ public class EdgesQueryIterator implements Iterator<Query> {
         Id sourceId = this.sources.next();
         ConditionQuery query = GraphTransaction.constructEdgesQuery(sourceId,
                                                                     
this.directions,
-                                                                    
this.labels.toArray(new Id[0]));
+                                                                    
this.labels);
         if (this.limit != Query.NO_LIMIT) {
             query.limit(this.limit);
             query.capacity(this.limit);
diff --git 
a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/backend/tx/GraphTransaction.java
 
b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/backend/tx/GraphTransaction.java
index e50fa5c6f..8ef070c44 100644
--- 
a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/backend/tx/GraphTransaction.java
+++ 
b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/backend/tx/GraphTransaction.java
@@ -46,6 +46,7 @@ import org.apache.hugegraph.backend.id.SplicingIdGenerator;
 import org.apache.hugegraph.backend.page.IdHolderList;
 import org.apache.hugegraph.backend.page.PageInfo;
 import org.apache.hugegraph.backend.page.QueryList;
+import org.apache.hugegraph.backend.query.AdjacentEdgesQuery;
 import org.apache.hugegraph.backend.query.Aggregate;
 import org.apache.hugegraph.backend.query.Aggregate.AggregateFunc;
 import org.apache.hugegraph.backend.query.Condition;
@@ -1298,55 +1299,16 @@ public class GraphTransaction extends 
IndexableTransaction {
     @Watched
     public static ConditionQuery constructEdgesQuery(Id sourceVertex,
                                                      Directions direction,
-                                                     EdgeLabel... edgeLabels) {
+                                                     List<Id> edgeLabels) {
         E.checkState(sourceVertex != null,
                      "The edge query must contain source vertex");
         E.checkState(direction != null,
                      "The edge query must contain direction");
 
-        ConditionQuery query = new ConditionQuery(HugeType.EDGE);
-
-        // Edge source vertex
-        query.eq(HugeKeys.OWNER_VERTEX, sourceVertex);
-
-        // Edge direction
-        if (direction == Directions.BOTH) {
-            query.query(Condition.or(
-                    Condition.eq(HugeKeys.DIRECTION, Directions.OUT),
-                    Condition.eq(HugeKeys.DIRECTION, Directions.IN)));
-        } else {
-            assert direction == Directions.OUT || direction == Directions.IN;
-            query.eq(HugeKeys.DIRECTION, direction);
-        }
-
-        // Edge labels
-        if (edgeLabels.length == 1) {
-            EdgeLabel edgeLabel = edgeLabels[0];
-            if (edgeLabel.hasFather()) {
-                query.eq(HugeKeys.LABEL, edgeLabel.fatherId());
-                query.eq(HugeKeys.SUB_LABEL, edgeLabel.id());
-            } else {
-                query.eq(HugeKeys.LABEL, edgeLabel.id());
-            }
-        } else if (edgeLabels.length >= 1) {
-            query.query(
-                    Condition.in(HugeKeys.LABEL,
-                                 Arrays.stream(edgeLabels)
-                                       .map(SchemaElement::id)
-                                       .collect(Collectors.toList())));
+        if (true) {
+            return new AdjacentEdgesQuery(sourceVertex, direction, edgeLabels);
         }
 
-        return query;
-    }
-
-    private static ConditionQuery constructEdgesQuery(Id sourceVertex,
-                                                      Directions direction,
-                                                      List<Id> edgeLabels) {
-        E.checkState(sourceVertex != null,
-                     "The edge query must contain source vertex");
-        E.checkState(direction != null,
-                     "The edge query must contain direction");
-
         ConditionQuery query = new ConditionQuery(HugeType.EDGE);
 
         // Edge source vertex
@@ -1449,19 +1411,30 @@ public class GraphTransaction extends 
IndexableTransaction {
     private static void verifyEdgesConditionQuery(ConditionQuery query) {
         assert query.resultType().isEdge();
 
+        if (query instanceof AdjacentEdgesQuery) {
+            return;
+        }
+
         int total = query.conditionsSize();
-        if (total == 1) {
+        boolean containsLabel = query.containsCondition(HugeKeys.LABEL);
+        boolean containsProps = query.containsCondition(HugeKeys.PROPERTIES);
+        boolean containsScan = query.containsScanRelation();
+
+        if (total == 1 && (containsLabel || containsProps || containsScan)) {
             /*
              * Supported query:
              *  1.query just by edge label
              *  2.query just by PROPERTIES (like containsKey, containsValue)
              *  3.query with scan
              */
-            if (query.containsCondition(HugeKeys.LABEL) ||
-                query.containsCondition(HugeKeys.PROPERTIES) ||
-                query.containsScanRelation()) {
-                return;
-            }
+            return;
+        }
+        if (total == 2 && (containsLabel && containsProps)) {
+            /*
+             * Supported query:
+             *  query by edge label + PROPERTIES
+             */
+            return;
         }
 
         int matched = 0;
@@ -1472,19 +1445,11 @@ public class GraphTransaction extends 
IndexableTransaction {
             }
             matched++;
         }
-        int count = matched;
-
-        if (query.containsCondition(HugeKeys.PROPERTIES)) {
-            matched++;
-            if (count < 3 && query.containsCondition(HugeKeys.LABEL)) {
-                matched++;
-            }
-        }
 
         if (matched != total) {
             throw new HugeException(
-                    "Not supported querying edges by %s, expect %s",
-                    query.conditions(), EdgeId.KEYS[count]);
+                      "Not supported querying edges by %s, expect %s",
+                      query.conditions(), EdgeId.KEYS[matched]);
         }
     }
 
diff --git 
a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/HugeTraverser.java
 
b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/HugeTraverser.java
index 8122c7908..e1824fd44 100644
--- 
a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/HugeTraverser.java
+++ 
b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/HugeTraverser.java
@@ -479,7 +479,7 @@ public class HugeTraverser {
     public Iterator<Edge> edgesOfVertex(Id source, Steps steps) {
         List<Id> edgeLabels = steps.edgeLabels();
         ConditionQuery cq = GraphTransaction.constructEdgesQuery(
-                source, steps.direction(), edgeLabels.toArray(new Id[0]));
+                            source, steps.direction(), edgeLabels);
         cq.capacity(Query.NO_CAPACITY);
         if (steps.limit() != NO_LIMIT) {
             cq.limit(steps.limit());
diff --git 
a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/optimize/HugeVertexStep.java
 
b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/optimize/HugeVertexStep.java
index bd2e1388c..3902846f3 100644
--- 
a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/optimize/HugeVertexStep.java
+++ 
b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/optimize/HugeVertexStep.java
@@ -133,7 +133,7 @@ public class HugeVertexStep<E extends Element>
 
         Id vertex = (Id) traverser.get().id();
         Directions direction = Directions.convert(this.getDirection());
-        EdgeLabel[] els = graph.mapElName2El(this.getEdgeLabels());
+        Id[] els = graph.mapElName2Id(this.getEdgeLabels());
 
         LOG.debug("HugeVertexStep.edges(): vertex={}, direction={}, " +
                   "edgeLabels={}, has={}",
diff --git 
a/hugegraph-server/hugegraph-example/src/main/java/org/apache/hugegraph/example/PerfExampleBase.java
 
b/hugegraph-server/hugegraph-example/src/main/java/org/apache/hugegraph/example/PerfExampleBase.java
index 684866674..dbba4bf96 100644
--- 
a/hugegraph-server/hugegraph-example/src/main/java/org/apache/hugegraph/example/PerfExampleBase.java
+++ 
b/hugegraph-server/hugegraph-example/src/main/java/org/apache/hugegraph/example/PerfExampleBase.java
@@ -31,6 +31,8 @@ import org.apache.hugegraph.backend.cache.Cache;
 import org.apache.hugegraph.backend.cache.CacheManager;
 import org.apache.hugegraph.backend.id.Id;
 import org.apache.hugegraph.backend.query.ConditionQuery;
+import org.apache.hugegraph.backend.query.Query;
+import org.apache.hugegraph.backend.tx.GraphTransaction;
 import org.apache.hugegraph.perf.PerfUtil;
 import org.apache.hugegraph.schema.SchemaManager;
 import org.apache.hugegraph.structure.HugeVertex;
@@ -38,6 +40,7 @@ import org.apache.hugegraph.testutil.Whitebox;
 import org.apache.hugegraph.type.HugeType;
 import org.apache.hugegraph.type.define.Directions;
 import org.apache.hugegraph.type.define.HugeKeys;
+
 import org.apache.hugegraph.util.Log;
 import 
org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
 import org.apache.tinkerpop.gremlin.structure.Edge;
@@ -281,11 +284,9 @@ public abstract class PerfExampleBase {
             return this.hugegraph.vertices(id).next();
         }
 
-        public Iterator<Edge> queryVertexEdge(Object id, Directions direction) 
{
-            ConditionQuery q = new ConditionQuery(HugeType.EDGE);
-            q.eq(HugeKeys.OWNER_VERTEX, id);
-            q.eq(HugeKeys.DIRECTION, direction);
-            return this.hugegraph.edges(q);
+        public Iterator<Edge> queryVertexEdge(Object id, Directions dir) {
+            Query query = GraphTransaction.constructEdgesQuery((Id) id, dir, 
new Id[0]);
+            return this.hugegraph.edges(query);
         }
     }
 }


Reply via email to