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 |
|
从左至右 |
字符串 |
|
从左至右 |
Logical NOT |
|
从左至右 |
Logical AND |
|
从左至右 |
Logical OR |
|
从左至右 |
数据类型
Type Name |
SQL type |
JSON 模式类型 |
Hosting Java 类型 |
文字表达 |
|---|---|---|---|---|
NULL |
NULL |
|
|
|
INT |
INTEGER |
int 或 java.lang.Integer |
|
|
LONG |
LONG |
integer |
long 或 java.lang.Long |
|
DOUBLE |
DOUBLE |
number |
double 或 java.lang.Double |
|
BOOL |
BOOLEAN |
boolean |
boolean 或 java.lang.Boolean |
|
STRING |
VARCHAR |
string |
|
|
BINARY |
BLOB |
|
||
DECIMAL |
DECIMAL |
|
||
DATE |
DATE |
|
||
TIME |
TIME |
|
||
TIMESTAMP |
TIMESTAMP |
|
||
OBJECT |
ANY |
object |
|
|
ARRAY |
|
|||
LIST |
ARRAY |
array |
|
|
MAP |
MAP |
object |
|
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 函数基于 |
说明 |
|---|---|---|
|
将 |
|
|
将 |
|
|
将 |
|
|
将 |
|
|
将 |
|
|
将 |
|
|
将 |
|
|
将 |
|
|
将 |
|
|
将 |
注意:没有 DATE、TIME 和 TIMESTAMP 字面,但可以写成 TIMESTAMP('2020-12-21')等。
逻辑
功能 |
说明 |
|---|---|
|
与 |
|
与 |
|
与 |
|
测试 |
|
测试 |
|
测试 |
|
测试 |
|
测试 |
|
测试 |
注意: null “不是 ”true “或 ”false“,不能用 ”x == null “来测试一个值是否为 ”null“,因为它会返回 ”null"。
数学运算
请参见 Math (Java Platform SE 8)。
功能 |
Java 函数基于 |
说明 |
|---|---|---|
|
Min value of |
|
|
Max value of |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
字符串
请参见 String (Java Platform SE 8).
功能 |
Java 函数基于 |
说明 |
|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
变量和上下文
变量可在表达式中使用。为了编译包含变量的表达式,必须提供一个 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
其中变量 a、b、c、d 是以指定类型定义的。根据模式,您可以提供以下数据源(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.b 和 a.c 分别访问 number 和 boolean 类型的变量。语法看起来与 map 索引相同,但它们实际上是不同的变量,而且 a 在运行时根本不是一个现有变量。此外,您可以使用 d[0] 和 d[1] 访问 integer 和 string 变量,而 d 并不是一个现有变量。
特殊变量 $ 可用来访问整个上下文,因此 $.a 与 a 相同。对于以数组为根的上下文,$ 非常有用。解析器也会将 a.b 视为 a['b'],因此访问变量的语法与 JSONPath 很相似。