全部產品
Search
文件中心

MaxCompute:MaxCompute UDF(Python)常見問題

更新時間:Jul 10, 2024

本文為您介紹使用Python語言編寫的MaxCompute UDF的常見問題。

類或資源問題

調用MaxCompute UDF運行代碼時的常見類或資源問題如下:

  • 問題現象一:運行報錯描述為function 'xxx' cannot be resolved

    • 產生原因:

      • 原因一:調用MaxCompute UDF運行代碼時,所處的專案不正確。即MaxCompute UDF不在MaxCompute專案中。例如MaxCompute UDF註冊到了開發專案,但卻在生產專案執行叫用作業。

      • 原因二:MaxCompute UDF的類不正確或資源不正確。

      • 原因三:MaxCompute UDF依賴的資源類型不正確。例如PY檔案,資源類型是PY,但MaxCompute UDF代碼中get_cache_file需要的類型是FILE。

      • 原因四:MaxCompute UDF依賴的資源不是最新的。當您通過DataWorks上傳MaxCompute資源時,從DataWorks同步至MaxCompute會存在延時情況,非最新資源。

      • 原因五:Python環境版本不正確。MaxCompute預設採用Python 2運行作業,當Python代碼中存在非ASCII編碼字元時,運行會報錯。

    • 解決措施:

      • 原因一的解決措施:在報錯的專案下通過MaxCompute用戶端執行list functions;命令,確保MaxCompute UDF是真實存在的。

      • 原因二的解決措施:通過MaxCompute用戶端執行desc function <function_name>;命令,檢查輸出結果中的ClassResources的正確性。

        如果不正確,需要執行create function <function_name> as <'package_to_class'> using <'resource_list'>;命令重新註冊函數,其中package_to_class為Python指令碼名.類名,resource_list為MaxCompute中需要引用的所有檔案資源、表資源、壓縮包資源或第三方包。

        更多註冊函數操作,請參見註冊函數

      • 原因三的解決措施:通過MaxCompute用戶端執行desc resource <resource_name>;命令,檢查輸出結果中的Type的正確性。如果資源類型不正確,可執行add <file_type> <file_name>;重新添加資源。

        • 如果MaxCompute UDF代碼中的引用資源方式為get_cache_file,表明引用的是檔案資源,資源類型必須為FILE。

        • 如果MaxCompute UDF代碼中的引用資源方式為get_cache_table,表明引用的是表資源,資源類型必須為TABLE。

        • 如果MaxCompute UDF代碼中的引用資源方式為get_cache_archive,表明引用的是壓縮包資源,資源類型必須為ARCHIVE。

        更多上傳資源操作,請參見添加資源

      • 原因四的解決措施:通過MaxCompute用戶端執行desc resource <resource_name>;命令,檢查輸出結果中的LastModifiedTime,確保為最近一次變更的時間。

      • 原因五的解決措施:在Python代碼頭部增加#coding:utf-8# -*- coding: utf-8 -*-編碼聲明,或在調用MaxCompute UDF的SQL語句前增加set odps.sql.python.version=cp37;與SQL語句一起提交,在Python 3環境下運行作業。

  • 問題現象二:MaxCompute UDF中使用get_cache_archive('xxx.zip')時,運行報錯描述為IOError: Download resource: xxx.zip failedodps.distcache.DistributedCacheErrorfuxi job failed: Download resource failed: xxx.zip

    • 產生原因:

      • 原因一:壓縮包資源不存在。註冊MaxCompute UDF時未同步指定壓縮包資源。

      • 原因二:壓縮包資源類型不正確,非ARCHIVE。

      • 原因三:壓縮包資源名及尾碼格式與實際資源套件名或尾碼格式不一致。例如壓縮包資源名及尾碼為xxx.zip,但實際上傳的檔案是xxx.tar.gz,此時會按ZIP格式解壓,導致解壓失敗報錯。

      • 原因四:同一個作業中有兩個UDF依賴了不同專案下的同名資源。

    • 解決措施:

      • 原因一的解決措施:通過MaxCompute用戶端執行desc function <function_name>;命令,檢查輸出結果中的Resources是否包含報錯資訊中的壓縮資源套件。

        如果不存在,可執行create function <function_name> as <'package_to_class'> using <'resource_list'>;命令重新註冊函數,並在resource_list中加上缺失的壓縮包資源。

        更多註冊函數操作,請參見註冊函數

      • 原因二的解決措施:通過MaxCompute用戶端執行desc resource <resource_name>;命令,檢查輸出結果中的Type是否為ARCHIVE。

        如果不是ARCHIVE類型,可執行add archive <file_name>;命令重新上傳資源。

        更多上傳資源操作,請參見添加資源

      • 原因三的解決措施:通過MaxCompute用戶端執行desc function <function_name>;命令,檢查輸出結果中的Resources中的壓縮包資源名及尾碼是否與實際檔案名稱、尾碼一致。

        如果不一致,可執行add archive <file_name>;命令重新上傳資源,file_name必須與實際壓縮包資源名及尾碼保持一致。

      • 原因四的解決措施:排查作業依賴的所有UDF(包括視圖中依賴的UDF),檢查UDF所屬專案和對應資源的名稱。如果不同專案下存在同名資源,建議修改依賴的UDF或資源名稱。

  • 問題現象三:MaxCompute UDF中使用get_cache_table(table_name)時,運行報錯描述為odps.distcache.DistributedCacheError: Table resource "xxx_table_name" not found

    • 產生原因:

      • 原因一:表資源不存在。註冊MaxCompute UDF時未同步指定表資源。

      • 原因二:表資源類型不正確,非TABLE。

    • 解決措施:

      • 原因一的解決措施:通過MaxCompute用戶端執行desc function <function_name>;命令,檢查輸出結果中的Resources是否包含報錯資訊中的表資源。

        如果不存在,可執行create function <function_name> as <'package_to_class'> using <'resource_list'>;命令重新註冊函數,並在resource_list中加上缺失的表資源。

        更多註冊函數操作,請參見註冊函數

      • 原因二的解決措施:通過MaxCompute用戶端執行desc resource <resource_name>;命令,檢查輸出結果中的Type是否為TABLE。

        如果不是TABLE類型,可執行add table <table_name>;命令重新上傳表資源。

        更多上傳資源操作,請參見添加資源

  • 問題現象四:MaxCompute UDF引用第三方包時,運行報錯描述為ImportError: No module named 'xxx'

    • 產生原因:

      • 原因一:第三方包的資源類型不正確,非ARCHIVE。

      • 原因二:註冊MaxCompute UDF時,未同步指定第三方包。

      • 原因三:MaxCompute UDF代碼中未添加第三方包路徑。

      • 原因四:第三方包為WHEEL包,但尾碼不正確。您需要根據Python環境版本下載對應的WHEEL檔案。

      • 原因五:第三方包不是WHEEL包,且非純Python包,但包中存在setup.py檔案。

      • 原因六:MaxCompute UDF對應的PY檔案名稱與需要引用的第三方模組的名稱衝突。例如MaxCompute UDF對應的Python檔案是A.py,import A時預設會匯入A.py而不是三方包裡的模組。

    • 解決措施:

      • 原因一的解決措施:通過MaxCompute用戶端執行desc resource <resource_name>;命令,檢查輸出結果中的Type是否為ARCHIVE。

        如果不是ARCHIVE類型,可執行add archive <file_name>;命令重新上傳資源。

        更多上傳資源操作,請參見添加資源

      • 原因二的解決措施:通過MaxCompute用戶端執行desc function <function_name>;命令,檢查輸出結果中的Resources是否包含第三方包。

        如果不包含,可執行create function <function_name> as <'package_to_class'> using <'resource_list'>;命令重新註冊函數,並在resource_list中加上第三方包。

        更多註冊函數操作,請參見註冊函數

      • 原因三的解決措施:檢查MaxCompute UDF代碼中是否添加了第三方包路徑,即是否配置了sys.path.insert(0, 'work/第三方包路徑')。假設模組名稱為A,對應Python檔案為A.py,確定其資源套件路徑及在代碼中添加路徑的方法如下:

        • 假設PY檔案位於檔案夾resource_dir中,如果將檔案夾resource_dir直接壓縮為resource-of-A.zip,sys.path.insert中填寫的路徑為work/resource-of-A.zip/resource_dir/

        • 假設PY檔案位於檔案夾resource_dir中,如果將檔案夾resource_dir內的所有檔案壓縮為resource-of-A.zip,sys.path.insert中填寫的路徑為work/resource-of-A.zip/

        • 假設PY檔案位於檔案夾resource_dir/path1/path2中,如果將檔案夾resource_dir內的所有檔案壓縮為resource-of-A.zip,sys.path.insert中填寫的路徑為work/resource-of-A.zip/path1/path2/

        說明

        ARCHIVE資源預設放在MaxCompute UDF執行路徑的相對路徑./work/中。

      • 原因四的解決措施:Python 2和Python 3環境對應的WHEEL檔案不相同,Python 2要求WHEEL檔案名稱中包含cp27-cp27m-manylinux1_x86_64,Python 3要求WHEEL檔案名稱中包含cp37-cp37m-manylinux1_x86_64,請下載合適的WHEEL檔案。下載的WHEEL檔案可以直接修改尾碼為.zip,不需要對WHEEL檔案再次打包產生ZIP檔案。

      • 原因五的解決措施:需要先在與MaxCompute相容的環境下將setup.py編譯產生WHEEL包,然後再執行上傳資源及註冊函數操作。更多編譯第三方包資訊,請參見使用需要編譯的第三方包

      • 原因六的解決措施:修改MaxCompute UDF對應的Python檔案名稱。

  • 問題現象五:MaxCompute UDF引用Python 3的標準庫時,運行報錯描述為ImportError: No module named enum

    • 產生原因:MaxCompute專案未開啟Python 3,預設使用Python 2環境運行MaxCompute UDF,無法識別Python 3的標準庫。

    • 解決措施:在調用MaxCompute UDF的SQL語句前增加set odps.sql.python.version=cp37;與SQL語句一起提交執行。

  • 問題現象六:運行報錯描述為ModuleNotFoundError: No module named 'six'

    • 產生原因:Python UDF引入第三方包時,沒有將包的路徑加入到sys.path中,導致第三方包無法正常匯入。

    • 解決措施:請參見在MaxCompute UDF中運行Scipy,將include_package_path('six.zip')修改為sys.path.insert(0, 'work/six.zip')

  • 問題現象七:運行報錯描述為failed to get Udf info from xxx.py

    • 產生原因:編寫的UDTF或UDAF代碼中,基類的匯入寫法不正確。例如import odps.udf.BaseUDTFimport odps.udf.BaseUDAF

    • 解決措施:修改為from odps.udf import BaseUDTFfrom odps.udf import BaseUDAF

