首页 / 工具 / 迁移清单 / Hologres → Spark SQL
Hologres 迁移到 Spark SQL 的函数改写清单
从 Hologres 迁移到 Spark SQL 时,在 Hologres 有对应写法的 43 个常用函数中,18 个需要改写(其中 1 个在 Spark SQL 没有对应函数),另有 8 个可以改用 Spark SQL 的原生函数。逐个列出两边写法和注意事项。
需要改写的函数 · 可以改用原生函数 · 迁移注意事项 · 可以直接用的函数 · 反向:Spark SQL 迁移到 Hologres
需要改写的函数
| 函数 | Hologres 写法 | Spark SQL 写法 | Spark SQL 说明 |
|---|---|---|---|
| ADD_MONTHS | d + interval '1 month' | 支持 add_months(start_date, num_months) | Spark 1.5.0 起提供。add_months('2016-08-31', 1) 返回 2016-09-30。 |
| COLLECT_LIST | ARRAY_AGG(expression) | 支持 collect_list(expr) | Spark 2.0.0 起提供,结果顺序不确定。3.3.0 起另有同义的 array_agg。 |
| COLLECT_SET | ARRAY_AGG(DISTINCT expression) | 支持 collect_set(expr) | Spark 2.0.0 起提供。文档注明结果顺序取决于 shuffle 后的行序,是不确定的。 |
| DATE_ADD | DATEADD(d, num, 'day') | 支持 date_add(start_date, num_days) | Spark 1.5.0 起提供。3.4.0 起另有同义的 dateadd。 |
| DATE_FORMAT | TO_CHAR(timestamp, 'YYYY-MM-DD HH24:MI:SS') | 支持 date_format(timestamp, fmt) | Spark 1.5.0 起提供。 |
| DATE_SUB | d - interval '1 day' | 支持 date_sub(start_date, num_days) | Spark 1.5.0 起提供。 |
| DATEADD | DATEADD(d, num, str) | 需改写 ts + INTERVAL n HOUR | Spark 3.4.0 起有 dateadd(start_date, num_days),但只能加天数,没有单位参数。按小时、月等单位加减用 INTERVAL 字面量,按月也可以用 add_months。 |
| EXPLODE | UNNEST(anyarray) | 支持 explode(expr) | Spark 1.0.0 起提供。数组默认列名为 col,map 为 key 和 value。需要保留空数组的行时用 explode_outer。 |
| FROM_JSON | json_str::jsonb ->> 'key' | 支持 from_json(jsonStr, schema[, options]) | Spark 2.2.0 起提供。schema 用 DDL 字符串,例如 'a INT, b DOUBLE'。options 可以指定 timestampFormat 等解析选项。 |
| FROM_UNIXTIME | TO_TIMESTAMP(seconds) | 支持 from_unixtime(unix_time[, fmt]) | Spark 1.5.0 起提供,结果按会话时区显示。 |
| GETDATE | NOW() 或 CURRENT_TIMESTAMP | 别名 current_timestamp() 或 now() | 返回查询开始执行时的时间戳,同一查询中各次调用结果相同。3.4.0 起还有不带时区的 localtimestamp()。 |
| INSTR | STRPOS(str, substr) | 支持 instr(str, substr) | Spark 1.5.0 起提供,下标从 1 开始。需要起始位置时用 locate(substr, str, pos)。 |
| MAX_PT | MAX_PT('table_name') | 不支持 | 函数索引中没有 MAX_PT。改写为 WHERE pt = (SELECT MAX(pt) FROM t)。 |
| PERCENTILE_APPROX | APPROX_PERCENTILE(p) WITHIN GROUP (ORDER BY col) | 支持 percentile_approx(col, percentage[, accuracy]) | Spark 2.1.0 起提供,别名 approx_percentile。accuracy 默认 10000,相对误差为 1.0/accuracy。返回排序后满足条件的最小值,percentage 可以传数组。 |
| REGEXP_EXTRACT | (REGEXP_MATCH(str, pattern))[n] | 支持 regexp_extract(str, regexp[, idx]) | Spark 1.5.0 起提供。idx 默认为 1,为 0 时返回整个匹配。使用 Java 正则,字符串字面量会先被 SQL 解析器反转义,文档建议用 r 前缀的原始字符串,例如 r'(\d+)'。 |
| SIZE | ARRAY_LENGTH(arr, 1) | 支持 size(expr) | Spark 1.5.0 起提供,同时有别名 cardinality。输入为 NULL 时,只有关闭 ANSI 模式并开启 spark.sql.legacy.sizeOfNull 才返回 -1,否则返回 NULL。最新文档写明默认配置下返回 NULL。 |
| SORT_ARRAY | ARRAY_SORT(anyarray) | 支持 sort_array(array[, ascendingOrder]) | Spark 1.5.0 起提供。升序时 NULL 在开头,降序时 NULL 在末尾。另有 array_sort,它把 NULL 放在末尾,3.0.0 起支持比较函数。 |
| SPLIT | REGEXP_SPLIT_TO_ARRAY(str, pattern) | 支持 split(str, regex[, limit]) | Spark 1.5.0 起提供,按正则拆分,limit 限制数组的最大长度。 |
可以改用原生函数
下面的函数在 Hologres 中只能用替代写法,Spark SQL 有对应的函数。原来的写法通常仍能运行,换成原生函数会更简洁。
| 函数 | Hologres 写法 | Spark SQL 写法 | Spark SQL 说明 |
|---|---|---|---|
| ANY_VALUE | MAX(col) | 支持 any_value(expr[, isIgnoreNull]) | Spark 3.4.0 起提供,结果不确定。isIgnoreNull 为 true 时只返回非 NULL 值,默认可能返回 NULL。 |
| DAYOFWEEK | EXTRACT(DOW FROM ts) + 1 | 支持 dayofweek(date) | Spark 2.3.0 起提供,周日为 1,周六为 7。weekday(date) 则以周一为 0、周日为 6。 |
| DECODE | CASE expr WHEN search THEN result ... ELSE default END | 支持 decode(expr, search, result [, search, result ] ... [, default]) | 多值匹配写法 3.2.0 起支持。没有匹配且省略 default 时返回 NULL。同名的 decode(bin, charset) 用于按字符集解码。 |
| MONTHS_BETWEEN | (EXTRACT(YEAR FROM a) - EXTRACT(YEAR FROM b)) * 12 + EXTRACT(MONTH FROM a) - EXTRACT(MONTH FROM b) | 支持 months_between(timestamp1, timestamp2[, roundOff]) | Spark 1.5.0 起提供。同一天或都是月末时忽略时间部分,否则按每月 31 天计算,默认保留 8 位小数,roundOff 为 false 时不舍入。 |
| NVL | COALESCE(value, default_value) | 支持 nvl(expr1, expr2) | Spark 2.0.0 起提供,同时有 ifnull、nvl2 和 coalesce。 |
| SUBSTR | SUBSTRING(str FROM start FOR len) | 支持 substr(str, pos[, len]) | Spark 1.5.0 起提供,与 substring 相同。负数从末尾倒数:substr('Spark SQL', -3) 返回 SQL。 |
| UNIX_TIMESTAMP | EXTRACT(EPOCH FROM ts) | 支持 unix_timestamp([timeExp[, fmt]]) | Spark 1.5.0 起提供,默认格式 yyyy-MM-dd HH:mm:ss。另有 to_unix_timestamp。 |
| WEEKOFYEAR | EXTRACT(WEEK FROM ts) | 支持 weekofyear(date) | 周一为一周的开始,第一周是第一个超过 3 天的周。 |
迁移注意事项
ADD_MONTHS 按月加减
- 月末日期:StarRocks、Doris 和 Spark 在目标月份没有对应日期时取当月最后一天。StarRocks 文档特别说明,2022-02-28 加 1 个月得到 3 月 28 日而不是 3 月 31 日,这和 Oracle 的行为不同。
- Hologres 和 Flink 的月末行为文档没有写明,迁移涉及月末日期时建议用已知数据核对。
DATE_FORMAT 日期格式化
- 从 MaxCompute 默认模式迁出时,hh:mi:ss 要改成目标引擎的分钟写法。原样照搬到 Spark 或 Flink,mi 不会被识别为分钟。
- Hologres 的 HH 默认是 12 小时制,下午的时间会少 12 小时,必须写 HH24。
DATEADD 按单位加减日期
- MaxCompute 和 Hologres 中 mm 表示月,mi 表示分钟。把 DATEADD(d, 1, 'mm') 当成加 1 分钟,是迁移时最常见的错误。
- Spark 3.4.0 起的 dateadd(d, 1) 表示加 1 天,参数个数和含义都与 MaxCompute 不同,不能直接照搬。
- Hologres 的 DATEADD 默认只支持 1925~2282 年。9999-12-31 这类表示“永久有效”的日期需要单独处理。
EXPLODE 数组展开为多行
- 空数组和 NULL 数组的行会被直接丢掉:MaxCompute、Doris 的 EXPLODE 和 StarRocks 的 UNNEST 都是这样。需要保留时,Doris 和 Spark 用 EXPLODE_OUTER,StarRocks 3.2.7 起用 LEFT JOIN UNNEST(...) ON TRUE。
- 需要元素位置时,Hive 和 Spark 的 posexplode 位置从 0 开始,Flink 的 WITH ORDINALITY 从 1 开始,迁移时要调整下标。
FROM_UNIXTIME 时间戳转日期
- 返回类型不同:MaxCompute 返回 DATETIME,Hologres 的 TO_TIMESTAMP 返回 TIMESTAMPTZ,其他引擎返回字符串。拿结果做日期计算前,确认是否需要再转换类型。
- 结果受会话时区影响。Spark 文档的示例中,from_unixtime(0) 返回 1969-12-31 16:00:00,因为示例环境的时区是 UTC-8。
GETDATE 获取当前时间
- 返回类型不同:MaxCompute、StarRocks 和 Doris 返回 DATETIME,Hologres 的 NOW 带时区(文档把不带时区的版本单独列为 LOCALTIMESTAMP),Flink 返回 TIMESTAMP_LTZ(3)。直接写入字符串或 DATETIME 字段时,格式可能变化。
- Hive 和 Spark 的 current_timestamp 可以不带括号,Doris 文档中的写法是 current_timestamp()。迁移时统一写 NOW() 更容易对齐。
INSTR 查找子串位置
- MaxCompute 的三参数和四参数写法,例如 INSTR(s, 'e', 3, 2),在 StarRocks、Doris、Hive、Spark 和 Flink 中都没有对应写法。只传起始位置时可以改成 LOCATE,取第 N 次出现时需要改写成多步计算。
- Hologres 的 INSTR 依赖 orafce 扩展。没有安装扩展时 SQL 会报函数不存在,改用 STRPOS 即可。
PERCENTILE_APPROX 近似分位数
- 第三个参数含义不同:MaxCompute 和 Hive 的 B、Spark 的 accuracy 都默认 10000;StarRocks 和 Doris 的 compression 只接受 2048~10000。从 Spark 迁移时,如果写了大于 10000 的 accuracy,要调整到这个范围内。
- 各引擎的算法不同,结果不会完全一致。MaxCompute 文档写明 p 落在两个值中间时取两者均值,Spark 返回满足条件的最小值,Flink 的 PERCENTILE 用线性插值。P50、P99 这类指标迁移后要实测对比。
- Hologres 的 APPROX_PERCENTILE 需要 V3.1 及以上版本,而且只抽样 8,192 个元素。数据量很大时,尾部分位数(例如 P999)的误差可能偏大。
REGEXP_EXTRACT 正则提取
- 第三个参数是否必填不一样:MaxCompute、Spark 和 Flink 可以省略,默认取第 1 组;StarRocks、Doris 和 Hive 必须写上。迁移时统一写出分组下标最稳妥。
- 反斜杠转义各引擎不同。MaxCompute 文档要求在客户端写两个反斜杠,Spark 文档建议用 r'' 原始字符串。示例里用 [0-9] 代替 \d,可以避开转义差异。
- Doris 默认用 RE2 语法,不支持 (?=...) 这类零宽断言。从 Hive 或 Spark 的 Java 正则迁移过来时,需要先确认是否用到这些写法。
SIZE 数组和 Map 元素个数
- Spark 对 NULL 输入可能返回 -1,也可能返回 NULL,取决于 ANSI 模式和 spark.sql.legacy.sizeOfNull 两个配置。Spark 3.x 默认关闭 ANSI 模式,所用版本的默认值要按对应版本文档确认。下游有 size(x) = -1 这类判断时,迁移前要先核对配置。
- Hologres 文档中 ARRAY_LENGTH 的签名带维度参数,一维数组也要写成 ARRAY_LENGTH(arr, 1)。
SORT_ARRAY 数组排序
- Spark 有两个排序函数:sort_array 升序时把 NULL 放在开头,array_sort 把 NULL 放在末尾。从 MaxCompute 或 Hive 迁移时应使用 sort_array,结果才一致。
- 降序的写法不同:MaxCompute 和 Spark 传第二个参数,Flink 传 ascending_order,Doris 用 ARRAY_REVERSE_SORT,Hive 和 Hologres 的函数只能升序。
- Hologres V1.3.18 之前会把 TEXT 数组转成 INT8 再排序,字符串内容不是数字时结果可能不符合预期,使用前先确认实例版本。
SPLIT 字符串拆分
- MaxCompute、Hive 和 Spark 按正则处理分隔符。用 . 或 | 拆分时要写成 '\\.' 或 '\\|',否则会被当成正则元字符,结果出错。
- 只需要取某一段时,Hologres 的 SPLIT_PART 和 Flink 的 SPLIT_INDEX 更直接。注意 SPLIT_PART 的序号从 1 开始,SPLIT_INDEX 为负数时返回 NULL。
ANY_VALUE 取组内任意值
- NULL 的处理不同:MaxCompute 和 Doris 会优先返回非 NULL 值,Spark 默认可能返回 NULL,需要传 true 才会跳过 NULL。
DAYOFWEEK 星期几
- Hologres 的 EXTRACT(DOW ...) 以周日为 0,直接替换 DAYOFWEEK 会让每天都差 1,周日从 1 变成 0。
- “星期几”的编号有三种:DAYOFWEEK 周日为 1;MaxCompute 和 Spark 的 WEEKDAY 周一为 0;Hologres 的 ISODOW 周一为 1、周日为 7。迁移时先确认原 SQL 用的是哪一种。
- 需要“周一为 1、周日为 7”时,可以写成 (DAYOFWEEK(d) + 5) % 7 + 1,在 Hologres 中直接用 EXTRACT(ISODOW FROM d)。
DECODE 多值匹配
- Spark 3.2 之前只有字符集解码的 decode,多值匹配写法在旧版本中会报错。
MONTHS_BETWEEN 相差月数
- StarRocks 的 months_diff、Flink 的 TIMESTAMPDIFF 和 Hologres 的 EXTRACT 写法都只返回整数月,原 SQL 中依赖小数部分的计算(例如按 0.5 个月判断)需要重新设计。
- 时间部分的处理不同:Doris 只看日期,Hive 会把时间部分算进小数,Spark 在同一天或都是月末时忽略时间。同样的输入可能得到不同的小数。
- 舍入不同:Hive 和 Spark 默认保留 8 位小数,MaxCompute 返回完整的 DOUBLE,Doris 由 round_type 控制。和原结果做等值比较前,先统一 ROUND。
NVL 空值替换
- 迁移到 Hologres、StarRocks 或 Flink SQL 时,统一改写为 COALESCE 最省事,因为 COALESCE 在七个引擎中都可用。
SUBSTR 截取子串
- Hologres 直接写 SUBSTR 可能报函数不存在,需要先创建 orafce 扩展,或改用标准的 SUBSTRING。
UNIX_TIMESTAMP 日期转时间戳
- 格式参数的写法不同:StarRocks 和 Doris 用 %Y-%m-%d %H:%i:%s,Hive、Spark 和 Flink 用 yyyy-MM-dd HH:mm:ss,MaxCompute 不支持格式参数。
WEEKOFYEAR 一年中的第几周
- Hologres 的 EXTRACT 返回 DOUBLE PRECISION,直接拼接字符串会得到 12.0 这类结果,需要先 CAST 成整数。
可以直接用的函数
下面 17 个函数在两个引擎中写法相同。参数、返回值和边界情况仍可能不同,点开函数页查看细节。