Skip to content
This repository has been archived by the owner on Aug 2, 2022. It is now read-only.

Commit

Permalink
Support mathematical functions rand and constants e, pi (#591)
Browse files Browse the repository at this point in the history
* support e, pi, rand

* updated doc

* update

* update

* update
  • Loading branch information
chloe-zh authored Jul 22, 2020
1 parent 7372a44 commit 78a51a4
Show file tree
Hide file tree
Showing 12 changed files with 266 additions and 33 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
import com.amazon.opendistroforelasticsearch.sql.expression.aggregation.Aggregator;
import com.amazon.opendistroforelasticsearch.sql.expression.function.BuiltinFunctionName;
import com.amazon.opendistroforelasticsearch.sql.expression.function.BuiltinFunctionRepository;
import com.amazon.opendistroforelasticsearch.sql.expression.function.FunctionName;
import java.util.Arrays;
import lombok.RequiredArgsConstructor;

Expand Down Expand Up @@ -81,6 +80,10 @@ public FunctionExpression crc32(Expression... expressions) {
return function(BuiltinFunctionName.CRC32, expressions);
}

public FunctionExpression euler(Expression... expressions) {
return function(BuiltinFunctionName.E, expressions);
}

public FunctionExpression exp(Expression... expressions) {
return function(BuiltinFunctionName.EXP, expressions);
}
Expand Down Expand Up @@ -109,6 +112,10 @@ public FunctionExpression mod(Expression... expressions) {
return function(BuiltinFunctionName.MOD, expressions);
}

public FunctionExpression pi(Expression... expressions) {
return function(BuiltinFunctionName.PI, expressions);
}

public FunctionExpression pow(Expression... expressions) {
return function(BuiltinFunctionName.POW, expressions);
}
Expand All @@ -117,6 +124,10 @@ public FunctionExpression power(Expression... expressions) {
return function(BuiltinFunctionName.POWER, expressions);
}

public FunctionExpression rand(Expression... expressions) {
return function(BuiltinFunctionName.RAND, expressions);
}

public FunctionExpression round(Expression... expressions) {
return function(BuiltinFunctionName.ROUND, expressions);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,18 @@ public enum BuiltinFunctionName {
CEILING(FunctionName.of("ceiling")),
CONV(FunctionName.of("conv")),
CRC32(FunctionName.of("crc32")),
E(FunctionName.of("e")),
EXP(FunctionName.of("exp")),
FLOOR(FunctionName.of("floor")),
LN(FunctionName.of("ln")),
LOG(FunctionName.of("log")),
LOG10(FunctionName.of("log10")),
LOG2(FunctionName.of("log2")),
MOD(FunctionName.of("mod")),
PI(FunctionName.of("pi")),
POW(FunctionName.of("pow")),
POWER(FunctionName.of("power")),
RAND(FunctionName.of("rand")),
ROUND(FunctionName.of("round")),
SIGN(FunctionName.of("sign")),
SQRT(FunctionName.of("sqrt")),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import java.util.function.BiFunction;
import java.util.function.BiPredicate;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import lombok.experimental.UtilityClass;

Expand Down Expand Up @@ -257,6 +258,36 @@ public String toString() {
};
}

/**
* Construct {@link FunctionBuilder} which call function with no argument.
*
* @param functionName function name
* @param function {@link Function}
* @param returnType return type
* @param <T> the type of the result to the function
* @return {@link FunctionBuilder}
*/
public static <T> FunctionBuilder noArgFunction(FunctionName functionName,
Supplier<T> function,
ExprCoreType returnType) {
return arguments -> new FunctionExpression(functionName, arguments) {
@Override
public ExprValue valueOf(Environment<Expression, ExprValue> valueEnv) {
return ExprValueUtils.fromObjectValue(function.get());
}

@Override
public ExprType type() {
return returnType;
}

@Override
public String toString() {
return String.format("%s()", functionName);
}
};
}

/**
* String comparator.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
package com.amazon.opendistroforelasticsearch.sql.expression.operator.arthmetic;

import static com.amazon.opendistroforelasticsearch.sql.expression.operator.OperatorUtils.doubleArgFunc;
import static com.amazon.opendistroforelasticsearch.sql.expression.operator.OperatorUtils.noArgFunction;
import static com.amazon.opendistroforelasticsearch.sql.expression.operator.OperatorUtils.tripleArgFunc;
import static com.amazon.opendistroforelasticsearch.sql.expression.operator.OperatorUtils.unaryOperator;

Expand All @@ -31,7 +32,9 @@
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Arrays;
import java.util.Collections;
import java.util.Map;
import java.util.Random;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.zip.CRC32;
Expand All @@ -50,6 +53,7 @@ public static void register(BuiltinFunctionRepository repository) {
repository.register(ceiling());
repository.register(conv());
repository.register(crc32());
repository.register(euler());
repository.register(exp());
repository.register(floor());
repository.register(ln());
Expand All @@ -63,6 +67,8 @@ public static void register(BuiltinFunctionRepository repository) {
repository.register(sign());
repository.register(sqrt());
repository.register(truncate());
repository.register(pi());
repository.register(rand());
}

/**
Expand Down Expand Up @@ -164,6 +170,20 @@ private static FunctionResolver crc32() {
.build());
}

/**
* Definition of e() function.
* Get the Euler's number.
* () -> DOUBLE
*/
private static FunctionResolver euler() {
FunctionName functionName = BuiltinFunctionName.E.getName();
return new FunctionResolver(functionName,
new ImmutableMap.Builder<FunctionSignature, FunctionBuilder>()
.put(new FunctionSignature(functionName, Collections.emptyList()),
noArgFunction(functionName, () -> Math.E, ExprCoreType.DOUBLE))
.build());
}

/**
* Definition of exp(x) function. Calculate exponent function e to the x The supported signature
* of exp function is INTEGER/LONG/FLOAT/DOUBLE -> DOUBLE
Expand Down Expand Up @@ -266,6 +286,20 @@ private static FunctionResolver mod() {
(v1, v2) -> v2 == 0 ? null : v1 % v2));
}

/**
* Definition of pi() function.
* Get the value of pi.
* () -> DOUBLE
*/
private static FunctionResolver pi() {
FunctionName functionName = BuiltinFunctionName.PI.getName();
return new FunctionResolver(functionName,
new ImmutableMap.Builder<FunctionSignature, FunctionBuilder>()
.put(new FunctionSignature(functionName, Collections.emptyList()),
noArgFunction(functionName, () -> Math.PI, ExprCoreType.DOUBLE))
.build());
}

/**
* Definition of pow(x, y)/power(x, y) function.
* Calculate the value of x raised to the power of y
Expand All @@ -285,6 +319,30 @@ private static FunctionResolver power() {
return new FunctionResolver(functionName, doubleArgumentsFunction(functionName, Math::pow));
}

/**
* Definition of rand() and rand(N) function.
* rand() returns a random floating-point value in the range 0 <= value < 1.0
* If integer N is specified, the seed is initialized prior to execution.
* One implication of this behavior is with identical argument N,rand(N) returns the same value
* each time, and thus produces a repeatable sequence of column values.
* The supported signature of rand function is
* ([INTEGER]) -> FLOAT
*/
private static FunctionResolver rand() {
FunctionName functionName = BuiltinFunctionName.RAND.getName();
return new FunctionResolver(functionName,
new ImmutableMap.Builder<FunctionSignature, FunctionBuilder>()
.put(
new FunctionSignature(functionName, Collections.emptyList()),
noArgFunction(functionName, () -> new Random().nextFloat(), ExprCoreType.FLOAT))
.put(
new FunctionSignature(functionName, Arrays.asList(ExprCoreType.INTEGER)),
unaryOperator(
functionName, n -> new Random(n).nextFloat(), ExprValueUtils::getIntegerValue,
ExprCoreType.FLOAT))
.build());
}

/**
* Definition of round(x)/round(x, d) function.
* Rounds the argument x to d decimal places, d defaults to 0 if not specified.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import static com.amazon.opendistroforelasticsearch.sql.config.TestConfig.STRING_TYPE_MISSING_VALUE_FILED;
import static com.amazon.opendistroforelasticsearch.sql.config.TestConfig.STRING_TYPE_NULL_VALUE_FILED;
import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils.getDoubleValue;
import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils.getFloatValue;
import static com.amazon.opendistroforelasticsearch.sql.data.type.ExprCoreType.DOUBLE;
import static com.amazon.opendistroforelasticsearch.sql.data.type.ExprCoreType.FLOAT;
import static com.amazon.opendistroforelasticsearch.sql.data.type.ExprCoreType.INTEGER;
Expand All @@ -35,16 +36,12 @@
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;

import com.amazon.opendistroforelasticsearch.sql.data.model.ExprValue;
import com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils;
import com.amazon.opendistroforelasticsearch.sql.expression.DSL;
import com.amazon.opendistroforelasticsearch.sql.expression.ExpressionTestBase;
import com.amazon.opendistroforelasticsearch.sql.expression.FunctionExpression;
import com.google.common.collect.Lists;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.List;
import java.util.stream.Collectors;
import java.util.Random;
import java.util.stream.Stream;
import java.util.zip.CRC32;
import org.junit.jupiter.api.DisplayNameGeneration;
Expand Down Expand Up @@ -425,6 +422,15 @@ public void crc32_missing_value() {
assertTrue(crc.valueOf(valueEnv()).isMissing());
}

/**
* Test constant e.
*/
@Test
public void test_e() {
FunctionExpression e = dsl.euler();
assertThat(e.valueOf(valueEnv()), allOf(hasType(DOUBLE), hasValue(Math.E)));
}

/**
* Test exp with integer value.
*/
Expand Down Expand Up @@ -1717,4 +1723,48 @@ public void truncate_null_missing() {
assertEquals(LONG, truncate.type());
assertTrue(truncate.valueOf(valueEnv()).isMissing());
}

/**
* Test constant pi.
*/
@Test
public void test_pi() {
FunctionExpression pi = dsl.pi();
assertThat(pi.valueOf(valueEnv()), allOf(hasType(DOUBLE), hasValue(Math.PI)));
}

/**
* Test rand with no argument.
*/
@Test
public void rand_no_arg() {
FunctionExpression rand = dsl.rand();
assertEquals(FLOAT, rand.type());
assertTrue(
getFloatValue(rand.valueOf(valueEnv())) >= 0
&& getFloatValue(rand.valueOf(valueEnv())) < 1);
assertEquals("rand()", rand.toString());
}

/**
* Test rand with integer value.
*/
@ParameterizedTest(name = "rand({0})")
@ValueSource(ints = {2, 3})
public void rand_int_value(Integer n) {
FunctionExpression rand = dsl.rand(DSL.literal(n));
assertEquals(FLOAT, rand.type());
assertTrue(
getFloatValue(rand.valueOf(valueEnv())) >= 0
&& getFloatValue(rand.valueOf(valueEnv())) < 1);
assertEquals(getFloatValue(rand.valueOf(valueEnv())), new Random(n).nextFloat());
assertEquals(String.format("rand(%s)", n), rand.toString());
}

@Test
public void rand_null_value() {
FunctionExpression rand = dsl.rand(DSL.ref(INT_TYPE_NULL_VALUE_FIELD, INTEGER));
assertEquals(FLOAT, rand.type());
assertTrue(rand.valueOf(valueEnv()).isNull());
}
}
45 changes: 38 additions & 7 deletions docs/user/dql/functions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -291,9 +291,19 @@ E
Description
-----------

Specifications:
Usage: E() returns the Euler's number

1. E() -> DOUBLE
Return type: DOUBLE

Example::

od> SELECT E()
fetched rows / total rows = 1/1
+-------------------+
| e() |
|-------------------|
| 2.718281828459045 |
+-------------------+


EXP
Expand Down Expand Up @@ -548,9 +558,19 @@ PI
Description
-----------

Specifications:
Usage: PI() returns the constant pi

Return type: DOUBLE

1. PI() -> DOUBLE
Example::

od> SELECT PI()
fetched rows / total rows = 1/1
+-------------------+
| pi() |
|-------------------|
| 3.141592653589793 |
+-------------------+


POW
Expand Down Expand Up @@ -616,10 +636,21 @@ RAND
Description
-----------

Specifications:
Usage: RAND()/RAND(N) returns a random floating-point value in the range 0 <= value < 1.0. If integer N is specified, the seed is initialized prior to execution. One implication of this behavior is with identical argument N, rand(N) returns the same value each time, and thus produces a repeatable sequence of column values.

Argument type: INTEGER

1. RAND() -> NUMBER
2. RAND(NUMBER T) -> T
Return type: FLOAT

Example::

od> SELECT RAND(3)
fetched rows / total rows = 1/1
+------------+
| rand(3) |
|------------|
| 0.73105735 |
+------------+


REPLACE
Expand Down
Loading

0 comments on commit 78a51a4

Please sign in to comment.