背景:
在客户+指标粒度的多个报表中,源表某个客户具有多个指标数据,有发生额、交易笔数、余额等指标。经过脚本加工处理后,发生额和余额指标(单位:元)丢失,只有交易笔数指标尚存。
由于报表产生非常多的指标,并且是同一数据源加工多个不同口径指标,表结构设计为指标纵表(每个指标一行)。源数据为指标宽表(每个指标一列),采用的是 LATERAL VIEW 侧视图进行列转行。为提升跑批效率,脚本主要采用 Spark 引擎(加载到内存计算) 执行任务,涉及到海量数据的情况采用 Hive (落地磁盘计算) 执行跑批。
上述问题经业务提出后发现同一数据源和相同处理逻辑的脚本,其采用的执行引擎不同,跑出的结果数据存在差异,Hive 执行会跑出所有的指标,Spark 仅跑出部分指标。由于执行引擎的不同而造成了数据差异,其带来的影响将会非常大,需要立马排查。通过控制变量法,逐步拆分脚本,分段跑出数据对比,最后定位到在 LATERAL VIEW 侧视图计算指标后的 where 条件中对数值为 0 的指标进行过滤,两个引擎的处理结果不一致。
示例代码:
select cust_nm,norm[0] as indx_nm,norm[1] as num
from (select 'shbank' as cust_nm,10 as jybs,800000000 as jyje) t1
lateral view posexplode(
array(array('交易笔数',jybs)
,array('交易金额',jyje)
)
) tmp as pos,norm
where norm[1] is not null and norm[1] != 0
;
代码最后一行中 norm[1] != 0 ,在 Spark 与 Hive 的计算中结果不一样。在该测试数据中 Hive 会跑出两条指标数据,而 Spark 会过滤掉一条,结果只有交易笔数指标。
是因为在 LATERAL VIEW 侧视图返回后的字段都是 string(字符串)类型,在 where 条件中对指标数值做非空、非0过滤 norm[1] != 0 ,在此处用到了隐式转义。
Hive中能够满足隐式转义,文本类型的数字也能与数值做比较,所以没有被剔除。
下图为Hive执行文本类型数字与数值比较结果:
而在 Spark 中对数据格式的隐式转换并没有 Hive 那么灵活,数据超过一定长度之后无法进行比较,最终返回null值
下图为 Spark 执行文本类型数字与数值比较结果:数字在10位之后无法进行隐式转换比较!
在该测试数据下使用 Spark 引擎处理,受到隐式转换的限制,交易金额指标在 where 条件中没有返回 True(正确),而是返回 null 值,因此会被剔除掉。丢失该指标数据。
因此需要考虑到侧视图返回值的数据类型,避免隐式转换,增加cast()转数据类型函数处理。以满足同时兼容 Hive 跑批和 Spark 执行脚本。
版权归原作者 cium_l 所有, 如有侵权,请联系我们删除。