效能問題

  • 問題現象:運行報錯描述為kInstanceMonitorTimeout

  • 產生原因:MaxCompute UDF處理時間過長導致逾時。預設情況下UDF處理資料的時間有限制,在處理一批(通常情況下為1024條)記錄時,必須在1800秒內處理完。這個時間限制並不是針對Worker的總已耗用時間,而是處理一小批記錄的時間。通常情況下SQL處理資料的速率超過了萬條/秒,該限制只是為了防止MaxCompute UDF中出現死迴圈,導致長時間佔用CPU資源的情況。

  • 解決措施:

    • 在MaxCompute UDF代碼中增加日誌,用於檢查代碼中是否有死迴圈問題,或者可以在日誌裡列印時間資訊來檢查MaxCompute UDF處理單條資料的時間長度是否符合預期。代碼中需要增加如下列印日誌相關資訊,作業運行成功後,您可以在LogviewStdOut中擷取到日誌資訊。

      • Python 2環境

        sys.stdout.write('your log')
        sys.stdout.flush()
      • Python 3環境

        print('your log', flush=True)
    • 如果實際計算量很大,MaxCompute UDF預計的已耗用時間很長,您可以通過調整如下參數避免逾時報錯。

      參數

      說明

      set odps.function.timeout=xxx;

      調整UDF運行逾時時間長度。預設值為1800s。可根據實際情況酌情調大。取值範圍為1s~3600s。

      set odps.sql.executionengine.batch.rowcount=xxx;

      調整MaxCompute一次處理的資料行數。預設值為1024行。可根據實際情況酌情調小。

