摘要: 新版 MaxCompute Isolation Session 支持 Python UDF。也就是說,Python UDF 中已經能夠跑二進制包。剛纔以 Scipy 爲例踩了一下坑,把相關的過程分享出來。html
新版 MaxCompute Isolation Session 支持 Python UDF。也就是說,Python UDF 中已經能夠跑二進制包。剛纔以 Scipy 爲例踩了一下坑,把相關的過程分享出來。python
首先,從 PyPI 或其餘鏡像下載 Scipy 包。你須要下載後綴爲「cp27-cp27m-manylinux1_x86_64.whl」的包,其餘的包會沒法加載,包括名爲「cp27-cp27mu」的包。如下的截圖來自 https://pypi.python.org/pypi/scipy ,僅有打勾的包能夠直接使用:linux
下載 whl 後,將文件名更改成 scipy.zip。此後,在 MaxCompute Console 中執行session
add archive scipy.zip;
此後,scipy.zip 即被建立爲 MaxCompute Archive 資源。不建議使用其餘類型的資源,由於在執行時,MaxCompute 會自動解壓 Archive 類型的資源,從而省去手動解壓的步驟。app
若是列出的包中包含 Whl,則能夠直接上傳並跳過此步驟。若是列出的包不包含 whl(如手中僅有圖中的 scipy-0.19.0.zip),須要在 Linux 環境中手動編譯並打包爲 whl。打包前,須要確保下列命令返回「cp27m」而不是「cp27mu」:函數
python -c "import pip; print pip.pep425tags.get_abi_tag()"
若是返回值爲「cp27mu」,你須要使用 「--enable-unicode=no" 選項編譯一個可用的 Python 2.7,再使用編譯獲得的 Python。若是返回值正確,一般能夠在該環境下使用lua
python setup.py bdist_wheel
完成,具體請參考各個包的編譯/安裝說明。spa
打包完成後,將生成的 whl 包上傳。code
咱們須要編寫一個 UDF 支持計算 psi。編寫下列代碼:orm
from odps.udf import annotate from odps.distcache import get_cache_archive def include_package_path(res_name): import os, sys archive_files = get_cache_archive(res_name) dir_names = sorted([os.path.dirname(os.path.normpath(f.name)) for f in archive_files if '.dist_info' not in f.name], key=lambda v: len(v)) sys.path.append(os.path.dirname(dir_names[0])) @annotate("double->double") class MyPsi(object): def __init__(self): include_package_path('scipy.zip') def evaluate(self, arg0): from scipy.special import psi return float(psi(arg0))
這裏有必要解釋一下 include_package_path 這個函數。get_cache_archive 返回一個包含包中全部文件的文件對象。咱們首先取出全部的文件名,此後得到最短的路徑做爲包的路徑,並加入 sys.path。此後,即可以正常 import scipy 這個包。
須要注意的是,由於 MaxCompute 會在執行前經過原有的沙箱檢查 UDF 的輸入/輸出,於是 include_package_path 和 import 在函數外調用會報錯。
編寫完成後,將代碼保存爲 my_psi.py,並在 MaxCompute Console 中執行
add py my_psi.py;
此後建立函數。在 MaxCompute Console 中輸入
create function my_psi as my_psi.MyPsi using my_psi.py,scipy.zip;
注意在 create function 時,不要忘記加上剛纔上傳的包,例如上面的 scipy.zip。
建立 UDF 後,即可以在 MaxCompute Console 中執行查詢(暫不支持 pypy,於是需禁用 pypy):
set odps.pypy.enabled=false; set odps.isolation.session.enable = true; select my_psi(sepal_length) from iris;
若是包依賴了其餘 Python 包,須要一併上傳並同時加入到 UDF 依賴中。
使用 0.7.4 以上的 PyODPS DataFrame 能夠簡化使用二進制包的 UDF 的編寫,無需手動調用 include_package_path,具體可見 http://pyodps.readthedocs.io/zh_CN/latest/df-element-zh.html#third-party-library 。