在数据仓库领域,Hive 作为基于 Hadoop 的分布式数据存储与计算工具,经常需要处理多样化的业务数据。除了基础的string
、int
等简单类型外,Hive 还提供了Array
(数组)、Map
(键值对)、Struct
(结构体)三种复杂数据类型,专门用于应对嵌套、多维的业务场景(如用户标签、商品属性、考试成绩等)。
本文将结合实际业务需求,通过完整的建表、数据加载、SQL 查询案例,带大家掌握这三种复杂数据类型的核心用法,并揭秘explode
、str_to_map
等关键函数的实战技巧。
一、Array(数组):有序的同类型集合
1.1 基本概念与特点
Array
是 Hive 中最常用的复杂类型,用于存储同一类型、有序的多个元素。其核心特点如下:
下标从 0 开始(如array[0]
表示第一个元素)
访问越界不会报错,返回null
(安全容错设计)
元素类型必须一致(如array<int>
或array<string>
)
1.2 实战:用 Array 存储学生多科成绩
假设我们需要存储学生的多科考试科目(如语文、数学、英语),就可以用Array
类型。
1.2.1 建表与数据加载
-- 创建包含Array类型的表
create table if not exists student_subjects (
name string, -- 学生姓名
subjects array<string> -- 报考科目(数组类型)
)
row format delimited
fields terminated by '\t' -- 字段分隔符(表级)
collection items terminated by ','; -- 数组元素分隔符(集合级)
-- 准备测试数据(/home/hivedata/array_data.txt)
-- zhangsan chinese,math,english
-- lisi math,physics
-- wangwu chinese
-- 加载数据
load data local inpath '/home/hivedata/array_data.txt' into table student_subjects;
1.2.2 关键操作:访问数组元素
Hive 中通过数组名[下标]
直接访问元素:
-- 查询每个学生的第一科和第三科(注意越界返回null)
select
name,
subjects[0] as first_subject, -- 下标0(第一个元素)
subjects[2] as third_subject -- 下标2(第三个元素,无则返回null)
from student_subjects;
执行结果:
name first_subject third_subject
zhangsan chinese english
lisi math null
wangwu chinese null
1.3 展开数组:explode 函数与 lateral view
业务中经常需要将数组 “炸开” 为多行数据(如统计所有学生的报考科目分布),这时需要用到explode
函数。
但explode
不能直接与原表字段关联,必须配合lateral view
(虚拟表关联)使用。
1.3.1 语法与逻辑
select 原表字段, 展开字段
from 原表
lateral view explode(数组字段) 虚拟表名 as 展开列名;
1.3.2 实战案例:统计所有报考科目
-- 将每个学生的报考科目展开为独立行
select
name,
subject
from student_subjects
lateral view explode(subjects) sub_view as subject;
执行结果:
name subject
zhangsan chinese
zhangsan math
zhangsan english
lisi math
lisi physics
wangwu chinese
通过这一步,我们可以轻松统计 “最热门报考科目”:
-- 统计各科目被报考次数
select
subject,
count(*) as cnt
from student_subjects
lateral view explode(subjects) sub_view as subject
group by subject
order by cnt desc;
结果
subject cnt
chinese 2
math 2
english 1
physics 1
二、Map(键值对):灵活的 KV 映射
2.1 基本概念与适用场景
Map
用于存储键值对(Key-Value)集合,适合需要 “属性 - 值” 映射的场景(如商品的 “颜色 - 数量”、学生的 “学科 - 成绩”)。其特点:
键(Key)唯一,值(Value)可重复
键值对无序(与 Array 的有序性区分)
支持map<key_type, value_type>
定义(如map<string, int>
)
2.2 实战:用 Map 存储学生各科成绩
假设需要存储学生的 “学科 - 成绩” 对应关系(如 “数学:90,语文:85”),Map
是更合适的选择。
2.2.1 建表与数据加载
-- 创建包含Map类型的表
create table if not exists student_scores (
name string, -- 学生姓名
score map<string, int> -- 学科-成绩(Map类型)
)
row format delimited
fields terminated by '\t' -- 字段分隔符
collection items terminated by ',' -- Map元素分隔符(键值对间)
map keys terminated by ':'; -- 键值对内部分隔符(Key与Value间)
-- 准备测试数据(/home/hivedata/map_data.txt)
-- zhangsan chinese:90,math:87,english:63
-- lisi chinese:60,math:30,physics:78
-- wangwu math:25,english:81
-- 加载数据
load data local inpath '/home/hivedata/map_data.txt' into table student_scores;
2.2.2 关键操作:访问 Map 值
Hive 中通过map[key]
获取对应值:
-- 查询每个学生的数学成绩(不存在则返回null)
select
name,
score['math'] as math_score
from student_scores;
执行结果:
name math_score
zhangsan 87
lisi 30
wangwu 25
2.3 字符串转 Map:str_to_map 函数
实际业务中,原始数据可能以字符串形式存储键值对(如"chinese:90,math:87"
),此时需要用str_to_map
函数将其转为 Map 类型。
2.3.1 函数语法
str_to_map(字符串, 键值对分隔符, 键值分隔符)
2.3.2 实战案例:将字符串转为 Map
假设原始数据存储为:
zhangsan chinese:90|math:87|english:63 -- 键值对用|分隔,键值用:分隔
lisi chinese:60|math:30|physics:78
我们可以通过str_to_map
动态转换:
-- 临时查询:将字符串列转为Map
select
name,
str_to_map(scores_str, '\\|', ':') as score_map -- 注意转义符\|表示|
from (
select
'zhangsan' as name,
'chinese:90|math:87|english:63' as scores_str
union all
select 'lisi', 'chinese:60|math:30|physics:78'
) t;
执行后score_map
字段将变为标准的 Map 类型,可以直接用score_map['math']
访问值。
三、Struct(结构体):强类型的复合对象
3.1 基本概念与适用场景
Struct
用于定义结构化的复合对象(类似 Java 的Class
或 Python 的dict
),适合需要固定格式的多属性组合场景(如学生的 “各科成绩” 需要明确字段名)。其特点:
字段名固定且有序(类似表的列)
字段类型可不同(如struct<name:string, age:int>
)
字段通过结构体名.字段名
访问
3.2 实战:用 Struct 存储学生详细成绩
假设需要存储学生的 “语文、数学、英语、自然” 四科成绩,且要求明确每个科目的字段名,Struct
是最佳选择。
3.2.1 建表与数据加载
-- 创建包含Struct类型的表
create table if not exists student_struct (
name string,
-- 结构体定义(各科成绩,明确字段名和类型)
score struct<chinese:int,math:int,english:int,natrue:int>
)
row format delimited
fields terminated by '\t' -- 表级字段分隔符
collection items terminated by ','; -- 结构体内字段分隔符
-- 准备测试数据(/home/hivedata/struct_data.txt)
-- zhangsan 90,87,63,76
-- lisi 60,30,78,0
-- wangwu 89,25,81,9
-- 加载数据
load data local inpath '/home/hivedata/struct_data.txt' into table student_struct;
3.2.2 关键操作:访问结构体字段
Hive 中通过结构体名.字段名
访问具体值:
-- 查询数学成绩>35分的学生的英语和语文成绩
select
name,
score.english as english_score,
score.chinese as chinese_score
from student_struct
where score.math > 35; -- 直接通过结构体.字段过滤
执行结果:
name english_score chinese_score
zhangsan 63 90
wangwu 81 89
3.3 Struct vs Map:如何选择?
很多新手会混淆Struct
和Map
的使用场景,这里总结关键区别:
特征 | Struct | Map |
---|---|---|
字段名是否固定 | 是(强类型,必须定义字段名) | 否(键动态,可灵活扩展) |
访问方式 | 结构体。字段名(如score.math ) | map [键](如score['math'] ) |
适用场景 | 固定格式的多属性对象(如学生成绩) | 动态键值对(如商品属性标签) |
此时若需查询数学成绩,必须用split
函数分割字符串:
select
name,
split(scores, ',')[1] as math_score -- 下标1对应数学成绩
from scores_str;