網路問題

  • 問題現象:調用MaxCompute UDF訪問外網時,代碼運行會報錯

  • 產生原因:MaxCompute UDF不支援訪問外網。

  • 解決措施:請根據業務情況填寫並提交網路連接申請表單,MaxCompute支援人員團隊會及時聯絡您完成網路開通操作。表單填寫指導,請參見網路開通流程

沙箱問題

  • 問題現象:運行報錯描述為RuntimeError: xxx has been blocked by sandbox

  • 產生原因:Python UDF中的某些函數調用被沙箱阻斷了。

  • 解決措施:

    • 在調用Python UDF的SQL語句前,增加set odps.isolation.session.enable=true; 設定,與SQL語句一起提交執行。

    • 使用Python 3 UDF,預設會設定set odps.isolation.session.enable=true;

編碼問題

調用MaxCompute UDF運行代碼時的常見編碼問題如下:

  • 問題現象一:運行報錯描述為 SyntaxError: Non-ASCII character '\xe8' in file xxx. on line yyy

    • 產生原因:MaxCompute UDF對應的Python檔案中存在非ASCII編碼字元,且運行在Python 2環境中。

    • 解決措施:

      • 在調用MaxCompute UDF的SQL語句前增加set odps.sql.python.version=cp37;與SQL語句一起提交,在Python 3環境下運行作業。

      • 將Python 2的預設解析器編碼方式修改為UTF-8,即在Python檔案開頭添加如下語句。

        import sys
        reload(sys)
        sys.setdefaultencoding('utf-8')
  • 問題現象二:調用Python 2 UDF時,運行報錯描述為UnicodeEncodeError: 'ascii' code can't encode characters in position x-y: ordinal not in range(128)

    • 產生原因:函數簽名中傳回值類型是STRING,但MaxCompute UDF返回UNICODE類型的Python對象,假設對象名為ret。MaxCompute預設會將傳回值ret按照ASCII編碼格式轉換為STR類型,返回str(ret)。當ret本身在ASCII編碼範圍內時,可以成功轉換為STR類型,但如果ret不在ASCII編碼範圍內時,轉換會失敗並返回報錯。

    • 解決措施:在Python代碼的evaluate方法中增加如下語句。

      return ret.encode('utf-8')
  • 問題現象三:調用Python 3 UDF時,運行報錯描述為UnicodeDecodeError: 'utf-8' codec can't decode byte xxx in position xxx: invalid continuation byte

    • 產生原因:函數簽名中輸入參數類型是STRING,但是調用Python 3 UDF時輸入的字串不能按照UTF-8解碼為STR類型的Python對象。

    • 解決措施:

      • 避免向MaxCompute表中寫入非UTF-8編碼的字串。

        例如,Python 2 UDF返回的Python對象是按GBK編碼的STR,可以正常寫入MaxCompute表中,但無法被Python 3 UDF讀取,Python 2 UDF返回資料時建議轉為UTF-8編碼後再返回,例如返回ret.decode('gbk').encode('utf-8')

      • 在SQL語句中使用內建函數is_encoding提前過濾掉非UTF-8編碼的資料。程式碼範例如下。

        select py_udf(input_col) from example_table where is_encoding(input_col, 'utf-8', 'utf-8') = true;
      • 將Python代碼中的函數簽名輸入參數類型修改為BINARY,並在SQL語句中將STRING類型列轉換為BINARY類型作為Python 3 UDF入參。程式碼範例如下。

        select py_udf(cast(input_col as binary)) from example_table;

