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

vgalaxies pushed a commit to branch father-sub-edge
in repository https://gitbox.apache.org/repos/asf/incubator-hugegraph.git

commit 0e202d4fd9468addc9b292cf9a7d9b88ad567bbc
Author: VGalaxies <[email protected]>
AuthorDate: Sun Sep 8 16:17:19 2024 +0800

    setup
---
 .../org/apache/hugegraph/api/graph/EdgeAPI.java    |  12 +-
 .../apache/hugegraph/api/schema/EdgeLabelAPI.java  |  29 ++
 .../main/java/org/apache/hugegraph/HugeGraph.java  |  19 +-
 .../backend/cache/CachedBackendStore.java          |  30 ++
 .../org/apache/hugegraph/backend/id/EdgeId.java    |  68 +++--
 .../org/apache/hugegraph/backend/query/Query.java  |   4 +
 .../backend/serializer/BinarySerializer.java       |  29 +-
 .../hugegraph/backend/serializer/BytesBuffer.java  |   5 +-
 .../backend/store/AbstractBackendStore.java        |  67 +++++
 .../hugegraph/backend/store/BackendStore.java      |   7 +
 .../backend/store/raft/RaftBackendStore.java       |   8 +
 .../backend/tx/GraphIndexTransaction.java          |  12 +
 .../hugegraph/backend/tx/GraphTransaction.java     |  42 ++-
 .../hugegraph/backend/tx/SchemaTransactionV2.java  |  25 +-
 .../hugegraph/io/GraphSONSchemaSerializer.java     |  57 ++--
 .../org/apache/hugegraph/schema/EdgeLabel.java     | 178 ++++++++----
 .../hugegraph/schema/builder/EdgeLabelBuilder.java | 198 ++++++++++---
 .../org/apache/hugegraph/structure/HugeEdge.java   |  38 ++-
 .../org/apache/hugegraph/structure/HugeVertex.java |   2 +
 .../hugegraph/type/define/EdgeLabelType.java       |   8 -
 .../org/apache/hugegraph/type/define/HugeKeys.java |   3 +
 .../backend/store/hstore/HstoreStore.java          | 318 +++++++++++----------
 22 files changed, 824 insertions(+), 335 deletions(-)

diff --git 
a/hugegraph-server/hugegraph-api/src/main/java/org/apache/hugegraph/api/graph/EdgeAPI.java
 
