Hive 迁移到 Doris 的函数改写清单
从 Hive 迁移到 Doris 时,在 Hive 有对应写法的 44 个常用函数中,14 个需要改写,另有 4 个可以改用 Doris 的原生函数。逐个列出两边写法和注意事项。
需要改写的函数 · 可以改用原生函数 · 迁移注意事项 · 可以直接用的函数 · 反向:Doris 迁移到 Hive
需要改写的函数
| 函数 | Hive 写法 | Doris 写法 | Doris 说明 |
|---|---|---|---|
| ADD_MONTHS | add_months(start_date, num_months[, output_date_format]) | 需改写 MONTHS_ADD(date, nums) | 文档没有列出 ADD_MONTHS 别名。返回类型与输入相同,2020-01-31 加 1 个月得到 2020-02-29。 |
| DATEADD | date_add(startdate, days) / add_months(startdate, n) | 需改写 TIMESTAMPADD(unit, n, datetime_expr) | 单位常用 SECOND、MINUTE、HOUR、DAY、WEEK、MONTH、YEAR。参数无效时返回 NULL。也可以写 DATE_ADD(dt, INTERVAL n unit)。 |
| DATETRUNC | trunc(date, 'MM') | 需改写 DATE_TRUNC(datetime, 'month') | 文档列出两种参数顺序,示例都是日期在前。 |
| FROM_JSON | json_tuple(jsonStr, k1, k2, ...) | 需改写 JSON_PARSE(json_str) | 没有 FROM_JSON。JSON_PARSE 遇到非法 JSON 会报错;希望返回 NULL 时用 JSON_PARSE_ERROR_TO_NULL。取字段用 JSON_EXTRACT 系列函数。 |
| GET_JSON_OBJECT | get_json_object(json_string, path) | 需改写 GET_JSON_STRING(json_str, json_path) | 路径以 $ 开头,不能包含双引号和方括号字符,含点号的键要用双引号括起来。官方建议改用 jsonb 类型和 jsonb_extract 系列函数。 |
| GETDATE | current_timestamp | 别名 NOW([precision]) | 别名是 current_timestamp(),返回 DATETIME。precision 取 0~6,默认 0,超出范围时报错。 |
| LENGTH | length(string A) | 需改写 CHAR_LENGTH(str) | LENGTH 返回 UTF-8 编码下的字节数,别名 OCTET_LENGTH。按字符计数要用 CHAR_LENGTH,别名 CHARACTER_LENGTH。 |
| SIZE | size(array_or_map) | 别名 ARRAY_SIZE(arr) / MAP_SIZE(m) | 数组用 ARRAY_SIZE,NULL 元素也计入,输入为 NULL 时返回 NULL。Map 用 MAP_SIZE,NULL 键和值都计入。 |
| SORT_ARRAY | sort_array(Array<T>) | 需改写 ARRAY_SORT(arr) | 升序排列,NULL 放在开头;降序用 ARRAY_REVERSE_SORT。也可以传 Lambda 表达式自定义排序。 |
| SPLIT | split(str, pat) | 需改写 SPLIT_BY_STRING(str, separator) | 返回字符串数组,任一参数为 NULL 时返回 NULL。分隔符为空字符串时按字节拆分。 |
| SPLIT_PART | split(str, pat)[n - 1] | 支持 SPLIT_PART(str, separator, part_index) | 下标从 1 开始。part_index 为 0 或越界时返回 NULL,任一参数为 NULL 时也返回 NULL。 |
| SUBSTR | substr(str, start[, len]) | 支持 SUBSTRING(str, pos[, len]) | 别名 SUBSTR。从 1 开始计数,负数从末尾倒数,pos 为 0 或超出长度时返回空字符串,任一参数为 NULL 时返回 NULL。 |
| TO_DATE | to_date(from_unixtime(unix_timestamp(str, pattern))) | 需改写 str_to_date(str, format) | Doris 的 TO_DATE 只接受 DATETIME 并取日期部分。按格式解析用 STR_TO_DATE,返回 DATETIME,也接受 yyyyMMdd 等三种格式。 |
| WM_CONCAT | concat_ws(',', collect_list(col)) | 需改写 GROUP_CONCAT([DISTINCT] str[, sep] [ORDER BY ...]) | 分隔符是第二个参数,默认是逗号加空格。DISTINCT 与 ORDER BY 同时使用从 2.1.6 起支持。 |
可以改用原生函数
下面的函数在 Hive 中只能用替代写法,Doris 有对应的函数。原来的写法通常仍能运行,换成原生函数会更简洁。
| 函数 | Hive 写法 | Doris 写法 | Doris 说明 |
|---|---|---|---|
| ANY_VALUE | max(col) | 支持 ANY_VALUE(expr) | 别名 ANY。组内有非 NULL 值时返回其中一个,全部为 NULL 时返回 NULL。 |
| APPROX_COUNT_DISTINCT | COUNT(DISTINCT col) | 支持 APPROX_COUNT_DISTINCT(expr) | 别名是 NDV。基于 HyperLogLog,只统计非 NULL 值,返回 BIGINT。 |
| DAYOFWEEK | extract(dayofweek FROM ts) | 支持 DAYOFWEEK(date) | 别名 DOW。周日为 1,周六为 7,与 MySQL 的 dayofweek 一致。 |
| MAX_BY | ROW_NUMBER() OVER (PARTITION BY ... ORDER BY y DESC) = 1 | 支持 MAX_BY(expr1, expr2) | 返回 expr2 最大时对应的 expr1。文档没有说明 NULL 和并列的处理。 |
迁移注意事项
ADD_MONTHS 按月加减
- 月末日期:StarRocks、Doris 和 Spark 在目标月份没有对应日期时取当月最后一天。StarRocks 文档特别说明,2022-02-28 加 1 个月得到 3 月 28 日而不是 3 月 31 日,这和 Oracle 的行为不同。
- MaxCompute 返回字符串,Hive 4.0.0 之前也会丢掉时间部分。结果和 DATE 或 DATETIME 字段比较时,注意类型转换。
DATETRUNC 日期截断
- 参数顺序不同:MaxCompute 是日期在前,Hologres、StarRocks 和 Spark 是单位在前,Doris 两种都接受。
- 周的起点:MaxCompute 的 week 默认从周一开始,Doris 和 Spark 文档的示例也截断到周一。按周汇总前确认业务定义的周起点。
- Hive 的 trunc 只能截断到月和年,按周、按季度汇总需要自己计算。
FROM_JSON 按 schema 解析 JSON
- StarRocks 的 parse_json 和 Doris 的 JSON_PARSE 返回的是 JSON 类型,下游需要 STRUCT 或 MAP 时要再做一次转换,不能直接替换 from_json。
- 非法 JSON 的处理不同:StarRocks 的 parse_json 返回 NULL,Doris 的 JSON_PARSE 直接报错。脏数据较多的表,在 Doris 中改用 JSON_PARSE_ERROR_TO_NULL。
GET_JSON_OBJECT 提取 JSON 字段
- StarRocks 和 Doris 返回字符串,取出的数字需要再做 CAST。Doris 中值无法无损转换为字符串时返回 NULL。
GETDATE 获取当前时间
- 返回类型不同:MaxCompute、StarRocks 和 Doris 返回 DATETIME,Hologres 的 NOW 带时区(文档把不带时区的版本单独列为 LOCALTIMESTAMP),Flink 返回 TIMESTAMP_LTZ(3)。直接写入字符串或 DATETIME 字段时,格式可能变化。
- 精度不同:MaxCompute 默认到秒,StarRocks 和 Doris 默认到秒、可传参数到微秒,Flink 到毫秒。用当前时间做去重或比较时要注意小数部分。
- Hive 和 Spark 的 current_timestamp 可以不带括号,Doris 文档中的写法是 current_timestamp()。迁移时统一写 NOW() 更容易对齐。
LENGTH 字符串长度
- StarRocks 和 Doris 的 LENGTH 返回字节数。像 WHERE LENGTH(name) > 10 这样的条件,迁移后对中文内容会多筛出很多行,而且不会报错。
- 按字符计数统一写 CHAR_LENGTH 最稳妥:Hologres、StarRocks、Doris、Flink 都支持,Hive 2.2.0 起也支持(char_length 是 character_length 的简写)。
SIZE 数组和 Map 元素个数
- StarRocks 和 Doris 区分数组和 Map 函数。从 MaxCompute 或 Hive 迁移时,要按字段类型分别改成 array_length、map_size 或 ARRAY_SIZE、MAP_SIZE。
- StarRocks 和 Doris 文档写明 NULL 元素也计入个数。需要只统计非空元素时,要先过滤再计数。
SORT_ARRAY 数组排序
- Spark 有两个排序函数:sort_array 升序时把 NULL 放在开头,array_sort 把 NULL 放在末尾。从 MaxCompute 或 Hive 迁移时应使用 sort_array,结果才一致。
- 降序的写法不同:MaxCompute 和 Spark 传第二个参数,Flink 传 ascending_order,Doris 用 ARRAY_REVERSE_SORT,Hive 和 Hologres 的函数只能升序。
SPLIT 字符串拆分
- MaxCompute、Hive 和 Spark 按正则处理分隔符。用 . 或 | 拆分时要写成 '\\.' 或 '\\|',否则会被当成正则元字符,结果出错。
SPLIT_PART 按分隔符取第 N 段
- 下标越界时结果不同:MaxCompute、StarRocks 和 Spark 返回空字符串,Hologres 和 Doris 返回 NULL。下游用 IS NULL 或 = '' 判断时,迁移后结果可能变化。
- Hive 的 split 按正则切分。分隔符是 .、| 这类正则特殊字符时,要写成 split(s, '\\.'),否则结果不对。
- Hive 的数组下标和 Flink 的 SPLIT_INDEX 都从 0 开始。从 SPLIT_PART 改写时要把下标减 1。
SUBSTR 截取子串
- 起始位置写 0 是常见错误。MaxCompute 默认、StarRocks 和 Doris 都返回空字符串,不会报错,结果却全是空值,很难发现。MaxCompute 开启 Hive 兼容模式后又会按 1 处理,同一条 SQL 在不同模式下结果不同。
TO_DATE 字符串转日期
- 同名不同义:把 MaxCompute 的 TO_DATE('20261013', 'yyyymmdd') 直接搬到 StarRocks、Doris 或 Hive 会报错或得到错误结果,需要改用 str_to_date 或 unix_timestamp。
WM_CONCAT 分组拼接字符串
- 分隔符的位置相反:WM_CONCAT 写在第一个参数,STRING_AGG、GROUP_CONCAT(Doris)和 LISTAGG 写在最后。直接替换函数名会把分隔符当成要拼接的值。
- 不写排序时,各引擎拼接的顺序都不固定。需要稳定结果时,MaxCompute 写 WITHIN GROUP (ORDER BY ...),StarRocks 和 Doris 在 GROUP_CONCAT 内写 ORDER BY。
ANY_VALUE 取组内任意值
- NULL 的处理不同:MaxCompute 和 Doris 会优先返回非 NULL 值,Spark 默认可能返回 NULL,需要传 true 才会跳过 NULL。
APPROX_COUNT_DISTINCT 近似去重计数
- 改写成 Hive 或 Flink 的 COUNT(DISTINCT) 后结果是精确值,但资源消耗会明显变大,大数据量下要评估内存和运行时间。
DAYOFWEEK 星期几
- Hive 的内置函数文档没有 dayofweek,只能用 Hive 2.2.0 起提供的 extract(dayofweek FROM ...)。
可以直接用的函数
下面 26 个函数在两个引擎中写法相同。参数、返回值和边界情况仍可能不同,点开函数页查看细节。
- ARRAY_CONTAINS 判断数组是否包含元素
- COALESCE 取第一个非空值
- COLLECT_LIST 聚合为数组
- COLLECT_SET 去重聚合为数组
- CONCAT 字符串拼接
- CONCAT_WS 按分隔符拼接
- DATE_ADD 日期加减
- DATE_FORMAT 日期格式化
- DATE_SUB 日期减天数
- DATEDIFF 日期差
- DECODE 多值匹配
- EXPLODE 数组展开为多行
- FROM_UNIXTIME 时间戳转日期
- IF 条件判断
- INSTR 查找子串位置
- LAST_DAY 当月最后一天
- MONTHS_BETWEEN 相差月数
- NVL 空值替换
- PERCENTILE_APPROX 近似分位数
- REGEXP_EXTRACT 正则提取
- REGEXP_REPLACE 正则替换
- STR_TO_MAP 字符串转 Map
- SUBSTRING_INDEX 按分隔符截取
- TO_CHAR 日期转字符串
- UNIX_TIMESTAMP 日期转时间戳
- WEEKOFYEAR 一年中的第几周