Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -256,24 +256,26 @@ public boolean containsLabelOrUserpropRelation() {
return false;
}

/**
* Returns the legacy condition value of the specified key.
*
* This method keeps the historical behavior for existing callers:
* <ul>
* <li>returns {@code null} if no top-level EQ/IN relation exists</li>
* <li>returns {@code null} if top-level EQ/IN relations resolve to empty</li>
* <li>returns the single value if only one value is resolved</li>
* <li>returns the raw IN list if there is exactly one top-level IN relation</li>
* <li>throws if multiple values remain after resolving several relations</li>
* </ul>
*
* Prefer {@link #conditionValues(Object)} or {@link #conditionValue(Object)}
* for new code that needs explicit semantics.
*/
@Watched
public <T> T condition(Object key) {
List<Object> valuesEQ = InsertionOrderUtil.newList();
List<Object> valuesIN = InsertionOrderUtil.newList();
for (Condition c : this.conditions) {
if (c.isRelation()) {
Condition.Relation r = (Condition.Relation) c;
if (r.key().equals(key)) {
if (r.relation() == RelationType.EQ) {
valuesEQ.add(r.value());
} else if (r.relation() == RelationType.IN) {
Object value = r.value();
assert value instanceof List;
valuesIN.add(value);
}
}
}
}
this.collectConditionValues(key, valuesEQ, valuesIN);
if (valuesEQ.isEmpty() && valuesIN.isEmpty()) {
return null;
}
Expand Down Expand Up @@ -323,20 +325,110 @@ public <T> T condition(Object key) {
return value;
}

/**
* Returns whether there is any top-level relation for the specified key.
*/
public boolean containsCondition(Object key) {
for (Condition c : this.conditions) {
if (c.isRelation()) {
Condition.Relation r = (Condition.Relation) c;
if (r.key().equals(key)) {
return true;
}
}
}
return false;
}

/**
* Returns the resolved candidate values of the specified key from
* top-level EQ/IN relations.
*
* Use {@link #containsCondition(Object)} to distinguish "no condition"
* from "conditions exist but resolve to an empty intersection".
*/
public Set<Object> conditionValues(Object key) {
List<Object> valuesEQ = InsertionOrderUtil.newList();
List<Object> valuesIN = InsertionOrderUtil.newList();
this.collectConditionValues(key, valuesEQ, valuesIN);
if (valuesEQ.isEmpty() && valuesIN.isEmpty()) {
return InsertionOrderUtil.newSet();
}
return this.resolveConditionValues(valuesEQ, valuesIN);
}

/**
* Returns the unique resolved value of the specified key from top-level
* EQ/IN relations.
*
* Returns {@code null} when the resolved candidate set is empty. Throws
* if multiple values remain after resolution.
*/
public <T> T conditionValue(Object key) {
Set<Object> values = this.conditionValues(key);
if (values.isEmpty()) {
return null;
}
E.checkState(values.size() == 1,
"Illegal key '%s' with more than one value: %s",
key, values);
@SuppressWarnings("unchecked")
T value = (T) values.iterator().next();
return value;
}

public void unsetCondition(Object key) {
this.conditions.removeIf(c -> c.isRelation() && ((Relation) c).key().equals(key));
}

public boolean containsCondition(HugeKeys key) {
return this.containsCondition((Object) key);
}

private void collectConditionValues(Object key, List<Object> valuesEQ,
List<Object> valuesIN) {
for (Condition c : this.conditions) {
if (c.isRelation()) {
Condition.Relation r = (Condition.Relation) c;
if (r.key().equals(key)) {
return true;
if (r.relation() == RelationType.EQ) {
valuesEQ.add(r.value());
} else if (r.relation() == RelationType.IN) {
Object value = r.value();
assert value instanceof List;
valuesIN.add(value);
}
}
}
}
return false;
}

private Set<Object> resolveConditionValues(List<Object> valuesEQ,
List<Object> valuesIN) {
boolean initialized = false;
Set<Object> intersectValues = InsertionOrderUtil.newSet();
for (Object value : valuesEQ) {
List<Object> valueAsList = ImmutableList.of(value);
if (!initialized) {
intersectValues.addAll(valueAsList);
initialized = true;
} else {
CollectionUtil.intersectWithModify(intersectValues,
valueAsList);
}
}
for (Object value : valuesIN) {
@SuppressWarnings("unchecked")
List<Object> valueAsList = (List<Object>) value;
if (!initialized) {
intersectValues.addAll(valueAsList);
initialized = true;
} else {
CollectionUtil.intersectWithModify(intersectValues,
valueAsList);
}
}
return intersectValues;
}

public boolean containsCondition(Condition.RelationType type) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -674,7 +674,7 @@ private Query writeQueryEdgeRangeCondition(ConditionQuery cq) {
if (direction == null) {
direction = Directions.OUT;
}
Id label = cq.condition(HugeKeys.LABEL);
Id label = cq.conditionValue(HugeKeys.LABEL);

BytesBuffer start = BytesBuffer.allocate(BytesBuffer.BUF_EDGE_ID);
writePartitionedId(HugeType.EDGE, vertex, start);
Expand Down Expand Up @@ -722,7 +722,8 @@ private Query writeQueryEdgePrefixCondition(ConditionQuery cq) {
int count = 0;
BytesBuffer buffer = BytesBuffer.allocate(BytesBuffer.BUF_EDGE_ID);
for (HugeKeys key : EdgeId.KEYS) {
Object value = cq.condition(key);
Object value = key == HugeKeys.LABEL ?
cq.conditionValue(key) : cq.condition(key);

if (value != null) {
count++;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -457,7 +457,7 @@ private Query writeQueryEdgeRangeCondition(ConditionQuery cq) {
if (direction == null) {
direction = Directions.OUT;
}
Object label = cq.condition(HugeKeys.LABEL);
Object label = cq.conditionValue(HugeKeys.LABEL);

List<String> start = new ArrayList<>(cq.conditionsSize());
start.add(writeEntryId((Id) vertex));
Expand Down Expand Up @@ -491,7 +491,8 @@ private Query writeQueryEdgePrefixCondition(ConditionQuery cq) {
List<String> condParts = new ArrayList<>(cq.conditionsSize());

for (HugeKeys key : EdgeId.KEYS) {
Object value = cq.condition(key);
Object value = key == HugeKeys.LABEL ?
cq.conditionValue(key) : cq.condition(key);
if (value == null) {
break;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,7 @@ public boolean matched(Query query) {
int conditionsSize = cq.conditionsSize();
Object owner = cq.condition(HugeKeys.OWNER_VERTEX);
Directions direction = cq.condition(HugeKeys.DIRECTION);
Id label = cq.condition(HugeKeys.LABEL);
Id label = uniqueLabel(cq);

if (direction == null && conditionsSize > 1) {
for (Condition cond : cq.conditions()) {
Expand Down Expand Up @@ -316,7 +316,7 @@ private Iterator<HugeEdge> query(ConditionQuery query) {
if (dir == null) {
dir = Directions.BOTH;
}
Id label = query.condition(HugeKeys.LABEL);
Id label = uniqueLabel(query);
if (label == null) {
label = IdGenerator.ZERO;
}
Expand Down Expand Up @@ -377,6 +377,14 @@ private static void ensureNumberId(Id id) {
}
}

private static Id uniqueLabel(ConditionQuery query) {
java.util.Set<Object> labels = query.conditionValues(HugeKeys.LABEL);
if (labels.size() != 1) {
return null;
}
return (Id) labels.iterator().next();
}

private static long encode(long target, Directions direction, int label) {
// TODO: support property
assert (label & 0x0fffffff) == label;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -415,8 +415,9 @@ private IdHolderList queryByLabel(ConditionQuery query) {
HugeType queryType = query.resultType();
IndexLabel il = IndexLabel.label(queryType);
validateIndexLabel(il);
Id label = query.condition(HugeKeys.LABEL);
assert label != null;
Id label = query.conditionValue(HugeKeys.LABEL);
E.checkState(label != null, "Expect one label value for query: %s",
query);

HugeType indexType;
SchemaLabel schemaLabel;
Expand Down Expand Up @@ -482,7 +483,7 @@ private IdHolderList queryByUserprop(ConditionQuery query) {
}
Set<MatchedIndex> indexes = this.collectMatchedIndexes(query);
if (indexes.isEmpty()) {
Id label = query.condition(HugeKeys.LABEL);
Id label = uniqueLabel(query);
throw noIndexException(this.graph(), query, label);
}

Expand Down Expand Up @@ -756,11 +757,16 @@ private PageIds doIndexQueryOnce(IndexLabel indexLabel,
@Watched(prefix = "index")
private Set<MatchedIndex> collectMatchedIndexes(ConditionQuery query) {
ISchemaTransaction schema = this.params().schemaTransaction();
Id label = query.condition(HugeKeys.LABEL);
boolean hasLabel = query.containsCondition(HugeKeys.LABEL);
Set<Object> labels = query.conditionValues(HugeKeys.LABEL);

List<? extends SchemaLabel> schemaLabels;
if (label != null) {
// Query has LABEL condition
if (hasLabel && labels.isEmpty()) {
return Collections.emptySet();
}
if (labels.size() == 1) {
Id label = (Id) labels.iterator().next();
// Query has one resolved LABEL condition
SchemaLabel schemaLabel;
if (query.resultType().isVertex()) {
schemaLabel = schema.getVertexLabel(label);
Expand All @@ -773,7 +779,8 @@ private Set<MatchedIndex> collectMatchedIndexes(ConditionQuery query) {
}
schemaLabels = ImmutableList.of(schemaLabel);
} else {
// Query doesn't have LABEL condition
// Query doesn't have LABEL condition or it doesn't resolve
// to a single label, so keep the conservative fallback.
if (query.resultType().isVertex()) {
schemaLabels = schema.getVertexLabels();
} else if (query.resultType().isEdge()) {
Expand Down Expand Up @@ -1781,7 +1788,7 @@ protected long removeIndexLeft(ConditionQuery query,
}

// Check label is matched
Id label = query.condition(HugeKeys.LABEL);
Id label = uniqueLabel(query);
// NOTE: original condition query may not have label condition,
// which means possibly label == null.
if (label != null && !element.schemaLabel().id().equals(label)) {
Expand Down Expand Up @@ -1981,4 +1988,12 @@ public Long reduce(Long t1, Long t2) {
return t1 + t2;
}
}

private static Id uniqueLabel(ConditionQuery query) {
Set<Object> labels = query.conditionValues(HugeKeys.LABEL);
if (labels.size() != 1) {
return null;
}
return (Id) labels.iterator().next();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1059,7 +1059,7 @@ protected Iterator<HugeEdge> queryEdgesFromBackend(Query query) {
ConditionQueryFlatten.flatten((ConditionQuery) query, supportIn).stream();

Stream<Iterator<HugeEdge>> edgeIterators = flattenedQueries.map(cq -> {
Id label = cq.condition(HugeKeys.LABEL);
Id label = uniqueLabel(cq);
if (this.storeFeatures().supportsFatherAndSubEdgeLabel() &&
label != null &&
graph().edgeLabel(label).isFather() &&
Expand Down Expand Up @@ -1389,7 +1389,7 @@ private static boolean matchEdgeSortKeys(ConditionQuery query,
boolean matchAll,
HugeGraph graph) {
assert query.resultType().isEdge();
Id label = query.condition(HugeKeys.LABEL);
Id label = uniqueLabel(query);
if (label == null) {
return false;
}
Expand Down Expand Up @@ -1522,7 +1522,7 @@ private Query optimizeQuery(ConditionQuery query) {
throw new HugeException("Not supported querying by id and conditions: %s", query);
}

Id label = query.condition(HugeKeys.LABEL);
Id label = uniqueLabel(query);

// Optimize vertex query
if (label != null && query.resultType().isVertex()) {
Expand Down Expand Up @@ -1914,7 +1914,7 @@ private boolean rightResultFromIndexQuery(Query query, HugeElement elem) {
}

ConditionQuery cq = (ConditionQuery) query;
if (cq.condition(HugeKeys.LABEL) != null && cq.resultType().isEdge()) {
if (uniqueLabel(cq) != null && cq.resultType().isEdge()) {
if (cq.conditions().size() == 1) {
// g.E().hasLabel(xxx)
return true;
Expand Down Expand Up @@ -1966,6 +1966,14 @@ private boolean rightResultFromIndexQuery(Query query, HugeElement elem) {
return false;
}

private static Id uniqueLabel(ConditionQuery query) {
Set<Object> labels = query.conditionValues(HugeKeys.LABEL);
if (labels.size() != 1) {
return null;
}
return (Id) labels.iterator().next();
}

private <T extends HugeElement> Iterator<T> filterExpiredResultFromBackend(
Query query, Iterator<T> results) {
if (this.store().features().supportsTtl() || query.showExpired()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -582,7 +582,7 @@ private void fillFilterBySortKeys(Query query, Id[] edgeLabels,

ConditionQuery condQuery = (ConditionQuery) query;
if (!GraphTransaction.matchFullEdgeSortKeys(condQuery, this.graph())) {
Id label = condQuery.condition(HugeKeys.LABEL);
Id label = condQuery.conditionValue(HugeKeys.LABEL);
E.checkArgument(false, "The properties %s does not match " +
"sort keys of edge label '%s'",
this.graph().mapPkId2Name(properties.keySet()),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -402,8 +402,8 @@ public IdPrefixQuery next() {
List<IdPrefixQuery> queryList = Lists.newArrayList();
if (hugeGraph != null) {
for (ConditionQuery conditionQuery :
ConditionQueryFlatten.flatten(cq)) {
Id label = conditionQuery.condition(HugeKeys.LABEL);
ConditionQueryFlatten.flatten(cq)) {
Id label = this.uniqueLabel(conditionQuery);
/* Parent type + sortKeys: g.V("V.id").outE("parentLabel")
.has("sortKey","value") converted to all subtypes + sortKeys */
if ((this.subEls == null ||
Expand Down Expand Up @@ -455,11 +455,19 @@ public IdPrefixQuery next() {
buffer.bytes(), ownerId));
}

private Id uniqueLabel(ConditionQuery query) {
Set<Object> labels = query.conditionValues(HugeKeys.LABEL);
if (labels.size() != 1) {
return null;
}
return (Id) labels.iterator().next();
}

private boolean matchEdgeSortKeys(ConditionQuery query,
boolean matchAll,
HugeGraph graph) {
assert query.resultType().isEdge();
Id label = query.condition(HugeKeys.LABEL);
Id label = this.uniqueLabel(query);
if (label == null) {
return false;
}
Expand Down
Loading
Loading