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 25010428c47f453f2e3f0ae4f114b211b361bc88 Author: VGalaxies <[email protected]> AuthorDate: Sun Sep 8 16:05:36 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 +- .../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 | 6 + .../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 +++++++++++---------- 20 files changed, 785 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/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..8bd1bb294 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,10 @@ public interface BackendStore { // Query data Iterator<BackendEntry> query(Query query); + 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/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) {
