Dingo 表达式

Dingo Expression 是 DingoDB 使用的表达式引擎。它的特殊之处在于其运行时代码库与解析和编译代码库是分开的。运行时的类是可序列化的,因此适用于分布式计算系统的运行时,如Apache Flink

快速入门

下面是一个使用 Dingo Expression 的示例。

class Example1 {
    Object test() {
        // The original expression string.
        String exprString = "(1 + 2) * (5 - (3 + 4))";
        // parse it into an Expr object, the compiler can be reused.
        DingoExprCompiler compiler = new DingoExprCompiler();
        Expr expr = compiler.parse(exprString);
        // Compile in a CompileContext (can be null without variables in the expression) and get an RtExpr object.
        RtExpr rtExpr = expr.compileIn(null);
        // Evaluate it in an EvalContext (can be null without variables in the expression).
        return rtExpr.eval(null);
    }
}

操作

类别

Operator

关联性

Parenthesis

( )

Function Call

( )

从左至右

Name Index

.

从左至右

Array Index

[ ]

从左至右

Unary

+ -

从右到左

Multiplicative

* /

从左至右

Additive

+ -

从左至右

Relational

< <= > >= == = != <>

从左至右

字符串

startsWith endsWith contains matches

从左至右

Logical NOT

! not

从左至右

Logical AND

&& and

从左至右

Logical OR

|| or

从左至右

数据类型

Type Name

SQL type

JSON 模式类型

Hosting Java 类型

文字表达

NULL

NULL

null

null

INT

INTEGER

int 或 java.lang.Integer

0 20 -375

LONG

LONG

integer

long 或 java.lang.Long

DOUBLE

DOUBLE

number

double 或 java.lang.Double

2.0 -6.28 3e-4

BOOL

BOOLEAN

boolean

boolean 或 java.lang.Boolean

true false

STRING

VARCHAR

string

java.lang.String

"hello" 'world'

BINARY

BLOB

byte[]

DECIMAL

DECIMAL

java.math.BigDecimal

DATE

DATE

java.sql.Date

TIME

TIME

java.sql.Time

TIMESTAMP

TIMESTAMP

java.sql.Timestamp

OBJECT

ANY

object

java.lang.Object

ARRAY

java.lang.Object[]

LIST

ARRAY

array

java.util.List

MAP

MAP

object

java.util.Map

Dingo 表达式自适应地解析整型字面量,如果整型字面量的值超出了 Java int 类型的范围,则解析为 LONG;如果超出了 Java long 类型的范围,则解析为 DECIMAL。相反,为了保持数值的精度,浮点数字面会被解析为 DECIMAL,然后您可以通过转换函数得到 DOUBLE 值。

三值逻辑

Dingo 表达式具有 NULL 类型,支持 SQL 中的三值逻辑。一般来说,除了某些逻辑运算符或函数外,如果运算符或函数的任何操作数为NULL,则其值为NULL

常数

名称

TAU

6.283185307179586476925

E

2.7182818284590452354

不是 “3.14159265”,而是 “TAU”。见 The Tau Manifesto

功能

函数名称不区分大小写。

数据类型转换

功能

Java 函数基于

说明

int(x)

x 转换为 INT

long(x)

x 转换为 LONG

bool(x)

x 转换为 LONG

double(x)

x 转换为 DOUBLE

decimal(x)

x 转换为十进制数

string(x)

x 转换为 STRING

date(x)

x 转换为日期

time(x)

x 转换为时间

timestamp(x)

x 转换为 时间戳

binary(x)

x 转换为二进制数

注意:没有 DATETIMETIMESTAMP 字面,但可以写成 TIMESTAMP('2020-12-21')等。

逻辑

功能

说明

and(a, b)

AND 运算符相同

or(a, b)

OR 运算符相同

not(x)

NOT 运算符相同

is_true(x)

测试 x 是否为 `true

is_not_true(x)

测试 x 是否为 `true

is_false(x)

测试 x 是否为 `false

is_not_false(x)

测试 x 是否为 `false

