package com.facebook.hive.udf; import org.apache.hadoop.hive.ql.exec.Description; 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.ListObjectInspector; import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector; import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspectorConverters; import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspectorUtils; import org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorFactory; import org.apache.hadoop.io.IntWritable; import java.util.List; /** * Subsets an array given an offset (zero-indexed) and length. * If offset is negative, the sequence will start that far from the end of the * array. * If length is negative, the sequence will stop that many elements from the * end of the array. * If length is not specified, the rest of the array is returned. * * If offset + length is greater than array length, the resulting array will * be truncated. */ @Description(name = "udfarrayslice", value = "_FUNC_(values, offset, length) - Slices the given array as specified by the offset and length parameters.") public class UDFArraySlice extends GenericUDF { private ObjectInspectorConverters.Converter int_converter1; private ObjectInspectorConverters.Converter int_converter2; private ListObjectInspector arrayOI = null; @Override public ObjectInspector initialize(ObjectInspector[] arguments) throws UDFArgumentException { if (arguments.length != 2 && arguments.length != 3) { throw new UDFArgumentLengthException("Expected 2 or 3 inputs, got " + arguments.length); } int_converter1 = ObjectInspectorConverters.getConverter(arguments[1], PrimitiveObjectInspectorFactory.writableIntObjectInspector); if (arguments.length == 3) { int_converter2 = ObjectInspectorConverters.getConverter(arguments[2], PrimitiveObjectInspectorFactory.writableIntObjectInspector); } arrayOI = (ListObjectInspector) arguments[0]; return ObjectInspectorUtils.getStandardObjectInspector(arrayOI); } @Override public Object evaluate(DeferredObject[] arguments) throws HiveException { if (arguments[0].get() == null) { return null; } List<?> arr = (List<?>) ObjectInspectorUtils.copyToStandardObject(arguments[0].get(), arrayOI); IntWritable intWritable1 = (IntWritable)int_converter1.convert(arguments[1].get()); if (intWritable1 == null) { return null; } int offset = intWritable1.get(); if (offset < 0) { offset = arr.size() + offset; } int length, toIndex; if (arguments.length == 3) { IntWritable intWritable2 = (IntWritable)int_converter2.convert(arguments[2].get()); if (intWritable2 == null) { return null; } length = intWritable2.get(); if (length < 0) { toIndex = arr.size() + length; } else { toIndex = Math.min(offset + length, arr.size()); } } else { // length not specified, return rest of array toIndex = arr.size(); } if (offset >= toIndex || offset < 0 || toIndex < 0) { return null; } return arr.subList(offset, toIndex); } @Override public String getDisplayString(String[] input) { return new String(); } }