From efa61a67428a53ef868f598c8b7de8c318e70e4b Mon Sep 17 00:00:00 2001 From: yanghua Date: Tue, 24 Jul 2018 19:13:39 +0800 Subject: [PATCH] [FLINK-9928] Add LOG2 function for table/sql API --- docs/dev/table/sql.md | 11 +++++++ docs/dev/table/tableApi.md | 11 +++++++ .../flink/table/api/scala/expressionDsl.scala | 5 +++ .../table/codegen/calls/BuiltInMethods.scala | 2 ++ .../codegen/calls/FunctionGenerator.scala | 6 ++++ .../table/expressions/mathExpressions.scala | 12 +++++++ .../functions/sql/ScalarSqlFunctions.scala | 9 ++++++ .../runtime/functions/ScalarFunctions.scala | 11 +++++++ .../table/validate/FunctionCatalog.scala | 2 ++ .../expressions/ScalarFunctionsTest.scala | 31 +++++++++++++++++++ 10 files changed, 100 insertions(+) diff --git a/docs/dev/table/sql.md b/docs/dev/table/sql.md index 5b83e9d23cbe2..364b936fcfcfa 100644 --- a/docs/dev/table/sql.md +++ b/docs/dev/table/sql.md @@ -1409,6 +1409,17 @@ LOG10(numeric) + + + {% highlight text %} +LOG2(numeric) +{% endhighlight %} + + +

Returns the base 2 logarithm of numeric.

+ + + {% highlight text %} diff --git a/docs/dev/table/tableApi.md b/docs/dev/table/tableApi.md index 2f651454903c1..80af8ee52e351 100644 --- a/docs/dev/table/tableApi.md +++ b/docs/dev/table/tableApi.md @@ -2067,6 +2067,17 @@ NUMERIC.log10() + + + {% highlight java %} +NUMERIC.log2() +{% endhighlight %} + + +

Calculates the base 2 logarithm of given value.

