ARTICLE DETAIL

资讯详情

深耕商务建站与企业官网运营的一线实战洞察。

Hive函数从入门到实战:内置函数、窗口函数与UDF自定义函数完整解析

Hive函数从入门到实战:内置函数、窗口函数与UDF自定义函数完整解析 1. 先搞清楚 Hive 函数到底是怎么回事做了这么多年数仓开发我发现很多人在接触 Hive 函数时习惯性地把它当成 SQL 函数的一个“方言版本”。这种理解不能说错但会埋下不少坑。Hive 函数真正特殊的地方在于它运行在分布式计算引擎上处理的是“一批数据”而不是“一行数据”这就让它的执行逻辑、使用边界和优化手段都和传统关系型数据库里的函数有很大区别。Hive 函数解决的核心问题说白了就是在海量数据上完成清洗、转换、聚合、分析这些动作而不用你去写 MapReduce 程序。而且 Hive 函数体系本身也足够庞大从最简单的字符串截取到复杂的自定义聚合基本覆盖了离线数仓开发里九成以上的数据处理诉求。这篇文章会从我实际项目的角度出发把 Hive 函数从内置到自定义从常用姿势到避坑经验完整拆一遍希望能给正在做数仓开发、数据分析和 ETL 的同学一些实在的参考。有一点得先说透只记住某个函数的语法是没用的如果你不清楚它的触发时机、NULL 值处理逻辑、以及它在分布式环境下的执行特性那上线之后出问题的概率会非常大。所以这篇文章里我不会只列函数清单更重要的是把“为什么这样用”“在什么场景下踩过坑”讲清楚。适合看这篇内容的人我大致分了三类刚入门的数据分析同学需要掌握核心函数来写日常取数逻辑做数仓 ETL 的开发需要理解自定义函数和窗口函数的底层行为以及所有被数据倾斜、NULL 值异常、UDF 性能问题折磨过的同学。1.1 Hive 函数的本质与核心使用场景Hive 函数的本质可以理解为把复杂的数据处理逻辑封装成一个可复用的操作单元并交给底层的计算引擎去分布式执行。比如你要对一亿条用户行为日志做正则匹配提取 URL 中的关键参数如果自己写 MapReduce要处理输入分片、map 阶段的逐行处理、输出序列化等等工作量不小而用regexp_extract这个 Hive 函数一行 SQL 就搞定了。所以 Hive 函数的核心价值就是把通用的数据处理逻辑做成标准化操作让你把精力集中在业务问题上。在实际的项目里Hive 函数主要覆盖这么几类场景数据清洗场景字段拼接、字符串分割、正则替换、JSON 解析、空值兜底这些是数据入仓后最常做的事。统计分析场景按照维度分组后做求和、均值、去重计数以及更复杂的百分位估算。行转列与列转行场景把一条记录展开成多行或者把多行数据合并成一个数组支撑宽表开发和特征加工。窗口分析场景排行、累计、同比环比、相邻行对比这是数仓需求中占比很大的部分。我一直主张一个观点看一个 Hive 开发者水平怎么样不要看他会不会写复杂的 join而是看他能不能把函数用得恰到好处。因为 join 的逻辑是固定的套路而函数的选择往往决定了一个任务的性能上限和代码的可维护性。1.2 Hive 函数的家族谱系从内置函数到自定义函数Hive 函数大体上可以分成两条主线内置函数和自定义函数。内置函数是 Hive 开箱即用的能力自定义函数则是当内置函数满足不了业务需求时你用 Java 或者其他语言自己扩展的实现。内置函数按用途又可以细分成几类我通常这样归类函数类别典型函数主要用途数值函数round, floor, ceil, abs, rand数值计算、取整、随机抽样字符串函数concat, substring, split, regexp_replace字符串加工、正则处理、字段拆分日期函数from_unixtime, unix_timestamp, datediff, date_add时间戳转换、日期偏移、间隔计算条件函数if, case when, nvl, coalesce, nullif逻辑分支、空值兜底聚合函数count, sum, avg, collect_list, collect_set分组统计、列转行窗口函数row_number, rank, lag, lead, sum over排行、同比环比、累计计算特殊函数explode, posexplode, lateral view行转列、JSON 展开而自定义函数这边按输入输出的关系分成三类。UDF 是一进一出比如给你一个字符串返回处理后的字符串UDAF 是多进一出做自定义聚合UDTF 是一进多出把一行展开成多行。这三类我在后面的第 4 节会详细拆。2. 最常用的内置函数数值、字符串与日期实操内置函数虽然多但说句实话日常开发中真正高频使用的也就那三四十个。我在多个项目里统计过开发人员写的 Hive SQL 中超过八成的函数调用集中在字符串处理、日期转换和条件判断这三类。所以先把这批函数玩熟比死记硬背完整的函数列表有用得多。2.1 数值处理与字符串函数的使用细节数值函数里常用的无非就是round做四舍五入、floor向下取整、ceil向上取整、abs求绝对值以及rand做随机抽样。这里要说一个细节round在 Hive 里的行为是“四舍五入”但它的实现方式和很多编程语言里的有点差异。Hive 的round是基于Math.round实现的对于负数它遵循的是“四舍五入到最接近的整数”的规则。比如round(-2.5)的结果是 -3而不是 -2。这在做金额分摊或者比率计算的时候如果没留意就会产生 1 分钱的误差。别小看这个误差对过账系统来说1 分钱的对不上都会被当成数据事故。字符串函数这块concat和concat_ws是出场率最高的两个。很多人习惯用concat拼字段但一旦要拼的某个字段是 NULL结果就会变成 NULL整个字段就废了。concat_ws就好用在这它会跳过 NULL 值而且支持指定分隔符。我写过一句很典型的 SQLconcat_ws(-, year, month, day)用来拼分区字段这样即使某一天的数据缺失也不会把整个分区路径弄坏。split用来做字符串切分返回结果是数组。这里要注意的是Hive 的split第二个参数是正则表达式不是普通字符串。如果你要按点号切分 IP 地址直接写split(ip, .)是切不动的因为点号在正则里是通配符必须写成split(ip, \\.)。类似的还有按竖线切分要写成split(str, \\|)。这个坑我见过不少同学踩过排查半天发现是正则的问题。regexp_replace和regexp_extract是正则处理里的黄金搭档。前者是做替换后者是提取子串。regexp_extract提取的时候第二个参数里用括号圈出你要的部分第三个参数指定取第几个括号里的内容。比如从 URL 里提取 user_idregexp_extract(url, user_id(\\d), 1)。这里第三个参数写 1 就表示取第一个括号匹配到的内容。另外要留意正则的贪婪匹配问题有时候你会提取到超出预期的内容。如果遇到这种情况可以在正则后面加问号改成非贪婪模式。JSON 解析函数在日志分析场景里是刚需。get_json_object可以从 JSON 字符串里取指定字段比如get_json_object(json_str, $.username)。但get_json_object的效率并不好尤其是对一个大 JSON 反复取多个字段时会执行多次解析。这里更推荐的做法是用一次json_tuple配合lateral view把多个字段一次性拆出来解析只做一遍性能会好很多。2.2 日期函数与类型转换的实战要点日期函数这块核心就围绕三类操作时间戳与字符串互转、日期加减、日期差计算。时间戳转字符串用from_unixtime(unix_timestamp, pattern)比如from_unixtime(ts, yyyy-MM-dd HH:mm:ss)。反过来字符串转时间戳用unix_timestamp(2024-06-01 12:00:00, yyyy-MM-dd HH:mm:ss)。这里的重点是格式模式里的字母区分大小写yyyy表示四位的年份YYYY在 Hive 里有时候代表的是“周所在的年份”在跨年的时候可能和yyyy结果不一致。我建议统一用yyyy避免年底年初这种边界时段出现意料之外的数据。日期加减是date_add和date_sub支持传入负数实现相反方向的操作。比如想拿到 30 天前的日期可以写date_sub(current_date(), 30)也可以写date_add(current_date(), -30)。我个人更推荐用date_sub表达往前推的语义代码读起来直观。求日期差用datediff(end_date, start_date)返回值是前者减后者的天数。这里有一个容易搞错的地方datediff是按天计算的会被取整如果两边带时分秒差值会被截断不会四舍五入。所以你如果想要精确到小时的间隔不要用datediff直接用两个时间戳相减再除以 3600 秒。类型转换函数里cast是通用的转换入口cast(x as int)、cast(x as decimal(10,2))。但cast有个非常坑的行为转换失败时不会报错而是返回 NULL。比如cast(abc as int)的结果是 NULL如果你的下游逻辑没有针对 NULL 做处理数据就悄悄丢了。所以我在写类型转换时几乎都会配合case when先做合法性校验。额外提一个函数try_cast这个不是 Hive 原生的是某些引擎扩展的功能是转换失败返回 NULL 而不是抛异常。如果你所在的环境支持可以放心用不支持就老实写校验逻辑。3. 聚合函数与窗口函数数仓开发的重头戏聚合函数和窗口函数是 Hive 函数体系里最有分析深度的一块。很多取数需求表面上看起来复杂拆解到最后基本都是聚合加窗口的组合拳。把这两类函数吃透复杂报表开发起来会顺手很多。3.1 聚合函数的行为细节与常见用法聚合函数的输入是多行数据输出是一行结果。count、sum、avg、max、min这五个是最基础的。先说count的细节count(*)统计的是行数包括某列为 NULL 的行count(column)统计的则是该列非 NULL 的值的个数。很多新手在这里栽过跟头统计用户量的时候用count(user_id)如果 user_id 存在 NULL结果就会偏少。而count(distinct column)是去重计数这个好用但在数据量很大的时候要特别小心因为count(distinct)的底层实现容易引发数据倾斜。聚合函数里有两个在数仓开发中出场率很高但很多人用不好的函数collect_list和collect_set。它们的作用是把分组内的多行数据合并成一个数组前者保留重复元素后者自动去重。典型场景是行转列比如把某个用户的所有订单号聚合成一个数组再配合concat_ws拼成字符串。但要注意collect_list得到的数组元素顺序是不保证的如果你想控制顺序先在子查询里排好序再在外面聚合。虽然官方没有严格保证这种方式必然生效但实际操作中大部分版本是可行的也算是一种广为流传的土办法。avg在 Hive 里的返回值是 double 类型如果你需要精确的小数位控制建议先转成 decimal 再求平均比如avg(cast(amount as decimal(10, 4)))。另外聚合函数处理 NULL 的规则是“忽略 NULL”比如sum遇到一组全是 NULL 的数据返回的是 NULL 而不是 0。这个和很多人的直觉相反所以在做指标计算时我习惯用coalesce(sum(x), 0)把 NULL 兜底成 0避免下游报表出现空值。百分位估算函数percentile和percentile_approx也值得单独说。前者要求输入是整数列后者可以接受浮点数列并且可以传入一个精度参数控制估算质量。在计算 UV 分布、耗时中位数这类指标时非常有用而且底层做了近似算法不会像count(distinct)那样产生严重的倾斜问题。3.2 窗口函数排序、偏移与累计计算的完整拆解窗口函数的计算方式和普通聚合函数最大的区别在于聚合函数把多行结果压缩成一行窗口函数保留每一行同时附加一个聚合结果在旁边。这个特性让窗口函数成了分析场景里的主力工具。排序相关的窗口函数有三个row_number、rank、dense_rank。它们的区别我在项目里验证过很多次row_number不管并列情况给一个连续且唯一的编号rank遇到并列时会跳号dense_rank不跳号。举个实际场景取每个用户最近一次订单直接用row_number() over(partition by user_id order by order_time desc)就能定位而做榜单排名希望并列名次占用相同位次就用rank。偏移函数lag和lead是做环比、同比分析的神器。lag(column, offset, default)取当前行往前数第 offset 行的值lead则往后取。比如计算日活环比增长可以先按日期排序再用lag(dau, 1)取前一行的日活值然后直接算增长率。需要注意lag在最前面几行是没有值可取的如果不传第三个默认值参数返回的是 NULL下游要做过滤或兜底。累计计算是另一种高频用法。sum(amount) over(partition by user_id order by order_time rows between unbounded preceding and current row)就是非常典型的累计求和的写法。这里的关键是窗口子句rows between ... and ...它定义了累加的范围。还有rows between 1 preceding and current row表示统计当前行和上一行两行的合计常用于滑动计算。如果你不加窗口子句默认窗口是从分区起点到当前行也就是自然形成累计效果。这里要提醒一个很多人忽略的坑在使用排序相关的窗口函数时如果order by的字段存在大量重复值不同函数的执行行为会产生差异。例如sum() over(order by x)在 x 重复时累计值会把所有相同 x 的行一起算进去而不是逐行累加。这个行为在不同引擎里可能不一致遇到需求明确要逐行累计的场景建议在 order by 后面加上唯一字段做次级排序。3.3 窗口函数与表生成函数的协同实战窗口函数偶尔需要配合表生成函数使用典型场景是展开 JSON 数组后再对展开后的行做编号或排名。表生成函数的核心是explode它可以把一个数组或者 map 展开成多行。比如埋点日志里某个字段存的是商品 id 列表用explode就能把一条日志展开成多条商品记录。但在 Hive 旧版本里explode不能直接在 select 语句里和其他字段一起查询必须配合lateral view。lateral view的字面意思就是“侧视图”它把 explode 产生的虚拟表和原始行关联起来。一个典型写法是select user_id, order_id from orders lateral view explode(split(product_list, ,)) t as order_id;这种写法把product_list字符串切成数组再展开成多行每一行都保留原来的user_id。posexplode是explode的增强版它会额外带一个下标列可以用于记录展开后元素的原始下标这在还原数组顺序时很有用比如拼接的商品顺序不能乱。在做用户标签场景时我经常把lateral view explode和窗口函数放在一起用。先把每个用户的标签数组展开再用row_number给每个标签做排序之后根据标签优先级取第一条整个处理链路非常流畅。4. 自定义函数系统函数不够用时的突围方案内置函数再丰富也总有覆盖不到的业务逻辑。比如解析一套内部自定义的加密协议字段、计算两个地理位置的距离、实现一套特殊的分组逻辑这些时候就需要自己写函数扩展 Hive 的能力。4.1 UDF、UDAF、UDTF 的选型与核心原理自定义函数按输入输出关系分成三类UDF输入一行输出一行。这是最常用、最容易上手的一类。典型场景是字符串加工、字段解析、格式标准化。UDAF输入多行输出一行本质是自定义聚合函数。典型场景是实现自定义统计指标比如加权平均、分组去重拼接。UDTF输入一行输出多行。典型场景是把一行数据展开成多行类似内置的explode。选型的原则其实很简单你在 SQL 里要替换的是一个普通字段转换就用 UDF要替换的是group by里的聚合逻辑就考虑 UDAF要替换的是explode这种行转列操作就写 UDTF。UDF 的实现底层依赖 Hive 的反射机制。你在 SQL 里写my_func(x)Hive 会去找到对应的 Java 类实例化后把每一行的数据传进去调用你实现的evaluate方法。这里的核心是同一个 UDF 实例会被多个计算节点并发使用所以你的实现里不能有可变的状态变量。我见过有人把计数器写在 UDF 的成员变量里以为能统计处理行数结果数据完全对不上原因就是每个节点各自维护了独立的实例。4.2 一个 UDF 从开发到上线的完整流程下面用一个实际案例走一遍全流程。假设业务方要求从订单号中解析出订单来源渠道订单号的规则是“渠道编码 日期 序列号”拼接而成比如A01_20240601_000123A01 就是渠道编码。内置函数当然也能用split来解析但这类逻辑如果散落在几十个 SQL 里维护成本会很高封装成 UDF 更合理。第一步创建 Maven 工程引入 Hive 依赖。dependency groupIdorg.apache.hive/groupId artifactIdhive-exec/artifactId version3.1.2/version scopeprovided/scope /dependency第二步写 UDF 实现类。继承org.apache.hadoop.hive.ql.exec.UDF实现evaluate方法。import org.apache.hadoop.hive.ql.exec.UDF; public class OrderChannelParser extends UDF { public String evaluate(String orderId) { if (orderId null || orderId.isEmpty()) { return null; } String[] parts orderId.split(_); return parts.length 0 ? parts[0] : null; } }evaluate方法可以重载多个版本Hive 会根据调用时传入的参数类型自动选择。所以同一个 UDF 类可以实现支持多种输入类型比如既有String evaluate(String)又有String evaluate(String, String)调用时的不同参数会路由到不同方法。第三步将项目打成 jar 包上传到 Hive 能访问到的目录然后注册函数。add jar hdfs://your-path/order-parser.jar; create temporary function parse_order_channel as com.example.OrderChannelParser;这里temporary关键字表示只在当前会话生效适合开发和测试。如果你要把函数做成永久能力可以执行create function parse_order_channel as com.example.OrderChannelParser using jar hdfs://your-path/order-parser.jar;第四步在 SQL 里调用验证结果。select parse_order_channel(order_id) as channel, count(*) as cnt from orders group by parse_order_channel(order_id);整个流程跑通之后业务方后续所有解析渠道的需求都只需要调用这一个函数代码复用性大幅提升而且排查问题时只需要看一个类不用翻十几个 SQL。4.3 UDAF 与 UDTF 的实现要点与注意事项UDAF 的实现会比 UDF 复杂一个量级。在 Hive 2.0 以上的版本里推荐使用org.apache.hadoop.hive.ql.udf.generic.AbstractGenericUDAFResolver配合GenericUDAFEvaluator的实现方式。核心逻辑是定义一个内部状态AggregationBuffer在iterate方法里接收每一行数据更新状态在terminatePartial里输出部分聚合结果最后在terminate里输出最终结果。这里的关键是要理解 Hive 的聚合计算模型数据分散在多个节点上先做局部聚合再做全局聚合。所以你的聚合状态必须支持合并这对应merge方法。我见过不少 UDAF 实现错误把全局聚合和局部聚合搞混导致结果翻倍或者丢失。UDTF 的实现则是继承GenericUDTF实现initialize、process和close三个方法。initialize里定义输出列名和类型process里接收一行数据可以多次调用forward输出多行。写 UDTF 时有一个限制需要留意Hive 不允许 UDTF 的输入参数和输出列在同一张表里出现重名否则会报错如果需要保留原字段必须配合lateral view使用。自定义函数上线前务必做三个层面的验证单测验证结果是必要条件造几组边界数据NULL、空串、超长字符串、特殊字符确认不会抛异常其次用一个小分区跑真实数据对比你预期的结果分布最后压测确认执行耗时不会拖垮整个任务。尤其是 UDF 里做了重量级操作比如在每一行都新建一个正则 Pattern 对象那在大表上就是灾难Pattern 对象应该在构造时初始化一次。5. 函数使用中的常见坑与排查实战不管内置函数还是自定义函数实际跑数时总会遇到各种问题。这一节我把自己在多个项目里踩过的坑集中整理一下。5.1 性能问题数据倾斜与函数副作用Hive 任务里最典型的性能问题就是数据倾斜。表现的样貌是整个任务卡在某个 reduce 上其他都跑完了就它一个在那慢慢磨。函数触发的倾斜有几个常见原因。第一个是count(distinct)在超大基数场景下的归并问题。比如统计上亿用户的去重设备数count(distinct device_id)会把所有设备的去重压力打到同一个 reduce 上。解决思路一般是改成先group by device_id去重再外层count(1)。这个优化的本质是把压力分散到多个 reduce 上内核是两阶段聚合。第二个是 UDF 里做了耗时操作比如正则回溯、解析超大 JSON、循环里做字符串拼接。这类问题在数据量小的时候完全无感一旦迁移到百亿级大表执行时间就会被无限放大。我在项目里优化过一个案例问题根源就是 UDF 的evaluate方法里调用了Pattern.compile做正则预处理后来改成在类初始化时把Pattern编译缓存好任务耗时直接从 3 小时降到 20 分钟。第三个是collect_list在大分组下的 OOM 风险。如果一个分组内的数据量巨大collect 出来的数组会占用大量内存。一个比较务实的策略是先对数据做抽样评估如果某个 key 的数据量确实异常大就需要考虑是否真的需要全量 collect还是可以先做一层预过滤。5.2 数据正确性问题NULL、精度、时区与隐式转换这类问题隐蔽性很强往往数据跑完了才发现不对重跑成本极高。NULL 值问题在前面反复出现这里再汇总一下。concat遇 NULL 返回 NULL、count(column)不统计 NULL、sum全 NULL 返回 NULL、concat_ws跳过 NULL、coalesce返回第一个非 NULL 值。我的习惯是数据清洗阶段尽量把 NULL 处理掉统一转成确定的默认值或者空串后续的分析查询就省心很多。精度问题是金额类指标的重灾区。Hive 的 double 类型在sum计算时会产生精度丢失尤其是对金额做累加结果可能出现 0.1 的误差。我在处理财务指标时一律要求上游把金额字段转成decimal(18, 2)或者精度更高的类型再参与后续聚合。round的负数舍入问题前面已经提过同样值得注意。时区问题在日期处理函数里很常见表现形式是取数结果和预期相差 8 个小时。原因在于from_unixtime默认使用服务器的本地时区来格式化时间戳如果你的集群时区配置和业务方预期不一致就会出现偏移。排查这类问题时先确认集群的hive.execution.timezone配置再确认时间戳字段本身是否是 UTC 时间。最稳妥的做法是统一约定所有时间戳存储都用 UTC展示时显式指定时区转换。隐式转换是另一个容易静默出错的点。比如一个字段被定义成字符串类型但你拿它和整数比较Hive 会做隐式转换如果那个字段的内容不是纯数字比较结果就会偏离预期。我建议在表结构定义阶段就严格要求字段类型不要在 SQL 里依赖隐式转换。举一个典型的错误把分区字段dt存成 string然后用dt 20240601 and dt 20240630这种不带引号的写法去查看起来能跑通但如果有一天分区字段里出现非数字内容这种行为就变得不可预测了。5.3 函数相关常见问题速查表我整理了一张日常排查速查表出现问题可以先对照排查。现象可能原因解决方向split按点切分无效点号是正则通配符写成split(ip, \\.)concat结果为 NULL某字段为 NULL改用concat_ws或nvl兜底count(distinct)任务卡死去重基数过大导致倾斜改成 group by count 两阶段日期结果差 8 小时时区配置不一致检查集群时区统一 UTC 存储cast(abc as int)无报错Hive 转换失败返回 NULL配合 case when 做校验金额求和结果有误差double 精度丢失字段转 decimal 再聚合collect_list内存溢出单分组数据过大预过滤、增大容器内存或改方案UDF 任务整体很慢evaluate 里有重操作初始化时缓存 Pattern避免重复编译row_number排名的结果和预期不同order by 字段重复增加唯一字段做次级排序datediff结果被取整按天计算截断时分秒用时间戳相减精确计算这个表是我在几个项目迭代中不断沉淀下来的后续遇到新的问题还在持续补充。排查思路的本质就一条先确认函数本身的行为再确认数据本身的特征。两者分开排查问题定位就快很多。6. 从实际项目里沉淀的 Hive 函数使用经验写到最后这部分分享一下我在实际项目中总结的一些使用经验。这里面没有特别高深的技术都是实打实提升开发和维护效率的做法。6.1 函数使用的基本原则第一条原则是能用内置函数解决的就不要写自定义函数。内置函数经过大量场景验证稳定性、性能都有保障。自定义函数的维护成本是隐性的后面换人接手要花时间理解函数逻辑一旦函数里有隐蔽的边界 bug排查代价很大。第二条原则是逻辑尽量后置到 SQL 层而不是前置在 UDF 里。比如字符串标准化、金额单位转换这类逻辑如果写到 UDF 里后续调整要改代码重新打包但如果写在 SQL 里一个字段改一下重跑就行。我见过一个项目把汇率转换写在 UDF 里结果汇率基准更新时整个 UDF 要重新上线非常折腾。第三条原则是函数调用的可读性要优先。写 SQL 不要炫技能用简单的case when说清楚就不要写一个嵌套三层的regexp_extract或者复杂的窗口函数表达式。数据开发最大的成本是别人读你代码的成本代码写得直白后面维护的人会感谢你。6.2 高价值函数组合与数据加工套路项目里有一种高频套路清洗阶段用case when加regexp_extract做字段规范化标准化阶段用from_unixtime和date_format做时间规整加工阶段用窗口函数做指标加工。这套组合打下来覆盖了从明细数据到指标宽表的绝大多数需求。有一个典型的宽表加工例子统计每个用户最近 7 天的下单金额和下单次数同时要算出和上一个自然周的同环比。实现思路是先用date_format(order_time, yyyy-ww)提取周维度再用datediff计算日期差值然后配合条件聚合把最近 7 天的数据框出来。这些函数单看都很简单但组合起来就能解决很复杂的业务诉求。还有一个经验值得分享在写窗口函数做指标加工时尽量把partition by的粒度控制在最小业务粒度。比如统计用户的每日指标时partition by user_id, order_date一定比partition by user_id然后靠order by来限定更可控因为前者能清晰地表达“每组只算一天的数据”排查时思路更明确。6.3 最后再分享一个我一直在用的小技巧在写任何一个带聚合或窗口的 SQL 之前先在脑子里过一遍数据特征这个字段有没有 NULL、这个维度有没有可能产生大量的重复值、这个时间字段的时区是什么。这些问题过完之后再动手写 SQL踩坑概率会下降一大半。很多看起来莫名其妙的数据异常本质都是写 SQL 之前没有想清楚数据的分布特征。函数本身没有错错的是你假设数据是干净有序的。另外一个习惯是在函数选型时主动考虑表的数据量和文件格式。在 Parquet 这类列式存储上某些函数在过滤条件下可以做到延迟物化整体执行效率比在 Text 格式上高很多。因此做方案设计时函数选型和存储格式需要通盘考虑不能只盯着一句 SQL 看。做 Hive 开发这么多年我的体会一直是函数只是工具真正拉开差距的是你对自己数据的理解程度。函数学得快慢不重要重要的是每一次使用函数时都能清楚知道它在这个数据集上会发生什么。这个意识建立起来之后你写的每一段 SQL 都会比之前稳得多。
返回列表
PREV
查看更多资讯
NEXT
返回资讯列表