Hive explode巨详细讲解

📅 2026/8/25 19:56:04
Hive explode巨详细讲解
一、explode是什么Hive 中的explode用于把一行中的数组或 Map 拆成多行。一行数组 ↓ explode 多行普通字段例如原始数据user_id | tags --------|------------------ 1 | [hive, spark] 2 | [flink, java]展开后user_id | tag --------|------ 1 | hive 1 | spark 2 | flink 2 | java二、展开数组Hive 中通常需要配合LATERAL VIEW使用SELECTuser_id,tagFROMuser_tags LATERALVIEWEXPLODE(tags)tAStag;其中EXPLODE(tags)展开 tags 数组 t 虚拟表别名 AS tag 定义展开后的字段名如果一行数组中有 3 个元素该行通常会变成 3 行。三、完整示例1. 建表示例CREATETABLEuser_tags(user_idBIGINT,tags ARRAYSTRING)STOREDASORC;2. 查询数组元素SELECTuser_id,tagFROMuser_tags LATERALVIEWEXPLODE(tags)tAStag;3. 展开后统计每个标签的用户数SELECTtag,COUNT(DISTINCTuser_id)ASuser_countFROMuser_tags LATERALVIEWEXPLODE(tags)tAStagGROUPBYtag;注意如果同一个用户的数组中重复出现同一个标签直接COUNT(*)可能会重复计数统计用户数时通常使用COUNT(DISTINCT user_id)。四、字符串转数组后再展开如果字段不是数组而是逗号分隔的字符串user_id | tags --------|---------------- 1 | hive,spark,flink 2 | java,hadoop可以先用split()转成数组再使用explode()SELECTuser_id,tagFROMuser_tags LATERALVIEWEXPLODE(SPLIT(tags,,))tAStag;结果user_id | tag --------|------- 1 | hive 1 | spark 1 | flink 2 | java 2 | hadoop如果分隔符是竖线由于split的分隔符是正则表达式需要转义LATERALVIEWEXPLODE(SPLIT(tags,\\|))tAStag;五、展开 Mapexplode()也可以展开 Map结果会得到两个字段key和value。原始数据user_id | attributes --------|----------------------------- 1 | {city:Beijing,age:20}SQLSELECTuser_id,attr_key,attr_valueFROMuser_attributes LATERALVIEWEXPLODE(attributes)tASattr_key,attr_value;结果user_id | attr_key | attr_value --------|----------|------------ 1 | city | Beijing 1 | age | 20六、posexplode展开并保留下标如果除了元素值还需要知道元素在数组中的位置可以使用posexplode()SELECTuser_id,pos,tagFROMuser_tags LATERALVIEWPOSEXPLODE(tags)tASpos,tag;结果user_id | pos | tag --------|-----|------ 1 | 0 | hive 1 | 1 | spark 2 | 0 | flink 2 | 1 | javaHive 数组下标从0开始。常见用途保留数组原始顺序获取元素所在位置两个数组按照相同下标进行匹配。七、两个数组按位置对应假设表中有user_id | subjects | scores --------|------------------|-------- 1 | [math, english] | [90, 85]目标是得到user_id | subject | score --------|---------|------ 1 | math | 90 1 | english | 85可以分别使用posexplode()再根据位置关联WITHsubject_dataAS(SELECTuser_id,pos,subjectFROMuser_score LATERALVIEWPOSEXPLODE(subjects)tASpos,subject),score_dataAS(SELECTuser_id,pos,scoreFROMuser_score LATERALVIEWPOSEXPLODE(scores)tASpos,score)SELECTs.user_id,s.subject,c.scoreFROMsubject_data sJOINscore_data cONs.user_idc.user_idANDs.posc.pos;不要直接对两个数组分别explode后放在同一条查询中否则容易产生笛卡尔积。八、LATERAL VIEW OUTER EXPLODE普通的explode()遇到NULL或空数组时可能不会保留原始行SELECTuser_id,tagFROMuser_tags LATERALVIEWEXPLODE(tags)tAStag;如果希望数组为空时仍保留用户记录可以使用OUTERSELECTuser_id,tagFROMuser_tags LATERALVIEWOUTEREXPLODE(tags)tAStag;没有元素的用户会保留展开后的tag通常为NULL。两者区别LATERAL VIEW EXPLODE没有元素时可能不输出该行 LATERAL VIEW OUTER EXPLODE没有元素时仍保留原始行九、展开数组中的 Struct如果数组元素是结构体例如orders [ {product: apple, price: 5}, {product: banana, price: 8} ]表结构CREATETABLEuser_orders(user_idBIGINT,orders ARRAYSTRUCTproduct:STRING,price:DOUBLE)STOREDASPARQUET;展开并访问 Struct 字段SELECTuser_id,order_item.productASproduct,order_item.priceASpriceFROMuser_orders LATERALVIEWEXPLODE(orders)tASorder_item;十、常见注意事项1.explode会放大数据量100 万行 × 每行 100 个数组元素 ≈ 1 亿行输出使用前要评估数据量和下游计算成本。2. 注意NULL、空数组和空字符串这几种情况含义不同NULL没有数组值 []数组存在但没有元素 []数组中有一个空字符串必要时可以过滤空值SELECTuser_id,tagFROMuser_tags LATERALVIEWEXPLODE(tags)tAStagWHEREtagISNOTNULLANDtag;3. 展开后再聚合可能重复计数展开会改变行数后续计算指标时要重新确认统计口径。4.explode通常不能直接放在普通SELECT中推荐写法SELECTid,itemFROMtable_name LATERALVIEWEXPLODE(array_col)tASitem;而不是简单写成-- 某些 Hive 版本或场景下不适用SELECTid,EXPLODE(array_col)FROMtable_name;十一、快速记忆-- 展开数组LATERALVIEWEXPLODE(array_col)tASitem-- 展开数组并保留下标LATERALVIEWPOSEXPLODE(array_col)tASpos,item-- 展开 MapLATERALVIEWEXPLODE(map_col)tASmap_key,map_value-- 数组为空时保留原始行LATERALVIEWOUTEREXPLODE(array_col)tASitem一句话总结explode用于把 Hive 一行中的数组或 Map 拆成多行数组展开后得到元素Map 展开后得到键和值若需要保留下标则使用posexplode。