4

我真的很想在我们的 AWS Elastic MapReduce 集群上利用 Pig 中的 Python UDF,但我不能让事情正常工作。无论我尝试什么,我的猪作业都会失败,并记录以下异常:

ERROR 2998: Unhandled internal error. org/python/core/PyException

java.lang.NoClassDefFoundError: org/python/core/PyException
        at org.apache.pig.scripting.jython.JythonScriptEngine.registerFunctions(JythonScriptEngine.java:127)
        at org.apache.pig.PigServer.registerCode(PigServer.java:568)
        at org.apache.pig.tools.grunt.GruntParser.processRegister(GruntParser.java:421)
        at org.apache.pig.tools.pigscript.parser.PigScriptParser.parse(PigScriptParser.java:419)
        at org.apache.pig.tools.grunt.GruntParser.parseStopOnError(GruntParser.java:188)
        at org.apache.pig.tools.grunt.GruntParser.parseStopOnError(GruntParser.java:164)
        at org.apache.pig.tools.grunt.Grunt.exec(Grunt.java:81)
        at org.apache.pig.Main.run(Main.java:437)
        at org.apache.pig.Main.main(Main.java:111)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:597)
        at org.apache.hadoop.util.RunJar.main(RunJar.java:156) Caused by: java.lang.ClassNotFoundException: org.python.core.PyException
        at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
        ... 14 more

在 Elastic MapReduce 中为 Pig 使用 Python UDF 需要做什么?

4

4 回答 4

4

嗯...为了澄清我刚刚在这里读到的一些内容,此时在存储在 s3 上的 EMR 上运行的 Pig 中使用 python UDF,就像您的 pig 脚本中的这一行一样简单:

使用 jython 作为 mynamespace 注册 's3://path/to/bucket/udfs.py'

也就是说,不需要修改类路径。我现在正在生产中使用它,但需要注意的是我没有在我的 udf 中引入任何额外的 python 模块。我认为这可能会影响您需要做的事情才能使其发挥作用。

于 2012-12-12T20:49:11.847 回答
2

经过几次错误的转折,我发现,至少在 Hadoop 的弹性映射 reduce 实现上,Pig 似乎忽略了 CLASSPATH 环境变量。相反,我发现我可以使用 HADOOP_CLASSPATH 变量来控制类路径。

一旦我意识到这一点,就很容易设置使用 Python UDFS:

  • 安装 Jython
    • sudo apt-get install jython -y -qq
  • 设置 HADOOP_CLASSPATH 环境变量。
    • export HADOOP_CLASSPATH=/usr/share/java/jython.jar:/usr/share/maven-repo/org/antlr/antlr-runtime/3.2/antlr-runtime-3.2.jar
      • jython.jar 确保 Hadoop 可以找到 PyException 类
      • antlr-runtime-3.2.jar 确保 Hadoop 可以找到 CharStream 类
  • 为 Jython 创建缓存目录(这在 Jython 常见问题解答中有记录
    • sudo mkdir /usr/share/java/cachedir/
    • sudo chmod a+rw /usr/share/java/cachedir

我应该指出,这似乎与我在寻找该问题的解决方案时发现的其他建议直接矛盾:

  • 设置 CLASSPATH 和 PIG_CLASSPATH 环境变量似乎没有任何作用。
  • 包含 UDF 的 .py 文件不需要包含在 HADOOP_CLASSPATH 环境变量中。
  • Pigregister语句中使用的 .py 文件的路径可能是相对的,也可能是绝对的,这似乎无关紧要。
于 2012-02-15T23:42:06.963 回答
0

我最近遇到了同样的问题。您的答案可以简化。您根本不需要安装 jython 或创建缓存目录。您确实需要在 EMR 引导脚本中包含 jython jar(或执行类似操作)。我用以下几行编写了一个 EMR 引导脚本。完全不使用 s3cmd,而是使用您的工作流程(将文件放在某个目录中),可以进一步简化这一点。通过 s3cmd 获取 UDF 绝对不方便,但是,当使用 EMR 版本的 pig 时,我无法在 s3 上注册 udf 文件。

如果您使用的是 CharStream,则必须将该 jar 以及包含到 piglib 路径中。根据您使用的框架,您可以将这些引导脚本作为选项传递给您的作业,EMR 通过他们的 elastic-mapreduce ruby​​ 客户端支持这一点。一个简单的选择是将引导脚本放在 s3 上。

如果您在引导脚本中使用 s3cmd,则需要另一个执行类似操作的引导脚本。该脚本应按引导顺序放在另一个之前。我不再使用 s3cmd,但是对于我的成功尝试,s3cmd 成功了。此外,s3cmd 可执行文件已经安装在亚马逊的 pig 映像中(例如 ami 版本 2.0 和 hadoop 版本 0.20.205。

脚本 #1(播种 s3cmd)

#!/bin/bash
cat <<-OUTPUT > /home/hadoop/.s3cfg
[default]
access_key = YOUR KEY
bucket_location = US
cloudfront_host = cloudfront.amazonaws.com
cloudfront_resource = /2010-07-15/distribution
default_mime_type = binary/octet-stream
delete_removed = False
dry_run = False
encoding = UTF-8
encrypt = False
follow_symlinks = False
force = False
get_continue = False
gpg_command = /usr/local/bin/gpg
gpg_decrypt = %(gpg_command)s -d --verbose --no-use-agent --batch --yes --passphrase-fd %  (passphrase_fd)s -o %(output_file)s %(input_file)s
gpg_encrypt = %(gpg_command)s -c --verbose --no-use-agent --batch --yes --passphrase-fd %(passphrase_fd)s -o %(output_file)s %(input_file)s
gpg_passphrase = YOUR PASSPHRASE
guess_mime_type = True
host_base = s3.amazonaws.com
host_bucket = %(bucket)s.s3.amazonaws.com
human_readable_sizes = False
list_md5 = False
log_target_prefix =
preserve_attrs = True
progress_meter = True
proxy_host =
proxy_port = 0
recursive = False
recv_chunk = 4096
reduced_redundancy = False
secret_key = YOUR SECRET
send_chunk = 4096
simpledb_host = sdb.amazonaws.com
skip_existing = False
socket_timeout = 10
urlencoding_mode = normal
use_https = False
verbosity = WARNING
OUTPUT

脚本 #2(播种 jython jar)

#!/bin/bash
set -e

s3cmd get <jython.jar>
# Very useful for extra libraries not available in the jython jar. I got these libraries from the 
# jython site and created a jar archive.
s3cmd get <jython_extra_libs.jar>
s3cmd get <UDF>

PIG_LIB_PATH=/home/hadoop/piglibs

mkdir -p $PIG_LIB_PATH

mv <jython.jar> $PIG_LIB_PATH
mv <jython_extra_libs.jar> $PIG_LIB_PATH
mv <UDF> $PIG_LIB_PATH

# Change hadoop classpath as well.
echo "HADOOP_CLASSPATH=$PIG_LIB_PATH/<jython.jar>:$PIG_LIB_PATH/<jython_extra_libs.jar>" >>    /home/hadoop/conf/hadoop-user-env.sh
于 2012-02-17T17:16:02.340 回答
0

截至今天,在 EMR 上使用 Pig 0.9.1,我发现以下内容就足够了:

env HADOOP_CLASSPATH=$HADOOP_CLASSPATH:/path/to/jython.jar pig -f script.pig

Python脚本的寄存器在哪里script.pig,但不是jython.jar

register Pig-UDFs/udfs.py using jython as mynamespace;
于 2012-04-05T19:03:14.617 回答