blob: a3b178b2da3d562cad6d6fdd10886ea4d5ea5192 [file] [view]
# Calcite
> Calcite SQL Transform 插件
## 描述
基于 [Apache Calcite](https://calcite.apache.org/) 的 SQL Transform 插件。使用标准 SQL 对数据行进行转换,在作业启动时编译 SQL 执行计划,运行时逐行应用。
:::tip
- 每行独立处理——不支持 `JOIN` 和跨行聚合(`GROUP BY``SUM``COUNT`)。
- 向量类型(FLOAT_VECTORBINARY_VECTOR 等)内部映射为 VARBINARY。请使用内置向量 UDF(如 `COSINE_DISTANCE``VECTOR_REDUCE`)进行向量运算。
:::
## 属性
| 名称 | 类型 | 必填 | 默认值 | 说明 |
|------|------|------|--------|------|
| sql | string | | - | 要执行的 SQL 语句 |
| table_transform | list | | [] | 多表 CDC 场景下的逐表 SQL 覆盖 |
| table_match_regex | string | | .* | 表路径匹配正则。不匹配的表直接透传 |
| row_error_handle_way | enum | | FAIL | 行级错误处理方式:`FAIL``SKIP``ROUTE_TO_TABLE` |
### sql [string]
```hocon
sql = "SELECT id, UPPER(name) AS name, age + 1 AS next_age FROM source_table WHERE age > 18"
```
### table_transform [list]
多表 CDC 场景下的逐表 SQL 覆盖。每项指定 `table_path` `sql`。未列出的表会回退到全局 `sql`(如果路径匹配 `table_match_regex`),否则直接透传。
```hocon
table_transform = [
{
table_path = "db.users"
sql = "SELECT id, name, UPPER(email) AS email FROM users"
},
{
table_path = "db.orders"
sql = "SELECT order_id, amount * 100 AS amount_cents FROM orders"
}
]
```
### table_match_regex [string]
用于过滤需要转换的表的正则表达式。只有路径匹配此正则的表才会应用全局 `sql`。不匹配的表直接透传。默认 `.*`(匹配所有)。
### row_error_handle_way [enum]
行级 SQL 执行错误的处理方式:
- `FAIL`(默认)-- 立即终止作业
- `SKIP` -- 跳过错误行,继续处理
- `ROUTE_TO_TABLE` -- 将错误行路由到独立的错误表
### 公共参数 [string]
Transform 公共参数,请参考 [Transform 插件公共参数](common-options/common-options.md)。
## 内置 UDF
所有内置 UDF 在任意必需参数为 `NULL` 时返回 `NULL`
函数名大小写不敏感。例如 `MASK(...)``mask(...)``Mask(...)` 等价。
### 数据脱敏函数
#### MASK
```MASK(value, start, end, maskChar) -> STRING```
`[start, end)` 范围内的字符替换为 `maskChar`。范围无效时返回原值。maskChar null 或空时默认 `*`
示例:
```sql
SELECT MASK(phone, 3, 7, '*') AS masked_phone FROM t
```
#### MASK_HASH
```MASK_HASH(value) -> STRING```
返回输入的 SHA-256 十六进制哈希(64 字符)。确定性——相同输入总是产生相同哈希。
示例:
```sql
SELECT MASK_HASH(phone) AS phone_hash FROM t
```
#### DES_ENCRYPT
```DES_ENCRYPT(password, data) -> STRING```
使用 `password`(不少于 8 字符)对 `data` 进行 DES 加密(CBC/PKCS5Padding),返回 Base64 编码密文。
示例:
```sql
SELECT DES_ENCRYPT('12345678', secret) AS encrypted FROM t
```
#### DES_DECRYPT
```DES_DECRYPT(password, data) -> STRING```
使用相同密码解密 Base64 编码的密文。
示例:
```sql
SELECT DES_DECRYPT('12345678', encrypted_secret) AS original FROM t
```
### 向量函数
#### COSINE_DISTANCE
```COSINE_DISTANCE(vector1, vector2) -> DOUBLE```
返回介于 0 1 之间的 DOUBLE 值:0 表示完全相同的向量,1 表示完全正交的向量。
示例:
```sql
SELECT COSINE_DISTANCE(vec1, vec2) AS distance FROM t
```
#### L1_DISTANCE
```L1_DISTANCE(vector1, vector2) -> DOUBLE```
计算两个向量之间的曼哈顿(L1)距离。
示例:
```sql
SELECT L1_DISTANCE(vec1, vec2) AS dist FROM t
```
#### L2_DISTANCE
```L2_DISTANCE(vector1, vector2) -> DOUBLE```
计算两个向量之间的欧几里得(L2)距离。
示例:
```sql
SELECT L2_DISTANCE(vec1, vec2) AS dist FROM t
```
#### VECTOR_DIMS
```VECTOR_DIMS(vector) -> INT```
返回一个 INT 值,表示向量中的维数(元素数量)。
示例:
```sql
SELECT VECTOR_DIMS(embedding) AS dims FROM t
```
#### VECTOR_NORM
```VECTOR_NORM(vector) -> DOUBLE```
计算向量的 L2 范数(欧几里得范数),表示向量的长度或大小。
示例:
```sql
SELECT VECTOR_NORM(embedding) AS norm FROM t
```
#### INNER_PRODUCT
```INNER_PRODUCT(vector1, vector2) -> DOUBLE```
计算两个向量的内积(点积),用于测量向量之间的相似性和投影。
示例:
```sql
SELECT INNER_PRODUCT(vec1, vec2) AS ip FROM t
```
#### VECTOR_REDUCE
```VECTOR_REDUCE(vector_field, target_dimension, method)```
通用向量降维函数,支持多种降维方法。
**参数:**
- `vector_field`:要降维的向量字段(VECTOR 类型)
- `target_dimension`:目标维度(INTEGER,必须小于源维度)
- `method`:降维方法(STRING):
- **'TRUNCATE'**:截断法,保留前 N 个元素。最简单快速,但可能丢失被截断维度的信息。
- **'RANDOM_PROJECTION'**:高斯随机投影法。在降维的同时保持向量间的相对距离,遵循 Johnson-Lindenstrauss 引理。
- **'SPARSE_RANDOM_PROJECTION'**:稀疏随机投影法,矩阵元素大多为零。比常规随机投影更高效。
**返回值:** VARBINARY——降维后的向量
**示例:**
```sql
SELECT id, VECTOR_REDUCE(embedding, 256, 'TRUNCATE') AS reduced FROM t
SELECT id, VECTOR_REDUCE(embedding, 128, 'RANDOM_PROJECTION') AS reduced FROM t
SELECT id, VECTOR_REDUCE(embedding, 64, 'SPARSE_RANDOM_PROJECTION') AS reduced FROM t
```
#### VECTOR_NORMALIZE
```VECTOR_NORMALIZE(vector_field)```
将向量归一化为单位长度(模长 = 1)。对于计算余弦相似度很有用。
**参数:**
- `vector_field`:要归一化的向量字段(VECTOR 类型)
**返回值:** VARBINARY——归一化后的向量
**示例:**
```sql
SELECT id, VECTOR_NORMALIZE(embedding) AS unit_vec FROM t
```
除上述 UDF 外,Apache Calcite 提供的所有标准 SQL 函数均可使用(字符串、数学、日期/时间、JSON、条件表达式等)。完整函数参考请见 [Apache Calcite SQL 参考文档](https://calcite.apache.org/docs/reference.html)。
## 示例
### 基础 SELECT + WHERE
Source 读取的数据如下:
| id | name | age |
|----|------|-----|
| 1 | Joy Ding | 20 |
| 2 | May Ding | 21 |
| 3 | Kin Dom | 24 |
| 4 | Joy Dom | 15 |
```hocon
transform {
Calcite {
plugin_input = "fake"
plugin_output = "result"
sql = "SELECT id, name, age FROM fake WHERE age >= 18"
}
}
```
结果表 `result` 中的数据为:
| id | name | age |
|----|------|-----|
| 1 | Joy Ding | 20 |
| 2 | May Ding | 21 |
| 3 | Kin Dom | 24 |
`age = 15` 的行被过滤。
### 字符串和数学函数
输入:
| id | name | salary |
|----|------|--------|
| 1 | Joy Ding | 5000 |
| 2 | May Ding | 8000 |
```hocon
transform {
Calcite {
plugin_input = "fake"
plugin_output = "result"
sql = "SELECT id, UPPER(name) AS name_upper, CHAR_LENGTH(name) AS name_len, salary * 1.1 AS new_salary FROM fake"
}
}
```
输出:
| id | name_upper | name_len | new_salary |
|----|------------|----------|------------|
| 1 | JOY DING | 8 | 5500.0 |
| 2 | MAY DING | 8 | 8800.0 |
### CASE WHEN 条件表达式
输入:
| id | name | age |
|----|------|-----|
| 1 | Alice | 8 |
| 2 | Bob | 15 |
| 3 | Carol | 30 |
| 4 | Dave | 70 |
```hocon
transform {
Calcite {
plugin_input = "fake"
plugin_output = "result"
sql = "SELECT id, name, CASE WHEN age < 13 THEN 'child' WHEN age < 18 THEN 'teen' WHEN age < 65 THEN 'adult' ELSE 'senior' END AS age_group FROM fake"
}
}
```
输出:
| id | name | age_group |
|----|------|-----------|
| 1 | Alice | child |
| 2 | Bob | teen |
| 3 | Carol | adult |
| 4 | Dave | senior |
### JSON 提取
输入:
| id | payload |
|----|---------|
| 1 | {"user": {"name": "Joy Ding", "email": "joy@example.com"}} |
| 2 | {"user": {"name": "May Ding", "email": "may@example.com"}} |
```hocon
transform {
Calcite {
plugin_input = "fake"
plugin_output = "result"
sql = "SELECT id, JSON_VALUE(payload, '$.user.name') AS user_name, JSON_VALUE(payload, '$.user.email') AS email FROM fake"
}
}
```
输出:
| id | user_name | email |
|----|-----------|-------|
| 1 | Joy Ding | joy@example.com |
| 2 | May Ding | may@example.com |
### 数据脱敏(MASK + MASK_HASH + DES)
输入:
| id | phone | secret |
|----|-------|--------|
| 1 | 13812345678 | seatunnel-password |
| 2 | 13987654321 | connector-api-key |
```hocon
transform {
Calcite {
plugin_input = "fake"
plugin_output = "result"
sql = "SELECT id, MASK(phone, 3, 7, '*') AS masked_phone, MASK_HASH(phone) AS phone_hash, DES_ENCRYPT('12345678', secret) AS encrypted_secret FROM fake"
}
}
```
输出:
| id | masked_phone | phone_hash | encrypted_secret |
|----|--------------|------------|------------------|
| 1 | 138\*\*\*\*5678 | a1b2c3...(64 字符 SHA-256 hex | Base64 编码密文 |
| 2 | 139\*\*\*\*4321 | d4e5f6...(64 字符 SHA-256 hex | Base64 编码密文 |
后续解密:
```hocon
transform {
Calcite {
plugin_input = "result"
plugin_output = "decrypted"
sql = "SELECT id, DES_DECRYPT('12345678', encrypted_secret) AS original_secret FROM result"
}
}
```
### 向量运算
使用内置向量 UDF 在数据管线中计算距离、降维或归一化(例如 Milvus/Qdrant 源与目标之间的处理)。
```hocon
transform {
Calcite {
plugin_input = "vector_source"
plugin_output = "result"
sql = "SELECT id, COSINE_DISTANCE(query_vec, doc_vec) AS distance, VECTOR_DIMS(doc_vec) AS dims, VECTOR_REDUCE(doc_vec, 128, 'TRUNCATE') AS reduced_vec FROM vector_source"
}
}
```
给定两个 FLOAT_VECTOR `query_vec` `doc_vec`,此配置计算余弦距离、提取维度,并将 `doc_vec` 从原始维度降至 128 维。
### 多表 CDC(table_transform)
```hocon
transform {
Calcite {
plugin_input = "cdc_source"
plugin_output = "result"
table_transform = [
{
table_path = "db.users"
sql = "SELECT id, name, UPPER(email) AS email FROM users"
},
{
table_path = "db.orders"
sql = "SELECT order_id, amount * 100 AS amount_cents FROM orders"
}
]
}
}
```
未列入 `table_transform` 但匹配 `table_match_regex`(默认 `.*`)的表会应用全局 `sql`。不匹配任何规则的表直接透传。
### 错误处理(row_error_handle_way)
```hocon
transform {
Calcite {
plugin_input = "source_table"
plugin_output = "result"
sql = "SELECT id, CAST(age AS VARCHAR) AS age_str FROM source_table"
row_error_handle_way = "SKIP"
}
}
```
行级 SQL 执行出错时:
- `FAIL` -- 立即终止作业(默认,推荐用于数据质量要求高的场景)
- `SKIP` -- 静默跳过错误行
- `ROUTE_TO_TABLE` -- 将错误行路由到独立错误表,便于后续排查
## 自定义 UDF
通过 `CalciteUdf` SPI 添加自定义标量函数。完整的开发指南、API 参考、示例和类型映射请参阅 [Calcite 用户自定义函数](calcite-udf.md)。
## 限制
| 限制 | 说明 |
|------|------|
| 单表输入 | 每个 Transform 只注册一张表到 Calcite Schema,不支持多表 `JOIN` |
| 逐行处理 | 每行独立处理。`GROUP BY` / `SUM()` / `COUNT()` 作用于单行,通常无实际聚合意义 |
| WHERE 过滤 | `WHERE` 条件为 `false` 的行会被丢弃(不透传) |
| 表名匹配 | SQL `FROM` 中的表名必须与 `plugin_input` 值完全一致 |
| 仅标量 UDF | 仅支持标量函数,不支持表值函数和聚合 UDF |
| 向量类型映射 | 向量类型内部映射为 VARBINARY。可使用内置向量 UDFCOSINE_DISTANCEL1_DISTANCE 等)进行向量运算 |
:::tip CDC Schema 变更
收到 `AlterTableEvent`(例如加列、删列)时,引擎会自动重建 SQL 执行计划并重新推导输出 Schema,无需手动干预。
:::
## 作业配置示例
```hocon
env {
job.mode = "BATCH"
}
source {
FakeSource {
plugin_output = "fake"
row.num = 100
schema = {
fields {
id = "int"
name = "string"
age = "int"
phone = "string"
}
}
}
}
transform {
Calcite {
plugin_input = "fake"
plugin_output = "result"
sql = "SELECT id, UPPER(name) AS name, age + 1 AS age, MASK(phone, 3, 7, '*') AS phone FROM fake WHERE age >= 0"
}
}
sink {
Console {
plugin_input = "result"
}
}
```
## 更新日志
### next-release
- 新增 Calcite Transform 插件