函數簽名問題

調用MaxCompute UDF運行代碼時的常見函數簽名問題如下:

  • 問題現象一:運行報錯描述為resolve annotation of class xxx for UDTF/UDF/UDAF yyy contains invalid content '<EOF>'

    • 產生原因:MaxCompute UDF的輸入或輸出參數為複雜資料類型,但函數簽名不合法。

    • 解決方案:修改函數簽名中的複雜資料類型寫法,確保為合法的函數簽名。更多函數簽名資訊,請參見函數簽名及資料類型

  • 問題現象二:運行報錯描述為TypeError: expected <class 'xxx'> but <class 'yyy'> found, value:zzz

    • 產生原因:函數簽名指定的傳回值類型與MaxCompute UDF代碼實際返回的資料類型不一致。

    • 解決措施:確認期望返回結果,修改函數簽名或MaxCompute UDF代碼,確保二者資料類型一致。

  • 問題現象三:運行報錯描述為Semantic analysis exception - evaluate function in class xxx.yyy for user defined function zz does not match annotation ***->***

    • 產生原因:函數簽名中指定的入參個數與MaxCompute UDF代碼中對應方法的入參個數不一致。

    • 解決措施:確認實際入參個數,修改函數簽名或MaxCompute UDF代碼,確保二者入參個數一致。

