HIVE如何校验map数据
内容目录
- HIVE如何校验map数据
- 一、描述
- 二、思路
- 三、实现:
- 实现方法1:
- 实现方法2
- 改进
在数据校验中,一般会进行checksum,即比较变换前后的hash值的和是否相同,再不考虑哈希碰撞的特别情况下,如果checksum的结果一致,就可以认为变更的结果是无误的。
但是hash只能对一些基本数据类型使用,对于map等类型来讲,其实并不太准确,那么如何进行map类型checksum呢?
一、描述
对于json转map之后,通过转换前的json和转换后的map做checksum是不可行的,因为两者结果差别还是挺大的
select hash(map("hi","bili","hello","world"))
union all
select hash('{"hi":"bili","hello":"world"}')
结果:
map: 55979077
json: 1202933987
二、思路
那么对于json转map后的checksum应该怎么做?或者如何确定转换的结果没有错?
采用的方法是通过get_json_object和element_at方法来确定转换前后结果是否又误。
- 获取转换后map的所有key数值
- 将获取的key数值结果分别分配给每行数据
- 分别提取每个key的数据,比较是否相同
三、实现:
实现方法1:
将转换后所有的map结果的key提取出来
key_s as (
select
-- map提取使用的key
key_one,
-- json提取使用的key
concat('$.',key_one) object_one,
1 as joinkey
from (
select
-- 将所有key去重合并在一起
collect_set(key_one) keys
from (
select
-- 将每一行的key炸开
key_one
from (
select
-- 得到每一行数据的key
map_keys(extended_map) keys
from
tmp_bdp.test_map
) t1
lateral view explode(keys) tmp as key_one
) t2
) t3
lateral view explode(keys) tmp as key_one
)
然后和转换前后的json和map进行关联提取每个key数据
check_object as (
select
extended_fields,
extended_map,
1 as joinkey
from
tmp_bdp.test_map
)
关联求解
check_key as (
select
t2.extended_fields,
t2.extended_map,
t1.key_one,
t1.object_one
from
key_s as t1
join
check_object t2
on t1.joinkey = t2.joinkey
)
select
-- 求每一行的hash值,如果不相同,说明此行变换的有问题
sum(hash(get_json_object(extended_fields, object_one))) json_hash,
sum(hash(extended_map[key_one]))
from
check_key
实现方法2
上面上个方法虽然可以得解,但是有一些很大的资源消耗,因为是找到的所有的map的key,但是对于单行数据来说,其实有些key是用不到的,所以造成了很大的资源消耗,所以可以针对每一行进行提取key即可,然后在该行使用即可
with key_s as (
select
extended_fields, -- json
extended_map, -- map
map_keys(extended_map) keys
from
tmp_bdp.test_map
)
,check_key as (
select
extended_fields,
extended_map,
-- 将key炸开,变为单个key
key_one,
concat('$.', key_one) key_json
from
key_s
lateral view explode(keys) tmp as key_one
)
-- 求解每行的key即可
select
extended_fields,
extended_map,
hash(get_json_object(extended_fields, key_json)) json_hash,
hash(extended_map[key_one] )map_hash
from
check_key
TIPS:
其实这里有一个小问题,在测试的时候发现有些行是的hash值并不相同,检测之后发现是有些key是多个字段是组合的,比如:“bundle.ver.demo”,这样在map中可以获得value值,而在json中使用get_json_object提取时就会返回null值,所以需要把get_json_object方法改为使用json_tuple方法。
但是需要注意的是,get_json_object是一个UDF,而json_tuple是一个UDTF,所以在使用的时候返回的是多个值,需要炸开才可以,否则会报错:
FAILED: SemanticException [Error 10081]: UDTF's are not supported outside the SELECT clause, nor nested in expressions
改进
修改之后的代码就是:
select
hash(json_s) json_hash,
hash(extended_map[key_one])map_hash
from
check_key
-- 将json炸开
lateral view JSON_TUPLE(extended_fields, key_one) tmp as json_s
整体代码就变为了:
with key_s as (select
extended_fields, -- json
extended_map, -- map
map_keys(extended_map) keys
from
tmp_bdp.test_map
)
,check_key as (
select
extended_fields,
extended_map,
key_one
from
key_s
lateral view explode(keys) tmp as key_one
)
,join_key as (
select
hash(json_s) json_hash,
hash(extended_map[key_one])map_hash
from
check_key
lateral view JSON_TUPLE(extended_fields, key_one) tmp as json_s
)
select * from join_key
如果存在hash值不一样的情况,就说明变换前后是有问题的