is_null(x)

测试 x 是否为 null

is_not_null(x)

测试 x 是否不是 null

注意: null “不是 ”true “或 ”false“,不能用 ”x == null “来测试一个值是否为 ”null“,因为它会返回 ”null"。

数学运算

请参见 Math (Java Platform SE 8)

功能

Java 函数基于

说明

min(a, b)

Min value of a, b

max(a, b)

Max value of a, b

abs(x)

java.lang.Math.abs

sin(x)

java.lang.Math.sin

cos(x)

java.lang.Math.cos

tan(x)

java.lang.Math.tan

asin(x)

java.lang.Math.asin

acos(x)

java.lang.Math.acos

atan(x)

java.lang.Math.atan

cosh(x)

java.lang.Math.cosh

sinh(x)

java.lang.Math.sinh

tanh(x)

java.lang.Math.tanh

log(x)

java.lang.Math.log

exp(x)

java.lang.Math.exp

字符串

请参见 String (Java Platform SE 8).

功能

Java 函数基于

说明

lower(s)

String::toLowerCase

upper(s)

String::toUpperCase

trim(s)

String::trim

replace(s, a, b)

String::replace

substr(s, i)

String::substring

substr(s, i, j)

String::substring

变量和上下文

变量可在表达式中使用。为了编译包含变量的表达式,必须提供一个 CompileContext 来定义变量的类型。JSON Schema](http://json-schema.org/)定义可用作 “编译上下文 ”的来源。例如(为简单起见使用 YAML 格式,但也可以使用 JSON 格式)

type: object
properties:
    a:
        type: integer
    b:
        type: number
    c:
        type: boolean
    d:
        type: string
additionalProperties: false

其中变量 abcd 是以指定类型定义的。根据模式,您可以提供以下数据源(YAML 格式)

{ a: 3, b: 4.0, c: false, d: bar }

那么,一个 RtExpr 的编译和评估过程如下

class Example2 {
    Object test() {
        // jsonSchemaInYamlFormat is a String/InputStream contains the JSON Schema definition.
        RtSchemaRoot schemaRoot = SchemaParser.YAML.parse(jsonSchemaInYamlFormat);
        DingoExprCompiler compiler = new DingoExprCompiler();
        Expr expr = compiler.parse("a + b");
        RtExpr rtExpr = expr.compileIn(schemaRoot.getSchema());
        DataParser parser = DataParser.yaml(schemaRoot);
        // dataInYamlFormat is a String contains the JSON Schema definition.
        Object[] tuple = parser.parse(dataInYamlFormat);
        return rtExpr.eval(new TupleEvalContext(tuple));
    }
}

嵌套上下文

在 JSON 模式定义中,对象和数组可以相互嵌套,例如

type: object
properties:
    a:
        type: object
        properties:
            b:
                type: number
            c:
                type: boolean
        additionalProperties: false
    d:
        type: array
        items:
            -   type: integer
            -   type: string
        additionalItems: false
additionalProperties: false

对于 array 类型的 JSON Schema,如果其 additionalItems 设置为 true,其元素的数量和类型将被确定,因此其每个元素将被编译为一个独立变量。如果 JSON Schema 的 properties 不为空,且 additionalProperties 设置为 false,那么它的每个属性都将被编译为一个独立变量。否则,"数组 "将被编译为 "LIST","映射 "将被编译为 "MAP"。

如果一个 object 类型没有定义 properties 属性,它将被编译为 OBJECT 类型。

在上面的 JSON 模式中,可以使用 a.ba.c 分别访问 numberboolean 类型的变量。语法看起来与 map 索引相同,但它们实际上是不同的变量,而且 a 在运行时根本不是一个现有变量。此外,您可以使用 d[0]d[1] 访问 integerstring 变量,而 d 并不是一个现有变量。

特殊变量 $ 可用来访问整个上下文,因此 $.aa 相同。对于以数组为根的上下文,$ 非常有用。解析器也会将 a.b 视为 a['b'],因此访问变量的语法与 JSONPath 很相似。