Pig:是否可以将 pytz 或 dateutils 用于 Python udfs?
Pig: is it possible to use pytz or dateutils for Python udfs?
我在 pig
脚本中使用的一些 Python udfs 中使用 datetime
。到目前为止,一切都很好。我在 Cloudera 5.5
上使用 pig 12.0
但是,我还需要使用 pytz
或 dateutil
包,它们似乎不是原始 python 安装的一部分。
我可以在我的 Pig
udf 中以某些方式使用它们吗?如果是这样,如何?我认为 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
怎么办?哇,我只想转换 Pig 中的时区:(
从 a different but related question 的回答看来,只要资源在每个节点上可用,您就应该能够使用它们。
我认为您可以按照 this answer regarding jython 中的说明添加路径,然后像往常一样加载模块。
Append the location to the sys.path in the Python script:
import sys
sys.path.append('/usr/local/lib/python2.7/dist-packages')
import happybase
好吧,正如您可能知道的那样,所有 Python UDF 函数都不是由 Python 解释器执行的,而是与 Pig 一起分发的 Jython。在 0.12.0 中默认应该是 Jython 2.5.3. Unfortunately six
package supports Python starting from Python 2.6 and it's package required by dateutil
. However pytz
seems not to have such dependency, and should support Python versions starting from Python 2.4.
因此,为了实现您的目标,您应该将 pytz
版本的包分发到您的所有节点,并在您的 Pig UDF 中将其路径添加到 sys.path
。如果您完成与 dateutil
相同的步骤,一切都应该如您所愿。我们对 pygeoip
使用了非常相同的方法,它的效果非常好。
它是如何工作的
当您 运行 Pig 脚本引用某些 Python UDF(更准确地说是 Jython UDF)时,您的脚本将被编译为 map/reduce 作业,所有 REGISTER
ed 文件包含在JAR文件中,分布在实际执行代码的节点上。现在,当您的代码被执行时,Jython 解释器将启动并从 Java 代码执行。所以现在当 Python 代码在每个参与计算的节点上执行时,所有 Python 导入都在节点上本地解析。从标准库导入是从 Jython 实现中获取的,但是所有 "packages" 都必须安装,否则就没有 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
的引用,其中 pytz
已安装。
现在一旦我们 运行 Pig 有了我们的测试脚本:
pig -x local /opt/pytz_test/test_pytz.pig
我们应该能够读取作业的输出,其中应该列出:
2011-01-11
2011-01-11
2011-01-11
2011-01-11
我在 pig
脚本中使用的一些 Python udfs 中使用 datetime
。到目前为止,一切都很好。我在 Cloudera 5.5
但是,我还需要使用 pytz
或 dateutil
包,它们似乎不是原始 python 安装的一部分。
我可以在我的 Pig
udf 中以某些方式使用它们吗?如果是这样,如何?我认为 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
怎么办?哇,我只想转换 Pig 中的时区:(
从 a different but related question 的回答看来,只要资源在每个节点上可用,您就应该能够使用它们。
我认为您可以按照 this answer regarding jython 中的说明添加路径,然后像往常一样加载模块。
Append the location to the sys.path in the Python script:
import sys sys.path.append('/usr/local/lib/python2.7/dist-packages') import happybase
好吧,正如您可能知道的那样,所有 Python UDF 函数都不是由 Python 解释器执行的,而是与 Pig 一起分发的 Jython。在 0.12.0 中默认应该是 Jython 2.5.3. Unfortunately six
package supports Python starting from Python 2.6 and it's package required by dateutil
. However pytz
seems not to have such dependency, and should support Python versions starting from Python 2.4.
因此,为了实现您的目标,您应该将 pytz
版本的包分发到您的所有节点,并在您的 Pig UDF 中将其路径添加到 sys.path
。如果您完成与 dateutil
相同的步骤,一切都应该如您所愿。我们对 pygeoip
使用了非常相同的方法,它的效果非常好。
它是如何工作的
当您 运行 Pig 脚本引用某些 Python UDF(更准确地说是 Jython UDF)时,您的脚本将被编译为 map/reduce 作业,所有 REGISTER
ed 文件包含在JAR文件中,分布在实际执行代码的节点上。现在,当您的代码被执行时,Jython 解释器将启动并从 Java 代码执行。所以现在当 Python 代码在每个参与计算的节点上执行时,所有 Python 导入都在节点上本地解析。从标准库导入是从 Jython 实现中获取的,但是所有 "packages" 都必须安装,否则就没有 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
的引用,其中 pytz
已安装。
现在一旦我们 运行 Pig 有了我们的测试脚本:
pig -x local /opt/pytz_test/test_pytz.pig
我们应该能够读取作业的输出,其中应该列出:
2011-01-11
2011-01-11
2011-01-11
2011-01-11