先说说需求吧。
hive中存了银行的很多历史数据。这些历史数据是不可能做更新的。随着时间迁移呢,银行的部门机构可能发生变。那么在银行机构发生变化时,想要统计某个变化机构的一些kpi(指标)。此时我们需要把旧机构号的数据统计到新机构号上。然后就用到了UDF。
好了,开始说说具体的解决方式吧。
变更机构号,我首先要拿到旧的机构号,以及统计的日期。另外,需要一个配置文件作为外部资源记录机构号的变更(旧机构号,新机构号,变更日期)。然后拿旧机构号与统计日期这两个参数跟配置文件对比。存在机构号变更,且变更日期小于等于统计日期,就返回新的机构号。
hive版本为1.2.0。用XML作为配置文件。initXML()为初始化XML文件,将配置文件中的机构变更存放于commOrgChangeMap这个map中。此处的XML文件就是外部资源。注意,一定不要将初始化工作放在构造函数里面。否则会出现内部错误,FAILED: Hive Internal Error: java.lang.RuntimeException(java.lang.reflect.InvocationTargetException)实际就是找不到配置文件。
通过beeline进入hive后,add jar 和add file分别添加jar包和xml配置文件。
格式:ADD { FILE[S] | JAR[S] | ARCHIVE[S] } <filepath1> [<filepath2>]*
filepath可以是本地路径,也可以是hdfs路径。注意权限。
给个hive命令的权威链接:https://cwiki.apache.org/confluence/display/Hive/LanguageManual+Cli#LanguageManualCli-HiveResources
最后贴了部分代码,可以看看。
/**
* udf的入口函数
*
* @param fieldValue
* @param period
* @return 存在对应变更机构号则返回变更后的机构号,否则返回原始机构号
* @throws Exception
*/
public String evaluate(String fieldValue, String period) throws Exception {
if (initFlag) {
initXML();
this.initFlag = false;
}
return changeOrgNum(fieldValue.trim(), period.trim());
}
/**
* 根据传递来的机构号,递归方式遍历公共机构变更map对象commOrgChangeTreeMap,有变更则返回参数日期内最新的变更,
* 否则返回原始机构号。
*
* @param fieldValue
* @param period
* @param commOrgChangeMap
* @return 存在对应变更机构号则返回参数日期内变更后的最新机构号,否则返回原始机构号
*/
private String changeOrgNum(String fieldValue, String period) {
System.out.println("日期过滤后的大小" + commOrgChangeMap.size());
if (!commOrgChangeMap.isEmpty()
&& commOrgChangeMap.containsKey(fieldValue)
&& period.compareTo(commOrgChangeMap.get(fieldValue)
.getChangeDate()) >= 0) {
return changeOrgNum(
commOrgChangeMap.get(fieldValue).getNewOrgNum(), period);
} else {
return fieldValue;
}
}