Hive利用宏自定义简短的函数

Posted by Yezhiwei on November 24, 2020

背景

Hive SQL 代码的可读性一直是个问题哈,因为业务比较复杂,一般情况下写出来的代码也会很冗长,存在重复的逻辑,本篇通过一个工作过程中的示例来优化一下重复逻辑的问题,希望能够写出可读性更好的代码。

重复代码及问题

通过股票代码来判断所属市场,代码片段如下:

.....
	CASE 
		WHEN substr( a.symbol, 1, 3 ) = '000' THEN
		'深圳主板' 
		WHEN substr( a.symbol, 1, 3 ) = '001' THEN
		'深圳主板' 
		WHEN substr( a.symbol, 1, 3 ) = '002' THEN
		'中小企业板' 
		WHEN substr( a.symbol, 1, 3 ) = '003' THEN
		'中小企业板' 
		WHEN substr( a.symbol, 1, 3 ) = '004' THEN
		'中小企业板' 
		WHEN substr( a.symbol, 1, 3 ) = '688' THEN
		'科创板' 
		WHEN substr( a.symbol, 1, 2 ) = '30' THEN
		'创业板' 
		WHEN substr( a.symbol, 1, 2 ) = '60' THEN
		'上海主板' 
		WHEN substr( a.symbol, 1, 1 ) IN ( '4', '8' ) THEN
		'三板' 
	END AS mar_plate
.....

重复代码带来最大的问题就是可维护性,如果上面的代码在多个地方拷贝过,当逻辑需要修改时,要同时修改多处,如果有一处遗漏,就会出现 bug,排查起问题来是非常困难的,把自己坑死~

解决方案

自定义函数

重复的逻辑最先想到的是通过自定义函数来解决这个问题,此时就可以考虑使用用户自定义函数(UDF:user-defined function)

根据用户自定义函数类别分为以下三种:

  1. UDF(User-Defined-Function)一进一出

  2. UDAF(User-Defined Aggregation Function)聚集函数,多进一出,类似于:count/max/min

  3. UDTF(User-Defined Table-Generating Functions)一进多出,如 lateral view explore()

自定义函数编程步骤:

  • 第一步:创建 Maven Java 工程,导入 jar 包
  • 第二步:继承 org.apache.hadoop.hive.ql.UDF,并重载 evaluate 方法
  • 第三步:将项目打包,并上传到 Hive 的 lib 目录下
  • 第四步:添加上传后的 jar 包
  • 第五步:设置函数与自定义函数关联

但是像我们遇到的问题,并不是真正需要 UDF,而且 UDF 有更新维护也挺麻烦的,我们只是需要把一些繁琐、结构简单的逻辑封装起来以便重复在多个地方使用。

宏可以看做是一个简短的函数,或者是对一个表达式取别名,同时可以将这个表达式中的一些值作为变量调用时传入,比较适合于需要用到很多次的表达式操作进行封装,然后取个简短点的别名来调用,省去了定义函数的复杂步骤哈。

创建一个宏,通过股票代码来判断所属市场

DROP TEMPORARY MACRO
IF
	EXISTS getMarPlate;
CREATE TEMPORARY MACRO getMarPlate ( symbol string )
CASE
		
		WHEN substr( symbol, 1, 3 ) = '000' THEN
		'深圳主板' 
		WHEN substr( symbol, 1, 3 ) = '001' THEN
		'深圳主板' 
		WHEN substr( symbol, 1, 3 ) = '002' THEN
		'中小企业板' 
		WHEN substr( symbol, 1, 3 ) = '003' THEN
		'中小企业板' 
		WHEN substr( symbol, 1, 3 ) = '004' THEN
		'中小企业板' 
		WHEN substr( symbol, 1, 3 ) = '688' THEN
		'科创板' 
		WHEN substr( symbol, 1, 2 ) = '30' THEN
		'创业板' 
		WHEN substr( symbol, 1, 2 ) = '60' THEN
		'上海主板' 
		WHEN substr( symbol, 1, 1 ) IN ( '4', '8' ) THEN
		'三板' 
	END

前面的 SQL 就可以简化成下面的样子

......
getMarPlate(a.symbol) AS mar_plate
......

使用宏对这段逻辑进行提炼,起到优化开发效率、提升程序可读性的效果。

工作中常用的宏的场景:有关空值的处理,时间处理,数值计算,只要发现有类似的逻辑被反复调用,就可以考虑这种方式。

如果觉得还有帮助的话,你的关注和转发是对我最大的支持,O(∩_∩)O: