订阅更新

什么时候需要自己写UDF?能举个例子吗?

Hive手册 第 13 题 约 3 分钟读完

本文目录
  1. 先说结论
  2. 实战场景一:广告归因窗口匹配(UDF)
  3. 实战场景二:解析埋点里的JSON数组(UDTF)
  4. 什么时候该写UDF,什么时候不该写?
  5. 一个容易踩的坑:UDF的序列化问题
  6. 总结

先说结论

三种UDF的区别:

类型输入→输出典型场景例子
UDF一行→一行字符串清洗/格式转换手机号脱敏、URL解析
UDAF多行→一行自定义聚合加权平均、中位数
UDTF一行→多行展开复杂结构拆分JSON数组、展开多值字段

先把这段讲顺;面试官追问时,再展开下面的原理和细节。

详细讲解

Hive的内置函数覆盖80%的场景,但总有些业务逻辑它处理不了。这时候就需要UDF。但很多人一问UDF就只能答“写一个类继承 GenericUDF”这种教科书式的回答。面试官其实想听的是“你在什么场景下写过,解决了什么问题”。

实战场景一:广告归因窗口匹配(UDF)

我在短剧出海公司做广告归因,需要一个复杂的匹配逻辑:给定一次安装事件,往前找7天内的所有广告点击,按“最后一次点击”归因,如果用户有多个广告渠道的点击,还要按渠道优先级排序。

这个逻辑用纯SQL写需要嵌套多层窗口函数 + CASE WHEN,可读性极差。我写了一个UDF封装归因窗口匹配逻辑:

-- 使用方式
SELECT
  install_event.user_id,
  install_event.install_time,
  attribution_match(
    install_event.install_time,
    click_events,            -- 点击事件数组
    7,                       -- 归因窗口(7天)
    'last_click'             -- 归因模型
  ) AS attributed_channel
FROM install_with_clicks;

封装成UDF后,SQL变得非常简洁,而且归因逻辑可以复用在不同的报表里。

实战场景二:解析埋点里的JSON数组(UDTF)

我们的埋点数据里有个字段是extra_params,存的是JSON格式,里面可能包含一个数组:

{
  "items": [
    {"id": "item_001", "price": 9.99},
    {"id": "item_002", "price": 19.99}
  ],
  "source": "homepage"
}

需要把items数组展开成多行。Hive内置的get_json_object只能取单个值,不能展开数组。我写了一个UDTF来处理:

SELECT user_id, event_time, item.id, item.price
FROM dwd_user_event
LATERAL VIEW explode_json_array(extra_params, '$.items')
  t AS item;

什么时候该写UDF,什么时候不该写?

该写的场景: 逻辑复杂且复用率高。像上面的归因匹配,在多个报表里都要用,写成UDF一劳永逸。

不该写的场景: 能用内置函数解决的。UDF的维护成本不低——升级Hive/Spark版本时可能不兼容,新同事接手时还要理解你的UDF逻辑。

我的经验是:先尝试用内置函数解决,解决不了再考虑UDF。写UDF前先搜一下有没有现成的开源UDF库(比如brickhouse)。

一个容易踩的坑:UDF的序列化问题

如果你的UDF输入或输出是复杂类型(比如Array、Map),要特别注意Hive和Spark的序列化方式不同。我在出海硬件公司迁移到Databricks时,有两个UDF因为序列化不兼容报错,花了不少时间改适配。

总结

能用内置函数就不写UDF,复杂 + 复用的场景才值得封装。面试的时候能举一个真实的例子(写过什么UDF、解决了什么问题),说明你是真正写过的,不是背的。

下一篇聊Hive的事务表和ACID——Hive也能做UPDATE和DELETE了?生产环境为什么很少有人用?

你们写过哪些UDF?评论区聊聊~

关注「Wood聊大数据」| 9年大数据老兵,聊技术、聊职场、聊成长

刷题进度保存在当前浏览器