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