第三方包問題

  • 問題現象:運行報錯描述為GLIBCXX_x.x.x not found

  • 產生原因:報錯的so連結庫檔案依賴的GLIBCXX版本高於MaxCompute本身支援的版本。GLIBC、CXXABI同理。

  • 解決措施:使用相容的WHEEL包或在相容的環境中重新編譯so連結庫檔案。MaxCompute支援的二進位可執行檔或so連結庫檔案依賴的最大版本如下。

    GLIBC <= 2.17
    CXXABI <= 1.3.8
    GLIBCXX <= 3.4.19
    GCC <= 4.2.0

UDTF相關問題

  • 問題現象:運行報錯描述為Semantic analysis exception - expect 2 aliases but have 0

  • 產生原因:Python UDTF代碼中沒有指定輸出資料行名。

  • 解決措施:您可以在調用Python UDTF的SELECT語句中通過as子句給出列名。命令樣本如下。

    select my_udtf(col0, col1) as (ret_col0, ret_col1, ret_col2) from tmp1;

UDAF相關問題

  • 問題現象一:運行報錯描述為Script exception - ValueError: unmarshallable object

    • 產生原因:Python UDAF代碼中的buffer不是Marshal對象。

    • 解決措施:為buffer賦值時,需要確保值為Marshal對象。假設Python UDAF中要使用兩個buffer,類型分別為LIST和DICT,則new_buffer方法中應該寫為return [list(), dict()]。在iterate/merge/terminate方法中使用buffer/pbuffer時,LIST類型的buffer對應 buffer[0]/pbuffer[0],DICT類型的buffer對應buffer[1]/pbuffer[1]。如果buffer的元素為LIST或DICT,這些元素也必須是Marshal對象。

  • 問題現象二:運行報錯描述為Python UDAF buffer size overflowed: 2821486749

    • 產生原因:Python UDAF中的buffer經過Marshal處理後的大小超過2 GB,使用者使用buffer的方式有誤,buffer的大小不應該隨資料量遞增。

    • 解決措施:重新設計Python UDAF的邏輯,buffer的大小不應該隨資料量遞增。例如聲明了一個bufferlistiteratemerge階段不能一直往buffer裡增加資料。更多Python UDAF資訊,請參見UDAF概述