我这里用到UDTF函数是为了将表中的一个json字段炸裂为多个字段。即一进多出。
思路
1.导入相关依赖
2.继承实现抽象类GenericUDTF。
3.调试代码。
依赖
<!-- 这是一定要导入的依赖,里面包含抽象类GenericUDTF -->
<dependency>
<groupId>org.apache.hive</groupId>
<artifactId>hive-exec</artifactId>
<version>${hive.version}</version>
</dependency>
<!-- hadoop-common -->
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-common</artifactId>
<version>2.8.1</version>
</dependency>
<!--json 包 ,我这里使用了,所以导入此依赖-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.3</version>
</dependency>
代码
import com.alibaba.fastjson.JSONObject;
import org.apache.hadoop.hive.ql.exec.UDFArgumentException;
import org.apache.hadoop.hive.ql.metadata.HiveException;
import org.apache.hadoop.hive.ql.udf.generic.GenericUDTF;
import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector;
import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspectorFactory;
import org.apache.hadoop.hive.serde2.objectinspector.StructObjectInspector;
import org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorFactory;
import org.apache.commons.logging.LogFactory;
import org.apache.commons.logging.Log;
import java.util.ArrayList;
import java.util.List;
/**
* @Author: Hyy
* @Date: 2021/7/12 17:13
* @Describe: hive 的 UDTF 函数,一进多出
* @Version 1.0
*/
public class ObjectiveQuestionParser extends GenericUDTF {
/*这里引入日志,是为了更加规范的编程,也是为了在调试这段代码的时候,可以在hive的日志中
*打印相关的信息,便于了解程序出错的地方,为调试提供方向。
*/
private Log logger = LogFactory.getLog(ObjectiveQuestionParser.class.getSimpleName());
@Override
public StructObjectInspector initialize(StructObjectInspector argOIs) throws UDFArgumentException {
logger.info("UDTF,开始你的表演吧!!!!");
// 参数个数检验
if (argOIs.getAllStructFieldRefs().size() != 1) {
throw new UDFArgumentException("ExplodeJSONArray 只需要一个参数");
}
// 第一个参数必须为 string
if (!"string".equals(argOIs.getAllStructFieldRefs().get(0).getFieldObjectInspector().getTypeName())) {
throw new UDFArgumentException("json_array_to_struct_array的第1个参数应为string类型");
}
//输出数据的默认列名,可以被别名覆盖
List<String> names = new ArrayList<String>();
//输出数据的类型,输入参数一定要和输入的类型一一对应,哪怕都是一样的。
List<ObjectInspector> fieldOIs = new ArrayList<ObjectInspector>();
names.add("questionId");
fieldOIs.add(PrimitiveObjectInspectorFactory.javaStringObjectInspector);
names.add("userAnswer");
fieldOIs.add(PrimitiveObjectInspectorFactory.javaStringObjectInspector);
names.add("score");
fieldOIs.add(PrimitiveObjectInspectorFactory.javaStringObjectInspector);
StructObjectInspector outputOI = ObjectInspectorFactory.getStandardStructObjectInspector(names, fieldOIs);
return outputOI;
}
public void process(Object[] objects) throws HiveException {
String data = objects[0].toString();
logger.info("数据是这样式的:" +data );
JSONObject jsonMark = null;
try{
jsonMark = JSONObject.parseObject(data);
}catch (Exception e) {
logger.error("解析json字符串错误! message:"+e.getMessage());
}
logger.info("get the JSONObject ....");
if (jsonMark != null){
for(String questionId : jsonMark.keySet()) {
List<String> result = new ArrayList<String>();
try{
result.add(questionId);
JSONObject jsonDetail = jsonMark.getJSONObject(questionId);
result.add(jsonDetail.getString("useranswer"));
result.add(jsonDetail.getString("score"));
}catch (Exception e){
logger.error("result add error! message: " + e.getStackTrace());
continue;
}
forward(result);
}
}
}
public void close() throws HiveException {
}
}
总结
在pom.xml文件中可以加入一下内容,这是一个打包插件,将所有的依赖导入到所打的jar中。
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.6</version>
<configuration>
<descriptorRefs>
<!-- 打好的jar以jar-with-dependencies结尾 -->
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
log日志可以给调试代码以很好的提示,尤其是需要打包运行的代码,看自己写的日志排错,是不是也比看别人写的日志爽很多。