Как вернуть Struct из Hive UDF?

1

У меня возникли проблемы с поиском документации о том, как использовать UUF Hive для возврата Struct.

Мои основные вопросы:

С какими типами объектов я начинаю с Java?

Как мне их преобразовать, чтобы они были интерпретированы как Struct in Hive?

Теги:
hadoop
hive
user-defined-functions

2 ответа

4

Вот очень простой пример такого типа UDF. Он получает строку User-Agent, анализирует ее с помощью внешней библиотеки и возвращает структуру с 4 текстовыми полями:

STRUCT <type: string, os: string, family: string, device: string>

Вам необходимо расширить класс GenericUDF и переопределить два наиболее важных метода: инициализировать и оценить.

initialize() описывает структуру и определяет типы данных внутри.

() заполняет структуру фактическими значениями.

Вам не нужны специальные классы для возврата, struct <> в Hive - это всего лишь массив объектов в Java.

import java.util.ArrayList;
import org.apache.hadoop.hive.ql.exec.UDFArgumentException;
import org.apache.hadoop.hive.ql.metadata.HiveException;
import org.apache.hadoop.hive.ql.udf.generic.GenericUDF;
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.hadoop.io.Text;

import eu.bitwalker.useragentutils.UserAgent;

public class UAStructUDF extends GenericUDF {

    private Object[] result;

    @Override
    public String getDisplayString(String[] arg0) {
        return "My display string";
    }

    @Override
    public ObjectInspector initialize(ObjectInspector[] arg0) throws UDFArgumentException {
        // Define the field names for the struct<> and their types
        ArrayList<String> structFieldNames = new ArrayList<String>();
        ArrayList<ObjectInspector> structFieldObjectInspectors = new ArrayList<ObjectInspector>();

        // fill struct field names
        // type
        structFieldNames.add("type");
        structFieldObjectInspectors.add(PrimitiveObjectInspectorFactory.writableStringObjectInspector);
        //family
        structFieldNames.add("family");
        structFieldObjectInspectors.add(PrimitiveObjectInspectorFactory.writableStringObjectInspector);
        // OS name
        structFieldNames.add("os");
        structFieldObjectInspectors.add(PrimitiveObjectInspectorFactory.writableStringObjectInspector);
        // device
        structFieldNames.add("device");
        structFieldObjectInspectors.add(PrimitiveObjectInspectorFactory.writableStringObjectInspector);

        StructObjectInspector si = ObjectInspectorFactory.getStandardStructObjectInspector(structFieldNames,
                structFieldObjectInspectors);
        return si;
    }

    @Override
    public Object evaluate(DeferredObject[] args) throws HiveException {
        if (args == null || args.length < 1) {
            throw new HiveException("args is empty");
        }
        if (args[0].get() == null) {
            throw new HiveException("args contains null instead of object");
        }

        Object argObj = args[0].get();

        // get argument
        String argument = null;     
        if (argObj instanceof Text){
            argument = ((Text) argObj).toString();
        } else if (argObj instanceof String){
            argument = (String) argObj;
        } else {
            throw new HiveException("Argument is neither a Text nor String, it is a " + argObj.getClass().getCanonicalName());
        }
        // parse UA string and return struct, which is just an array of objects: Object[] 
        return parseUAString(argument);
    }

    private Object parseUAString(String argument) {
        result = new Object[4];
        UserAgent ua = new UserAgent(argument);
        result[0] = new Text(ua.getBrowser().getBrowserType().getName());
        result[1] = new Text(ua.getBrowser().getGroup().getName());
        result[2] = new Text(ua.getOperatingSystem().getName());
        result[3] = new Text(ua.getOperatingSystem().getDeviceType().getName());
        return result;
    }
}
0

В HIVE существует концепция SerDe (сериализатор и десеризатор), которая может использоваться с форматом данных, который вы играете в нее. Он сериализует объекты (сложные), а затем де-сериализует его в соответствии с потребностью. Например, если у вас есть JSON файл, содержащий объекты и значения, поэтому вам нужно сохранить этот контент в улье. Для этого вы используете JsonSerde, который на самом деле представляет собой файл jar, содержащий код парсера, написанный в java для воспроизведения данных Json.

Итак, теперь у вас есть банка (SerDe), а другое требование - для схемы для хранения этих данных. Например, для XML файлов вам нужен XSD, аналогично для JSON вы определяете отношения объектов, массивов и структур. Вы можете проверить эту ссылку: http://thornydev.blogspot.in/2013/07/querying-json-records-via-hive.html Пожалуйста, дайте мне знать, если это поможет и решит вашу цель :)

Ещё вопросы

Сообщество Overcoder
Наверх
Меню