Skip to content

Commit a0a1e01

Browse files
authored
closes #54. Transient fields (#56)
1 parent 8590015 commit a0a1e01

File tree

17 files changed

+224
-85
lines changed

17 files changed

+224
-85
lines changed

src/main/java/com/yahoo/bullet/parsing/BinaryExpression.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,10 @@
1212
import lombok.Setter;
1313

1414
import java.util.Collections;
15+
import java.util.HashSet;
1516
import java.util.List;
1617
import java.util.Optional;
18+
import java.util.Set;
1719

1820
import static com.yahoo.bullet.common.BulletError.makeError;
1921

@@ -39,6 +41,13 @@ public BinaryExpression() {
3941
right = null;
4042
}
4143

44+
@Override
45+
public Set<String> getRequiredFields() {
46+
Set<String> result = new HashSet<>(left.getRequiredFields());
47+
result.addAll(right.getRequiredFields());
48+
return result;
49+
}
50+
4251
@Override
4352
public String toString() {
4453
return "{" + super.toString() + ", left: " + left + ", right: " + right + ", type: " + type + "}";

src/main/java/com/yahoo/bullet/parsing/Expression.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import lombok.Setter;
1313

1414
import java.util.List;
15+
import java.util.Set;
1516

1617
import static java.util.Arrays.asList;
1718

@@ -36,6 +37,13 @@ public enum Operation {
3637

3738
public static final String OPERATION_FIELD = "operation";
3839

40+
/**
41+
* Return a {@link Set} of required fields to compute this expression.
42+
*
43+
* @return A {@link Set} of required fields.
44+
*/
45+
abstract public Set<String> getRequiredFields();
46+
3947
@Override
4048
public String toString() {
4149
return OPERATION_FIELD + ": " + operation;

src/main/java/com/yahoo/bullet/parsing/LeafExpression.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import java.util.Collections;
1515
import java.util.List;
1616
import java.util.Optional;
17+
import java.util.Set;
1718

1819
import static com.yahoo.bullet.common.BulletError.makeError;
1920

@@ -37,6 +38,11 @@ public LeafExpression() {
3738
value = null;
3839
}
3940

41+
@Override
42+
public Set<String> getRequiredFields() {
43+
return value.getKind() == Value.Kind.FIELD ? Collections.singleton(value.getValue()) : Collections.emptySet();
44+
}
45+
4046
@Override
4147
public String toString() {
4248
return "{" + super.toString() + ", value: " + value + "}";

src/main/java/com/yahoo/bullet/parsing/OrderBy.java

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
import com.google.gson.annotations.Expose;
99
import com.yahoo.bullet.common.BulletError;
10+
import lombok.AllArgsConstructor;
1011
import lombok.Getter;
1112
import lombok.Setter;
1213

@@ -23,25 +24,45 @@ public enum Direction {
2324
DESC
2425
}
2526

27+
@Getter @AllArgsConstructor
28+
public static class SortItem {
29+
@Expose
30+
private String field;
31+
@Expose
32+
private Direction direction;
33+
34+
/**
35+
* Default constructor. GSON recommended
36+
*/
37+
public SortItem() {
38+
field = null;
39+
direction = Direction.ASC;
40+
}
41+
42+
@Override
43+
public String toString() {
44+
return "{field: " + field + ", direction: " + direction + "}";
45+
}
46+
}
47+
2648
@Expose
27-
private List<String> fields;
28-
@Expose
29-
private Direction direction;
49+
private List<SortItem> fields;
3050

3151
public static final BulletError ORDERBY_REQUIRES_FIELDS_ERROR =
3252
makeError("The ORDERBY post aggregation needs at least one field", "Please add fields.");
53+
public static final BulletError ORDERBY_REQUIRES_NON_EMPTY_FIELDS_ERROR =
54+
makeError("The fields in ORDERBY post aggregation must not be empty", "Please add non-empty fields.");
3355

3456
/**
3557
* Default constructor. GSON recommended
3658
*/
3759
public OrderBy() {
3860
fields = null;
39-
direction = Direction.ASC;
4061
}
4162

4263
@Override
4364
public String toString() {
44-
return "{type: " + type + ", fields: " + fields + ", direction: " + direction + "}";
65+
return "{type: " + type + ", fields: " + fields + "}";
4566
}
4667

4768
@Override
@@ -53,6 +74,9 @@ public Optional<List<BulletError>> initialize() {
5374
if (fields == null || fields.isEmpty()) {
5475
return Optional.of(Collections.singletonList(ORDERBY_REQUIRES_FIELDS_ERROR));
5576
}
77+
if (fields.stream().anyMatch(sortItem -> sortItem.getField() == null || sortItem.getField().isEmpty())) {
78+
return Optional.of(Collections.singletonList(ORDERBY_REQUIRES_NON_EMPTY_FIELDS_ERROR));
79+
}
5680
return Optional.empty();
5781
}
5882

src/main/java/com/yahoo/bullet/parsing/Query.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ public class Query implements Configurable, Initializable {
4242
"Change your aggregation type or your window emit type to \"TIME\"");
4343
public static final BulletError NO_RAW_ALL = makeError("The \"RAW\" aggregation types cannot have window include \"ALL\"",
4444
"Change your aggregation type or your window include type");
45+
public static final BulletError AT_MOST_ONE_ORDERBY = makeError("The post aggregations cannot have multiple \"ORDERBY\"",
46+
"Change your post aggregations to keep at most one \"ORDERBY\"");
4547
/**
4648
* Default constructor. GSON recommended.
4749
*/
@@ -99,6 +101,9 @@ public Optional<List<BulletError>> initialize() {
99101
aggregation.initialize().ifPresent(errors::addAll);
100102

101103
if (postAggregations != null) {
104+
if (postAggregations.stream().filter(postAggregation -> postAggregation.getType() == PostAggregation.Type.ORDER_BY).count() > 1) {
105+
errors.add(AT_MOST_ONE_ORDERBY);
106+
}
102107
postAggregations.forEach(p -> p.initialize().ifPresent(errors::addAll));
103108
}
104109

src/main/java/com/yahoo/bullet/postaggregations/ComputationStrategy.java

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,46 +17,53 @@
1717
import lombok.AllArgsConstructor;
1818
import lombok.extern.slf4j.Slf4j;
1919

20+
import java.util.Set;
21+
2022
import static com.yahoo.bullet.common.Utilities.extractTypedObject;
2123

2224
@Slf4j @AllArgsConstructor
2325
public class ComputationStrategy implements PostStrategy {
24-
private Computation postAggregation;
26+
private Computation computation;
2527

2628
@Override
2729
public Clip execute(Clip clip) {
2830
clip.getRecords().forEach(r -> {
2931
try {
30-
TypedObject result = calculate(postAggregation.getExpression(), r);
32+
TypedObject result = calculate(computation.getExpression(), r);
3133
switch (result.getType()) {
3234
case INTEGER:
33-
r.setInteger(postAggregation.getNewName(), (Integer) result.getValue());
35+
r.setInteger(computation.getNewName(), (Integer) result.getValue());
3436
break;
3537
case LONG:
36-
r.setLong(postAggregation.getNewName(), (Long) result.getValue());
38+
r.setLong(computation.getNewName(), (Long) result.getValue());
3739
break;
3840
case DOUBLE:
39-
r.setDouble(postAggregation.getNewName(), (Double) result.getValue());
41+
r.setDouble(computation.getNewName(), (Double) result.getValue());
4042
break;
4143
case FLOAT:
42-
r.setFloat(postAggregation.getNewName(), (Float) result.getValue());
44+
r.setFloat(computation.getNewName(), (Float) result.getValue());
4345
break;
4446
case BOOLEAN:
45-
r.setBoolean(postAggregation.getNewName(), (Boolean) result.getValue());
47+
r.setBoolean(computation.getNewName(), (Boolean) result.getValue());
4648
break;
4749
case STRING:
48-
r.setString(postAggregation.getNewName(), (String) result.getValue());
50+
r.setString(computation.getNewName(), (String) result.getValue());
4951
break;
5052
}
5153
} catch (RuntimeException e) {
5254
// Ignore the exception and skip setting the field.
53-
log.error("Unable to calculate the expression: " + postAggregation.getExpression());
55+
log.error("Unable to calculate the expression: " + computation.getExpression());
5456
log.error("Skip it due to: " + e);
5557
}
5658
});
5759
return clip;
5860
}
5961

62+
@Override
63+
public Set<String> getRequiredFields() {
64+
return computation.getExpression().getRequiredFields();
65+
}
66+
6067
private TypedObject calculateLeafExpression(LeafExpression expression, BulletRecord record) {
6168
Value value = expression.getValue();
6269
TypedObject result = null;

src/main/java/com/yahoo/bullet/postaggregations/OrderByStrategy.java

Lines changed: 15 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -9,47 +9,44 @@
99
import com.yahoo.bullet.record.BulletRecord;
1010
import com.yahoo.bullet.result.Clip;
1111
import com.yahoo.bullet.typesystem.TypedObject;
12+
import lombok.AllArgsConstructor;
1213
import lombok.extern.slf4j.Slf4j;
1314

1415
import java.util.List;
16+
import java.util.Set;
17+
import java.util.stream.Collectors;
1518

1619
import static com.yahoo.bullet.common.Utilities.extractTypedObject;
1720

18-
@Slf4j
21+
@Slf4j @AllArgsConstructor
1922
public class OrderByStrategy implements PostStrategy {
20-
private OrderBy postAggregation;
21-
private int multiplyingFactor;
22-
23-
/**
24-
* Contructor takes a {@link OrderBy} object.
25-
*
26-
* @param postAggregation The {@link OrderBy} object.
27-
*/
28-
public OrderByStrategy(OrderBy postAggregation) {
29-
this.postAggregation = postAggregation;
30-
multiplyingFactor = postAggregation.getDirection() == OrderBy.Direction.ASC ? 1 : -1;
31-
}
23+
private OrderBy orderBy;
3224

3325
@Override
3426
public Clip execute(Clip clip) {
3527
List<BulletRecord> records = clip.getRecords();
3628
records.sort((a, b) -> {
37-
for (String field : postAggregation.getFields()) {
38-
TypedObject typedObjectA = extractTypedObject(field, a);
39-
TypedObject typedObjectB = extractTypedObject(field, b);
29+
for (OrderBy.SortItem sortItem : orderBy.getFields()) {
30+
TypedObject typedObjectA = extractTypedObject(sortItem.getField(), a);
31+
TypedObject typedObjectB = extractTypedObject(sortItem.getField(), b);
4032
try {
4133
int compareValue = typedObjectA.compareTo(typedObjectB);
4234
if (compareValue != 0) {
43-
return multiplyingFactor * compareValue;
35+
return (sortItem.getDirection() == OrderBy.Direction.ASC ? 1 : -1) * compareValue;
4436
}
4537
} catch (RuntimeException e) {
4638
// Ignore the exception and skip this field.
47-
log.error("Unable to compare field " + field);
39+
log.error("Unable to compare field " + sortItem.getField());
4840
log.error("Skip it due to: " + e);
4941
}
5042
}
5143
return 0;
5244
});
5345
return clip;
5446
}
47+
48+
@Override
49+
public Set<String> getRequiredFields() {
50+
return orderBy.getFields().stream().map(OrderBy.SortItem::getField).collect(Collectors.toSet());
51+
}
5552
}

src/main/java/com/yahoo/bullet/postaggregations/PostStrategy.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
import java.util.List;
1313
import java.util.Optional;
14+
import java.util.Set;
1415

1516
public interface PostStrategy extends Initializable {
1617
/**
@@ -29,4 +30,11 @@ public interface PostStrategy extends Initializable {
2930
default Optional<List<BulletError>> initialize() {
3031
return Optional.empty();
3132
}
33+
34+
/**
35+
* Get the list of required fields.
36+
*
37+
* @return An @{link List} of fields.
38+
*/
39+
Set<String> getRequiredFields();
3240
}

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

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,24 +10,33 @@
1010
import com.yahoo.bullet.record.BulletRecordProvider;
1111
import lombok.extern.slf4j.Slf4j;
1212

13+
import java.util.HashMap;
1314
import java.util.Map;
1415

1516
import static com.yahoo.bullet.common.Utilities.splitField;
1617

1718
@Slf4j
1819
public class ProjectionOperations {
1920
/**
20-
* Projects the given {@link BulletRecord} based on the given {@link Projection}.
21+
* Projects the given {@link BulletRecord} based on the given fields.
2122
*
2223
* @param record The record to project.
2324
* @param projection The projection to apply.
25+
* @param transientFields The map of fields to apply.
2426
* @param provider A BulletRecordProvider to generate BulletRecords.
2527
* @return The projected record.
2628
*/
27-
public static BulletRecord project(BulletRecord record, Projection projection, BulletRecordProvider provider) {
28-
Map<String, String> fields = projection.getFields();
29+
public static BulletRecord project(BulletRecord record, Projection projection, Map<String, String> transientFields, BulletRecordProvider provider) {
30+
Map<String, String> fields = new HashMap<>();
31+
Map<String, String> projectionFields = projection.getFields();
32+
if (projectionFields != null) {
33+
fields.putAll(projectionFields);
34+
}
35+
if (transientFields != null) {
36+
fields.putAll(transientFields);
37+
}
2938
// Returning the record itself if no projections. The record itself should never be modified so it's ok.
30-
if (fields == null) {
39+
if (fields.isEmpty()) {
3140
return record;
3241
}
3342
// More efficient if fields << the fields in the BulletRecord

0 commit comments

Comments
 (0)