Skip to content

Commit 804208a

Browse files
committed
perf(core): add AdjacentEdgesQuery
Change-Id: Ie7169fdb707495ff0a298ea97fa4d105117a132d
1 parent 0946d5d commit 804208a

File tree

9 files changed

+472
-91
lines changed

9 files changed

+472
-91
lines changed
Lines changed: 396 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,396 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
package org.apache.hugegraph.backend.query;
19+
20+
import java.util.ArrayList;
21+
import java.util.Arrays;
22+
import java.util.Collection;
23+
import java.util.List;
24+
25+
import org.apache.hugegraph.backend.id.Id;
26+
import org.apache.hugegraph.backend.query.Condition.Relation;
27+
import org.apache.hugegraph.backend.query.Condition.RelationType;
28+
import org.apache.hugegraph.structure.HugeEdge;
29+
import org.apache.hugegraph.structure.HugeElement;
30+
import org.apache.hugegraph.type.HugeType;
31+
import org.apache.hugegraph.type.define.Directions;
32+
import org.apache.hugegraph.type.define.HugeKeys;
33+
import org.apache.hugegraph.util.CollectionUtil;
34+
import org.apache.hugegraph.util.E;
35+
import org.apache.hugegraph.util.InsertionOrderUtil;
36+
37+
import com.google.common.collect.ImmutableList;
38+
39+
public class AdjacentEdgesQuery extends ConditionQuery {
40+
41+
private Id ownerVertex;
42+
private Directions direction;
43+
private Id[] edgeLabels;
44+
45+
private List<Condition> selfConditions;
46+
47+
private static final Id[] EMPTY = new Id[0];
48+
49+
public AdjacentEdgesQuery(Id ownerVertex, Directions direction) {
50+
this(ownerVertex, direction, EMPTY);
51+
}
52+
53+
public AdjacentEdgesQuery(Id ownerVertex, Directions direction,
54+
Id[] edgeLabels) {
55+
super(HugeType.EDGE);
56+
E.checkArgument(ownerVertex != null,
57+
"The edge query must contain source vertex");
58+
E.checkArgument(direction != null,
59+
"The edge query must contain direction");
60+
this.ownerVertex = ownerVertex;
61+
this.direction = direction;
62+
this.edgeLabels = edgeLabels;
63+
this.selfConditions = null;
64+
}
65+
66+
@Override
67+
public int conditionsSize() {
68+
int size = super.conditionsSize() + 2;
69+
if (this.edgeLabels.length > 0) {
70+
size += 1;
71+
}
72+
return size;
73+
}
74+
75+
@Override
76+
public ConditionQuery query(Condition condition) {
77+
if (!condition.isRelation()) {
78+
return super.query(condition);
79+
}
80+
81+
// Reset this.selfConditions cache
82+
this.selfConditions = null;
83+
84+
// Update condition fields
85+
Relation relation = ((Condition.Relation) condition);
86+
Object key = relation.key();
87+
RelationType relationType = relation.relation();
88+
89+
if (key == HugeKeys.OWNER_VERTEX) {
90+
this.ownerVertex = (Id) relation.value();
91+
return this;
92+
}
93+
if (key == HugeKeys.DIRECTION) {
94+
this.direction = (Directions) relation.value();
95+
return this;
96+
}
97+
if (key == HugeKeys.LABEL) {
98+
Collection<Id> labels = null;
99+
if (relationType == RelationType.EQ) {
100+
labels = ImmutableList.of((Id) relation.value());
101+
} else if (relationType == RelationType.IN) {
102+
@SuppressWarnings("unchecked")
103+
Collection<Id> value = (Collection<Id>) relation.value();
104+
labels = value;
105+
} else {
106+
E.checkArgument(false,
107+
"Unexpected relation type '%s' for '%s'",
108+
relationType, key);
109+
}
110+
111+
if (this.edgeLabels.length == 0) {
112+
this.edgeLabels = labels.toArray(new Id[0]);
113+
} else {
114+
Collection<Id> edgeLabels = CollectionUtil.intersect(
115+
Arrays.asList(this.edgeLabels),
116+
labels);
117+
if (edgeLabels.isEmpty()) {
118+
// Returns empty result if conditions are conflicting
119+
this.limit(0L);
120+
}
121+
this.edgeLabels = edgeLabels.toArray(new Id[0]);
122+
}
123+
return this;
124+
}
125+
126+
return super.query(condition);
127+
}
128+
129+
@Override
130+
public Collection<Condition> conditions() {
131+
List<Condition> conds = this.selfConditions();
132+
if (super.conditionsSize() > 0) {
133+
conds.addAll(super.conditions());
134+
}
135+
return conds;
136+
}
137+
138+
private List<Condition> selfConditions() {
139+
if (this.selfConditions != null) {
140+
/*
141+
* Return selfConditions cache if it has been collected before
142+
* NOTE: it's also to keep the serialized condition value
143+
*/
144+
return this.selfConditions;
145+
}
146+
147+
List<Condition> conds = InsertionOrderUtil.newList();
148+
149+
conds.add(Condition.eq(HugeKeys.OWNER_VERTEX, this.ownerVertex));
150+
151+
if (this.direction == Directions.BOTH) {
152+
conds.add(Condition.in(HugeKeys.DIRECTION, ImmutableList.of(
153+
Directions.OUT,
154+
Directions.IN)));
155+
} else {
156+
conds.add(Condition.eq(HugeKeys.DIRECTION, this.direction));
157+
}
158+
159+
if (this.edgeLabels.length == 1) {
160+
conds.add(Condition.eq(HugeKeys.LABEL, this.edgeLabels[0]));
161+
} else if (this.edgeLabels.length > 1) {
162+
conds.add(Condition.in(HugeKeys.LABEL,
163+
Arrays.asList(this.edgeLabels)));
164+
}
165+
166+
this.selfConditions = conds;
167+
return conds;
168+
}
169+
170+
@Override
171+
public <T> T condition(Object key) {
172+
T cond = this.selfCondition(key);
173+
if (cond != null) {
174+
return cond;
175+
}
176+
return super.condition(key);
177+
}
178+
179+
@SuppressWarnings("unchecked")
180+
private <T> T selfCondition(Object key) {
181+
if (key == HugeKeys.OWNER_VERTEX) {
182+
return (T) this.ownerVertex;
183+
}
184+
if (key == HugeKeys.DIRECTION) {
185+
return (T) this.direction;
186+
}
187+
if (key == HugeKeys.LABEL) {
188+
if (this.edgeLabels.length == 0) {
189+
return null;
190+
}
191+
if (this.edgeLabels.length == 1) {
192+
return (T) this.edgeLabels[0];
193+
}
194+
E.checkState(false,
195+
"Illegal key '%s' with more than one value", key);
196+
}
197+
return null;
198+
}
199+
200+
private Condition.Relation selfRelation(Object key) {
201+
if (key == HugeKeys.OWNER_VERTEX) {
202+
return Condition.eq(HugeKeys.OWNER_VERTEX, this.ownerVertex);
203+
}
204+
if (key == HugeKeys.DIRECTION) {
205+
if (this.direction == Directions.BOTH) {
206+
return Condition.in(HugeKeys.DIRECTION, ImmutableList.of(
207+
Directions.OUT,
208+
Directions.IN));
209+
} else {
210+
return Condition.eq(HugeKeys.DIRECTION, this.direction);
211+
}
212+
}
213+
if (key == HugeKeys.LABEL) {
214+
if (this.edgeLabels.length == 0) {
215+
return null;
216+
}
217+
if (this.edgeLabels.length == 1) {
218+
return Condition.eq(HugeKeys.LABEL, this.edgeLabels[0]);
219+
}
220+
return Condition.in(HugeKeys.LABEL, Arrays.asList(this.edgeLabels));
221+
}
222+
return null;
223+
}
224+
225+
@Override
226+
public boolean containsCondition(HugeKeys key) {
227+
if (key == HugeKeys.OWNER_VERTEX) {
228+
return true;
229+
}
230+
if (key == HugeKeys.DIRECTION) {
231+
return true;
232+
}
233+
if (key == HugeKeys.LABEL) {
234+
if (this.edgeLabels.length == 0) {
235+
return false;
236+
}
237+
return true;
238+
}
239+
return super.containsCondition(key);
240+
}
241+
242+
@Override
243+
public void unsetCondition(Object key) {
244+
if (key == HugeKeys.OWNER_VERTEX ||
245+
key == HugeKeys.DIRECTION ||
246+
key == HugeKeys.LABEL) {
247+
E.checkArgument(false, "Can't unset condition '%s'", key);
248+
}
249+
super.unsetCondition(key);
250+
}
251+
252+
@Override
253+
public List<Condition> syspropConditions() {
254+
List<Condition> conds = this.selfConditions();
255+
if (super.conditionsSize() > 0) {
256+
conds.addAll(super.syspropConditions());
257+
}
258+
return conds;
259+
}
260+
261+
@Override
262+
public List<Condition> syspropConditions(HugeKeys key) {
263+
Condition cond = this.selfRelation(key);
264+
if (cond != null) {
265+
return ImmutableList.of(cond);
266+
}
267+
return super.syspropConditions(key);
268+
}
269+
270+
@Override
271+
public List<Condition.Relation> relations() {
272+
// NOTE: selfConditions() actually return a list of Relation
273+
@SuppressWarnings({ "rawtypes", "unchecked" })
274+
List<Condition.Relation> relations = (List) this.selfConditions();
275+
if (super.conditionsSize() > 0) {
276+
relations.addAll(super.relations());
277+
}
278+
return relations;
279+
}
280+
281+
@Override
282+
public Relation relation(Id key){
283+
Relation relation = this.selfRelation(key);
284+
if (relation != null) {
285+
return relation;
286+
}
287+
return super.relation(key);
288+
}
289+
290+
@Override
291+
public boolean allSysprop() {
292+
return super.allSysprop();
293+
}
294+
295+
@Override
296+
public boolean allRelation() {
297+
if (!this.isFlattened()) {
298+
return false;
299+
}
300+
return super.allRelation();
301+
}
302+
303+
@Override
304+
public AdjacentEdgesQuery copy() {
305+
return (AdjacentEdgesQuery) super.copy();
306+
}
307+
308+
@Override
309+
public AdjacentEdgesQuery copyAndResetUnshared() {
310+
return (AdjacentEdgesQuery) super.copyAndResetUnshared();
311+
}
312+
313+
@Override
314+
public boolean isFlattened() {
315+
if (this.direction == Directions.BOTH) {
316+
return false;
317+
}
318+
if (this.edgeLabels.length > 1) {
319+
return false;
320+
}
321+
return super.isFlattened();
322+
}
323+
324+
@Override
325+
public boolean canFlatten() {
326+
return super.conditionsSize() == 0;
327+
}
328+
329+
@Override
330+
public List<ConditionQuery> flatten() {
331+
int labels = this.edgeLabels.length;
332+
int directions = this.direction == Directions.BOTH ? 2 : 1;
333+
int size = labels * directions;
334+
List<ConditionQuery> queries = new ArrayList<>(size);
335+
if (labels == 0) {
336+
Id label = null;
337+
if (this.direction == Directions.BOTH) {
338+
queries.add(this.copyQuery(Directions.OUT, label));
339+
queries.add(this.copyQuery(Directions.IN, label));
340+
} else {
341+
queries.add(this.copyQuery(this.direction, label));
342+
}
343+
} else {
344+
for (Id label : this.edgeLabels) {
345+
if (this.direction == Directions.BOTH) {
346+
queries.add(this.copyQuery(Directions.OUT, label));
347+
queries.add(this.copyQuery(Directions.IN, label));
348+
} else {
349+
queries.add(this.copyQuery(this.direction, label));
350+
}
351+
}
352+
}
353+
E.checkState(super.conditionsSize() == 0,
354+
"Can't flatten query: %s", this);
355+
return queries;
356+
}
357+
358+
private AdjacentEdgesQuery copyQuery(Directions direction,
359+
Id edgeLabel) {
360+
AdjacentEdgesQuery query = this.copy();
361+
query.direction = direction;
362+
if (edgeLabel != null) {
363+
query.edgeLabels = new Id[]{edgeLabel};
364+
} else {
365+
query.edgeLabels = EMPTY;
366+
}
367+
query.selfConditions = null;
368+
return query;
369+
}
370+
371+
@Override
372+
public boolean test(HugeElement element) {
373+
if (!super.test(element)) {
374+
return false;
375+
}
376+
HugeEdge edge = (HugeEdge) element;
377+
if (!edge.ownerVertex().id().equals(this.ownerVertex)) {
378+
return false;
379+
}
380+
if (!edge.matchDirection(this.direction)) {
381+
return false;
382+
}
383+
384+
boolean matchedLabel = false;
385+
if (this.edgeLabels.length == 0) {
386+
matchedLabel = true;
387+
} else {
388+
for (Id label : this.edgeLabels) {
389+
if (edge.schemaLabel().id().equals(label)) {
390+
matchedLabel = true;
391+
}
392+
}
393+
}
394+
return matchedLabel;
395+
}
396+
}

0 commit comments

Comments
 (0)