+ + + {% highlight java %} diff --git a/flink-libraries/flink-table/src/main/scala/org/apache/flink/table/api/scala/expressionDsl.scala b/flink-libraries/flink-table/src/main/scala/org/apache/flink/table/api/scala/expressionDsl.scala index b0bc5b66c3353..5a191243f5cdd 100644 --- a/flink-libraries/flink-table/src/main/scala/org/apache/flink/table/api/scala/expressionDsl.scala +++ b/flink-libraries/flink-table/src/main/scala/org/apache/flink/table/api/scala/expressionDsl.scala @@ -300,6 +300,11 @@ trait ImplicitExpressionOperations { */ def log10() = Log10(expr) + /** + * Calculates the base 2 logarithm of the given value. + */ + def log2() = Log2(expr) + /** * Calculates the natural logarithm of the given value. */ diff --git a/flink-libraries/flink-table/src/main/scala/org/apache/flink/table/codegen/calls/BuiltInMethods.scala b/flink-libraries/flink-table/src/main/scala/org/apache/flink/table/codegen/calls/BuiltInMethods.scala index ea4f0fd2f92d6..11f4a1fa5e0ee 100644 --- a/flink-libraries/flink-table/src/main/scala/org/apache/flink/table/codegen/calls/BuiltInMethods.scala +++ b/flink-libraries/flink-table/src/main/scala/org/apache/flink/table/codegen/calls/BuiltInMethods.scala @@ -33,6 +33,8 @@ object BuiltInMethods { val LOG10 = Types.lookupMethod(classOf[Math], "log10", classOf[Double]) + val LOG2 = Types.lookupMethod(classOf[ScalarFunctions], "log2", classOf[Double]) + val EXP = Types.lookupMethod(classOf[Math], "exp", classOf[Double]) val POWER = Types.lookupMethod(classOf[Math], "pow", classOf[Double], classOf[Double]) diff --git a/flink-libraries/flink-table/src/main/scala/org/apache/flink/table/codegen/calls/FunctionGenerator.scala b/flink-libraries/flink-table/src/main/scala/org/apache/flink/table/codegen/calls/FunctionGenerator.scala index bd75617f47426..f6c5a3d6a2196 100644 --- a/flink-libraries/flink-table/src/main/scala/org/apache/flink/table/codegen/calls/FunctionGenerator.scala +++ b/flink-libraries/flink-table/src/main/scala/org/apache/flink/table/codegen/calls/FunctionGenerator.scala @@ -156,6 +156,12 @@ object FunctionGenerator { DOUBLE_TYPE_INFO, BuiltInMethods.LOG10) + addSqlFunctionMethod( + LOG2, + Seq(DOUBLE_TYPE_INFO), + DOUBLE_TYPE_INFO, + BuiltInMethods.LOG2) + addSqlFunctionMethod( LN, Seq(DOUBLE_TYPE_INFO), diff --git a/flink-libraries/flink-table/src/main/scala/org/apache/flink/table/expressions/mathExpressions.scala b/flink-libraries/flink-table/src/main/scala/org/apache/flink/table/expressions/mathExpressions.scala index 0378ce58c2afb..10ba0079263b3 100644 --- a/flink-libraries/flink-table/src/main/scala/org/apache/flink/table/expressions/mathExpressions.scala +++ b/flink-libraries/flink-table/src/main/scala/org/apache/flink/table/expressions/mathExpressions.scala @@ -92,6 +92,18 @@ case class Log10(child: Expression) extends UnaryExpression with InputTypeSpec { } } +case class Log2(child: Expression) extends UnaryExpression with InputTypeSpec { + override private[flink] def expectedTypes: Seq[TypeInformation[_]] = DOUBLE_TYPE_INFO :: Nil + + override private[flink] def resultType: TypeInformation[_] = DOUBLE_TYPE_INFO + + override private[flink] def toRexNode(implicit relBuilder: RelBuilder) = { + relBuilder.call(ScalarSqlFunctions.LOG2, child.toRexNode) + } + + override def toString: String = s"log2($child)" +} + case class Log(base: Expression, antilogarithm: Expression) extends Expression with InputTypeSpec { def this(antilogarithm: Expression) = this(null, antilogarithm) diff --git a/flink-libraries/flink-table/src/main/scala/org/apache/flink/table/functions/sql/ScalarSqlFunctions.scala b/flink-libraries/flink-table/src/main/scala/org/apache/flink/table/functions/sql/ScalarSqlFunctions.scala index 69f430b399e7d..32e5d3482775f 100644 --- a/flink-libraries/flink-table/src/main/scala/org/apache/flink/table/functions/sql/ScalarSqlFunctions.scala +++ b/flink-libraries/flink-table/src/main/scala/org/apache/flink/table/functions/sql/ScalarSqlFunctions.scala @@ -67,6 +67,15 @@ object ScalarSqlFunctions { OperandTypes.family(SqlTypeFamily.NUMERIC, SqlTypeFamily.NUMERIC)), SqlFunctionCategory.NUMERIC) + val LOG2 = new SqlFunction( + "LOG2", + SqlKind.OTHER_FUNCTION, + ReturnTypes.DOUBLE_NULLABLE, + null, + OperandTypes.NUMERIC, + SqlFunctionCategory.NUMERIC + ) + val LPAD = new SqlFunction( "LPAD", SqlKind.OTHER_FUNCTION, diff --git a/flink-libraries/flink-table/src/main/scala/org/apache/flink/table/runtime/functions/ScalarFunctions.scala b/flink-libraries/flink-table/src/main/scala/org/apache/flink/table/runtime/functions/ScalarFunctions.scala index 2e7c9f6825fc3..3d0e0d3254223 100644 --- a/flink-libraries/flink-table/src/main/scala/org/apache/flink/table/runtime/functions/ScalarFunctions.scala +++ b/flink-libraries/flink-table/src/main/scala/org/apache/flink/table/runtime/functions/ScalarFunctions.scala @@ -108,6 +108,17 @@ object ScalarFunctions { } } + /** + * Returns the logarithm of "x" with base 2. + */ + def log2(x: Double): Double = { + if (x <= 0.0) { + throw new IllegalArgumentException(s"x of 'log2(x)' must be > 0, but x = $x") + } else { + Math.log(x) / Math.log(2) + } + } + /** * Returns the string str left-padded with the string pad to a length of len characters. * If str is longer than len, the return value is shortened to len characters. diff --git a/flink-libraries/flink-table/src/main/scala/org/apache/flink/table/validate/FunctionCatalog.scala b/flink-libraries/flink-table/src/main/scala/org/apache/flink/table/validate/FunctionCatalog.scala index 3184e0001ea9a..2806e3478e45b 100644 --- a/flink-libraries/flink-table/src/main/scala/org/apache/flink/table/validate/FunctionCatalog.scala +++ b/flink-libraries/flink-table/src/main/scala/org/apache/flink/table/validate/FunctionCatalog.scala @@ -213,6 +213,7 @@ object FunctionCatalog { "exp" -> classOf[Exp], "floor" -> classOf[Floor], "log10" -> classOf[Log10], + "log2" -> classOf[Log2], "ln" -> classOf[Ln], "log" -> classOf[Log], "power" -> classOf[Power], @@ -397,6 +398,7 @@ class BasicOperatorTable extends ReflectiveSqlOperatorTable { SqlStdOperatorTable.MOD, SqlStdOperatorTable.LN, SqlStdOperatorTable.LOG10, + ScalarSqlFunctions.LOG2, SqlStdOperatorTable.ABS, SqlStdOperatorTable.EXP, SqlStdOperatorTable.NULLIF, diff --git a/flink-libraries/flink-table/src/test/scala/org/apache/flink/table/expressions/ScalarFunctionsTest.scala b/flink-libraries/flink-table/src/test/scala/org/apache/flink/table/expressions/ScalarFunctionsTest.scala index 8b0c3808f227c..3687c3b2be3c5 100644 --- a/flink-libraries/flink-table/src/test/scala/org/apache/flink/table/expressions/ScalarFunctionsTest.scala +++ b/flink-libraries/flink-table/src/test/scala/org/apache/flink/table/expressions/ScalarFunctionsTest.scala @@ -553,6 +553,37 @@ class ScalarFunctionsTest extends ScalarTypesTestBase { math.log10(4.6).toString) } + @Test + def testLog2(): Unit = { + testAllApis( + 'f6.log2(), + "f6.log2", + "LOG2(f6)", + (math.log(4.6) / math.log(2)).toString + ) + + testAllApis( + ('f6 - 'f6 + 100).log2(), + "(f6 - f6 + 100).log2()", + "LOG2(f6 - f6 + 100)", + (math.log(100.0) / math.log(2)).toString + ) + + testAllApis( + ('f6 + 20).log2(), + "(f6+20).log2", + "LOG2(f6+20)", + (math.log(24.6) / math.log(2)).toString + ) + + testAllApis( + 10.log2(), + "10.log2", + "LOG2(10)", + (math.log(10.0) / math.log(2)).toString + ) + } + @Test def testPower(): Unit = { // f7: int , f4: long, f6: double