package com.livingsocial.hive.udtf;
import java.util.ArrayList;
import java.util.List;
import java.lang.StringBuffer;
import com.livingsocial.hive.utils.KISSInspector;
import org.apache.hadoop.hive.ql.udf.UDFBin;
import org.apache.hadoop.hive.ql.udf.generic.GenericUDTF;
import org.apache.hadoop.hive.ql.exec.UDF;
import org.apache.hadoop.hive.ql.exec.Description;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.hive.ql.exec.UDFArgumentException;
import org.apache.hadoop.hive.ql.metadata.HiveException;
import org.apache.hadoop.hive.serde2.objectinspector.ListObjectInspector;
import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector;
import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspectorFactory;
import org.apache.hadoop.hive.serde2.objectinspector.StructObjectInspector;
@Description(name = "bin_case",
value = "_FUNC_(column, (array of bit field names)) - table generating function that spits out column name for each bit position that is a 1")
public class BinCase extends GenericUDTF {
private class BinCaseSelector {
private KISSInspector bitfield_inspector;
private ListObjectInspector bitnames_inspector;
private UDFBin b;
private ArrayList result;
public BinCaseSelector(ObjectInspector bfi, ObjectInspector bni) {
bitfield_inspector = new KISSInspector(bfi);
bitnames_inspector = (ListObjectInspector) bni;
result = new ArrayList();
b = new UDFBin();
}
public ArrayList getNames(Object bf, Object bn) {
result.clear();
List<?> names = bitnames_inspector.getList(bn);
long value = bitfield_inspector.toLong(bf);
String values = b.evaluate(new LongWritable(value)).toString();
String reversed = (new StringBuffer(values)).reverse().toString();
for(int i=0; i<reversed.length(); i++) {
if(reversed.charAt(i) == '1' && i < names.size())
result.add(names.get(i));
}
return result;
}
public ObjectInspector getNamesInspector() {
return bitnames_inspector.getListElementObjectInspector();
}
}
private BinCaseSelector bcs = null;
@Override
public void close() throws HiveException {
}
@Override
public StructObjectInspector initialize(ObjectInspector[] args) throws UDFArgumentException {
if(args.length != 2 || !KISSInspector.isPrimitive(args[0]) || !KISSInspector.isList(args[1]))
throw new UDFArgumentException("bin_case() takes two arguments: an integer and an array of strings");
bcs = new BinCaseSelector(args[0], args[1]);
ArrayList<String> fieldNames = new ArrayList<String>();
ArrayList<ObjectInspector> fieldOIs = new ArrayList<ObjectInspector>();
fieldNames.add("col");
fieldOIs.add(bcs.getNamesInspector());
return ObjectInspectorFactory.getStandardStructObjectInspector(fieldNames, fieldOIs);
}
private final Object[] forwardObj = new Object[1];
@Override
public void process(Object[] o) throws HiveException {
ArrayList names = bcs.getNames(o[0], o[1]);
for (Object r : names) {
forwardObj[0] = r;
forward(forwardObj);
}
}
@Override
public String toString() {
return "bin_case";
}
}