查询map字段

Hive Map 字段:键值对怎么存、怎么查、什么场景该用

Hive 支持 MAP 类型,用来存键值对——比如”科目:分数”、”属性:值”这种结构不确定的数据。

Map 类型适合的场景:

  • 字段的 key 不固定(不同行可能有不同的键)
  • 键值对的数量不固定(有的行 3 个键,有的行 10 个键)

Map 类型不适合的场景:

  • 键是固定的(比如所有学生都考语数英)→ 拆成普通列 math_scoreenglish_score,查询效率高得多
  • 需要频繁按 key 过滤 → Map 字段没有索引,每次都要扫全表

原则:能用普通列就用普通列,只有键不固定的时候才用 Map。

建表:指定三层分隔符

建 Map 类型表要指定三层分隔符:

CREATE TABLE student_score (
  name STRING,
  score MAP<STRING, INT>   -- 键:科目名,值:分数
)
ROW FORMAT DELIMITED
  FIELDS TERMINATED BY '\t'    -- 列分隔符(name 和 score 之间)
  COLLECTION ITEMS TERMINATED BY ','  -- Map 中键值对之间的分隔符
  MAP KEYS TERMINATED BY ':';   -- 键和值之间的分隔符

数据文件格式示例:

张三    数学:90,英语:85,语文:95
李四    数学:88,英语:92
王五    语文:80,物理:75,数学:90

基本查询:取某个 key 的值

-- 查张三的数学成绩
SELECT name, score['数学'] AS math_score
FROM student_score
WHERE name = '张三';
-- 输出:张三  90

-- 查所有学生的英语成绩(没有英语成绩的返回 NULL)
SELECT name, score['英语'] AS english_score
FROM student_score;
-- 输出:
-- 张三  85
-- 李四  92
-- 王五  NULL

判断某个 key 是否存在

-- 查找有"物理"成绩的学生
SELECT name, score
FROM student_score
WHERE array_contains(map_keys(score), '物理');
-- 输出:王五  {"语文":80,"物理":75,"数学":90}

map_keys(score) 返回所有键的数组,array_contains 判断目标键是否在数组里。

获取键或值的集合

-- 查每个学生考了哪些科目
SELECT name, map_keys(score) AS subjects
FROM student_score;
-- 张三  ["数学","英语","语文"]
-- 李四  ["数学","英语"]
-- 王五  ["语文","物理","数学"]

-- 查每个学生的所有分数
SELECT name, map_values(score) AS scores
FROM student_score;
-- 张三  [90,85,95]
-- 李四  [88,92]
-- 王五  [80,75,90]

展开 Map 做聚合分析

Map 字段存的是”成组”的数据,但分析的时候经常需要”拆开”看——比如统计各科目的平均分。

explode(score) 把 Map 拆成多行:

-- 每个学生各科成绩展开
SELECT name, subject, s_score
FROM student_score
LATERAL VIEW explode(score) t AS subject, s_score;
-- 输出:
-- 张三  数学  90
-- 张三  英语  85
-- 张三  语文  95
-- 李四  数学  88
-- 李四  英语  92
-- 王五  语文  80
-- 王五  物理  75
-- 王五  数学  90

展开之后就可以做普通聚合了:

统计各科目平均分:

SELECT subject, AVG(s_score) AS avg_score
FROM student_score
LATERAL VIEW explode(score) t AS subject, s_score
GROUP BY subject;
-- 数学  89.33
-- 英语  88.5
-- 语文  87.5
-- 物理  75

统计每个学生平均分:

SELECT name, AVG(s_score) AS avg_score
FROM student_score
LATERAL VIEW explode(map_values(score)) t AS s_score
GROUP BY name;
-- 张三  90.0
-- 李四  90.0
-- 王五  81.67

Map 的局限性

Map 类型灵活,但有三个硬伤:

问题 说明
没有索引 查询 score['数学'] 要扫全表,不像普通列能走分区或索引
key 值不统一 同一个 key 可能写成”数学”、”Math”、”数”,数据质量难保证
查询语法复杂 想按科目过滤必须 array_contains(map_keys(score), '数学'),又长又慢