引擎选择路由指南
1. 概述
AIR 通过 QueueRule 实现基于规则的引擎路由。分别为查询(Query)和构建(Build)两类场景提供规则匹配。
核心流程:
请求进入 → 按 priority 排序的规则列表 → 逐条匹配 expr → 命中则返回对应 queueName → 全部未命中则回退到默认引擎
2. QueueRule 字段说明
| 字段 |
类型 |
必填 |
说明 |
name |
String |
是 |
规则名称,用于标识 |
description |
String |
否 |
规则描述 |
expr |
String |
是* |
Aviator 表达式,求值结果必须为 Boolean。 |
queueName |
String |
是 |
匹配成功后路由到的队列名,需与 ComputeUnit.queueName 对应 |
priority |
int |
是 |
优先级,数字越小优先级越高,优先匹配 |
3. 可用变量
3.1 查询规则(queryRules)可用变量
| 变量名 |
类型 |
默认值 |
说明 |
userName |
String |
"" |
执行查询的用户名 |
groupName |
String |
"" |
用户所属分组 |
queryCost |
double |
0.0 |
查询预估代价 |
clientType |
String |
"" |
客户端类型 |
clientIp |
String |
"" |
客户端 IP 地址 |
catalogs |
String |
"" |
逗号分隔的 catalog 名称列表 |
originalCatalogs |
String |
"" |
原始 catalog 名称列表 |
schemas |
String |
"" |
逗号分隔的 schema 名称列表 |
originalSchemas |
String |
"" |
原始 schema 名称列表 |
tables |
String |
"" |
逗号分隔的表名列表 |
originalTables |
String |
"" |
原始表名列表 |
sourceTypes |
String |
"" |
逗号分隔的数据源类型列表 |
3.2 构建规则(buildRules)可用变量
| 变量名 |
类型 |
默认值 |
说明 |
owner |
String |
"" |
数据集 / 投影 的 owner |
queryCost |
double |
0.0 |
构建预估代价 |
datasetPath |
String |
"" |
数据集路径 |
taskType |
String |
"" |
任务类型,如 "RP"、"EXPORT" |
sourceTypes |
String |
null |
逗号分隔的数据源类型列表 |
rpName |
String |
"" |
RP 名称(RP 构建时使用) |
exportName |
String |
"" |
导出名称(Export 任务时使用) |
3.3 内置变量取值范围
clientType 取值
| 变量名 |
说明 |
PRESTO_JDBC |
Presto JDBC 连接 |
SERVICE |
数据服务调用 |
REPORT |
报表查询 |
ACCELERATION |
加速/投影构建查询 |
UI |
DWS UI 界面查询 |
INTERNAL |
内部系统查询 |
EXPORT |
导出任务查询 |
MYSQL_JDBC |
MySQL 协议连接 |
PyHive |
Python DB-API |
TRINO_JDBC |
Trino JDBC 连接 |
UNKNOWN |
无法识别的客户端,兜底值 |
taskType 取值
| 变量名 |
说明 |
RP |
投影构建 |
EXPORT |
数据导出任务 |
sourceTypes 取值
HIVE2,HIVE3,HIVE2_JDBC,HIVE3_JDBC,ICEBERG_HIVE,ICEBERG_HADOOP,MYSQL,MYSQL5,POSTGRESQL,ORACLE,MSSQL,MSSQL_2022,TIDB,
DAMENG,GAUSS,OPEN_GAUSS,HANA,DB2,VERTICA,INTER_SYSTEMS,OCEANBASE_MYSQL,OCEANBASE_ORACLE,STARROCKS,DORIS,CLICKHOUSE,
CMB_CLICKHOUSE,PRESTO,PRESTO_JDBC,SPARK,TRINO,IMPALA,CALCITE,DATABRICKS,ATHENA,SNOWFLAKE,HUAWEI_DWS,ELASTICSEARCH,
HBASE,MONGODB,NEBULA,ARGODB,HDFS,FILE,S3,AZURE_BLOB,API,AIR,LARKSUITE,UNKNOWN_SOURCE_TYPE
4. 表达式语法(Aviator 5.3.0)
expr 字段使用 AviatorScript 表达式语言,求值结果必须返回 true 或 false。
4.1 运算符
比较运算符
| 运算符 |
说明 |
示例 |
== |
等于 |
userName == "admin" |
!= |
不等于 |
clientType != "JDBC" |
> |
大于 |
queryCost > 1000 |
>= |
大于等于 |
queryCost >= 500 |
< |
小于 |
queryCost < 100 |
<= |
小于等于 |
queryCost <= 200 |
逻辑运算符
| 运算符 |
说明 |
示例 |
&& |
逻辑与 |
userName == "admin" && queryCost > 100 |
\|\| |
逻辑或 |
clientType == "JDBC" \|\| clientType == "REST" |
! |
逻辑非 |
!string.contains(sourceTypes, "MYSQL") |
三元运算符
queryCost > 1000 ? true : false
正则匹配运算符
| 运算符 |
说明 |
示例 |
=~ |
正则匹配 |
userName =~ /admin.*/ |
4.2 内置字符串函数
以下是在规则表达式中最常用的函数:
| 函数 |
返回值 |
说明 |
示例 |
string.contains(s, sub) |
boolean |
字符串包含判断 |
string.contains(sourceTypes, "DORIS") |
string.startsWith(s, prefix) |
boolean |
前缀判断 |
string.startsWith(datasetPath, "/prod/") |
string.endsWith(s, suffix) |
boolean |
后缀判断 |
string.endsWith(rpName, "_daily") |
string.length(s) |
long |
字符串长度 |
string.length(userName) > 0 |
string.substring(s, begin, end) |
String |
子串截取 |
string.substring(catalogs, 0, 4) == "prod" |
string.indexOf(s, sub) |
int |
查找子串位置,不存在返回 -1 |
string.indexOf(sourceTypes, "HIVE") >= 0 |
string.replace_first(s, regex, replacement) |
String |
正则替换第一个 |
- |
string.replace_all(s, regex, replacement) |
String |
正则替换全部 |
- |
string.split(s, regex, limit) |
String[] |
字符串分割 |
count(string.split(sourceTypes, ",", -1)) > 2 |
4.3 内置数学函数
| 函数 |
说明 |
示例 |
math.abs(n) |
绝对值 |
math.abs(queryCost) > 100 |
math.ceil(n) |
向上取整 |
math.ceil(queryCost) > 500 |
math.floor(n) |
向下取整 |
- |
math.round(n) |
四舍五入 |
- |
math.pow(a, b) |
幂运算 |
- |
math.log(n) |
自然对数 |
- |
math.log10(n) |
以10为底对数 |
- |
math.sqrt(n) |
平方根 |
- |
4.4 其他常用内置函数
| 函数 |
说明 |
示例 |
nil |
空值常量 |
sourceTypes != nil |
count(collection) |
集合/数组元素个数 |
count(string.split(catalogs, ",", -1)) > 1 |
include(collection, element) |
集合是否包含元素 |
include(string.split(sourceTypes, ",", -1), "DORIS") |
seq.every(seq, predicate) |
所有元素满足条件 |
- |
seq.some(seq, predicate) |
至少一个元素满足条件 |
- |
seq.filter(seq, predicate) |
过滤元素 |
- |
seq.map(seq, function) |
映射函数 |
- |
5. 配置示例
在 queryComputeUnits / buildComputeUnits 中为需要路由的引擎配置 “queueName”,然后配置对应的逻辑规则 queryRules / buildRules
5.1 按数据源类型路由构建引擎
{
"buildRules": [
{
"name": "iceberg-hive-doris-build-rule",
"description": "Route ICEBERG_HIVE and DORIS RP builds to dedicated engine",
"expr": "string.contains(sourceTypes, \"ICEBERG_HIVE\") || string.contains(sourceTypes, \"DORIS\")",
"queueName": "doris_build_queue",
"priority": 1
}
]
}
5.2 按用户名路由查询引擎
{
"queryRules": [
{
"name": "admin-query-rule",
"description": "Admin users route to high-priority engine",
"expr": "userName == \"admin\" || userName == \"root\"",
"queueName": "high_priority_queue",
"priority": 1
}
]
}
5.3 按查询代价路由
{
"queryRules": [
{
"name": "heavy-query-rule",
"description": "Route heavy queries to dedicated engine",
"expr": "queryCost > 10000",
"queueName": "heavy_query_queue",
"priority": 1
},
{
"name": "light-query-rule",
"description": "Route light queries to fast engine",
"expr": "queryCost <= 100",
"queueName": "fast_query_queue",
"priority": 2
}
]
}
5.4 按客户端 IP 段路由
{
"queryRules": [
{
"name": "internal-ip-rule",
"description": "Internal network uses dedicated engine",
"expr": "string.startsWith(clientIp, \"10.5.\")",
"queueName": "internal_queue",
"priority": 1
}
]
}
5.5 组合条件
{
"queryRules": [
{
"name": "specific-catalog-user-rule",
"description": "Specific user querying specific catalog",
"expr": "userName == \"analyst\" && string.contains(catalogs, \"prod_catalog\")",
"queueName": "analyst_prod_queue",
"priority": 1
}
]
}
5.6 正则匹配
{
"queryRules": [
{
"name": "table-pattern-rule",
"description": "Route queries on tmp tables to temp engine",
"expr": "tables =~ /.*tmp_.*/",
"queueName": "temp_query_queue",
"priority": 1
}
]
}
5.7 按任务类型路由构建引擎
{
"buildRules": [
{
"name": "export-task-rule",
"description": "Export tasks use dedicated engine",
"expr": "taskType == \"EXPORT\"",
"queueName": "export_queue",
"priority": 1
}
]
}
5.8 精确匹配数据源类型(使用 split + include)
{
"buildRules": [
{
"name": "exact-doris-rule",
"description": "Exact match DORIS in sourceTypes (avoid matching DORIS_XXX)",
"expr": "include(string.split(sourceTypes, \",\", -1), \"DORIS\")",
"queueName": "doris_queue",
"priority": 1
}
]
}