1. 含义
和Java中的Map一样,多个Key-Value的组合。
2. 场景
什么样的数据,适合使用map类型来存储呢?这里列举了几个我在开发中实际用到的场景。
2.1 数量不固定的多个KeyValue
这类,本身就是Map类型的数据。例如:用户购买不同类目的商品个数、商家销往不同城市的商品个数等等。可能用户昨天之前没买过数码类商品、而今天就买了;也可能商家昨天之前没把东西卖到过深圳、而今天就有深圳的买家买了。所以KV对的个数是不固定的,无法用常规的字段固化下来,更合适采用Map来存储这类动态的数据。
2.2 标签类的数据
之前说过,标签类的数据适合用array存储,绝大部分情况下是合适的。
但是有些场景,例如数据分析展示到BI报表中,一般我们需要直接把标签展示成中文。而一般情况下,我们的标签都是通过“数字ID”或者“字母”来存储的。如果这类数据需要展示成中文,又要再额外关联一次字典表取得中文,每个统计任务都关联一次,就有点儿麻烦了。
所以这里建议,直接在基础数据表中,就把ID对应的中文保存起来。Map的key是“标签ID”、value是“标签中文”。用空间,换效率。
2.3 嵌套struct
之前说过,对象有多种固定的属性,简单的key-value格式无法满足,可以使用array嵌套struct的方式定义。
但是这类的array如果想解析,只能先全部展开,再拿到我们需要的部分。如果我们可以事先知道常用的检索条件,并且该字段唯一、不重复,就可以用map代替array。map的key就是我们常用的检索条件字段,value则是一个struct对象。
3. 玩转map
3.1 构造map
3.1.1 直接拼
SELECT map('k1','v1','k2','v2','k3','v3') AS c;
c |
---|
{"k3":"v3","k1":"v1","k2":"v2"} |
这种直接拼成map的方法,需要开发自己去保证所有的key的类型一致、所有的value的类型一致,否则会报错。
但实际应用过程中,key和value一般都直接用string类型,简单粗暴。用的时候现去做类型转换。
3.1.2 将一定格式的字符串转为map
实际应用中,这种构造方法最为常见。默认,每个KV对之间的分隔符为英文逗号,K和V之间的分隔符为等号。
SELECT str_to_map('k1=v1,k2=v2,k3=v3') AS c;
c |
---|
{"k3":"v3","k1":"v1","k2":"v2"} |
如果实际的分隔符不是逗号与等号,就需要传入实际的分隔符作为参数。
SELECT str_to_map('k1:v1;k2:v2;k3:v3',';',':') AS c;
c |
---|
{"k3":"v3","k1":"v1","k2":"v2"} |
第二个参数为“每个KV对之间的分隔符”,第三个参数为“K和V之间的分隔符”。
3.2 查元素个数
SELECT size(str_to_map('k1=v1,k2=v2,k3=v3')) AS c;
c |
---|
3 |
3.3 取出所有Key
SELECT map_keys(str_to_map('k1=v1,k2=v2,k3=v3')) AS c;
c |
---|
["k1","k2","k3"] |
3.4 取出所有Value
SELECT map_values(str_to_map('k1=v1,k2=v2,k3=v3')) AS c;
c |
---|
["v1","v2","v3"] |
3.5 根据Key值取Value
SELECT str_to_map('k1=v1,k2=v2,k3=v3')['k3'] AS c;
c |
---|
v3 |
3.6 展开
主要有两种展开方式。一种是“只展开map”,即select后边只有展开后的map。
SELECT explode(str_to_map('k1=v1,k2=v2,k3=v3')) AS (c1,c2);
c1 | c2 |
---|---|
k1 | v1 |
k2 | v2 |
k3 | v3 |
另一种是展开map的同时,还要带上其他字段。即select后边除了展开后的map之外,还有其他字段。
SELECT t1.id,t2.k,t2.v
FROM (
SELECT 666 AS id,
str_to_map('k1=v1,k2=v2,k3=v3') AS c
) t1
LATERAL VIEW EXPLODE(t1.c) t2 AS k,v;
id | k | v |
---|---|---|
666 | k1 | v1 |
666 | k2 | v2 |
666 | k3 | v3 |
4. 常见用法
- 使用map的时候,不要去过分纠结“字段类型”、“键值对的顺序”这类没有意义或者意义不大的问题。完全可以key和value都弄成字符串类型,顺序等到最后再去排;
- 列转行。常见的思路是,先把待转的列拼成一个map,再用explode展开;
- map类型不止用在数据存储上,还可以用在复杂SQL的中间过程中。主要和explode联用,做行列转化;