Skip to content

Commit 4c42786

Browse files
committed
improve(query): consolidate unique label resolution
1 parent 5f15699 commit 4c42786

9 files changed

Lines changed: 69 additions & 73 deletions

File tree

hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/backend/query/ConditionQuery.java

Lines changed: 23 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -268,8 +268,9 @@ public boolean containsLabelOrUserpropRelation() {
268268
* <li>throws if multiple values remain after resolving several relations</li>
269269
* </ul>
270270
*
271-
* Prefer {@link #conditionValues(Object)} or {@link #conditionValue(Object)}
272-
* for new code that needs explicit semantics.
271+
* Prefer {@link #conditionValues(Object)}, {@link #uniqueConditionValue(Object)}
272+
* or {@link #conditionValue(Object)} for new code that needs explicit
273+
* semantics.
273274
*/
274275
@Watched
275276
public <T> T condition(Object key) {
@@ -290,29 +291,8 @@ public <T> T condition(Object key) {
290291
return value;
291292
}
292293

293-
boolean initialized = false;
294-
Set<Object> intersectValues = InsertionOrderUtil.newSet();
295-
for (Object value : valuesEQ) {
296-
List<Object> valueAsList = ImmutableList.of(value);
297-
if (!initialized) {
298-
intersectValues.addAll(valueAsList);
299-
initialized = true;
300-
} else {
301-
CollectionUtil.intersectWithModify(intersectValues,
302-
valueAsList);
303-
}
304-
}
305-
for (Object value : valuesIN) {
306-
@SuppressWarnings("unchecked")
307-
List<Object> valueAsList = (List<Object>) value;
308-
if (!initialized) {
309-
intersectValues.addAll(valueAsList);
310-
initialized = true;
311-
} else {
312-
CollectionUtil.intersectWithModify(intersectValues,
313-
valueAsList);
314-
}
315-
}
294+
Set<Object> intersectValues = this.resolveConditionValues(valuesEQ,
295+
valuesIN);
316296

317297
if (intersectValues.isEmpty()) {
318298
return null;
@@ -377,6 +357,24 @@ public <T> T conditionValue(Object key) {
377357
return value;
378358
}
379359

360+
/**
361+
* Returns the unique resolved value of the specified key from top-level
362+
* EQ/IN relations, or {@code null} if the resolved candidate set doesn't
363+
* contain exactly one value.
364+
*
365+
* Use this method when callers want "single-or-null" semantics instead of
366+
* treating multiple remaining values as an error.
367+
*/
368+
public <T> T uniqueConditionValue(Object key) {
369+
Set<Object> values = this.conditionValues(key);
370+
if (values.size() != 1) {
371+
return null;
372+
}
373+
@SuppressWarnings("unchecked")
374+
T value = (T) values.iterator().next();
375+
return value;
376+
}
377+
380378
public void unsetCondition(Object key) {
381379
this.conditions.removeIf(c -> c.isRelation() && ((Relation) c).key().equals(key));
382380
}

hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/backend/serializer/BinarySerializer.java

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -674,7 +674,7 @@ private Query writeQueryEdgeRangeCondition(ConditionQuery cq) {
674674
if (direction == null) {
675675
direction = Directions.OUT;
676676
}
677-
Id label = cq.conditionValue(HugeKeys.LABEL);
677+
Id label = (Id) this.edgeIdConditionValue(cq, HugeKeys.LABEL);
678678

679679
BytesBuffer start = BytesBuffer.allocate(BytesBuffer.BUF_EDGE_ID);
680680
writePartitionedId(HugeType.EDGE, vertex, start);
@@ -722,8 +722,7 @@ private Query writeQueryEdgePrefixCondition(ConditionQuery cq) {
722722
int count = 0;
723723
BytesBuffer buffer = BytesBuffer.allocate(BytesBuffer.BUF_EDGE_ID);
724724
for (HugeKeys key : EdgeId.KEYS) {
725-
Object value = key == HugeKeys.LABEL ?
726-
cq.conditionValue(key) : cq.condition(key);
725+
Object value = this.edgeIdConditionValue(cq, key);
727726

728727
if (value != null) {
729728
count++;
@@ -764,6 +763,17 @@ private Query writeQueryEdgePrefixCondition(ConditionQuery cq) {
764763
return null;
765764
}
766765

766+
private Object edgeIdConditionValue(ConditionQuery cq, HugeKeys key) {
767+
if (key == HugeKeys.LABEL) {
768+
/*
769+
* LABEL may still be represented by multiple top-level EQ/IN
770+
* relations before strict edge-id serialization.
771+
*/
772+
return cq.conditionValue(key);
773+
}
774+
return cq.condition(key);
775+
}
776+
767777
@Override
768778
protected Query writeQueryCondition(Query query) {
769779
HugeType type = query.resultType();

hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/backend/serializer/TextSerializer.java

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -457,7 +457,7 @@ private Query writeQueryEdgeRangeCondition(ConditionQuery cq) {
457457
if (direction == null) {
458458
direction = Directions.OUT;
459459
}
460-
Object label = cq.conditionValue(HugeKeys.LABEL);
460+
Object label = this.edgeIdConditionValue(cq, HugeKeys.LABEL);
461461

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

493493
for (HugeKeys key : EdgeId.KEYS) {
494-
Object value = key == HugeKeys.LABEL ?
495-
cq.conditionValue(key) : cq.condition(key);
494+
Object value = this.edgeIdConditionValue(cq, key);
496495
if (value == null) {
497496
break;
498497
}
@@ -517,6 +516,17 @@ private Query writeQueryEdgePrefixCondition(ConditionQuery cq) {
517516
return null;
518517
}
519518

519+
private Object edgeIdConditionValue(ConditionQuery cq, HugeKeys key) {
520+
if (key == HugeKeys.LABEL) {
521+
/*
522+
* LABEL may still be represented by multiple top-level EQ/IN
523+
* relations before strict edge-id serialization.
524+
*/
525+
return cq.conditionValue(key);
526+
}
527+
return cq.condition(key);
528+
}
529+
520530
@Override
521531
protected Query writeQueryCondition(Query query) {
522532
ConditionQuery result = (ConditionQuery) query;

hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/backend/store/ram/RamTable.java

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,7 @@ public boolean matched(Query query) {
269269
int conditionsSize = cq.conditionsSize();
270270
Object owner = cq.condition(HugeKeys.OWNER_VERTEX);
271271
Directions direction = cq.condition(HugeKeys.DIRECTION);
272-
Id label = uniqueLabel(cq);
272+
Id label = cq.uniqueConditionValue(HugeKeys.LABEL);
273273

274274
if (direction == null && conditionsSize > 1) {
275275
for (Condition cond : cq.conditions()) {
@@ -316,7 +316,7 @@ private Iterator<HugeEdge> query(ConditionQuery query) {
316316
if (dir == null) {
317317
dir = Directions.BOTH;
318318
}
319-
Id label = uniqueLabel(query);
319+
Id label = query.uniqueConditionValue(HugeKeys.LABEL);
320320
if (label == null) {
321321
label = IdGenerator.ZERO;
322322
}
@@ -377,14 +377,6 @@ private static void ensureNumberId(Id id) {
377377
}
378378
}
379379

380-
private static Id uniqueLabel(ConditionQuery query) {
381-
java.util.Set<Object> labels = query.conditionValues(HugeKeys.LABEL);
382-
if (labels.size() != 1) {
383-
return null;
384-
}
385-
return (Id) labels.iterator().next();
386-
}
387-
388380
private static long encode(long target, Directions direction, int label) {
389381
// TODO: support property
390382
assert (label & 0x0fffffff) == label;

hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/backend/tx/GraphIndexTransaction.java

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -415,6 +415,8 @@ private IdHolderList queryByLabel(ConditionQuery query) {
415415
HugeType queryType = query.resultType();
416416
IndexLabel il = IndexLabel.label(queryType);
417417
validateIndexLabel(il);
418+
// Query-by-label builds a label index entry and requires one
419+
// deterministically resolved label instead of best-effort fallback.
418420
Id label = query.conditionValue(HugeKeys.LABEL);
419421
E.checkState(label != null, "Expect one label value for query: %s",
420422
query);
@@ -483,7 +485,7 @@ private IdHolderList queryByUserprop(ConditionQuery query) {
483485
}
484486
Set<MatchedIndex> indexes = this.collectMatchedIndexes(query);
485487
if (indexes.isEmpty()) {
486-
Id label = uniqueLabel(query);
488+
Id label = query.uniqueConditionValue(HugeKeys.LABEL);
487489
throw noIndexException(this.graph(), query, label);
488490
}
489491

@@ -1788,7 +1790,7 @@ protected long removeIndexLeft(ConditionQuery query,
17881790
}
17891791

17901792
// Check label is matched
1791-
Id label = uniqueLabel(query);
1793+
Id label = query.uniqueConditionValue(HugeKeys.LABEL);
17921794
// NOTE: original condition query may not have label condition,
17931795
// which means possibly label == null.
17941796
if (label != null && !element.schemaLabel().id().equals(label)) {
@@ -1988,12 +1990,4 @@ public Long reduce(Long t1, Long t2) {
19881990
return t1 + t2;
19891991
}
19901992
}
1991-
1992-
private static Id uniqueLabel(ConditionQuery query) {
1993-
Set<Object> labels = query.conditionValues(HugeKeys.LABEL);
1994-
if (labels.size() != 1) {
1995-
return null;
1996-
}
1997-
return (Id) labels.iterator().next();
1998-
}
19991993
}

hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/backend/tx/GraphTransaction.java

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1057,7 +1057,7 @@ protected Iterator<HugeEdge> queryEdgesFromBackend(Query query) {
10571057
ConditionQueryFlatten.flatten((ConditionQuery) query, supportIn).stream();
10581058

10591059
Stream<Iterator<HugeEdge>> edgeIterators = flattenedQueries.map(cq -> {
1060-
Id label = uniqueLabel(cq);
1060+
Id label = cq.uniqueConditionValue(HugeKeys.LABEL);
10611061
if (this.storeFeatures().supportsFatherAndSubEdgeLabel() &&
10621062
label != null &&
10631063
graph().edgeLabel(label).isFather() &&
@@ -1387,7 +1387,7 @@ private static boolean matchEdgeSortKeys(ConditionQuery query,
13871387
boolean matchAll,
13881388
HugeGraph graph) {
13891389
assert query.resultType().isEdge();
1390-
Id label = uniqueLabel(query);
1390+
Id label = query.uniqueConditionValue(HugeKeys.LABEL);
13911391
if (label == null) {
13921392
return false;
13931393
}
@@ -1520,7 +1520,7 @@ private Query optimizeQuery(ConditionQuery query) {
15201520
throw new HugeException("Not supported querying by id and conditions: %s", query);
15211521
}
15221522

1523-
Id label = uniqueLabel(query);
1523+
Id label = query.uniqueConditionValue(HugeKeys.LABEL);
15241524

15251525
// Optimize vertex query
15261526
if (label != null && query.resultType().isVertex()) {
@@ -1912,7 +1912,8 @@ private boolean rightResultFromIndexQuery(Query query, HugeElement elem) {
19121912
}
19131913

19141914
ConditionQuery cq = (ConditionQuery) query;
1915-
if (uniqueLabel(cq) != null && cq.resultType().isEdge()) {
1915+
if (cq.uniqueConditionValue(HugeKeys.LABEL) != null &&
1916+
cq.resultType().isEdge()) {
19161917
if (cq.conditions().size() == 1) {
19171918
// g.E().hasLabel(xxx)
19181919
return true;
@@ -1964,14 +1965,6 @@ private boolean rightResultFromIndexQuery(Query query, HugeElement elem) {
19641965
return false;
19651966
}
19661967

1967-
private static Id uniqueLabel(ConditionQuery query) {
1968-
Set<Object> labels = query.conditionValues(HugeKeys.LABEL);
1969-
if (labels.size() != 1) {
1970-
return null;
1971-
}
1972-
return (Id) labels.iterator().next();
1973-
}
1974-
19751968
private <T extends HugeElement> Iterator<T> filterExpiredResultFromBackend(
19761969
Query query, Iterator<T> results) {
19771970
if (this.store().features().supportsTtl() || query.showExpired()) {

hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/algorithm/HugeTraverser.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -582,6 +582,8 @@ private void fillFilterBySortKeys(Query query, Id[] edgeLabels,
582582

583583
ConditionQuery condQuery = (ConditionQuery) query;
584584
if (!GraphTransaction.matchFullEdgeSortKeys(condQuery, this.graph())) {
585+
// Sort-key validation needs one concrete edge label so that the
586+
// error message points to the exact schema label in use.
585587
Id label = condQuery.conditionValue(HugeKeys.LABEL);
586588
E.checkArgument(false, "The properties %s does not match " +
587589
"sort keys of edge label '%s'",

hugegraph-server/hugegraph-hstore/src/main/java/org/apache/hugegraph/backend/store/hstore/HstoreStore.java

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -403,7 +403,7 @@ public IdPrefixQuery next() {
403403
if (hugeGraph != null) {
404404
for (ConditionQuery conditionQuery :
405405
ConditionQueryFlatten.flatten(cq)) {
406-
Id label = this.uniqueLabel(conditionQuery);
406+
Id label = conditionQuery.uniqueConditionValue(HugeKeys.LABEL);
407407
/* Parent type + sortKeys: g.V("V.id").outE("parentLabel")
408408
.has("sortKey","value") converted to all subtypes + sortKeys */
409409
if ((this.subEls == null ||
@@ -455,19 +455,11 @@ public IdPrefixQuery next() {
455455
buffer.bytes(), ownerId));
456456
}
457457

458-
private Id uniqueLabel(ConditionQuery query) {
459-
Set<Object> labels = query.conditionValues(HugeKeys.LABEL);
460-
if (labels.size() != 1) {
461-
return null;
462-
}
463-
return (Id) labels.iterator().next();
464-
}
465-
466458
private boolean matchEdgeSortKeys(ConditionQuery query,
467459
boolean matchAll,
468460
HugeGraph graph) {
469461
assert query.resultType().isEdge();
470-
Id label = this.uniqueLabel(query);
462+
Id label = query.uniqueConditionValue(HugeKeys.LABEL);
471463
if (label == null) {
472464
return false;
473465
}

hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/unit/core/QueryTest.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ public void testConditionWithoutLabel() {
5555
Assert.assertFalse(query.containsCondition(HugeKeys.LABEL));
5656
Assert.assertEquals(ImmutableSet.of(),
5757
query.conditionValues(HugeKeys.LABEL));
58+
Assert.assertNull(query.uniqueConditionValue(HugeKeys.LABEL));
5859
Assert.assertNull(query.conditionValue(HugeKeys.LABEL));
5960
Assert.assertNull(query.condition(HugeKeys.LABEL));
6061
}
@@ -72,6 +73,7 @@ public void testConditionWithEqAndIn() {
7273
Assert.assertTrue(query.containsCondition(HugeKeys.LABEL));
7374
Assert.assertEquals(ImmutableSet.of(label1),
7475
query.conditionValues(HugeKeys.LABEL));
76+
Assert.assertEquals(label1, query.uniqueConditionValue(HugeKeys.LABEL));
7577
Assert.assertEquals(label1, query.conditionValue(HugeKeys.LABEL));
7678
Assert.assertEquals(label1, query.condition(HugeKeys.LABEL));
7779
}
@@ -88,6 +90,7 @@ public void testConditionWithSingleInValues() {
8890
Assert.assertTrue(query.containsCondition(HugeKeys.LABEL));
8991
Assert.assertEquals(ImmutableSet.of(label1, label2),
9092
query.conditionValues(HugeKeys.LABEL));
93+
Assert.assertNull(query.uniqueConditionValue(HugeKeys.LABEL));
9194
Assert.assertThrows(IllegalStateException.class,
9295
() -> query.conditionValue(HugeKeys.LABEL),
9396
e -> Assert.assertContains("Illegal key 'LABEL'",
@@ -111,6 +114,7 @@ public void testConditionWithConflictingEqAndIn() {
111114
Assert.assertTrue(query.containsCondition(HugeKeys.LABEL));
112115
Assert.assertEquals(ImmutableSet.of(),
113116
query.conditionValues(HugeKeys.LABEL));
117+
Assert.assertNull(query.uniqueConditionValue(HugeKeys.LABEL));
114118
Assert.assertNull(query.conditionValue(HugeKeys.LABEL));
115119
Assert.assertNull(query.condition(HugeKeys.LABEL));
116120
}
@@ -131,6 +135,7 @@ public void testConditionWithMultipleMatchedInValues() {
131135
Assert.assertTrue(query.containsCondition(HugeKeys.LABEL));
132136
Assert.assertEquals(ImmutableSet.of(label1, label2),
133137
query.conditionValues(HugeKeys.LABEL));
138+
Assert.assertNull(query.uniqueConditionValue(HugeKeys.LABEL));
134139
Assert.assertThrows(IllegalStateException.class,
135140
() -> query.conditionValue(HugeKeys.LABEL),
136141
e -> Assert.assertContains("Illegal key 'LABEL'",

0 commit comments

Comments
 (0)