Skip to content

Commit 4229e56

Browse files
authored
Support SizeOf (#45)
1 parent e1ddc2d commit 4229e56

File tree

3 files changed

+47
-6
lines changed

3 files changed

+47
-6
lines changed

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ public enum Operation {
3939
LESS_EQUALS,
4040
@SerializedName("RLIKE")
4141
REGEX_LIKE,
42+
@SerializedName("SIZEOF")
43+
SIZE_OF,
4244
@SerializedName("AND")
4345
AND,
4446
@SerializedName("OR")
@@ -47,7 +49,7 @@ public enum Operation {
4749
NOT;
4850

4951
public static final List<String> LOGICALS = asList("AND", "OR", "NOT");
50-
public static final List<String> RELATIONALS = asList("==", "!=", ">=", "<=", ">", "<", "RLIKE");
52+
public static final List<String> RELATIONALS = asList("==", "!=", ">=", "<=", ">", "<", "RLIKE", "SIZEOF");
5153
}
5254

5355
@Expose

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

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

88
import com.yahoo.bullet.parsing.FilterClause;
99
import com.yahoo.bullet.parsing.LogicalClause;
10+
import com.yahoo.bullet.typesystem.Type;
1011
import com.yahoo.bullet.typesystem.TypedObject;
1112
import com.yahoo.bullet.parsing.Clause;
1213
import com.yahoo.bullet.record.BulletRecord;
@@ -57,6 +58,7 @@ public interface LogicalOperator extends BiPredicate<BulletRecord, Stream<Boolea
5758
private static final Comparator<TypedObject> GE = (t, s) -> s.anyMatch(i -> t.compareTo(i) >= 0);
5859
private static final Comparator<TypedObject> LE = (t, s) -> s.anyMatch(i -> t.compareTo(i) <= 0);
5960
private static final Comparator<Pattern> RLIKE = (t, s) -> s.map(p -> p.matcher(t.toString())).anyMatch(Matcher::matches);
61+
private static final Comparator<TypedObject> SIZEOF = (t, s) -> s.anyMatch(i -> sizeOf(t) == i.getValue());
6062
private static final LogicalOperator AND = (r, s) -> s.allMatch(Boolean::valueOf);
6163
private static final LogicalOperator OR = (r, s) -> s.anyMatch(Boolean::valueOf);
6264
private static final LogicalOperator NOT = (r, s) -> !s.findFirst().get();
@@ -71,6 +73,7 @@ public interface LogicalOperator extends BiPredicate<BulletRecord, Stream<Boolea
7173
COMPARATORS.put(Clause.Operation.LESS_EQUALS, isNotNullAnd(LE));
7274
}
7375
static final Comparator<Pattern> REGEX_LIKE = isNotNullAnd(RLIKE);
76+
static final Comparator<TypedObject> SIZE_OF = isNotNullAnd(SIZEOF);
7477
static final Map<Clause.Operation, LogicalOperator> LOGICAL_OPERATORS = new EnumMap<>(Clause.Operation.class);
7578
static {
7679
LOGICAL_OPERATORS.put(Clause.Operation.AND, AND);
@@ -95,16 +98,34 @@ private static <T> Comparator<T> isNotNullAnd(Comparator<T> comparator) {
9598
return (t, s) -> IS_NOT_NULL.test(t) && comparator.compare(t, s);
9699
}
97100

101+
private static Integer sizeOf(TypedObject object) {
102+
Object o = object.getValue();
103+
if (o instanceof List) {
104+
return List.class.cast(o).size();
105+
}
106+
if (o instanceof Map) {
107+
return Map.class.cast(o).size();
108+
}
109+
if (o instanceof String) {
110+
return String.class.cast(o).length();
111+
}
112+
return 1;
113+
}
114+
98115
private static boolean performRelational(BulletRecord record, FilterClause clause) {
99116
Clause.Operation operator = clause.getOperation();
100117
if (isEmpty(clause.getValues())) {
101118
return true;
102119
}
103120
TypedObject object = extractTypedObject(clause.getField(), record);
104-
if (operator == Clause.Operation.REGEX_LIKE) {
105-
return REGEX_LIKE.compare(object, clause.getPatterns().stream());
121+
switch (operator) {
122+
case REGEX_LIKE:
123+
return REGEX_LIKE.compare(object, clause.getPatterns().stream());
124+
case SIZE_OF:
125+
return SIZE_OF.compare(object, cast(new TypedObject(Type.INTEGER, 0), clause.getValues()));
126+
default:
127+
return COMPARATORS.get(operator).compare(object, cast(object, clause.getValues()));
106128
}
107-
return COMPARATORS.get(operator).compare(object, cast(object, clause.getValues()));
108129
}
109130

110131
private static boolean performLogical(BulletRecord record, LogicalClause clause) {

src/test/java/com/yahoo/bullet/querying/FilterOperationsTest.java

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,14 @@
1717
import org.testng.Assert;
1818
import org.testng.annotations.Test;
1919

20+
import java.util.ArrayList;
2021
import java.util.Arrays;
22+
import java.util.HashMap;
2123
import java.util.List;
2224
import java.util.regex.Pattern;
2325
import java.util.stream.Collectors;
2426
import java.util.stream.Stream;
2527

26-
import static com.yahoo.bullet.parsing.FilterUtils.getFieldFilter;
27-
import static com.yahoo.bullet.parsing.FilterUtils.makeClause;
2828
import static com.yahoo.bullet.parsing.Clause.Operation.AND;
2929
import static com.yahoo.bullet.parsing.Clause.Operation.EQUALS;
3030
import static com.yahoo.bullet.parsing.Clause.Operation.GREATER_EQUALS;
@@ -35,6 +35,9 @@
3535
import static com.yahoo.bullet.parsing.Clause.Operation.NOT_EQUALS;
3636
import static com.yahoo.bullet.parsing.Clause.Operation.OR;
3737
import static com.yahoo.bullet.parsing.Clause.Operation.REGEX_LIKE;
38+
import static com.yahoo.bullet.parsing.Clause.Operation.SIZE_OF;
39+
import static com.yahoo.bullet.parsing.FilterUtils.getFieldFilter;
40+
import static com.yahoo.bullet.parsing.FilterUtils.makeClause;
3841
import static java.util.Arrays.asList;
3942
import static java.util.Collections.emptyList;
4043
import static java.util.Collections.singletonList;
@@ -352,6 +355,21 @@ public void testBadRegex() {
352355
Assert.assertFalse(FilterOperations.perform(RecordBox.get().add("id", "*TEST*").getRecord(), clause));
353356
}
354357

358+
@Test
359+
public void testSizeOf() {
360+
FilterClause clause = getFieldFilter("id", SIZE_OF, "1", "2");
361+
Assert.assertFalse(FilterOperations.perform(RecordBox.get().getRecord(), clause));
362+
Assert.assertTrue(FilterOperations.perform(RecordBox.get().add("id", 1).getRecord(), clause));
363+
Assert.assertTrue(FilterOperations.perform(RecordBox.get().add("id", "12").getRecord(), clause));
364+
Assert.assertFalse(FilterOperations.perform(RecordBox.get().add("id", "123").getRecord(), clause));
365+
Assert.assertFalse(FilterOperations.perform(RecordBox.get().getRecord().setListOfStringMap("id", new ArrayList<>()), clause));
366+
Assert.assertTrue(FilterOperations.perform(RecordBox.get().addList("id", singletonMap("1", 1)).getRecord(), clause));
367+
Assert.assertTrue(FilterOperations.perform(RecordBox.get().addList("id", singletonMap("1", 1), singletonMap("2", 2)).getRecord(), clause));
368+
Assert.assertFalse(FilterOperations.perform(RecordBox.get().addList("id", singletonMap("1", 1), singletonMap("2", 2), singletonMap("3", 3)).getRecord(), clause));
369+
Assert.assertFalse(FilterOperations.perform(RecordBox.get().getRecord().setStringMap("id", new HashMap<>()), clause));
370+
Assert.assertTrue(FilterOperations.perform(RecordBox.get().addMap("id", Pair.of("1", 1), Pair.of("2", 2)).getRecord(), clause));
371+
}
372+
355373
@Test
356374
public void testComparisonNestedField() {
357375
FilterClause clause = getFieldFilter("demographic_map.age", GREATER_THAN, "30");

0 commit comments

Comments
 (0)