/
HasStepFolder.java
159 lines (135 loc) · 6.55 KB
/
HasStepFolder.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
package com.thinkaurelius.titan.graphdb.tinkerpop.optimize;
import com.thinkaurelius.titan.core.Cardinality;
import com.thinkaurelius.titan.core.PropertyKey;
import com.thinkaurelius.titan.core.TitanTransaction;
import com.thinkaurelius.titan.graphdb.query.QueryUtil;
import com.thinkaurelius.titan.graphdb.query.TitanPredicate;
import com.tinkerpop.gremlin.process.Step;
import com.tinkerpop.gremlin.process.Traversal;
import com.tinkerpop.gremlin.process.graph.marker.HasContainerHolder;
import com.tinkerpop.gremlin.process.graph.marker.Ranging;
import com.tinkerpop.gremlin.process.graph.step.filter.FilterStep;
import com.tinkerpop.gremlin.process.graph.step.filter.HasStep;
import com.tinkerpop.gremlin.process.graph.step.filter.RangeStep;
import com.tinkerpop.gremlin.process.graph.step.map.OrderStep;
import com.tinkerpop.gremlin.process.graph.step.sideEffect.IdentityStep;
import com.tinkerpop.gremlin.process.graph.util.HasContainer;
import com.tinkerpop.gremlin.process.util.ElementValueComparator;
import com.tinkerpop.gremlin.process.util.TraversalHelper;
import com.tinkerpop.gremlin.structure.Order;
import java.util.Comparator;
import java.util.List;
/**
* @author Matthias Broecheler (me@matthiasb.com)
*/
public interface HasStepFolder<S, E> extends Step<S, E> {
public void addAll(Iterable<HasContainer> hasContainers);
public void orderBy(String key, Order order);
public void setLimit(int limit);
public int getLimit();
public static boolean validTitanHas(HasContainer has) {
return TitanPredicate.Converter.supports(has.predicate);
}
public static boolean validTitanHas(Iterable<HasContainer> has) {
for (HasContainer h : has) {
if (!validTitanHas(h)) return false;
}
return true;
}
public static boolean validTitanOrder(OrderStep ostep, Traversal rootTraversal,
boolean isVertexOrder) {
for (Comparator comp : (List<Comparator>)ostep.getComparators()) {
if (!(comp instanceof ElementValueComparator)) return false;
ElementValueComparator evc = (ElementValueComparator)comp;
if (!(evc.getValueComparator() instanceof Order)) return false;
TitanTransaction tx = TitanTraversalUtil.getTx(rootTraversal);
String key = evc.getPropertyKey();
PropertyKey pkey = tx.getPropertyKey(key);
if (pkey==null || !(Comparable.class.isAssignableFrom(pkey.dataType())) ) return false;
if (isVertexOrder && pkey.cardinality()!=Cardinality.SINGLE) return false;
}
return true;
}
public static void foldInHasContainer(final HasStepFolder titanStep, final Traversal.Admin<?, ?> traversal) {
Step currentStep = titanStep.getNextStep();
while (true) {
if (currentStep.getLabel().isPresent()) break;
if (currentStep instanceof HasContainerHolder) {
Iterable<HasContainer> containers = ((HasContainerHolder) currentStep).getHasContainers();
if (validTitanHas(containers)) {
titanStep.addAll(containers);
addLabeledStepAsIdentity(currentStep, traversal);
traversal.removeStep(currentStep);
}
} else if (currentStep instanceof OrderStep) {
//do nothing, we can pull filters over those
} else if (currentStep instanceof IdentityStep) {
// do nothing, has no impact
} else if (currentStep instanceof HasStep) {
// do nothing, we can rearrange filters
} else {
break;
}
currentStep = currentStep.getNextStep();
}
}
public static void addLabeledStepAsIdentity(Step<?,?> currentStep, final Traversal.Admin<?, ?> traversal) {
currentStep.getLabel().ifPresent(label -> {
final IdentityStep identityStep = new IdentityStep<>(traversal);
identityStep.setLabel(label);
TraversalHelper.insertAfterStep(identityStep, currentStep, traversal);
});
}
public static void foldInOrder(final HasStepFolder titanStep, final Traversal.Admin<?, ?> traversal,
final Traversal<?,?> rootTraversal, boolean isVertexOrder) {
Step currentStep = titanStep.getNextStep();
OrderStep lastOrder = null;
while (true) {
if (currentStep instanceof OrderStep) {
if (lastOrder!=null) { //Previous orders are rendered irrelevant by next order (since re-ordered)
addLabeledStepAsIdentity(lastOrder, traversal);
traversal.removeStep(lastOrder);
}
lastOrder = (OrderStep)currentStep;
} else if (currentStep instanceof IdentityStep) {
// do nothing, can be skipped
} else if (currentStep instanceof HasStep) {
// do nothing, can be skipped
} else {
break;
}
currentStep = currentStep.getNextStep();
}
if (lastOrder!=null && lastOrder instanceof OrderStep) {
if (validTitanOrder(lastOrder,rootTraversal,isVertexOrder)) {
//Add orders to HasStepFolder
for (Comparator comp : (List<Comparator>)lastOrder.getComparators()) {
ElementValueComparator evc = (ElementValueComparator)comp;
titanStep.orderBy(evc.getPropertyKey(),(Order)evc.getValueComparator());
}
addLabeledStepAsIdentity(lastOrder, traversal);
traversal.removeStep(lastOrder);
}
}
}
public static class OrderEntry {
public final String key;
public final Order order;
public OrderEntry(String key, Order order) {
this.key = key;
this.order = order;
}
}
public static <E extends Ranging> void foldInRange(final HasStepFolder titanStep, final Traversal.Admin<?, ?> traversal) {
Step nextStep = TitanTraversalUtil.getNextNonIdentityStep(titanStep);
if (nextStep instanceof RangeStep) {
RangeStep range = (RangeStep)nextStep;
int limit = QueryUtil.convertLimit(range.getHighRange());
titanStep.setLimit(QueryUtil.mergeLimits(limit, titanStep.getLimit()));
if (range.getLowRange() == 0) { //Range can be removed since there is no offset
addLabeledStepAsIdentity(nextStep, traversal);
traversal.removeStep(nextStep);
}
}
}
}