猪:是否有可能将pytz或dateutils用于Python udfs?

时间:2016-08-26 22:52:34

标签: python apache-pig jython cloudera pytz

我在datetime脚本中使用的一些Python udfs中使用pig。到现在为止还挺好。我在Cloudera 5.5上使用猪12.0

但是,我还需要使用pytzdateutil包,它们似乎不是vanilla python安装的一部分。

我可以在某些方面在Pig udfs中使用它们吗?如果是这样,怎么样?我认为我的节点上安装了dateutil(我不是管理员,所以我怎么能真正检查是这种情况?),但是当我输入时:

import sys
#I append the path to dateutil on my local windows machine. Is that correct?
sys.path.append('C:/Users/me/AppData/Local/Continuum/Anaconda2/lib/site-packages')

from dateutil import tz

在我的udfs.py脚本中,我得到了:

2016-08-30 09:56:06,572 [main] ERROR org.apache.pig.tools.grunt.Grunt - ERROR 1121: Python Error. Traceback (most recent call last):
  File "udfs.py", line 23, in <module>
    from dateutil import tz
ImportError: No module named dateutil

当我运行我的猪脚本时。

我所有的其他python udfs(例如使用datetime)都可以正常工作。知道怎么解决这个问题吗?

非常感谢!

更新

在使用python路径玩了一下之后,我现在能够

import dateutil 

(至少Pig不会崩溃)。但如果我尝试:

from dateutil import tz

我收到错误。

  from dateutil import tz 
  File "/opt/python/lib/python2.7/site-packages/dateutil/tz.py", line 16, in <module>
    from six import string_types, PY3
  File "/opt/python/lib/python2.7/site-packages/six.py", line 604, in <module>
    viewkeys = operator.methodcaller("viewkeys")
AttributeError: type object 'org.python.modules.operator' has no attribute 'methodcaller'

如何克服这个问题?我用以下方式使用tz

to_zone = dateutil.tz.gettz('US/Eastern')
from_zone = dateutil.tz.gettz('UTC')

然后我更改时间戳的时区。我可以直接导入dateutil吗?什么是正确的语法?

更新2

根据yakuza的建议,我能够

import sys
sys.path.append('/opt/python/lib/python2.7/site-packages')
sys.path.append('/opt/python/lib/python2.7/site-packages/pytz/zoneinfo')

import pytz

但现在我又得到了错误

Caused by: Traceback (most recent call last): File "udfs.py", line 158, in to_date_local File "__pyclasspath__/pytz/__init__.py", line 180, in timezone pytz.exceptions.UnknownTimeZoneError: 'America/New_York'

当我定义

to_zone = pytz.timezone('America/New_York')
from_zone = pytz.timezone('UTC')

UnknownTimezoneError Exception Raised with Python Application Compiled with Py2Exe

找到了一些提示

怎么办? Awww,我只想转换Pig中的时区:(

2 个答案:

答案 0 :(得分:3)

好吧,你可能知道所有Python UDF函数都不是由Python解释器执行的,而是与Pig一起分发的Jython。默认情况下,在0.12.0中应为Jython 2.5.3。不幸的是,six包从Python 2.6开始支持Python,dateutil需要它的包。但是pytz似乎没有这种依赖性,并且应该支持从Python 2.4开始的Python版本。

为了实现您的目标,您应该将pytz包分发到版本2.5的所有节点,并在Pig UDF中添加它到sys.path的路径。如果您完成了为dateutil所做的相同步骤,一切都应该按预期工作。我们使用与pygeoip完全相同的方法,它就像一个魅力。

它是如何运作的

当您运行引用某些Python UDF(更准确地说是Jython UDF)的Pig脚本时,您的脚本会被编译为map / reduce作业,所有REGISTER ed文件都包含在JAR文件中,并分布在其中的节点上代码实际上是执行的。现在,当您的代码执行时,Jython解释器将从Java代码启动并执行。所以现在当在参与计算的每个节点上执行Python代码时,所有Python导入都在节点上本地解析。标准库中的导入来自Jython实现,但是所有“包”都必须安装,因为没有pip。因此,要使外部程序包可用于Python UDF,您必须使用其他pip手动安装所需的程序包或从源代码安装,但请记住下载与Python 2.5兼容的程序包!然后在每个UDF文件中,您必须在安装包的每个节点上附加site-packages(在每个节点上使用相同的目录很重要)。例如:

import sys
sys.path.append('/path/to/site-packages')
# Imports of non-stdlib packages

概念证明

让我们假设一些我们有以下文件:

/opt/pytz_test/test_pytz.pig

REGISTER '/opt/pytz_test/test_pytz_udf.py' using jython as test;

A = LOAD '/opt/pytz_test/test_pytz_data.csv' AS (timestamp:int);
B = FOREACH A GENERATE
    test.to_date_local(timestamp);

STORE B INTO '/tmp/test_pytz_output.csv' using PigStorage(',');

/opt/pytz_test/test_pytz_udf.py

from datetime import datetime
import sys

sys.path.append('/usr/lib/python2.6/site-packages/')

import pytz

@outputSchema('date:chararray')
def to_date_local(unix_timestamp):
    """
    converts unix timestamp to a rounded date
    """
    to_zone = pytz.timezone('America/New_York')
    from_zone = pytz.timezone('UTC')

    try :
        as_datetime = datetime.utcfromtimestamp(unix_timestamp)
            .replace(tzinfo=from_zone).astimezone(to_zone)
            .date().strftime('%Y-%m-%d')
    except:
        as_datetime = unix_timestamp
    return as_datetime

/opt/pytz_test/test_pytz_data.csv

1294778181
1294778182
1294778183
1294778184

现在让我们在我们的节点上安装pytz(它必须使用Python版本安装,其中pytz与Python 2.5(2.5-2.7)兼容,在我的情况下我将使用Python 2.6 ):

sudo pip2.6 install pytz

请确保该文件 /opt/pytz_test/test_pytz_udf.py 添加sys.path对已安装site-packages的{​​{1}}的引用。

现在我们用我们的测试脚本运行Pig:

pytz

我们应该能够从我们的工作中读取输出,应该列出:

pig -x local /opt/pytz_test/test_pytz.pig

答案 1 :(得分:1)

a different but related question的答案来看,只要资源在每个节点上都可用,您就应该能够使用资源。

我认为您可以按this answer regarding jython中所述添加路径,并照常加载模块。

  

将位置附加到Python脚本中的sys.path:

import sys
sys.path.append('/usr/local/lib/python2.7/dist-packages')
import happybase