This is an automated email from the ASF dual-hosted git repository.
cwylie pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-druid.git
The following commit(s) were added to refs/heads/master by this push:
new 5464c89 Add array_slice and array_unshift function expr (#7950)
5464c89 is described below
commit 5464c8938f32a7a3338a7e87dbaf0fc9236db940
Author: Xue Yu <[email protected]>
AuthorDate: Thu Jun 27 07:56:09 2019 +0800
Add array_slice and array_unshift function expr (#7950)
* add array_slice and array_unshift function expr
* feedback address
---
.../java/org/apache/druid/math/expr/Function.java | 137 ++++++++++++++++++++-
.../org/apache/druid/math/expr/FunctionTest.java | 20 +++
docs/content/misc/math-expr.md | 2 +
3 files changed, 158 insertions(+), 1 deletion(-)
diff --git a/core/src/main/java/org/apache/druid/math/expr/Function.java
b/core/src/main/java/org/apache/druid/math/expr/Function.java
index 65643e2..c81790b 100644
--- a/core/src/main/java/org/apache/druid/math/expr/Function.java
+++ b/core/src/main/java/org/apache/druid/math/expr/Function.java
@@ -258,7 +258,7 @@ interface Function
public void validateArguments(List<Expr> args)
{
if (args.size() != 2) {
- throw new IAE("Function[%s] needs 2 argument", name());
+ throw new IAE("Function[%s] needs 2 arguments", name());
}
}
@@ -2062,4 +2062,139 @@ interface Function
return ExprEval.bestEffortOf(any);
}
}
+
+ class ArraySliceFunction implements Function
+ {
+ @Override
+ public String name()
+ {
+ return "array_slice";
+ }
+
+ @Override
+ public void validateArguments(List<Expr> args)
+ {
+ if (args.size() != 2 && args.size() != 3) {
+ throw new IAE("Function[%s] needs 2 or 3 arguments", name());
+ }
+ }
+
+ @Override
+ public ExprEval apply(List<Expr> args, Expr.ObjectBinding bindings)
+ {
+ final ExprEval expr = args.get(0).eval(bindings);
+ final Object[] array = expr.asArray();
+ if (array == null) {
+ return ExprEval.of(null);
+ }
+
+ final int start = args.get(1).eval(bindings).asInt();
+ int end = array.length;
+ if (args.size() == 3) {
+ end = args.get(2).eval(bindings).asInt();
+ }
+
+ if (start < 0 || start > array.length || start > end) {
+ // Arrays.copyOfRange will throw exception in these cases
+ return ExprEval.of(null);
+ }
+
+ switch (expr.type()) {
+ case STRING:
+ case STRING_ARRAY:
+ return
ExprEval.ofStringArray(Arrays.copyOfRange(expr.asStringArray(), start, end));
+ case LONG:
+ case LONG_ARRAY:
+ return ExprEval.ofLongArray(Arrays.copyOfRange(expr.asLongArray(),
start, end));
+ case DOUBLE:
+ case DOUBLE_ARRAY:
+ return
ExprEval.ofDoubleArray(Arrays.copyOfRange(expr.asDoubleArray(), start, end));
+ }
+ throw new RE("Unable to slice to unknown type %s", expr.type());
+ }
+
+ @Override
+ public Set<Expr> getScalarInputs(List<Expr> args)
+ {
+ if (args.size() == 3) {
+ return ImmutableSet.of(args.get(1), args.get(2));
+ } else {
+ return ImmutableSet.of(args.get(1));
+ }
+ }
+
+ @Override
+ public Set<Expr> getArrayInputs(List<Expr> args)
+ {
+ return ImmutableSet.of(args.get(0));
+ }
+ }
+
+ class ArrayPrependFunction implements Function
+ {
+ @Override
+ public String name()
+ {
+ return "array_prepend";
+ }
+
+ @Override
+ public void validateArguments(List<Expr> args)
+ {
+ if (args.size() != 2) {
+ throw new IAE("Function[%s] needs 2 arguments", name());
+ }
+ }
+
+ @Override
+ public ExprEval apply(List<Expr> args, Expr.ObjectBinding bindings)
+ {
+ final ExprEval scalarExpr = args.get(0).eval(bindings);
+ final ExprEval arrayExpr = args.get(1).eval(bindings);
+ if (arrayExpr.asArray() == null) {
+ return ExprEval.of(null);
+ }
+ switch (arrayExpr.type()) {
+ case STRING:
+ case STRING_ARRAY:
+ return ExprEval.ofStringArray(this.prepend(scalarExpr.asString(),
arrayExpr.asStringArray()).toArray(String[]::new));
+ case LONG:
+ case LONG_ARRAY:
+ return ExprEval.ofLongArray(
+ this.prepend(
+ scalarExpr.isNumericNull() ? null : scalarExpr.asLong(),
+ arrayExpr.asLongArray()).toArray(Long[]::new
+ )
+ );
+ case DOUBLE:
+ case DOUBLE_ARRAY:
+ return ExprEval.ofDoubleArray(
+ this.prepend(
+ scalarExpr.isNumericNull() ? null : scalarExpr.asDouble(),
+ arrayExpr.asDoubleArray()).toArray(Double[]::new
+ )
+ );
+ }
+
+ throw new RE("Unable to prepend to unknown type %s", arrayExpr.type());
+ }
+
+ private <T> Stream<T> prepend(T val, T[] array)
+ {
+ List<T> l = new ArrayList<>(Arrays.asList(array));
+ l.add(0, val);
+ return l.stream();
+ }
+ @Override
+ public Set<Expr> getScalarInputs(List<Expr> args)
+ {
+ return ImmutableSet.of(args.get(0));
+ }
+
+ @Override
+ public Set<Expr> getArrayInputs(List<Expr> args)
+ {
+ return ImmutableSet.of(args.get(1));
+ }
+ }
}
diff --git a/core/src/test/java/org/apache/druid/math/expr/FunctionTest.java
b/core/src/test/java/org/apache/druid/math/expr/FunctionTest.java
index ec0884c..51df20c 100644
--- a/core/src/test/java/org/apache/druid/math/expr/FunctionTest.java
+++ b/core/src/test/java/org/apache/druid/math/expr/FunctionTest.java
@@ -260,6 +260,26 @@ public class FunctionTest
assertExpr("cast(['1.0', '2.0', '3.0'], 'LONG_ARRAY')", new Long[]{1L, 2L,
3L});
}
+ @Test
+ public void testArraySlice()
+ {
+ assertExpr("array_slice([1, 2, 3, 4], 1, 3)", new Long[] {2L, 3L});
+ assertExpr("array_slice([1.0, 2.1, 3.2, 4.3], 2)", new Double[] {3.2,
4.3});
+ assertExpr("array_slice(['a', 'b', 'c', 'd'], 4, 6)", new String[] {null,
null});
+ assertExpr("array_slice([1, 2, 3, 4], 2, 2)", new Long[] {});
+ assertExpr("array_slice([1, 2, 3, 4], 5, 7)", null);
+ assertExpr("array_slice([1, 2, 3, 4], 2, 1)", null);
+ }
+
+ @Test
+ public void testArrayPrepend()
+ {
+ assertExpr("array_prepend(4, [1, 2, 3])", new Long[]{4L, 1L, 2L, 3L});
+ assertExpr("array_prepend('bar', [1, 2, 3])", new Long[]{null, 1L, 2L,
3L});
+ assertExpr("array_prepend(1, [])", new String[]{"1"});
+ assertExpr("array_prepend(1, cast([], 'LONG_ARRAY'))", new Long[]{1L});
+ }
+
private void assertExpr(final String expression, final Object expectedResult)
{
final Expr expr = Parser.parse(expression, ExprMacroTable.nil());
diff --git a/docs/content/misc/math-expr.md b/docs/content/misc/math-expr.md
index 57427a9..9a686a1 100644
--- a/docs/content/misc/math-expr.md
+++ b/docs/content/misc/math-expr.md
@@ -179,6 +179,8 @@ See javadoc of java.lang.Math for detailed explanation for
each function.
| `array_concat(arr1,arr2)` | concatenates 2 arrays, the resulting array type
determined by the type of the first array |
| `array_to_string(arr,str)` | joins all elements of arr by the delimiter
specified by str |
| `string_to_array(str1,str2)` | splits str1 into an array on the delimiter
specified by str2 |
+| `array_slice(arr,start,end)` | return the subarray of arr from the 0 based
index start(inclusive) to end(exclusive), or `null`, if start is less than 0,
greater than length of arr or less than end|
+| `array_prepend(expr,arr)` | adds expr to arr at the beginning, the resulting
array type determined by the type of the array |
## Apply Functions
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]