Skip to content

Commit 7b20f38

Browse files
authored
Efficient Lateral View Bullet Record (#105)
1 parent d5e5431 commit 7b20f38

File tree

10 files changed

+284
-61
lines changed

10 files changed

+284
-61
lines changed

src/main/java/com/yahoo/bullet/common/Utilities.java

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,19 +187,32 @@ public static double[] generatePoints(double start, Function<Double, Double> gen
187187
*/
188188
public static Number extractFieldAsNumber(String field, BulletRecord record) {
189189
TypedObject value = record.typedGet(field);
190-
if (value.isNull()) {
190+
if (isNull(value)) {
191191
return null;
192192
}
193193
if (Type.isNumeric(value.getType())) {
194194
return (Number) value.getValue();
195195
}
196+
if (value.getType() == Type.BOOLEAN) {
197+
return (Boolean) value.getValue() ? 1L : 0L;
198+
}
196199
try {
197200
return (Number) value.forceCast(Type.DOUBLE).getValue();
198201
} catch (Exception e) {
199202
return null;
200203
}
201204
}
202205

206+
/**
207+
* Returns if the {@link TypedObject} has type {@link TypedObject#NULL} or value null.
208+
*
209+
* @param typedObject The typed object to check for null.
210+
* @return true if the {@link TypedObject} has type {@link TypedObject#NULL} or value null and false otherwise.
211+
*/
212+
public static boolean isNull(TypedObject typedObject) {
213+
return typedObject.isNull() || typedObject.getValue() == null;
214+
}
215+
203216
/**
204217
* This method loads a given class name with the class name key and creates an instance of it by using a constructor
205218
* that has a single argument for a {@link BulletConfig}. It then passes in the provided config and returns the

src/main/java/com/yahoo/bullet/querying/Projection.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
import java.util.Map;
1717
import java.util.stream.Collectors;
1818

19+
import static com.yahoo.bullet.common.Utilities.isNull;
20+
1921
/**
2022
* Projection consists of a mapping of names to evaluators built from the projection in the Bullet query.
2123
*
@@ -48,7 +50,7 @@ public BulletRecord project(BulletRecord record, BulletRecordProvider provider)
4850
evaluators.forEach((name, evaluator) -> {
4951
try {
5052
TypedObject value = evaluator.evaluate(record);
51-
if (!value.isNull()) {
53+
if (!isNull(value)) {
5254
projected.typedSet(name, value);
5355
}
5456
} catch (Exception ignored) {
@@ -68,7 +70,7 @@ public BulletRecord project(BulletRecord record) {
6870
evaluators.forEach((name, evaluator) -> {
6971
try {
7072
TypedObject value = evaluator.evaluate(record);
71-
if (!value.isNull()) {
73+
if (!isNull(value)) {
7274
map.put(name, value);
7375
}
7476
} catch (Exception ignored) {

src/main/java/com/yahoo/bullet/querying/evaluators/BinaryOperations.java

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
import java.util.stream.Collectors;
2222
import java.util.stream.IntStream;
2323

24+
import static com.yahoo.bullet.common.Utilities.isNull;
25+
2426
/**
2527
* Binary operations used by BinaryEvaluator.
2628
*/
@@ -296,15 +298,15 @@ static TypedObject notIn(Evaluator left, Evaluator right, BulletRecord record) {
296298

297299
static TypedObject and(Evaluator left, Evaluator right, BulletRecord record) {
298300
TypedObject leftValue = left.evaluate(record);
299-
if (!leftValue.isNull() && !((Boolean) leftValue.forceCast(Type.BOOLEAN).getValue())) {
301+
if (!isNull(leftValue) && !((Boolean) leftValue.forceCast(Type.BOOLEAN).getValue())) {
300302
return TypedObject.FALSE;
301303
}
302304
TypedObject rightValue = right.evaluate(record);
303-
if (rightValue.isNull()) {
305+
if (isNull(rightValue)) {
304306
return TypedObject.NULL;
305307
} else if (!((Boolean) rightValue.forceCast(Type.BOOLEAN).getValue())) {
306308
return TypedObject.FALSE;
307-
} else if (leftValue.isNull()) {
309+
} else if (isNull(leftValue)) {
308310
return TypedObject.NULL;
309311
} else {
310312
return TypedObject.TRUE;
@@ -313,15 +315,15 @@ static TypedObject and(Evaluator left, Evaluator right, BulletRecord record) {
313315

314316
static TypedObject or(Evaluator left, Evaluator right, BulletRecord record) {
315317
TypedObject leftValue = left.evaluate(record);
316-
if (!leftValue.isNull() && (Boolean) leftValue.forceCast(Type.BOOLEAN).getValue()) {
318+
if (!isNull(leftValue) && (Boolean) leftValue.forceCast(Type.BOOLEAN).getValue()) {
317319
return TypedObject.TRUE;
318320
}
319321
TypedObject rightValue = right.evaluate(record);
320-
if (rightValue.isNull()) {
322+
if (isNull(rightValue)) {
321323
return TypedObject.NULL;
322324
} else if ((Boolean) rightValue.forceCast(Type.BOOLEAN).getValue()) {
323325
return TypedObject.TRUE;
324-
} else if (leftValue.isNull()) {
326+
} else if (isNull(leftValue)) {
325327
return TypedObject.NULL;
326328
} else {
327329
return TypedObject.FALSE;
@@ -348,11 +350,11 @@ static TypedObject filter(Evaluator left, Evaluator right, BulletRecord record)
348350

349351
private static TypedObject checkNull(Evaluator left, Evaluator right, BulletRecord record, BiFunction<TypedObject, TypedObject, TypedObject> operator) {
350352
TypedObject leftValue = left.evaluate(record);
351-
if (leftValue.isNull()) {
353+
if (isNull(leftValue)) {
352354
return TypedObject.NULL;
353355
}
354356
TypedObject rightValue = right.evaluate(record);
355-
if (rightValue.isNull()) {
357+
if (isNull(rightValue)) {
356358
return TypedObject.NULL;
357359
}
358360
return operator.apply(leftValue, rightValue);

src/main/java/com/yahoo/bullet/querying/evaluators/NAryOperations.java

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
import java.util.List;
2020
import java.util.Map;
2121

22+
import static com.yahoo.bullet.common.Utilities.isNull;
23+
2224
public class NAryOperations {
2325
@FunctionalInterface
2426
public interface NAryOperator extends Serializable {
@@ -41,7 +43,7 @@ static TypedObject allMatch(List<Evaluator> evaluators, BulletRecord record) {
4143
boolean containsNull = false;
4244
for (Evaluator evaluator : evaluators) {
4345
TypedObject value = evaluator.evaluate(record);
44-
if (value.isNull()) {
46+
if (isNull(value)) {
4547
containsNull = true;
4648
} else if (!((Boolean) value.forceCast(Type.BOOLEAN).getValue())) {
4749
return TypedObject.FALSE;
@@ -54,7 +56,7 @@ static TypedObject anyMatch(List<Evaluator> evaluators, BulletRecord record) {
5456
boolean containsNull = false;
5557
for (Evaluator evaluator : evaluators) {
5658
TypedObject value = evaluator.evaluate(record);
57-
if (value.isNull()) {
59+
if (isNull(value)) {
5860
containsNull = true;
5961
} else if ((Boolean) value.forceCast(Type.BOOLEAN).getValue()) {
6062
return TypedObject.TRUE;
@@ -65,13 +67,13 @@ static TypedObject anyMatch(List<Evaluator> evaluators, BulletRecord record) {
6567

6668
static TypedObject ternary(List<Evaluator> evaluators, BulletRecord record) {
6769
TypedObject condition = evaluators.get(0).evaluate(record);
68-
return !condition.isNull() && (Boolean) condition.getValue() ? evaluators.get(1).evaluate(record) :
69-
evaluators.get(2).evaluate(record);
70+
return !isNull(condition) && (Boolean) condition.getValue() ? evaluators.get(1).evaluate(record) :
71+
evaluators.get(2).evaluate(record);
7072
}
7173

7274
static TypedObject between(List<Evaluator> evaluators, BulletRecord record) {
7375
TypedObject valueArg = evaluators.get(0).evaluate(record);
74-
if (valueArg.isNull()) {
76+
if (isNull(valueArg)) {
7577
return TypedObject.NULL;
7678
}
7779
if (Type.isNumeric(valueArg.getType())) {
@@ -80,11 +82,11 @@ static TypedObject between(List<Evaluator> evaluators, BulletRecord record) {
8082
TypedObject upperArg = evaluators.get(2).evaluate(record);
8183
Number lower = (Number) lowerArg.getValue();
8284
Number upper = (Number) upperArg.getValue();
83-
if (lowerArg.isNull() && upperArg.isNull()) {
85+
if (lower == null && upper == null) {
8486
return TypedObject.NULL;
85-
} else if (lowerArg.isNull()) {
87+
} else if (lower == null) {
8688
return upper.doubleValue() < value ? TypedObject.FALSE : TypedObject.NULL;
87-
} else if (upperArg.isNull()) {
89+
} else if (upper == null) {
8890
return value < lower.doubleValue() ? TypedObject.FALSE : TypedObject.NULL;
8991
}
9092
return TypedObject.valueOf(lower.doubleValue() <= value && value <= upper.doubleValue());
@@ -94,11 +96,11 @@ static TypedObject between(List<Evaluator> evaluators, BulletRecord record) {
9496
TypedObject upperArg = evaluators.get(2).evaluate(record);
9597
String lower = (String) lowerArg.getValue();
9698
String upper = (String) upperArg.getValue();
97-
if (lowerArg.isNull() && upperArg.isNull()) {
99+
if (lower == null && upper == null) {
98100
return TypedObject.NULL;
99-
} else if (lowerArg.isNull()) {
101+
} else if (lower == null) {
100102
return upper.compareTo(value) < 0 ? TypedObject.FALSE : TypedObject.NULL;
101-
} else if (upperArg.isNull()) {
103+
} else if (upper == null) {
102104
return value.compareTo(lower) < 0 ? TypedObject.FALSE : TypedObject.NULL;
103105
}
104106
return TypedObject.valueOf(lower.compareTo(value) <= 0 && value.compareTo(upper) <= 0);
@@ -115,17 +117,17 @@ static TypedObject notBetween(List<Evaluator> evaluators, BulletRecord record) {
115117

116118
static TypedObject substring(List<Evaluator> evaluators, BulletRecord record) {
117119
TypedObject stringArg = evaluators.get(0).evaluate(record);
118-
if (stringArg.isNull()) {
120+
if (isNull(stringArg)) {
119121
return TypedObject.NULL;
120122
}
121123
TypedObject startArg = evaluators.get(1).evaluate(record);
122-
if (startArg.isNull()) {
124+
if (isNull(startArg)) {
123125
return TypedObject.NULL;
124126
}
125127
TypedObject lengthArg = null;
126128
if (evaluators.size() > 2) {
127129
lengthArg = evaluators.get(2).evaluate(record);
128-
if (lengthArg.isNull()) {
130+
if (isNull(lengthArg)) {
129131
return TypedObject.NULL;
130132
}
131133
}
@@ -157,18 +159,18 @@ static TypedObject substring(List<Evaluator> evaluators, BulletRecord record) {
157159
static TypedObject unixTimestamp(List<Evaluator> evaluators, BulletRecord record) {
158160
if (evaluators.size() == 1) {
159161
TypedObject dateArg = evaluators.get(0).evaluate(record);
160-
if (dateArg.isNull()) {
162+
if (isNull(dateArg)) {
161163
return TypedObject.NULL;
162164
}
163165
Timestamp timestamp = Timestamp.valueOf((String) dateArg.getValue());
164166
return TypedObject.valueOf(timestamp.toLocalDateTime().toEpochSecond(ZoneOffset.UTC));
165167
} else if (evaluators.size() == 2) {
166168
TypedObject dateArg = evaluators.get(0).evaluate(record);
167-
if (dateArg.isNull()) {
169+
if (isNull(dateArg)) {
168170
return TypedObject.NULL;
169171
}
170172
TypedObject patternArg = evaluators.get(1).evaluate(record);
171-
if (patternArg.isNull()) {
173+
if (isNull(patternArg)) {
172174
return TypedObject.NULL;
173175
}
174176
// First argument can be a number

src/main/java/com/yahoo/bullet/querying/evaluators/UnaryOperations.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
*/
66
package com.yahoo.bullet.querying.evaluators;
77

8+
import com.yahoo.bullet.common.Utilities;
89
import com.yahoo.bullet.query.expressions.Operation;
910
import com.yahoo.bullet.record.BulletRecord;
1011
import com.yahoo.bullet.typesystem.Type;
@@ -46,11 +47,11 @@ static TypedObject sizeOf(Evaluator evaluator, BulletRecord record) {
4647
}
4748

4849
static TypedObject isNull(Evaluator evaluator, BulletRecord record) {
49-
return TypedObject.valueOf(evaluator.evaluate(record).isNull());
50+
return TypedObject.valueOf(Utilities.isNull(evaluator.evaluate(record)));
5051
}
5152

5253
static TypedObject isNotNull(Evaluator evaluator, BulletRecord record) {
53-
return TypedObject.valueOf(!evaluator.evaluate(record).isNull());
54+
return TypedObject.valueOf(!Utilities.isNull(evaluator.evaluate(record)));
5455
}
5556

5657
static TypedObject trim(Evaluator evaluator, BulletRecord record) {
@@ -92,7 +93,7 @@ static TypedObject abs(Evaluator evaluator, BulletRecord record) {
9293

9394
private static TypedObject checkNull(Evaluator evaluator, BulletRecord record, Function<TypedObject, TypedObject> operator) {
9495
TypedObject value = evaluator.evaluate(record);
95-
if (value.isNull()) {
96+
if (Utilities.isNull(value)) {
9697
return TypedObject.NULL;
9798
}
9899
return operator.apply(value);

src/main/java/com/yahoo/bullet/querying/partitioning/SimpleEqualityPartitioner.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626
import java.util.stream.Collectors;
2727
import java.util.stream.IntStream;
2828

29+
import static com.yahoo.bullet.common.Utilities.isNull;
30+
2931
/**
3032
* This partitioner uses a list of fields to partition. If fields A and B are used to partition, this partitioner
3133
* tries to make sure that queries with equality filters on A and/or B are partitioned appropriately and makes sure
@@ -186,7 +188,7 @@ private Map<String, String> getFieldValues(BulletRecord record) {
186188
Map<String, String> fieldValues = new HashMap<>();
187189
for (String field : fields) {
188190
TypedObject value = record.typedExtract(field);
189-
fieldValues.put(field, value.isNull() ? NULL : makeKeyEntry(value.getValue().toString()));
191+
fieldValues.put(field, isNull(value) ? NULL : makeKeyEntry(value.getValue().toString()));
190192
}
191193
return fieldValues;
192194
}

0 commit comments

Comments
 (0)