【问题标题】:Hadoop Hive UDF with external library带有外部库的 Hadoop Hive UDF
【发布时间】:2016-03-29 20:26:13
【问题描述】:

我正在尝试为 Hadoop Hive 编写一个解析用户代理的 UDF。以下代码在我的本地机器上运行良好,但在 Hadoop 上我得到了:

org.apache.hadoop.hive.ql.metadata.HiveException:无法执行方法 public java.lang.String MyUDF .evaluate(java.lang.String) 抛出 org.apache.hadoop.hive.ql.metadata。类 MyUDF 的对象 MyUDF@64ca8bfb 上的 HiveException,参数 {All Occupations:java.lang.String} 大小为 1',

代码:

import java.io.IOException;
import org.apache.hadoop.hive.ql.exec.UDF;
import org.apache.hadoop.hive.ql.metadata.HiveException;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.*;
import com.decibel.uasparser.OnlineUpdater;
import com.decibel.uasparser.UASparser;
import com.decibel.uasparser.UserAgentInfo;

public class MyUDF extends UDF {

    public String evaluate(String i) {
        UASparser parser = null;         
        parser = new UASparser(); 
        String key = "";
        OnlineUpdater update = new OnlineUpdater(parser, key);
        UserAgentInfo info = null;
        info = parser.parse(i);
        return info.getDeviceType();
    }
}

我应该提到的事实:

  • 我正在使用 Eclipse 进行“导出可运行 jar 文件”的编译,并将所需的库提取到生成的 jar 选项中

  • 我正在上传这个带有 Hue 的“fat jar”文件

  • 我设法运行的最小工作示例:

    public String evaluate(String i) { return "hello" + i.toString()"; }

  • 我猜问题出在我正在使用的那个库(从 https://udger.com 下载)周围的某个地方,但我不知道在哪里。

有什么建议吗?

谢谢,米哈尔

【问题讨论】:

  • 您是否查看了 application_xxxx_xxxx 的 YARN 日志(由 Hive 报告)以检查一些线索,例如使用比 Hive 使用的 JRE 更新的 Java 版本编译的 JAR 的一些内部异常(只是一个示例)?

标签: java hadoop hive user-agent udf


【解决方案1】:

这可能是一些事情。最好的办法是检查日志,但这里列出了一些您可以在一分钟内快速检查的事情。

  1. jar 不包含所有依赖项。我不确定 eclipse 如何构建可运行的 jar,但它可能不包含所有依赖项。你可以这样做

    jar tf your-udf-jar.jar

查看包含的内容。你应该看到来自com.decibel.uasparser 的东西。如果没有,则必须使用适当的依赖项构建 jar(通常使用 maven)。

  1. JVM 的不同版本。如果你用jdk8编译,集群运行jdk7,也会失败

  2. Hive 版本。有时 Hive API 会稍有变化,足以不兼容。这里可能不是这种情况,但请确保针对集群中相同版本的 hadoop 和 hive 编译 UDF

  3. 在调用 parse() 之后,您应该始终检查 info 是否为空

  4. 看起来图书馆使用了密钥,这意味着实际上是从在线服务 (udger.com) 获取数据,因此如果没有实际密钥,它可能无法工作。更重要的是,图书馆在线更新,为每条记录联系在线服务。这意味着,查看代码,它将创建每条记录一个更新线程。您应该在构造函数中只更改一次代码,如下所示:

以下是如何更改它:

public class MyUDF extends UDF {
  UASparser parser = new UASparser();

  public MyUDF() {
    super()
    String key = "PUT YOUR KEY HERE";
    // update only once, when the UDF is instantiated
    OnlineUpdater update = new OnlineUpdater(parser, key);
  }

  public String evaluate(String i) {
        UserAgentInfo info = parser.parse(i);
        if(info!=null) return info.getDeviceType();
        // you want it to return null if it's unparseable
        // otherwise one bad record will stop your processing
        // with an exception
        else return null; 
    }
}

但要确定,您必须查看日志...纱线日志,但您也可以查看您提交作业的机器上的配置单元日志(可能在 /var/log/hive但这取决于您的安装)。

【讨论】:

  • 我们的 Hadoop 机器已经宕机了一段时间,所以我没有机会检查日志,但是... 1) 我检查了依赖项,它们似乎没问题 2) 这是发行人退后一步。但是,当版本不兼容时,Java 会抛出一个关于错误版本的异常,而不是 IOException / HiveException 3) 应该没问题 4) 我会试试这个 5) 它可以在没有密钥的情况下工作(我在 Hadoop 之外检查过)。我知道效率低下,但我认为下一步应该解决这个问题。
  • 但是,当我正在浏览库时,我想到了另一个想法......它试图写入临时文件,这对于 UDF 功能是否合法操作(写入文件系统? HDFS 是仅附加系统,所以我在这里闻到了一些麻烦?...谢谢,感谢您的帮助 :)
  • UDF 读/写本地文件是合法的,但绝对不推荐!但在某些情况下可以安全地完成。在之前的工作中,我们将一个配置文件推送到所有机器,以及一个读取它并将其内容提供给查询的 UDF。但是那个库为每条记录打开一个网络连接..这非常非常低效和糟糕......所以是的,它闻起来很麻烦:)那个库不是为使用hadoop而设计的。在编写使用库的 UDF 时,您应该非常小心并了解其内部工作方式。
  • 所以我发现该库还支持从文件中导入该配置。但是我仍然收到文件未找到异常,所以我的问题是,我如何找到上传文件的路径?我通过 Hue 上传了它,与 .jar 文件位于同一目录中。
【解决方案2】:

这样的问题大概可以分步解决:

  1. 覆盖UDF.getRequiredJars() 方法,使其返回hdfs 文件路径列表,其值取决于您将以下xxx_lib 文件夹放入hdfs 的位置。需要注意的是,listmist 中正好包含了每个jar 的完整hdfs 路径字符串,比如hdfs://yourcluster/some_path/xxx_lib/some.jar

  2. 按照“可运行的 jar 文件导出向导”导出您的 udf 代码(选择“将所需库复制到生成的 jar 旁边的子文件夹中”。此步骤将生成 xxx.jar 和 lib xxx.jar 旁边的文件夹 xxx_lib

  3. 根据步骤 0 中的代码,将 xxx.jar 和文件夹 xxx_lib 放入 hdfs 文件系统。

  4. 使用以下命令创建 udf:添加 jar ${the-xxx.jar-hdfs-path}; create function your-function as $}udf class 的限定名};

试试看。我对此进行了测试,它可以工作

【讨论】:

    猜你喜欢
    • 2014-02-12
    • 2012-12-05
    • 1970-01-01
    • 2014-08-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多