b/hugegraph-server/hugegraph-api/src/main/java/org/apache/hugegraph/api/graph/EdgeAPI.java
index 25e8cacf0..6a289368e 100644
--- 
a/hugegraph-server/hugegraph-api/src/main/java/org/apache/hugegraph/api/graph/EdgeAPI.java
+++ 
b/hugegraph-server/hugegraph-api/src/main/java/org/apache/hugegraph/api/graph/EdgeAPI.java
@@ -426,7 +426,15 @@ public class EdgeAPI extends BatchAPI {
 
     private Id getEdgeId(HugeGraph g, JsonEdge newEdge) {
         String sortKeys = "";
-        Id labelId = g.edgeLabel(newEdge.label).id();
+        EdgeLabel edgeLabel = g.edgeLabel(newEdge.label);
+        E.checkArgument(!edgeLabel.edgeLabelType().parent(),
+                        "The label of the created/updated edge is not allowed" 
+
+                        " to be the parent type");
+        Id labelId = edgeLabel.id();
+        Id subLabelId = edgeLabel.id();
+        if (edgeLabel.edgeLabelType().sub()) {
+            labelId = edgeLabel.fatherId();
+        }
         List<Id> sortKeyIds = g.edgeLabel(labelId).sortKeys();
         if (!sortKeyIds.isEmpty()) {
             List<Object> sortKeyValues = new ArrayList<>(sortKeyIds.size());
@@ -442,7 +450,7 @@ public class EdgeAPI extends BatchAPI {
             sortKeys = ConditionQuery.concatValues(sortKeyValues);
         }
         EdgeId edgeId = new EdgeId(HugeVertex.getIdValue(newEdge.source),
-                                   Directions.OUT, labelId, sortKeys,
+                                   Directions.OUT, labelId, subLabelId, 
sortKeys,
                                    HugeVertex.getIdValue(newEdge.target));
         if (newEdge.id != null) {
             E.checkArgument(edgeId.asString().equals(newEdge.id),
diff --git 
a/hugegraph-server/hugegraph-api/src/main/java/org/apache/hugegraph/api/schema/EdgeLabelAPI.java
 
b/hugegraph-server/hugegraph-api/src/main/java/org/apache/hugegraph/api/schema/EdgeLabelAPI.java
index 97bad8c77..09eb93bd7 100644
--- 
a/hugegraph-server/hugegraph-api/src/main/java/org/apache/hugegraph/api/schema/EdgeLabelAPI.java
+++ 
b/hugegraph-server/hugegraph-api/src/main/java/org/apache/hugegraph/api/schema/EdgeLabelAPI.java
@@ -21,6 +21,7 @@ import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 import org.apache.commons.collections.CollectionUtils;
 import org.apache.hugegraph.HugeGraph;
@@ -32,6 +33,7 @@ import org.apache.hugegraph.core.GraphManager;
 import org.apache.hugegraph.define.Checkable;
 import org.apache.hugegraph.schema.EdgeLabel;
 import org.apache.hugegraph.schema.Userdata;
+import org.apache.hugegraph.type.define.EdgeLabelType;
 import org.apache.hugegraph.type.define.Frequency;
 import org.apache.hugegraph.type.define.GraphMode;
 import org.apache.hugegraph.util.E;
@@ -183,10 +185,16 @@ public class EdgeLabelAPI extends API {
         public long id;
         @JsonProperty("name")
         public String name;
+        @JsonProperty("edge_label_type")
+        public EdgeLabelType edgeLabelType;
+        @JsonProperty("parent_label")
+        public String fatherLabel;
         @JsonProperty("source_label")
         public String sourceLabel;
         @JsonProperty("target_label")
         public String targetLabel;
+        @JsonProperty("links")
+        public Set<Map<String, String>> links;
         @JsonProperty("frequency")
         public Frequency frequency;
         @JsonProperty("properties")
@@ -223,12 +231,33 @@ public class EdgeLabelAPI extends API {
                                 g, g.mode());
                 builder.id(this.id);
             }
+            if (this.edgeLabelType == null) {
+                this.edgeLabelType = EdgeLabelType.NORMAL;
+            } else if (this.edgeLabelType.parent()) {
+                builder.asBase();
+            } else if (this.edgeLabelType.sub()) {
+                builder.withBase(this.fatherLabel);
+            } else {
+                E.checkArgument(this.edgeLabelType.normal(),
+                                "Please enter a valid edge_label_type value " +
+                                "in [NORMAL, PARENT, SUB]");
+            }
             if (this.sourceLabel != null) {
                 builder.sourceLabel(this.sourceLabel);
             }
             if (this.targetLabel != null) {
                 builder.targetLabel(this.targetLabel);
             }
+            if (this.links != null && !this.links.isEmpty()) {
+                for (Map<String, String> map : this.links) {
+                    E.checkArgument(map.size() == 1,
+                                    "The map size must be 1, due to it is a " +
+                                    "pair");
+                    Map.Entry<String, String> entry =
+                            map.entrySet().iterator().next();
+                    builder.link(entry.getKey(), entry.getValue());
+                }
+            }
             if (this.frequency != null) {
                 builder.frequency(this.frequency);
             }
diff --git 
a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/HugeGraph.java
 
b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/HugeGraph.java
index ab460d495..5e09f34f7 100644
--- 
a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/HugeGraph.java
+++ 
b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/HugeGraph.java
@@ -19,9 +19,12 @@ package org.apache.hugegraph;
 
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Set;
 
+import org.apache.commons.lang3.tuple.Pair;
 import org.apache.hugegraph.auth.AuthManager;
 import org.apache.hugegraph.backend.id.Id;
 import org.apache.hugegraph.backend.query.Query;
@@ -300,11 +303,25 @@ public interface HugeGraph extends Graph {
         Id[] ids = new Id[edgeLabels.length];
         for (int i = 0; i < edgeLabels.length; i++) {
             EdgeLabel edgeLabel = this.edgeLabel(edgeLabels[i]);
-            ids[i] = edgeLabel.id();
+            if (edgeLabel.hasFather()) {
+                ids[i] = edgeLabel.fatherId();
+            } else {
+                ids[i] = edgeLabel.id();
+            }
         }
         return ids;
     }
 
+    default Set<Pair<String, String>> mapPairId2Name(
+            Set<Pair<Id, Id>> pairs) {
+        Set<Pair<String, String>> results = new HashSet<>(pairs.size());
+        for (Pair<Id, Id> pair : pairs) {
+            results.add(Pair.of(this.vertexLabel(pair.getLeft()).name(),
+                                this.vertexLabel(pair.getRight()).name()));
+        }
+        return results;
+    }
+
     default Id[] mapVlName2Id(String[] vertexLabels) {
         Id[] ids = new Id[vertexLabels.length];
         for (int i = 0; i < vertexLabels.length; i++) {
diff --git 
a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/backend/cache/CachedBackendStore.java
 
b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/backend/cache/CachedBackendStore.java
index a1c632d9f..e266c0623 100644
--- 
a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/backend/cache/CachedBackendStore.java
+++ 
b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/backend/cache/CachedBackendStore.java
@@ -18,8 +18,13 @@
 package org.apache.hugegraph.backend.cache;
 
 import java.util.Iterator;
+import java.util.List;
+import java.util.function.Function;
 
+import org.apache.hugegraph.HugeGraph;
 import org.apache.hugegraph.backend.id.Id;
+import org.apache.hugegraph.backend.query.ConditionQuery;
+import org.apache.hugegraph.backend.query.ConditionQueryFlatten;
 import org.apache.hugegraph.backend.query.Query;
 import org.apache.hugegraph.backend.store.BackendEntry;
 import org.apache.hugegraph.backend.store.BackendFeatures;
@@ -28,6 +33,8 @@ import org.apache.hugegraph.backend.store.BackendStore;
 import org.apache.hugegraph.backend.store.BackendStoreProvider;
 import org.apache.hugegraph.backend.store.SystemSchemaStore;
 import org.apache.hugegraph.config.HugeConfig;
+import org.apache.hugegraph.iterator.ExtendableIterator;
+import org.apache.hugegraph.iterator.MapperIterator;
 import org.apache.hugegraph.type.HugeType;
 import org.apache.hugegraph.util.StringEncoding;
 
@@ -177,6 +184,29 @@ public class CachedBackendStore implements BackendStore {
         }
     }
 
+    @Override
+    public Iterator<Iterator<BackendEntry>> query(Iterator<Query> queries,
+                                                  Function<Query, Query> 
queryWriter,
+                                                  HugeGraph hugeGraph) {
+        return new MapperIterator<>(queries, query -> {
+            assert query instanceof ConditionQuery;
+            List<ConditionQuery> flattenQueryList =
+                    ConditionQueryFlatten.flatten((ConditionQuery) query);
+
+            if (flattenQueryList.size() > 1) {
+                ExtendableIterator<BackendEntry> itExtend
+                        = new ExtendableIterator<>();
+                flattenQueryList.forEach(cq -> {
+                    Query cQuery = queryWriter.apply(cq);
+                    itExtend.extend(this.query(cQuery));
+                });
+                return itExtend;
+            } else {
+                return this.query(queryWriter.apply(query));
+            }
+        });
+    }
+
     @Override
     public Number queryNumber(Query query) {
         return this.store.queryNumber(query);
diff --git 
a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/backend/id/EdgeId.java
 
b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/backend/id/EdgeId.java
index a9053e513..fe030a153 100644
--- 
a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/backend/id/EdgeId.java
+++ 
b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/backend/id/EdgeId.java
@@ -28,8 +28,13 @@ import org.apache.hugegraph.util.StringEncoding;
 
 /**
  * Class used to format and parse id of edge, the edge id consists of:
- * { source-vertex-id + edge-label + edge-name + target-vertex-id }
- * NOTE: if we use `entry.type()` which is IN or OUT as a part of id,
+ * EdgeId = { source-vertex-id > direction > parentEdgeLabelId > subEdgeLabelId
+ * > sortKeys > target-vertex-id }
+ * NOTE:
+ * <p>1. for edges with edgeLabelType = NORMAL: edgeLabelId = 
parentEdgeLabelId = subEdgeLabelId;
+ *       for edges with edgeLabelType = PARENT: edgeLabelId = subEdgeLabelId, 
parentEdgeLabelId =
+ *       edgeLabelId.fatherId
+ * <p>2.if we use `entry.type()` which is IN or OUT as a part of id,
  * an edge's id will be different due to different directions (belongs
  * to 2 owner vertex)
  */
@@ -39,6 +44,7 @@ public class EdgeId implements Id {
             HugeKeys.OWNER_VERTEX,
             HugeKeys.DIRECTION,
             HugeKeys.LABEL,
+            HugeKeys.SUB_LABEL,
             HugeKeys.SORT_VALUES,
             HugeKeys.OTHER_VERTEX
     };
@@ -46,6 +52,7 @@ public class EdgeId implements Id {
     private final Id ownerVertexId;
     private final Directions direction;
     private final Id edgeLabelId;
+    private final Id subLabelId;
     private final String sortValues;
     private final Id otherVertexId;
 
@@ -53,22 +60,23 @@ public class EdgeId implements Id {
     private String cache;
 
     public EdgeId(HugeVertex ownerVertex, Directions direction,
-                  Id edgeLabelId, String sortValues, HugeVertex otherVertex) {
-        this(ownerVertex.id(), direction, edgeLabelId,
+                  Id edgeLabelId, Id subLabelId, String sortValues, HugeVertex 
otherVertex) {
+        this(ownerVertex.id(), direction, edgeLabelId, subLabelId,
              sortValues, otherVertex.id());
     }
 
-    public EdgeId(Id ownerVertexId, Directions direction, Id edgeLabelId,
+    public EdgeId(Id ownerVertexId, Directions direction, Id edgeLabelId, Id 
subLabelId,
                   String sortValues, Id otherVertexId) {
-        this(ownerVertexId, direction, edgeLabelId,
+        this(ownerVertexId, direction, edgeLabelId, subLabelId,
              sortValues, otherVertexId, false);
     }
 
-    public EdgeId(Id ownerVertexId, Directions direction, Id edgeLabelId,
+    public EdgeId(Id ownerVertexId, Directions direction, Id edgeLabelId, Id 
subLabelId,
                   String sortValues, Id otherVertexId, boolean directed) {
         this.ownerVertexId = ownerVertexId;
         this.direction = direction;
         this.edgeLabelId = edgeLabelId;
+        this.subLabelId = subLabelId;
         this.sortValues = sortValues;
         this.otherVertexId = otherVertexId;
         this.directed = directed;
@@ -78,12 +86,12 @@ public class EdgeId implements Id {
     @Watched
     public EdgeId switchDirection() {
         Directions direction = this.direction.opposite();
-        return new EdgeId(this.otherVertexId, direction, this.edgeLabelId,
+        return new EdgeId(this.otherVertexId, direction, this.edgeLabelId, 
this.subLabelId,
                           this.sortValues, this.ownerVertexId, this.directed);
     }
 
     public EdgeId directed(boolean directed) {
-        return new EdgeId(this.ownerVertexId, this.direction, this.edgeLabelId,
+        return new EdgeId(this.ownerVertexId, this.direction, 
this.edgeLabelId, this.subLabelId,
                           this.sortValues, this.otherVertexId, directed);
     }
 
@@ -107,6 +115,10 @@ public class EdgeId implements Id {
         return this.edgeLabelId;
     }
 
+    public Id subLabelId() {
+        return this.subLabelId;
+    }
+
     public Directions direction() {
         return this.direction;
     }
@@ -138,12 +150,14 @@ public class EdgeId implements Id {
                     IdUtil.writeString(this.ownerVertexId),
                     this.direction.type().string(),
                     IdUtil.writeLong(this.edgeLabelId),
+                    IdUtil.writeLong(this.subLabelId),
                     this.sortValues,
                     IdUtil.writeString(this.otherVertexId));
         } else {
             this.cache = SplicingIdGenerator.concat(
                     IdUtil.writeString(this.sourceVertexId()),
                     IdUtil.writeLong(this.edgeLabelId),
+                    IdUtil.writeLong(this.subLabelId),
                     this.sortValues,
                     IdUtil.writeString(this.targetVertexId()));
         }
@@ -181,11 +195,13 @@ public class EdgeId implements Id {
             return this.ownerVertexId.hashCode() ^
                    this.direction.hashCode() ^
                    this.edgeLabelId.hashCode() ^
+                   this.subLabelId.hashCode() ^
                    this.sortValues.hashCode() ^
                    this.otherVertexId.hashCode();
         } else {
             return this.sourceVertexId().hashCode() ^
                    this.edgeLabelId.hashCode() ^
+                   this.subLabelId.hashCode() ^
                    this.sortValues.hashCode() ^
                    this.targetVertexId().hashCode();
         }
@@ -201,11 +217,13 @@ public class EdgeId implements Id {
             return this.ownerVertexId.equals(other.ownerVertexId) &&
                    this.direction == other.direction &&
                    this.edgeLabelId.equals(other.edgeLabelId) &&
+                   this.subLabelId.equals(other.subLabelId) &&
                    this.sortValues.equals(other.sortValues) &&
                    this.otherVertexId.equals(other.otherVertexId);
         } else {
             return this.sourceVertexId().equals(other.sourceVertexId()) &&
                    this.edgeLabelId.equals(other.edgeLabelId) &&
+                   this.subLabelId.equals(other.subLabelId) &&
                    this.sortValues.equals(other.sortValues) &&
                    this.targetVertexId().equals(other.targetVertexId());
         }
@@ -235,31 +253,33 @@ public class EdgeId implements Id {
     public static EdgeId parse(String id, boolean returnNullIfError)
             throws NotFoundException {
         String[] idParts = SplicingIdGenerator.split(id);
-        if (!(idParts.length == 4 || idParts.length == 5)) {
+        if (!(idParts.length == 5 || idParts.length == 6)) {
             if (returnNullIfError) {
                 return null;
             }
-            throw new NotFoundException("Edge id must be formatted as 4~5 " +
+            throw new NotFoundException("Edge id must be formatted as 5~6 " +
                                         "parts, but got %s parts: '%s'",
                                         idParts.length, id);
         }
         try {
-            if (idParts.length == 4) {
+            if (idParts.length == 5) {
                 Id ownerVertexId = IdUtil.readString(idParts[0]);
                 Id edgeLabelId = IdUtil.readLong(idParts[1]);
-                String sortValues = idParts[2];
-                Id otherVertexId = IdUtil.readString(idParts[3]);
-                return new EdgeId(ownerVertexId, Directions.OUT, edgeLabelId,
+                Id subLabelId = IdUtil.readLong(idParts[2]);
+                String sortValues = idParts[3];
+                Id otherVertexId = IdUtil.readString(idParts[4]);
+                return new EdgeId(ownerVertexId, Directions.OUT, edgeLabelId, 
subLabelId,
                                   sortValues, otherVertexId);
             } else {
-                assert idParts.length == 5;
+                assert idParts.length == 6;
                 Id ownerVertexId = IdUtil.readString(idParts[0]);
                 HugeType direction = HugeType.fromString(idParts[1]);
                 Id edgeLabelId = IdUtil.readLong(idParts[2]);
-                String sortValues = idParts[3];
-                Id otherVertexId = IdUtil.readString(idParts[4]);
+                Id subLabelId = IdUtil.readLong(idParts[3]);
+                String sortValues = idParts[4];
+                Id otherVertexId = IdUtil.readString(idParts[5]);
                 return new EdgeId(ownerVertexId, Directions.convert(direction),
-                                  edgeLabelId, sortValues, otherVertexId);
+                                  edgeLabelId, subLabelId, sortValues, 
otherVertexId);
             }
         } catch (Throwable e) {
             if (returnNullIfError) {
@@ -272,12 +292,13 @@ public class EdgeId implements Id {
 
     public static Id parseStoredString(String id) {
         String[] idParts = split(id);
-        E.checkArgument(idParts.length == 4, "Invalid id format: %s", id);
+        E.checkArgument(idParts.length == 5, "Invalid id format: %s", id);
         Id ownerVertexId = IdUtil.readStoredString(idParts[0]);
         Id edgeLabelId = IdGenerator.ofStoredString(idParts[1], IdType.LONG);
-        String sortValues = idParts[2];
-        Id otherVertexId = IdUtil.readStoredString(idParts[3]);
-        return new EdgeId(ownerVertexId, Directions.OUT, edgeLabelId,
+        Id subLabelId = IdGenerator.ofStoredString(idParts[2], IdType.LONG);
+        String sortValues = idParts[3];
+        Id otherVertexId = IdUtil.readStoredString(idParts[4]);
+        return new EdgeId(ownerVertexId, Directions.OUT, edgeLabelId, 
subLabelId,
                           sortValues, otherVertexId);
     }
 
@@ -286,6 +307,7 @@ public class EdgeId implements Id {
         return SplicingIdGenerator.concat(
                 IdUtil.writeStoredString(eid.sourceVertexId()),
                 IdGenerator.asStoredString(eid.edgeLabelId()),
+                IdGenerator.asStoredString(eid.subLabelId()),
                 eid.sortValues(),
                 IdUtil.writeStoredString(eid.targetVertexId()));
     }
diff --git 
a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/backend/query/Query.java
 
b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/backend/query/Query.java
index 4d8e39ccb..3a024283f 100644
--- 
a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/backend/query/Query.java
+++ 
b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/backend/query/Query.java
@@ -139,6 +139,10 @@ public class Query implements Cloneable {
         return this.originQuery;
     }
 
+    public void setOriginQuery(Query query) {
+        this.originQuery = query;
+    }
+
     public Query rootOriginQuery() {
         Query root = this;
         while (root.originQuery != null) {
diff --git 
a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/backend/serializer/BinarySerializer.java
 
b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/backend/serializer/BinarySerializer.java
index 0dd4c9d3e..bb985cc43 100644
--- 
a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/backend/serializer/BinarySerializer.java
+++ 
b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/backend/serializer/BinarySerializer.java
@@ -59,6 +59,7 @@ import org.apache.hugegraph.type.define.AggregateType;
 import org.apache.hugegraph.type.define.Cardinality;
 import org.apache.hugegraph.type.define.DataType;
 import org.apache.hugegraph.type.define.Directions;
+import org.apache.hugegraph.type.define.EdgeLabelType;
 import org.apache.hugegraph.type.define.Frequency;
 import org.apache.hugegraph.type.define.HugeKeys;
 import org.apache.hugegraph.type.define.IdStrategy;
@@ -73,6 +74,8 @@ import org.apache.hugegraph.util.NumericUtil;
 import org.apache.hugegraph.util.StringEncoding;
 import org.apache.tinkerpop.gremlin.structure.Edge;
 
+import static org.apache.hugegraph.schema.SchemaElement.UNDEF;
+
 public class BinarySerializer extends AbstractSerializer {
 
     /*
@@ -277,15 +280,27 @@ public class BinarySerializer extends AbstractSerializer {
         }
         byte type = buffer.read();
         Id labelId = buffer.readId();
+        Id subLabelId = buffer.readId();
         String sortValues = buffer.readStringWithEnding();
         Id otherVertexId = buffer.readId();
 
         boolean direction = EdgeId.isOutDirectionFromCode(type);
-        EdgeLabel edgeLabel = graph.edgeLabelOrNone(labelId);
 
-        // Construct edge
-        HugeEdge edge = HugeEdge.constructEdge(vertex, direction, edgeLabel,
-                                               sortValues, otherVertexId);
+        HugeEdge edge;
+        if (graph == null) { /* when calculation sinking */
+            EdgeLabel edgeLabel = new EdgeLabel(null, subLabelId, UNDEF);
+            if (subLabelId != labelId) {
+                edgeLabel.edgeLabelType(EdgeLabelType.SUB);
+                edgeLabel.fatherId(labelId);
+            }
+            edge = HugeEdge.constructEdgeWithoutGraph(vertex, direction, 
edgeLabel,
+                                                      sortValues, 
otherVertexId);
+        } else {
+            EdgeLabel edgeLabel = graph.edgeLabelOrNone(subLabelId);
+
+            edge = HugeEdge.constructEdge(vertex, direction, edgeLabel,
+                                          sortValues, otherVertexId);
+        }
 
         // Parse edge-id + edge-properties
         buffer = BytesBuffer.wrap(col.value);
@@ -1104,8 +1119,7 @@ public class BinarySerializer extends AbstractSerializer {
         public BinaryBackendEntry writeEdgeLabel(EdgeLabel schema) {
             this.entry = newBackendEntry(schema);
             writeString(HugeKeys.NAME, schema.name());
-            writeId(HugeKeys.SOURCE_LABEL, schema.sourceLabel());
-            writeId(HugeKeys.TARGET_LABEL, schema.targetLabel());
+            writeIds(HugeKeys.LINKS, schema.linksIds());
             writeEnum(HugeKeys.FREQUENCY, schema.frequency());
             writeIds(HugeKeys.PROPERTIES, schema.properties());
             writeIds(HugeKeys.SORT_KEYS, schema.sortKeys());
@@ -1127,8 +1141,7 @@ public class BinarySerializer extends AbstractSerializer {
             String name = readString(HugeKeys.NAME);
 
             EdgeLabel edgeLabel = new EdgeLabel(graph, id, name);
-            edgeLabel.sourceLabel(readId(HugeKeys.SOURCE_LABEL));
-            edgeLabel.targetLabel(readId(HugeKeys.TARGET_LABEL));
+            edgeLabel.linksIds(readIds(HugeKeys.LINKS));
             edgeLabel.frequency(readEnum(HugeKeys.FREQUENCY, Frequency.class));
             edgeLabel.properties(readIds(HugeKeys.PROPERTIES));
             edgeLabel.sortKeys(readIds(HugeKeys.SORT_KEYS));
diff --git 
a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/backend/serializer/BytesBuffer.java
 
b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/backend/serializer/BytesBuffer.java
index c13d61108..2c890ebe4 100644
--- 
a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/backend/serializer/BytesBuffer.java
+++ 
b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/backend/serializer/BytesBuffer.java
@@ -697,11 +697,12 @@ public final class BytesBuffer extends OutputStream {
     }
 
     public BytesBuffer writeEdgeId(Id id) {
-        // owner-vertex + dir + edge-label + sort-values + other-vertex
+        // owner-vertex + dir + edge-label + sub-edge-label + sort-values + 
other-vertex
         EdgeId edge = (EdgeId) id;
         this.writeId(edge.ownerVertexId());
         this.write(edge.directionCode());
         this.writeId(edge.edgeLabelId());
+        this.writeId(edge.subLabelId());
         this.writeStringWithEnding(edge.sortValues());
         this.writeId(edge.otherVertexId());
         return this;
@@ -709,7 +710,7 @@ public final class BytesBuffer extends OutputStream {
 
     public Id readEdgeId() {
         return new EdgeId(this.readId(), EdgeId.directionFromCode(this.read()),
-                          this.readId(), this.readStringWithEnding(),
+                          this.readId(), this.readId(), 
this.readStringWithEnding(),
                           this.readId());
     }
 
diff --git 
a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/backend/store/AbstractBackendStore.java
 
b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/backend/store/AbstractBackendStore.java
index 2ef9a6db7..adb3c8c40 100644
--- 
a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/backend/store/AbstractBackendStore.java
+++ 
b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/backend/store/AbstractBackendStore.java
@@ -17,8 +17,24 @@
 
 package org.apache.hugegraph.backend.store;
 
+import org.apache.hugegraph.HugeGraph;
+import org.apache.hugegraph.backend.query.Condition;
+import org.apache.hugegraph.backend.query.ConditionQuery;
+import org.apache.hugegraph.backend.query.ConditionQueryFlatten;
+import org.apache.hugegraph.backend.query.Query;
 import org.apache.hugegraph.exception.ConnectionException;
+import org.apache.hugegraph.iterator.ExtendableIterator;
+import org.apache.hugegraph.iterator.FlatMapperIterator;
 import org.apache.hugegraph.type.HugeType;
+import org.apache.hugegraph.type.define.Directions;
+import org.apache.hugegraph.type.define.HugeKeys;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+import java.util.function.Function;
 
 public abstract class AbstractBackendStore<Session extends BackendSession>
         implements BackendStore {
@@ -36,6 +52,57 @@ public abstract class AbstractBackendStore<Session extends 
BackendSession>
         return this.dispatcher;
     }
 
+    protected List<HugeType> getHugeTypes(Query sampleQuery) {
+        Set<HugeType> typeSet = new HashSet<>();
+        for (Condition c : sampleQuery.conditions()) {
+            if (c.isRelation() && c.isSysprop()) {
+                Condition.SyspropRelation sr = (Condition.SyspropRelation) c;
+                if (sr.relation() == Condition.RelationType.EQ) {
+                    if (sr.key().equals(HugeKeys.DIRECTION)) {
+                        typeSet.add(((Directions) sr.value()).type());
+                    }
+                }
+            } else if (c.type() == Condition.ConditionType.OR && 
c.isSysprop()) {
+                for (Condition.Relation r : c.relations()) {
+                    if (r.relation() == Condition.RelationType.EQ) {
+                        if (r.key().equals(HugeKeys.DIRECTION)) {
+                            typeSet.add(((Directions) r.value()).type());
+                        }
+                    }
+                }
+            }
+        }
+        return new ArrayList<>(typeSet);
+    }
+
+    @Override
+    public Iterator<Iterator<BackendEntry>> query(Iterator<Query> queries,
+                                                  Function<Query, Query> 
queryWriter,
+                                                  HugeGraph hugeGraph) {
+        List<Iterator<BackendEntry>> result = new ArrayList<>();
+
+        FlatMapperIterator<Query, BackendEntry> it =
+                new FlatMapperIterator<>(queries, query -> {
+                    assert query instanceof ConditionQuery;
+                    List<ConditionQuery> flattenQueryList =
+                            ConditionQueryFlatten.flatten((ConditionQuery) 
query);
+
+                    if (flattenQueryList.size() > 1) {
+                        ExtendableIterator<BackendEntry> itExtend
+                                = new ExtendableIterator<>();
+                        flattenQueryList.forEach(cq -> {
+                            Query cQuery = queryWriter.apply(cq);
+                            itExtend.extend(this.query(cQuery));
+                        });
+                        return itExtend;
+                    } else {
+                        return this.query(queryWriter.apply(query));
+                    }
+                });
+        result.add(it);
+        return result.iterator();
+    }
+
     public void registerMetaHandler(String name, MetaHandler<Session> handler) 
{
         this.dispatcher.registerMetaHandler(name, handler);
     }
diff --git 
a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/backend/store/BackendStore.java
 
b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/backend/store/BackendStore.java
index 5c05e37c5..6486d353c 100644
--- 
a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/backend/store/BackendStore.java
+++ 
b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/backend/store/BackendStore.java
@@ -19,7 +19,9 @@ package org.apache.hugegraph.backend.store;
 
 import java.util.Iterator;
 import java.util.Map;
+import java.util.function.Function;
 
+import org.apache.hugegraph.HugeGraph;
 import org.apache.hugegraph.backend.id.Id;
 import org.apache.hugegraph.backend.id.IdGenerator;
 import org.apache.hugegraph.backend.query.Query;
@@ -70,6 +72,11 @@ public interface BackendStore {
     // Query data
     Iterator<BackendEntry> query(Query query);
 
+    // TODO: unused now
+    Iterator<Iterator<BackendEntry>> query(Iterator<Query> queries,
+                                           Function<Query, Query> queryWriter,
+                                           HugeGraph hugeGraph);
+
     Number queryNumber(Query query);
 
     // Transaction
diff --git 
a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/backend/store/raft/RaftBackendStore.java
 
b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/backend/store/raft/RaftBackendStore.java
index bf89c6b17..176556212 100644
--- 
a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/backend/store/raft/RaftBackendStore.java
+++ 
b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/backend/store/raft/RaftBackendStore.java
@@ -22,6 +22,7 @@ import java.util.Iterator;
 import java.util.List;
 import java.util.function.Function;
 
+import org.apache.hugegraph.HugeGraph;
 import org.apache.hugegraph.backend.BackendException;
 import org.apache.hugegraph.backend.query.Query;
 import org.apache.hugegraph.backend.store.BackendEntry;
@@ -152,6 +153,13 @@ public class RaftBackendStore implements BackendStore {
                 this.queryByRaft(query, o -> this.store.query(query));
     }
 
+    @Override
+    public Iterator<Iterator<BackendEntry>> query(Iterator<Query> queries,
+                                                  Function<Query, Query> 
queryWriter,
+                                                  HugeGraph hugeGraph) {
+        throw new UnsupportedOperationException("unimplemented for 
RaftBackendStore");
+    }
+
     @Override
     public Number queryNumber(Query query) {
         return (Number)
diff --git 
a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/backend/tx/GraphIndexTransaction.java
 
b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/backend/tx/GraphIndexTransaction.java
index 3905ebb0c..b7c0c3d7e 100644
--- 
a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/backend/tx/GraphIndexTransaction.java
+++ 
b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/backend/tx/GraphIndexTransaction.java
@@ -67,6 +67,7 @@ import org.apache.hugegraph.iterator.Metadatable;
 import org.apache.hugegraph.job.EphemeralJob;
 import org.apache.hugegraph.job.system.DeleteExpiredJob;
 import org.apache.hugegraph.perf.PerfUtil.Watched;
+import org.apache.hugegraph.schema.EdgeLabel;
 import org.apache.hugegraph.schema.IndexLabel;
 import org.apache.hugegraph.schema.PropertyKey;
 import org.apache.hugegraph.schema.SchemaLabel;
@@ -147,6 +148,17 @@ public class GraphIndexTransaction extends 
AbstractTransaction {
         } else {
             this.doAppend(this.serializer.writeIndex(index));
         }
+
+        if (element instanceof HugeEdge && ((EdgeLabel) label).hasFather()) {
+            HugeIndex fatherIndex = new HugeIndex(this.graph(), 
IndexLabel.label(element.type()));
+            fatherIndex.fieldValues(((EdgeLabel) label).fatherId());
+            fatherIndex.elementIds(element.id(), element.expiredTime());
+            if (removed) {
+                this.doEliminate(this.serializer.writeIndex(fatherIndex));
+            } else {
+                this.doAppend(this.serializer.writeIndex(fatherIndex));
+            }
+        }
     }
 
     @Watched(prefix = "index")
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 10aa73f71..8ecfc2eed 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
@@ -31,6 +31,8 @@ import java.util.function.Consumer;
 import java.util.function.Function;
 import java.util.stream.Collectors;
 
+import com.google.common.collect.Iterators;
+
 import org.apache.commons.collections.CollectionUtils;
 import org.apache.hugegraph.HugeException;
 import org.apache.hugegraph.HugeGraph;
@@ -1044,6 +1046,20 @@ public class GraphTransaction extends 
IndexableTransaction {
     protected Iterator<HugeEdge> queryEdgesFromBackend(Query query) {
         assert query.resultType().isEdge();
 
+        if (query instanceof ConditionQuery) {
+            ConditionQuery cq = (ConditionQuery) query;
+            Id label = cq.condition(HugeKeys.LABEL);
+            if (label != null &&
+                graph().edgeLabel(label).isFather() &&
+                cq.condition(HugeKeys.SUB_LABEL) == null &&
+                cq.condition(HugeKeys.OWNER_VERTEX) != null &&
+                cq.condition(HugeKeys.DIRECTION) != null &&
+                matchEdgeSortKeys(cq, false, this.graph())) {
+                return parentElQueryWithSortKeys(graph().edgeLabel(label), 
graph().edgeLabels(),
+                                                 cq);
+            }
+        }
+
         QueryResults<BackendEntry> results = this.query(query);
         Iterator<BackendEntry> entries = results.iterator();
 
@@ -1070,6 +1086,26 @@ public class GraphTransaction extends 
IndexableTransaction {
         return edges;
     }
 
+    private Iterator<HugeEdge> parentElQueryWithSortKeys(EdgeLabel label,
+                                                         Collection<EdgeLabel> 
allEls,
+                                                         ConditionQuery cq) {
+        Iterator<HugeEdge> edges = null;
+        int count = 0;
+        for (EdgeLabel el : allEls) {
+            if (el.edgeLabelType().sub() && el.fatherId().equals(label.id())) {
+                ConditionQuery tempQuery = cq.copy();
+                tempQuery.eq(HugeKeys.SUB_LABEL, el.id());
+                count++;
+                if (count == 1) {
+                    edges = this.queryEdgesFromBackend(tempQuery);
+                } else {
+                    edges = Iterators.concat(edges, 
this.queryEdgesFromBackend(tempQuery));
+                }
+            }
+        }
+        return edges;
+    }
+
     @Watched(prefix = "graph")
     public <V> void addVertexProperty(HugeVertexProperty<V> prop) {
         // NOTE: this method can also be used to update property
@@ -1522,7 +1558,8 @@ public class GraphTransaction extends 
IndexableTransaction {
                 query.optimized(OptimizedType.SORT_KEYS);
                 query = query.copy();
                 // Serialize sort-values
-                List<Id> keys = this.graph().edgeLabel(label).sortKeys();
+                EdgeLabel el = this.graph().edgeLabel(label);
+                List<Id> keys = el.sortKeys();
                 List<Condition> conditions = GraphIndexTransaction
                         .constructShardConditions(query, keys, 
HugeKeys.SORT_VALUES);
                 query.query(conditions);
@@ -1532,6 +1569,9 @@ public class GraphTransaction extends 
IndexableTransaction {
                  */
                 query.resetUserpropConditions();
 
+                if (query.condition(HugeKeys.SUB_LABEL) == null) {
+                    query.eq(HugeKeys.SUB_LABEL, el.id());
+                }
                 LOG.debug("Query edges by sortKeys: {}", query);
                 return query;
             }
diff --git 
a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/backend/tx/SchemaTransactionV2.java
 
b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/backend/tx/SchemaTransactionV2.java
index 8bf0a68b2..903bfade6 100644
--- 
a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/backend/tx/SchemaTransactionV2.java
+++ 
b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/backend/tx/SchemaTransactionV2.java
@@ -288,19 +288,18 @@ public class SchemaTransactionV2 implements 
ISchemaTransaction {
          */
         LOG.debug("SchemaTransaction remove edge label '{}'", id);
         EdgeLabel schema = this.getEdgeLabel(id);
-        // TODO: uncomment later - sub edge labels
-        //if (schema.edgeLabelType().parent()) {
-        //    List<EdgeLabel> edgeLabels = this.getEdgeLabels();
-        //    for (EdgeLabel edgeLabel : edgeLabels) {
-        //        if (edgeLabel.edgeLabelType().sub() &&
-        //            edgeLabel.fatherId() == id) {
-        //            throw new NotAllowException(
-        //                    "Not allowed to remove a parent edge label: '%s' 
" +
-        //                    "because the sub edge label '%s' is still 
existing",
-        //                    schema.name(), edgeLabel.name());
-        //        }
-        //    }
-        //}
+        if (schema.edgeLabelType().parent()) {
+            List<EdgeLabel> edgeLabels = this.getEdgeLabels();
+            for (EdgeLabel edgeLabel : edgeLabels) {
+                if (edgeLabel.edgeLabelType().sub() &&
+                    edgeLabel.fatherId() == id) {
+                    throw new NotAllowException(
+                            "Not allowed to remove a parent edge label: '%s' " 
+
+                            "because the sub edge label '%s' is still 
existing",
+                            schema.name(), edgeLabel.name());
+                }
+            }
+        }
         SchemaJob job = new EdgeLabelRemoveJob();
         return asyncRun(this.graph(), schema, job);
     }
diff --git 
a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/io/GraphSONSchemaSerializer.java
 
b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/io/GraphSONSchemaSerializer.java
index b92d50653..31d197c09 100644
--- 
a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/io/GraphSONSchemaSerializer.java
+++ 
b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/io/GraphSONSchemaSerializer.java
@@ -20,12 +20,15 @@ package org.apache.hugegraph.io;
 import java.util.LinkedHashMap;
 import java.util.Map;
 
+import com.google.common.collect.ImmutableList;
+
 import org.apache.hugegraph.HugeGraph;
 import org.apache.hugegraph.schema.EdgeLabel;
 import org.apache.hugegraph.schema.IndexLabel;
 import org.apache.hugegraph.schema.PropertyKey;
 import org.apache.hugegraph.schema.VertexLabel;
 import org.apache.hugegraph.type.HugeType;
+import org.apache.hugegraph.type.define.EdgeLabelType;
 import org.apache.hugegraph.type.define.HugeKeys;
 
 public class GraphSONSchemaSerializer {
@@ -64,25 +67,43 @@ public class GraphSONSchemaSerializer {
         Map<HugeKeys, Object> map = new LinkedHashMap<>();
         map.put(HugeKeys.ID, edgeLabel.id().asLong());
         map.put(HugeKeys.NAME, edgeLabel.name());
-        map.put(HugeKeys.SOURCE_LABEL, edgeLabel.sourceLabelName());
-        map.put(HugeKeys.TARGET_LABEL, edgeLabel.targetLabelName());
-        map.put(HugeKeys.FREQUENCY, edgeLabel.frequency());
-        map.put(HugeKeys.SORT_KEYS,
-                graph.mapPkId2Name(edgeLabel.sortKeys()));
-        map.put(HugeKeys.NULLABLE_KEYS,
-                graph.mapPkId2Name(edgeLabel.nullableKeys()));
-        map.put(HugeKeys.INDEX_LABELS,
-                graph.mapIlId2Name(edgeLabel.indexLabels()));
-        map.put(HugeKeys.PROPERTIES,
-                graph.mapPkId2Name(edgeLabel.properties()));
-        map.put(HugeKeys.STATUS, edgeLabel.status());
-        map.put(HugeKeys.TTL, edgeLabel.ttl());
-        String ttlStartTimeName = edgeLabel.ttlStartTimeName();
-        if (ttlStartTimeName != null) {
-            map.put(HugeKeys.TTL_START_TIME, ttlStartTimeName);
+        if (edgeLabel.isFather()) {
+            map.put(HugeKeys.EDGELABEL_TYPE, EdgeLabelType.PARENT);
+            if (edgeLabel.links().size() > 0) {
+                map.put(HugeKeys.LINKS,
+                        graph.mapPairId2Name(edgeLabel.links()));
+            }
+        } else if (edgeLabel.hasFather()) {
+            map.put(HugeKeys.EDGELABEL_TYPE, EdgeLabelType.SUB);
+            map.put(HugeKeys.PARENT_LABEL,
+                    graph.mapElId2Name(ImmutableList.of(edgeLabel.fatherId()))
+                         .get(0));
+        } else {
+            map.put(HugeKeys.EDGELABEL_TYPE, edgeLabel.edgeLabelType());
         }
-        map.put(HugeKeys.ENABLE_LABEL_INDEX, edgeLabel.enableLabelIndex());
-        map.put(HugeKeys.USER_DATA, edgeLabel.userdata());
+
+        if (!edgeLabel.isFather()) {
+            map.put(HugeKeys.LINKS,
+                    graph.mapPairId2Name(edgeLabel.links()));
+            map.put(HugeKeys.FREQUENCY, edgeLabel.frequency());
+            map.put(HugeKeys.SORT_KEYS,
+                    graph.mapPkId2Name(edgeLabel.sortKeys()));
+            map.put(HugeKeys.NULLABLE_KEYS,
+                    graph.mapPkId2Name(edgeLabel.nullableKeys()));
+            map.put(HugeKeys.INDEX_LABELS,
+                    graph.mapIlId2Name(edgeLabel.indexLabels()));
+            map.put(HugeKeys.PROPERTIES,
+                    graph.mapPkId2Name(edgeLabel.properties()));
+            map.put(HugeKeys.STATUS, edgeLabel.status());
+            map.put(HugeKeys.TTL, edgeLabel.ttl());
+            String ttlStartTimeName = edgeLabel.ttlStartTimeName();
+            if (ttlStartTimeName != null) {
+                map.put(HugeKeys.TTL_START_TIME, ttlStartTimeName);
+            }
+            map.put(HugeKeys.ENABLE_LABEL_INDEX, edgeLabel.enableLabelIndex());
+            map.put(HugeKeys.USER_DATA, edgeLabel.userdata());
+        }
+
         return map;
     }
 
diff --git 
a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/schema/EdgeLabel.java
 
b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/schema/EdgeLabel.java
index b9fac4643..8ce63ad96 100644
--- 
a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/schema/EdgeLabel.java
+++ 
b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/schema/EdgeLabel.java
@@ -21,11 +21,13 @@ import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.stream.Collectors;
 
+import org.apache.commons.lang3.tuple.Pair;
 import org.apache.hugegraph.HugeGraph;
 import org.apache.hugegraph.backend.id.Id;
 import org.apache.hugegraph.backend.id.IdGenerator;
@@ -43,11 +45,13 @@ public class EdgeLabel extends SchemaLabel {
 
     public static final EdgeLabel NONE = new EdgeLabel(null, NONE_ID, UNDEF);
 
+    private Set<Pair<Id, Id>> links = new HashSet<>();
     private Id sourceLabel = NONE_ID;
-    private Id targetLabel = NONE_ID;
     private Frequency frequency;
     private List<Id> sortKeys;
-    private EdgeLabelType edgeLabelType;
+
+    private EdgeLabelType edgeLabelType = EdgeLabelType.NORMAL;
+    private Id fatherId;
 
     public EdgeLabel(final HugeGraph graph, Id id, String name) {
         super(graph, id, name);
@@ -60,14 +64,34 @@ public class EdgeLabel extends SchemaLabel {
         return HugeType.EDGE_LABEL;
     }
 
-    public Frequency frequency() {
-        return this.frequency;
+    public boolean isFather() {
+        return this.edgeLabelType.parent();
     }
 
     public void edgeLabelType(EdgeLabelType type) {
         this.edgeLabelType = type;
     }
 
+    public EdgeLabelType edgeLabelType() {
+        return this.edgeLabelType;
+    }
+
+    public boolean hasFather() {
+        return this.edgeLabelType.sub();
+    }
+
+    public Id fatherId() {
+        return this.fatherId;
+    }
+
+    public void fatherId(Id fatherId) {
+        this.fatherId = fatherId;
+    }
+
+    public Frequency frequency() {
+        return this.frequency;
+    }
+
     public void frequency(Frequency frequency) {
         this.frequency = frequency;
     }
@@ -78,53 +102,107 @@ public class EdgeLabel extends SchemaLabel {
     }
 
     public String sourceLabelName() {
-        return this.graph.vertexLabelOrNone(this.sourceLabel).name();
+        E.checkState(this.links.size() == 1,
+                     "Only edge label has single vertex label pair can call " +
+                     "sourceLabelName(), but current edge label got %s",
+                     this.links.size());
+        return 
this.graph.vertexLabelOrNone(this.links.iterator().next().getLeft()).name();
+    }
+
+    public List<Id> linksIds() {
+        List<Id> ids = new ArrayList<>(this.links.size() * 2);
+        for (Pair<Id, Id> link : this.links) {
+            ids.add(link.getLeft());
+            ids.add(link.getRight());
+        }
+        return ids;
+    }
+
+    public void linksIds(Id[] ids) {
+        this.links = new HashSet<>(ids.length / 2);
+        for (int i = 0; i < ids.length; i += 2) {
+            this.links.add(Pair.of(ids[i], ids[i + 1]));
+        }
     }
 
     public Id sourceLabel() {
-        return this.sourceLabel;
+        if (links.size() == 1) {
+            return links.iterator().next().getLeft();
+        }
+        return NONE_ID;
     }
 
     public void sourceLabel(Id id) {
-        E.checkArgument(this.sourceLabel == NONE_ID,
-                        "Not allowed to set source label multi times " +
-                        "of edge label '%s'", this.name());
+        E.checkArgument(this.links.isEmpty(),
+                        "Not allowed add source label to an edge label which " 
+
+                        "already has links");
         this.sourceLabel = id;
     }
 
     public String targetLabelName() {
-        return this.graph.vertexLabelOrNone(this.targetLabel).name();
+        E.checkState(this.links.size() == 1,
+                     "Only edge label has single vertex label pair can call " +
+                     "sourceLabelName(), but current edge label got %s",
+                     this.links.size());
+        return 
this.graph.vertexLabelOrNone(this.links.iterator().next().getRight()).name();
     }
 
     public Id targetLabel() {
-        return this.targetLabel;
+        if (links.size() == 1) {
+            return links.iterator().next().getRight();
+        }
+        return NONE_ID;
     }
 
     public void targetLabel(Id id) {
-        E.checkArgument(this.targetLabel == NONE_ID,
-                        "Not allowed to set target label multi times " +
-                        "of edge label '%s'", this.name());
-        this.targetLabel = id;
+        E.checkArgument(this.links.isEmpty(),
+                        "Not allowed add source label to an edge label which " 
+
+                        "already has links");
+        E.checkArgument(this.sourceLabel != NONE_ID,
+                        "Not allowed add target label to an edge label which " 
+
+                        "not has source label yet");
+        this.links.add(Pair.of(this.sourceLabel, id));
+        this.sourceLabel = NONE_ID;
     }
 
     public boolean linkWithLabel(Id id) {
-        return this.sourceLabel.equals(id) || this.targetLabel.equals(id);
+        for (Pair<Id, Id> link : this.links) {
+            if (link.getLeft().equals(id) || link.getRight().equals(id)) {
+                return true;
+            }
+        }
+        return false;
     }
 
     public boolean linkWithVertexLabel(Id label, Directions dir) {
+        if (this.links.size() != 1) {
+            return false;
+        }
+        Id sourceLabel = this.links.iterator().next().getLeft();
+        Id targetLabel = this.links.iterator().next().getRight();
         if (dir.equals(Directions.IN)) {
-            return this.targetLabel.equals(label);
+            return targetLabel.equals(label);
         } else if (dir.equals(Directions.OUT)) {
-            return this.sourceLabel.equals(label);
+            return sourceLabel.equals(label);
         } else if (dir.equals(Directions.BOTH)) {
-            return this.targetLabel.equals(label) || 
this.sourceLabel.equals(label);
+            return targetLabel.equals(label) || sourceLabel.equals(label);
         }
         return false;
     }
 
     public boolean checkLinkEqual(Id sourceLabel, Id targetLabel) {
-        return this.sourceLabel.equals(sourceLabel) &&
-               this.targetLabel.equals(targetLabel);
+        return this.links.contains(Pair.of(sourceLabel, targetLabel));
+    }
+
+    public Set<Pair<Id, Id>> links() {
+        return this.links;
+    }
+
+    public void links(Pair<Id, Id> link) {
+        if (this.links == null) {
+            this.links = new HashSet<>();
+        }
+        this.links.add(link);
     }
 
     public boolean existSortKeys() {
@@ -160,6 +238,10 @@ public class EdgeLabel extends SchemaLabel {
 
         Id rebuildIndex();
 
+        Builder asBase();
+
+        Builder withBase(String fatherLabel);
+
         Builder link(String sourceLabel, String targetLabel);
 
         Builder sourceLabel(String label);
@@ -221,13 +303,13 @@ public class EdgeLabel extends SchemaLabel {
             map.put(P.SORT_KEYS, this.sortKeys);
         }
 
-        //map.put(P.EDGELABEL_TYPE, this.edgeLabelType);
-        //if (this.fatherId() != null) {
-        //    map.put(P.FATHER_ID, this.fatherId().asString());
-        //}
+        map.put(P.EDGELABEL_TYPE, this.edgeLabelType);
+        if (this.fatherId() != null) {
+            map.put(P.FATHER_ID, this.fatherId().asString());
+        }
         map.put(P.ENABLE_LABEL_INDEX, this.enableLabelIndex());
         map.put(P.TTL, String.valueOf(this.ttl()));
-        //map.put(P.LINKS, this.links());
+        map.put(P.LINKS, this.links());
         map.put(P.FREQUENCY, this.frequency().toString());
 
         return super.asMap(map);
@@ -278,17 +360,17 @@ public class EdgeLabel extends SchemaLabel {
                             Long.parseLong((String) entry.getValue());
                     edgeLabel.ttlStartTime(IdGenerator.of(ttlStartTime));
                     break;
-                //case P.LINKS:
-                //    // TODO: serialize and deserialize
-                //    List<Map> list = (List<Map>) entry.getValue();
-                //    for (Map m : list) {
-                //        for (Object key : m.keySet()) {
-                //            Id sid = IdGenerator.of(Long.parseLong((String) 
key));
-                //            Id tid = 
IdGenerator.of(Long.parseLong(String.valueOf(m.get(key))));
-                //            edgeLabel.links(Pair.of(sid, tid));
-                //        }
-                //    }
-                //    break;
+                case P.LINKS:
+                    // TODO: serialize and deserialize
+                    List<Map> list = (List<Map>) entry.getValue();
+                    for (Map m : list) {
+                        for (Object key : m.keySet()) {
+                            Id sid = IdGenerator.of(Long.parseLong((String) 
key));
+                            Id tid = 
IdGenerator.of(Long.parseLong(String.valueOf(m.get(key))));
+                            edgeLabel.links(Pair.of(sid, tid));
+                        }
+                    }
+                    break;
                 case P.SOURCE_LABEL:
                     long sourceLabel =
                             Long.parseLong((String) entry.getValue());
@@ -299,17 +381,17 @@ public class EdgeLabel extends SchemaLabel {
                             Long.parseLong((String) entry.getValue());
                     edgeLabel.targetLabel(IdGenerator.of(targetLabel));
                     break;
-                //case P.FATHER_ID:
-                //    long fatherId =
-                //            Long.parseLong((String) entry.getValue());
-                //    edgeLabel.fatherId(IdGenerator.of(fatherId));
-                //    break;
-                //case P.EDGELABEL_TYPE:
-                //    EdgeLabelType edgeLabelType =
-                //            EdgeLabelType.valueOf(
-                //                    ((String) 
entry.getValue()).toUpperCase());
-                //    edgeLabel.edgeLabelType(edgeLabelType);
-                //    break;
+                case P.FATHER_ID:
+                    long fatherId =
+                            Long.parseLong((String) entry.getValue());
+                    edgeLabel.fatherId(IdGenerator.of(fatherId));
+                    break;
+                case P.EDGELABEL_TYPE:
+                    EdgeLabelType edgeLabelType =
+                            EdgeLabelType.valueOf(
+                                    ((String) entry.getValue()).toUpperCase());
+                    edgeLabel.edgeLabelType(edgeLabelType);
+                    break;
                 case P.FREQUENCY:
                     Frequency frequency =
                             Frequency.valueOf(((String) 
entry.getValue()).toUpperCase());
diff --git 
a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/schema/builder/EdgeLabelBuilder.java
 
b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/schema/builder/EdgeLabelBuilder.java
index f7aa460e1..01047d6fa 100644
--- 
a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/schema/builder/EdgeLabelBuilder.java
+++ 
b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/schema/builder/EdgeLabelBuilder.java
@@ -26,6 +26,7 @@ import java.util.Map;
 import java.util.Set;
 
 import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.lang3.tuple.Pair;
 import org.apache.hugegraph.HugeGraph;
 import org.apache.hugegraph.backend.id.Id;
 import org.apache.hugegraph.backend.id.IdGenerator;
@@ -40,6 +41,7 @@ import org.apache.hugegraph.schema.Userdata;
 import org.apache.hugegraph.schema.VertexLabel;
 import org.apache.hugegraph.type.HugeType;
 import org.apache.hugegraph.type.define.Action;
+import org.apache.hugegraph.type.define.EdgeLabelType;
 import org.apache.hugegraph.type.define.Frequency;
 import org.apache.hugegraph.util.CollectionUtil;
 import org.apache.hugegraph.util.E;
@@ -51,8 +53,10 @@ public class EdgeLabelBuilder extends AbstractBuilder
 
     private Id id;
     private String name;
+    private Set<Pair<String, String>> links;
+    private EdgeLabelType edgeLabelType;
+    private String fatherLabel;
     private String sourceLabel;
-    private String targetLabel;
     private Frequency frequency;
     private Set<String> properties;
     private List<String> sortKeys;
@@ -69,8 +73,9 @@ public class EdgeLabelBuilder extends AbstractBuilder
         E.checkNotNull(name, "name");
         this.id = null;
         this.name = name;
-        this.sourceLabel = null;
-        this.targetLabel = null;
+        this.links = new HashSet<>();
+        this.edgeLabelType = EdgeLabelType.NORMAL;
+        this.fatherLabel = null;
         this.frequency = Frequency.DEFAULT;
         this.properties = new HashSet<>();
         this.sortKeys = new ArrayList<>();
@@ -89,8 +94,11 @@ public class EdgeLabelBuilder extends AbstractBuilder
         HugeGraph origin = copy.graph();
         this.id = null;
         this.name = copy.name();
-        this.sourceLabel = copy.sourceLabelName();
-        this.targetLabel = copy.targetLabelName();
+        this.links = mapPairId2Name(origin, copy.links());
+        this.edgeLabelType = copy.edgeLabelType();
+        if (copy.edgeLabelType().sub()) {
+            this.fatherLabel = mapElId2Name(origin, copy.fatherId());
+        }
         this.frequency = copy.frequency();
         this.properties = mapPkId2Name(origin, copy.properties());
         this.sortKeys = mapPkId2Name(origin, copy.sortKeys());
@@ -108,8 +116,10 @@ public class EdgeLabelBuilder extends AbstractBuilder
                                        this.id, this.name);
         HugeGraph graph = this.graph();
         EdgeLabel edgeLabel = new EdgeLabel(graph, id, this.name);
-        edgeLabel.sourceLabel(graph.vertexLabel(this.sourceLabel).id());
-        edgeLabel.targetLabel(graph.vertexLabel(this.targetLabel).id());
+        for (Pair<String, String> link : this.links) {
+            edgeLabel.links(Pair.of(graph.vertexLabel(link.getLeft()).id(),
+                                    graph.vertexLabel(link.getRight()).id()));
+        }
         edgeLabel.frequency(this.frequency == Frequency.DEFAULT ?
                             Frequency.SINGLE : this.frequency);
         edgeLabel.ttl(this.ttl);
@@ -132,9 +142,52 @@ public class EdgeLabelBuilder extends AbstractBuilder
             edgeLabel.nullableKey(propertyKey.id());
         }
         edgeLabel.userdata(this.userdata);
+        if (this.edgeLabelType.sub()) {
+            edgeLabel.edgeLabelType(EdgeLabelType.SUB);
+            EdgeLabel fatherEl = graph.edgeLabel(this.fatherLabel);
+            edgeLabel.fatherId(fatherEl.id());
+            registerInfoToFatherEl(fatherEl, edgeLabel);
+        } else {
+            edgeLabel.edgeLabelType(this.edgeLabelType);
+        }
         return edgeLabel;
     }
 
+    private void registerInfoToFatherEl(EdgeLabel fatherEl, EdgeLabel subEl) {
+        HugeGraph graph = this.graph();
+        // When the new edge label is a subtype, register the links information
+        // of the sub edgelabel to the parent edge Label
+        for (Pair<String, String> link : this.links) {
+            
fatherEl.links(Pair.of(this.graph().vertexLabel(link.getLeft()).id(),
+                                   graph.vertexLabel(link.getRight()).id()));
+        }
+
+        List<Id> fatherSortKeys = fatherEl.sortKeys();
+        List<Id> subSortKeys = subEl.sortKeys();
+        if (fatherSortKeys == null || fatherSortKeys.size() == 0) {
+            for (Id sortKey : subSortKeys) {
+                fatherEl.sortKeys(sortKey);
+            }
+        } else {
+            E.checkArgument(fatherSortKeys.size() == subSortKeys.size(),
+                            "The sortKeys of each sub edgelabel need to be " +
+                            "consistent. " + "Currently, the sortKeys of 
already exist edgelabel " +
+                            "are " + "'%s', " + "and the sortKeys of newly 
added " +
+                            "sub edgelabel are '%s'",
+                            fatherSortKeys, subSortKeys);
+            for (int i = 0; i < fatherSortKeys.size(); i++) {
+                
E.checkArgument(fatherSortKeys.get(i).equals(subSortKeys.get(i)),
+                                "The sortKeys of each sub edgelabel need to be 
" +
+                                "consistent. " +
+                                "Currently, the sortKeys of already exist 
edgelabel " +
+                                "are " + "'%s', " + "and the sortKeys of newly 
added " +
+                                "sub edgelabel are '%s'",
+                                fatherSortKeys, subSortKeys);
+            }
+        }
+        this.graph().updateEdgeLabel(fatherEl);
+    }
+
     @Override
     public EdgeLabel create() {
         HugeType type = HugeType.EDGE_LABEL;
@@ -177,14 +230,12 @@ public class EdgeLabelBuilder extends AbstractBuilder
      */
     private boolean hasSameProperties(EdgeLabel existedEdgeLabel) {
         HugeGraph graph = this.graph();
-        Id sourceId = graph.vertexLabel(this.sourceLabel).id();
-        if (!existedEdgeLabel.sourceLabel().equals(sourceId)) {
-            return false;
-        }
-
-        Id targetId = graph.vertexLabel(this.targetLabel).id();
-        if (!existedEdgeLabel.targetLabel().equals(targetId)) {
-            return false;
+        for (Pair<Id, Id> link : existedEdgeLabel.links()) {
+            String sourceName = graph.vertexLabel(link.getLeft()).name();
+            String targetName = graph.vertexLabel(link.getRight()).name();
+            if (!this.links.contains(Pair.of(sourceName, targetName))) {
+                return false;
+            }
         }
 
         if ((this.frequency == Frequency.DEFAULT &&
@@ -302,6 +353,28 @@ public class EdgeLabelBuilder extends AbstractBuilder
         return this.graph().rebuildIndex(edgeLabel);
     }
 
+    @Override
+    public EdgeLabel.Builder asBase() {
+        this.edgeLabelType = EdgeLabelType.PARENT;
+        return this;
+    }
+
+    @Override
+    public EdgeLabel.Builder withBase(String fatherLabel) {
+        // Check if fatherLabel is reasonable (if it exists or not)
+        E.checkArgumentNotNull(fatherLabel, "When creating a subtype 
edgeLabel, " +
+                                            "the edgeLabel name of the parent 
type edgeLabel must" +
+                                            " be entered");
+        EdgeLabel edgeLabel = this.edgeLabelOrNull(fatherLabel);
+        if (edgeLabel == null) {
+            throw new NotFoundException("Can't create subtype edge label '%s' 
" +
+                                        "since it's parent edge label doesn't 
exist", this.name);
+        }
+        this.edgeLabelType = EdgeLabelType.SUB;
+        this.fatherLabel = fatherLabel;
+        return this;
+    }
+
     @Override
     public EdgeLabelBuilder id(long id) {
         E.checkArgument(id != 0L, "Not allowed to assign 0 as edge label id");
@@ -340,20 +413,32 @@ public class EdgeLabelBuilder extends AbstractBuilder
 
     @Override
     public EdgeLabelBuilder link(String sourceLabel, String targetLabel) {
-        this.sourceLabel(sourceLabel);
-        this.targetLabel(targetLabel);
+        if (this.links == null) {
+            this.links = new HashSet<>();
+        }
+        this.links.add(Pair.of(sourceLabel, targetLabel));
         return this;
     }
 
     @Override
     public EdgeLabelBuilder sourceLabel(String label) {
+        E.checkArgument(this.links.isEmpty(),
+                        "Not allowed add source label to an edge label which " 
+
+                        "already has links");
         this.sourceLabel = label;
         return this;
     }
 
     @Override
     public EdgeLabelBuilder targetLabel(String label) {
-        this.targetLabel = label;
+        E.checkArgument(this.links.isEmpty(),
+                        "Not allowed add source label to an edge label which " 
+
+                        "already has links");
+        E.checkArgument(this.sourceLabel != null,
+                        "Not allowed add target label to an edge label which " 
+
+                        "not has source label yet");
+        this.links.add(Pair.of(this.sourceLabel, label));
+        this.sourceLabel = null;
         return this;
     }
 
@@ -518,30 +603,38 @@ public class EdgeLabelBuilder extends AbstractBuilder
     }
 
     private void checkRelation() {
-        String srcLabel = this.sourceLabel;
-        String tgtLabel = this.targetLabel;
-
-        E.checkArgument(srcLabel != null && tgtLabel != null,
-                        "Must set source and target label " +
-                        "for edge label '%s'", this.name);
-
-        E.checkArgumentNotNull(this.vertexLabelOrNull(srcLabel),
-                               "Undefined source vertex label '%s' " +
-                               "in edge label '%s'", srcLabel, this.name);
-        E.checkArgumentNotNull(this.vertexLabelOrNull(tgtLabel),
-                               "Undefined target vertex label '%s' " +
-                               "in edge label '%s'", tgtLabel, this.name);
+        if (this.edgeLabelType.parent()) {
+            E.checkArgument(this.links.isEmpty(),
+                            "The links of the parent edge label must be 
empty");
+        } else {
+            E.checkArgument(!this.links.isEmpty(),
+                            "The links of standard and subtype edge label " +
+                            "can't be empty");
+            E.checkArgument(this.links.size() == 1,
+                            "The links size of standard and subtype edge " +
+                            "label must be 1");
+            for (Pair<String, String> link : this.links) {
+                String srcLabel = link.getLeft();
+                String tgtLabel = link.getRight();
+                E.checkArgument(srcLabel != null && tgtLabel != null,
+                                "Must set source and target label " +
+                                "for edge label '%s'", this.name);
+                E.checkArgumentNotNull(this.vertexLabelOrNull(srcLabel),
+                                       "Undefined source vertex label '%s' " +
+                                       "in edge label '%s'", srcLabel,
+                                       this.name);
+                E.checkArgumentNotNull(this.vertexLabelOrNull(tgtLabel),
+                                       "Undefined target vertex label '%s' " +
+                                       "in edge label '%s'", tgtLabel,
+                                       this.name);
+            }
+        }
     }
 
     private void checkStableVars() {
-        if (this.sourceLabel != null) {
-            throw new NotAllowException(
-                    "Not allowed to update source label " +
-                    "for edge label '%s', it must be null", this.name);
-        }
-        if (this.targetLabel != null) {
+        if (this.links != null && !this.links.isEmpty()) {
             throw new NotAllowException(
-                    "Not allowed to update target label " +
+                    "Not allowed to update source/target label " +
                     "for edge label '%s', it must be null", this.name);
         }
         if (this.frequency != Frequency.DEFAULT) {
@@ -569,15 +662,17 @@ public class EdgeLabelBuilder extends AbstractBuilder
                             "Can't set ttl start time if ttl is not set");
             return;
         }
-        VertexLabel source = this.graph().vertexLabel(this.sourceLabel);
-        VertexLabel target = this.graph().vertexLabel(this.targetLabel);
-        E.checkArgument((source.ttl() == 0L || this.ttl <= source.ttl()) &&
-                        (target.ttl() == 0L || this.ttl <= target.ttl()),
-                        "The ttl(%s) of edge label '%s' should less than " +
-                        "ttl(%s) of source label '%s' and ttl(%s) of target " +
-                        "label '%s'", this.ttl, this.name,
-                        source.ttl(), this.sourceLabel,
-                        target.ttl(), this.targetLabel);
+        for (Pair<String, String> link : this.links) {
+            VertexLabel source = this.graph().vertexLabel(link.getLeft());
+            VertexLabel target = this.graph().vertexLabel(link.getRight());
+            E.checkArgument((source.ttl() == 0L || this.ttl <= source.ttl()) &&
+                            (target.ttl() == 0L || this.ttl <= target.ttl()),
+                            "The ttl(%s) of edge label '%s' should less than " 
+
+                            "ttl(%s) of source label '%s' and ttl(%s) of 
target " +
+                            "label '%s'", this.ttl, this.name,
+                            source.ttl(), link.getLeft(),
+                            target.ttl(), link.getRight());
+        }
         if (this.ttlStartTime == null) {
             return;
         }
@@ -624,4 +719,13 @@ public class EdgeLabelBuilder extends AbstractBuilder
     private static List<String> mapPkId2Name(HugeGraph graph, List<Id> ids) {
         return graph.mapPkId2Name(ids);
     }
+
+    private static String mapElId2Name(HugeGraph graph, Id fatherId) {
+        return graph.mapElId2Name(ImmutableList.of(fatherId)).get(0);
+    }
+
+    private static Set<Pair<String, String>> mapPairId2Name(HugeGraph graph,
+                                                            Set<Pair<Id, Id>> 
pairs) {
+        return graph.mapPairId2Name(pairs);
+    }
 }
diff --git 
a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/structure/HugeEdge.java
 
b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/structure/HugeEdge.java
index f38c2b067..5bf7011a6 100644
--- 
a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/structure/HugeEdge.java
+++ 
b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/structure/HugeEdge.java
@@ -21,6 +21,7 @@ import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
 
+import org.apache.commons.lang3.tuple.Pair;
 import org.apache.hugegraph.HugeException;
 import org.apache.hugegraph.HugeGraph;
 import org.apache.hugegraph.backend.id.EdgeId;
@@ -141,9 +142,18 @@ public class HugeEdge extends HugeElement implements Edge, 
Cloneable {
     @Watched(prefix = "edge")
     public void assignId() {
         // Generate an id and assign
-        this.id = new EdgeId(this.ownerVertex(), this.direction(),
-                             this.schemaLabel().id(), this.name(),
-                             this.otherVertex());
+        if (this.schemaLabel().hasFather()) {
+            this.id = new EdgeId(this.ownerVertex(), this.direction(),
+                                 this.schemaLabel().fatherId(),
+                                 this.schemaLabel().id(),
+                                 this.name(),
+                                 this.otherVertex());
+        } else {
+            this.id = new EdgeId(this.ownerVertex(), this.direction(),
+                                 this.schemaLabel().id(),
+                                 this.schemaLabel().id(),
+                                 this.name(), this.otherVertex());
+        }
 
         if (this.fresh()) {
             int len = this.id.length();
@@ -315,9 +325,15 @@ public class HugeEdge extends HugeElement implements Edge, 
Cloneable {
             case OWNER_VERTEX:
                 return this.ownerVertex().id();
             case LABEL:
-                return this.schemaLabel().id();
+                if (this.schemaLabel().hasFather()) {
+                    return this.schemaLabel().fatherId();
+                } else {
+                    return this.schemaLabel().id();
+                }
             case DIRECTION:
                 return this.direction();
+            case SUB_LABEL:
+                return this.schemaLabel().id();
             case OTHER_VERTEX:
                 return this.otherVertex().id();
             case SORT_VALUES:
@@ -363,11 +379,15 @@ public class HugeEdge extends HugeElement implements 
Edge, Cloneable {
 
     public void vertices(HugeVertex owner, HugeVertex other) {
         Id ownerLabel = owner.schemaLabel().id();
-        if (ownerLabel.equals(this.label.sourceLabel())) {
-            this.vertices(true, owner, other);
-        } else {
-            assert ownerLabel.equals(this.label.targetLabel());
-            this.vertices(false, owner, other);
+        Id otherLabel = other.schemaLabel().id();
+        for (Pair<Id, Id> link : this.label.links()) {
+            if (ownerLabel.equals(link.getLeft()) &&
+                otherLabel.equals(link.getRight())) {
+                this.vertices(true, owner, other);
+            } else if (ownerLabel.equals(link.getRight()) &&
+                       otherLabel.equals(link.getLeft())) {
+                this.vertices(false, owner, other);
+            }
         }
     }
 
diff --git 
a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/structure/HugeVertex.java
 
b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/structure/HugeVertex.java
index 4726e88e5..389b0f0e8 100644
--- 
a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/structure/HugeVertex.java
+++ 
b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/structure/HugeVertex.java
@@ -303,6 +303,8 @@ public class HugeVertex extends HugeElement implements 
Vertex, Cloneable {
         E.checkArgument(label != null && !label.isEmpty(),
                         "Edge label can't be null or empty");
         EdgeLabel edgeLabel = this.graph().edgeLabel(label);
+        E.checkArgument(!edgeLabel.isFather(), "Adding an edge of parent type 
" +
+                                               "is not allowed");
         // Check link
         E.checkArgument(edgeLabel.checkLinkEqual(this.schemaLabel().id(),
                                                  vertex.schemaLabel().id()),
diff --git 
a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/type/define/EdgeLabelType.java
 
b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/type/define/EdgeLabelType.java
index 912ed43d5..2857c6e3b 100644
--- 
a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/type/define/EdgeLabelType.java
+++ 
b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/type/define/EdgeLabelType.java
@@ -19,14 +19,11 @@ package org.apache.hugegraph.type.define;
 
 public enum EdgeLabelType implements SerialEnum {
 
-
     NORMAL(1, "NORMAL"),
 
     PARENT(2, "PARENT"),
 
     SUB(3, "SUB"),
-
-    GENERAL(4, "GENERAL"),
     ;
 
     static {
@@ -62,9 +59,4 @@ public enum EdgeLabelType implements SerialEnum {
     public boolean sub() {
         return this == SUB;
     }
-
-    public boolean general() {
-        return this == GENERAL;
-    }
-
 }
diff --git 
a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/type/define/HugeKeys.java
 
b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/type/define/HugeKeys.java
index 5ffa3997f..0e3536b01 100644
--- 
a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/type/define/HugeKeys.java
+++ 
b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/type/define/HugeKeys.java
@@ -48,6 +48,8 @@ public enum HugeKeys {
     SORT_KEYS(84, "sort_keys"),
     TTL(85, "ttl"),
     TTL_START_TIME(86, "ttl_start_time"),
+    EDGELABEL_TYPE(87, "edgelabel_type"),
+    PARENT_LABEL(89, "parent_label"),
 
     /* Column names of schema type (PropertyKey) */
     DATA_TYPE(120, "data_type"),
@@ -77,6 +79,7 @@ public enum HugeKeys {
     SORT_VALUES(206, "sort_values"),
     PRIMARY_VALUES(207, "primary_values"),
     EXPIRED_TIME(208, "expired_time"),
+    SUB_LABEL(211, "sub_label"),
 
     PROPERTY_TYPE(249, "property_type"),
     AGGREGATE_PROPERTIES(250, "aggregate_properties");
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 954fe3507..643909667 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
@@ -19,6 +19,7 @@ package org.apache.hugegraph.backend.store.hstore;
 
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.LinkedHashSet;
@@ -29,12 +30,18 @@ import java.util.Set;
 import java.util.concurrent.locks.Lock;
 import java.util.concurrent.locks.ReadWriteLock;
 import java.util.concurrent.locks.ReentrantReadWriteLock;
+import java.util.function.Function;
 import java.util.function.Supplier;
 import java.util.stream.Collectors;
 
+import com.google.common.collect.Lists;
+
 import org.apache.commons.collections.CollectionUtils;
+import org.apache.hugegraph.HugeGraph;
 import org.apache.hugegraph.backend.id.Id;
 import org.apache.hugegraph.backend.id.IdGenerator;
+import org.apache.hugegraph.backend.query.ConditionQuery;
+import org.apache.hugegraph.backend.query.ConditionQueryFlatten;
 import org.apache.hugegraph.backend.query.IdPrefixQuery;
 import org.apache.hugegraph.backend.query.IdQuery;
 import org.apache.hugegraph.backend.query.Query;
@@ -52,10 +59,12 @@ import 
org.apache.hugegraph.backend.store.hstore.HstoreSessions.Session;
 import org.apache.hugegraph.config.CoreOptions;
 import org.apache.hugegraph.config.HugeConfig;
 import org.apache.hugegraph.iterator.CIter;
+import org.apache.hugegraph.schema.EdgeLabel;
 import org.apache.hugegraph.type.HugeTableType;
 import org.apache.hugegraph.type.HugeType;
 import org.apache.hugegraph.type.define.Action;
 import org.apache.hugegraph.type.define.GraphMode;
+import org.apache.hugegraph.type.define.HugeKeys;
 import org.apache.hugegraph.util.E;
 import org.apache.hugegraph.util.Log;
 import org.slf4j.Logger;
@@ -339,161 +348,160 @@ public abstract class HstoreStore extends 
AbstractBackendStore<Session> {
         }
     }
 
-    // TODO: uncomment later - sub edge labels
-    //@Override
-    //public Iterator<Iterator<BackendEntry>> query(Iterator<Query> queries,
-    //                                              Function<Query, Query> 
queryWriter,
-    //                                              HugeGraph hugeGraph) {
-    //    if (queries == null || !queries.hasNext()) {
-    //        return Collections.emptyIterator();
-    //    }
-    //
-    //    class QueryWrapper implements Iterator<IdPrefixQuery> {
-    //        Query first;
-    //        final Iterator<Query> queries;
-    //        Iterator<Id> subEls;
-    //        Query preQuery;
-    //        Iterator<IdPrefixQuery> queryListIterator;
-    //
-    //        QueryWrapper(Iterator<Query> queries, Query first) {
-    //            this.queries = queries;
-    //            this.first = first;
-    //        }
-    //
-    //        @Override
-    //        public boolean hasNext() {
-    //            return first != null || (this.subEls != null && 
this.subEls.hasNext())
-    //                   || (queryListIterator != null && 
queryListIterator.hasNext()) ||
-    //                   queries.hasNext();
-    //        }
-    //
-    //        @Override
-    //        public IdPrefixQuery next() {
-    //            if (queryListIterator != null && 
queryListIterator.hasNext()) {
-    //                return queryListIterator.next();
-    //            }
-    //
-    //            Query q;
-    //            if (first != null) {
-    //                q = first;
-    //                preQuery = q.copy();
-    //                first = null;
-    //            } else {
-    //                if (this.subEls == null || !this.subEls.hasNext()) {
-    //                    q = queries.next();
-    //                    preQuery = q.copy();
-    //                } else {
-    //                    q = preQuery.copy();
-    //                }
-    //            }
-    //
-    //            assert q instanceof ConditionQuery;
-    //            ConditionQuery cq = (ConditionQuery) q;
-    //            ConditionQuery originQuery = (ConditionQuery) q.copy();
-    //
-    //            List<IdPrefixQuery> queryList = Lists.newArrayList();
-    //            if (hugeGraph != null) {
-    //                for (ConditionQuery conditionQuery :
-    //                    ConditionQueryFlatten.flatten(cq)) {
-    //                    Id label = conditionQuery.condition(HugeKeys.LABEL);
-    //                 /* Parent type + sortKeys: 
g.V("V.id").outE("parentLabel").has
-    //                 ("sortKey","value") converted to all subtypes + 
sortKeys */
-    //                    if ((this.subEls == null ||
-    //                         !this.subEls.hasNext()) && label != null &&
-    //                        hugeGraph.edgeLabel(label).isFather() &&
-    //                        conditionQuery.condition(HugeKeys.SUB_LABEL) ==
-    //                        null &&
-    //                        conditionQuery.condition(HugeKeys.OWNER_VERTEX) 
!=
-    //                        null &&
-    //                        conditionQuery.condition(HugeKeys.DIRECTION) !=
-    //                        null &&
-    //                        matchEdgeSortKeys(conditionQuery, false,
-    //                                          hugeGraph)) {
-    //                        this.subEls =
-    //                            getSubLabelsOfParentEl(
-    //                                hugeGraph.edgeLabels(),
-    //                                label);
-    //                    }
-    //
-    //                    if (this.subEls != null &&
-    //                        this.subEls.hasNext()) {
-    //                        conditionQuery.eq(HugeKeys.SUB_LABEL,
-    //                                          subEls.next());
-    //                    }
-    //
-    //                    HugeType hugeType = conditionQuery.resultType();
-    //                    if (hugeType != null && hugeType.isEdge() &&
-    //                        !conditionQuery.conditions().isEmpty()) {
-    //                        IdPrefixQuery idPrefixQuery =
-    //                            (IdPrefixQuery) queryWriter.apply(
-    //                                conditionQuery);
-    //                        idPrefixQuery.setOriginQuery(originQuery);
-    //                        queryList.add(idPrefixQuery);
-    //                    }
-    //                }
-    //
-    //                queryListIterator = queryList.iterator();
-    //                if (queryListIterator.hasNext()) {
-    //                    return queryListIterator.next();
-    //                }
-    //            }
-    //
-    //            Id ownerId = cq.condition(HugeKeys.OWNER_VERTEX);
-    //            assert ownerId != null;
-    //            BytesBuffer buffer =
-    //                BytesBuffer.allocate(BytesBuffer.BUF_EDGE_ID);
-    //            buffer.writeId(ownerId);
-    //            return new IdPrefixQuery(cq, new BinaryBackendEntry.BinaryId(
-    //                buffer.bytes(), ownerId));
-    //        }
-    //
-    //        private boolean matchEdgeSortKeys(ConditionQuery query,
-    //                                          boolean matchAll,
-    //                                          HugeGraph graph) {
-    //            assert query.resultType().isEdge();
-    //            Id label = query.condition(HugeKeys.LABEL);
-    //            if (label == null) {
-    //                return false;
-    //            }
-    //            List<Id> sortKeys = graph.edgeLabel(label).sortKeys();
-    //            if (sortKeys.isEmpty()) {
-    //                return false;
-    //            }
-    //            Set<Id> queryKeys = query.userpropKeys();
-    //            for (int i = sortKeys.size(); i > 0; i--) {
-    //                List<Id> subFields = sortKeys.subList(0, i);
-    //                if (queryKeys.containsAll(subFields)) {
-    //                    if (queryKeys.size() == subFields.size() || 
!matchAll) {
-    //                        /*
-    //                         * Return true if:
-    //                         * matchAll=true and all queryKeys are in 
sortKeys
-    //                         *  or
-    //                         * partial queryKeys are in sortKeys
-    //                         */
-    //                        return true;
-    //                    }
-    //                }
-    //            }
-    //            return false;
-    //        }
-    //    }
-    //    Query first = queries.next();
-    //    List<HugeType> typeList = getHugeTypes(first);
-    //    QueryWrapper idPrefixQueries = new QueryWrapper(queries, first);
-    //
-    //    return query(typeList, idPrefixQueries);
-    //}
-
-    //private Iterator<Id> getSubLabelsOfParentEl(Collection<EdgeLabel> allEls,
-    //                                            Id label) {
-    //    List<Id> list = new ArrayList<>();
-    //    for (EdgeLabel el : allEls) {
-    //        if (el.edgeLabelType().sub() && el.fatherId().equals(label)) {
-    //            list.add(el.id());
-    //        }
-    //    }
-    //    return list.iterator();
-    //}
+    @Override
+    public Iterator<Iterator<BackendEntry>> query(Iterator<Query> queries,
+                                                  Function<Query, Query> 
queryWriter,
+                                                  HugeGraph hugeGraph) {
+        if (queries == null || !queries.hasNext()) {
+            return Collections.emptyIterator();
+        }
+
+        class QueryWrapper implements Iterator<IdPrefixQuery> {
+            Query first;
+            final Iterator<Query> queries;
+            Iterator<Id> subEls;
+            Query preQuery;
+            Iterator<IdPrefixQuery> queryListIterator;
+
+            QueryWrapper(Iterator<Query> queries, Query first) {
+                this.queries = queries;
+                this.first = first;
+            }
+
+            @Override
+            public boolean hasNext() {
+                return first != null || (this.subEls != null && 
this.subEls.hasNext())
+                       || (queryListIterator != null && 
queryListIterator.hasNext()) ||
+                       queries.hasNext();
+            }
+
+            @Override
+            public IdPrefixQuery next() {
+                if (queryListIterator != null && queryListIterator.hasNext()) {
+                    return queryListIterator.next();
+                }
+
+                Query q;
+                if (first != null) {
+                    q = first;
+                    preQuery = q.copy();
+                    first = null;
+                } else {
+                    if (this.subEls == null || !this.subEls.hasNext()) {
+                        q = queries.next();
+                        preQuery = q.copy();
+                    } else {
+                        q = preQuery.copy();
+                    }
+                }
+
+                assert q instanceof ConditionQuery;
+                ConditionQuery cq = (ConditionQuery) q;
+                ConditionQuery originQuery = (ConditionQuery) q.copy();
+
+                List<IdPrefixQuery> queryList = Lists.newArrayList();
+                if (hugeGraph != null) {
+                    for (ConditionQuery conditionQuery :
+                        ConditionQueryFlatten.flatten(cq)) {
+                        Id label = conditionQuery.condition(HugeKeys.LABEL);
+                        /* Parent type + sortKeys: 
g.V("V.id").outE("parentLabel")
+                           .has("sortKey","value") converted to all subtypes + 
sortKeys */
+                        if ((this.subEls == null ||
+                             !this.subEls.hasNext()) && label != null &&
+                            hugeGraph.edgeLabel(label).isFather() &&
+                            conditionQuery.condition(HugeKeys.SUB_LABEL) ==
+                            null &&
+                            conditionQuery.condition(HugeKeys.OWNER_VERTEX) !=
+                            null &&
+                            conditionQuery.condition(HugeKeys.DIRECTION) !=
+                            null &&
+                            matchEdgeSortKeys(conditionQuery, false,
+                                              hugeGraph)) {
+                            this.subEls =
+                                getSubLabelsOfParentEl(
+                                    hugeGraph.edgeLabels(),
+                                    label);
+                        }
+
+                        if (this.subEls != null &&
+                            this.subEls.hasNext()) {
+                            conditionQuery.eq(HugeKeys.SUB_LABEL,
+                                              subEls.next());
+                        }
+
+                        HugeType hugeType = conditionQuery.resultType();
+                        if (hugeType != null && hugeType.isEdge() &&
+                            !conditionQuery.conditions().isEmpty()) {
+                            IdPrefixQuery idPrefixQuery =
+                                (IdPrefixQuery) queryWriter.apply(
+                                    conditionQuery);
+                            idPrefixQuery.setOriginQuery(originQuery);
+                            queryList.add(idPrefixQuery);
+                        }
+                    }
+
+                    queryListIterator = queryList.iterator();
+                    if (queryListIterator.hasNext()) {
+                        return queryListIterator.next();
+                    }
+                }
+
+                Id ownerId = cq.condition(HugeKeys.OWNER_VERTEX);
+                assert ownerId != null;
+                BytesBuffer buffer =
+                    BytesBuffer.allocate(BytesBuffer.BUF_EDGE_ID);
+                buffer.writeId(ownerId);
+                return new IdPrefixQuery(cq, new BinaryBackendEntry.BinaryId(
+                    buffer.bytes(), ownerId));
+            }
+
+            private boolean matchEdgeSortKeys(ConditionQuery query,
+                                              boolean matchAll,
+                                              HugeGraph graph) {
+                assert query.resultType().isEdge();
+                Id label = query.condition(HugeKeys.LABEL);
+                if (label == null) {
+                    return false;
+                }
+                List<Id> sortKeys = graph.edgeLabel(label).sortKeys();
+                if (sortKeys.isEmpty()) {
+                    return false;
+                }
+                Set<Id> queryKeys = query.userpropKeys();
+                for (int i = sortKeys.size(); i > 0; i--) {
+                    List<Id> subFields = sortKeys.subList(0, i);
+                    if (queryKeys.containsAll(subFields)) {
+                        if (queryKeys.size() == subFields.size() || !matchAll) 
{
+                            /*
+                             * Return true if:
+                             * matchAll=true and all queryKeys are in sortKeys
+                             *  or
+                             * partial queryKeys are in sortKeys
+                             */
+                            return true;
+                        }
+                    }
+                }
+                return false;
+            }
+        }
+        Query first = queries.next();
+        List<HugeType> typeList = getHugeTypes(first);
+        QueryWrapper idPrefixQueries = new QueryWrapper(queries, first);
+
+        return query(typeList, idPrefixQueries);
+    }
+
+    private Iterator<Id> getSubLabelsOfParentEl(Collection<EdgeLabel> allEls,
+                                                Id label) {
+        List<Id> list = new ArrayList<>();
+        for (EdgeLabel el : allEls) {
+            if (el.edgeLabelType().sub() && el.fatherId().equals(label)) {
+                list.add(el.id());
+            }
+        }
+        return list.iterator();
+    }
 
     public List<CIter<BackendEntry>> query(List<HugeType> typeList,
                                            List<IdPrefixQuery> queries) {


Reply via email to