这是我的Hive桌
create table if not exists dumdum (val map<string,map<string,struct<student_id:string,age:int>>>);
insert into dumdum select map('A',map('1',named_struct('student_id','123a', 'age',11)));
insert into dumdum select map('B',map('2',named_struct('student_id','987z', 'age',11)));
select * from dumdum;
我明白了
{"A":{"1":{"student_id":"123a","age":11}}}
{"B":{"2":{"student_id":"987z","age":11}}}
我要提取所有 student_id
从内部Map,即。 123a
以及 987z
. 这就是我想做的
select some_udf(val) from dumdum;
结果应该是
["123a","987z"]
这是我写的javaudf
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.hive.ql.exec.UDFArgumentException;
import org.apache.hadoop.hive.ql.exec.UDFArgumentLengthException;
import org.apache.hadoop.hive.ql.metadata.HiveException;
import org.apache.hadoop.hive.ql.udf.generic.GenericUDF;
import org.apache.hadoop.hive.serde2.objectinspector.*;
import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspectorConverters.Converter;
import org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorFactory;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
public class CustomUDF extends GenericUDF {
private MapObjectInspector inputMapOI = null;
private Converter inputMapKeyConverter = null;
private MapObjectInspector inputMapValueMapOI = null;
private Converter inputMapValueConverter;
@Override
public String getDisplayString(String[] arguments) {
return "my udf";
}
@Override
public ObjectInspector initialize(ObjectInspector[] arguments) throws UDFArgumentException {
if ((null == arguments) || (arguments.length != 1)) {
throw new UDFArgumentLengthException("1 arguments are expected.");
}
if (!(arguments[0] instanceof MapObjectInspector)) {
throw new UDFArgumentException("The first parameter should be a map object ");
}
inputMapOI = (MapObjectInspector) arguments[0];
ObjectInspector mapKeyOI = PrimitiveObjectInspectorFactory.getPrimitiveJavaObjectInspector(PrimitiveObjectInspector.PrimitiveCategory.STRING);
inputMapKeyConverter = ObjectInspectorConverters.getConverter(this.inputMapOI.getMapKeyObjectInspector(), mapKeyOI);
if (!(inputMapOI.getMapValueObjectInspector() instanceof MapObjectInspector)) {
throw new UDFArgumentException("The map value type must be a map ");
}
inputMapValueMapOI = (MapObjectInspector) this.inputMapOI.getMapValueObjectInspector();
List<String> structFieldNames = new ArrayList<String>();
structFieldNames.add("student_id");
structFieldNames.add("age");
List<ObjectInspector> structFieldObjectInspectors = new ArrayList<ObjectInspector>();
structFieldObjectInspectors.add(PrimitiveObjectInspectorFactory.javaStringObjectInspector);
structFieldObjectInspectors.add(PrimitiveObjectInspectorFactory.javaIntObjectInspector);
ObjectInspector inputMapElementOI = inputMapValueMapOI.getMapValueObjectInspector();
ObjectInspector outputMapElementOI = ObjectInspectorFactory.getStandardStructObjectInspector(structFieldNames, structFieldObjectInspectors);
inputMapValueConverter = ObjectInspectorConverters.getConverter(inputMapElementOI, outputMapElementOI);
return ObjectInspectorFactory.getStandardListObjectInspector(PrimitiveObjectInspectorFactory.javaStringObjectInspector);
}
@Override
public Object evaluate(DeferredObject[] arguments) throws HiveException {
if ((null == arguments) || (arguments.length != 1)) {
throw new UDFArgumentLengthException("1 argument is expected.");
}
Map<?, ?> map = inputMapOI.getMap(arguments[0].get());
List<String> dataList = new ArrayList<String>();
for (Object key : map.keySet()) {
Map<?, ?> valueMap = this.inputMapValueMapOI.getMap(map.get(key));
if ((valueMap == null) || (valueMap.size() == 0)) {
continue;
}
for (Object value : valueMap.keySet()) {
try{
String innerkey = (String) this.inputMapKeyConverter.convert(value);
System.out.println("Got "+innerKey);
Map<?, ?> innerMap = (Map<?, ?>) this.inputMapValueMapOI.getMap(valueMap.get(key));
if ((innerMap == null) || (innerMap.size() == 0)) {
System.out.println("Got null");
continue;
}
for (Object struct : innerMap.keySet()) {
String strValue = (String) this.inputMapValueConverter.convert(struct);
StructField str = (StructField) inputMapValueConverter.convert(innerMap.get(strValue));
/*
Not sure what to do here. Maybe
str.getFieldID();
dataList.add(str.toString());
*/
}
}
catch (ClassCastException c){
System.out.println("Got ClassCastException");
}
}
}
return dataList;
}
}
当我把它当作
add jar /path/to/my/jar;
CREATE TEMPORARY FUNCTION modudf AS 'some.package.CustomUDF';
select modudf(val) from dumdum;
我永远也过不去
Map<?, ?> innerMap = (Map<?, ?>) this.inputMapValueMapOI.getMap(valueMap.get(inner));
if ((innerMap == null) || (innerMap.size() == 0)) {
System.out.println("Got null");
continue;
}
我可以看到
System.out.println("Got "+innerKey);
在控制台上。
为什么我的转换器不能访问内部Map?
另外,一旦能够访问内部Map,我将如何取消对structfield的引用?
更新
谢谢谢尔盖的建议。恐怕我还需要一个转换器,否则我就拿不到钥匙了。这是我试过的
首先,我将第二个Map检查器和结构检查器定义为
inputMapValueMapOI = (MapObjectInspector) this.inputMapOI.getMapValueObjectInspector();
List<String> structFieldNames = new ArrayList<String>();
structFieldNames.add("student_id");
structFieldNames.add("age");
List<ObjectInspector> structFieldObjectInspectors = new ArrayList<ObjectInspector>();
structFieldObjectInspectors.add(PrimitiveObjectInspectorFactory.javaStringObjectInspector);
structFieldObjectInspectors.add(PrimitiveObjectInspectorFactory.javaIntObjectInspector);
structOI = ObjectInspectorFactory.getStandardStructObjectInspector(structFieldNames, structFieldObjectInspectors);
我试过了
String innerkey = (String) inputMapKeyConverter.convert(value);
System.out.println(innerKey);
Map<?, ?> innerMap = (Map<?, ?>) this.inputMapValueMapOI.getMap(valueMap.get(innerkey));
if ((innerMap == null) || (innerMap.size() == 0)) {
System.out.println("null inner map");
continue;
}
for (Object struct : innerMap.keySet()) {
String ikey = (String) inputMapKeyConverter.convert(struct);
Object obj = structOI.getStructFieldData(innerMap.get(ikey), structOI.getStructFieldRef("student_id"));
dataList.add(obj.toString());
}
但我还是明白了
null inner map
我没有正确定义内部Map检查器吗?
1条答案
按热度按时间nukf8bse1#
我建议你不要使用转换器,只要定义第二个
MapObjectInspector
对于内部Map,获取外部Map值并调用getMap
就像第一张Map。要获取结构值,需要定义一个StructObjectInspector
输入initialize
,例如。然后
更新:尝试将贴图键转换为标准键,如下所示
看到了吗https://github.com/klout/brickhouse/blob/master/src/main/java/brickhouse/udf/collect/mapremovekeysudf.java 更多细节