給技術新人的ODPS優化建議

来源:https://www.cnblogs.com/88223100/archive/2023/04/12/ODPS-optimization-suggestions-for-technical-newcomers.html
-Advertisement-
Play Games

數據開發基本都是從陌生到熟悉,但是寫多了就會發現各種好用的工具/函數,也會發現各種坑,本文分享了作者從拿到數據到數據開發到數據監控的一些實操經驗。 ...


數據開發基本都是從陌生到熟悉,但是寫多了就會發現各種好用的工具/函數,也會發現各種坑,本文分享了作者從拿到數據到數據開發到數據監控的一些實操經驗。

寫在前面

本文檔是組內的一份演算法ODPS離線開發分享,僅列出了這些年積累下來的一些重要經驗和結論,特別是在演算法日常數據處理和調度中的技巧和配置方法,至於具體為什麼,建議大家去阿裡雲官網查看底層map reduce以及data flow的工作原理,會有更加深刻的體會:)
參考文檔:https://help.aliyun.com/document_detail/89993.html

各種join的用法篇

輸入數據:zhule_a, zhule_b兩張測試表,具體schema和數據如下(後續為了說明重覆數據帶來的問題,會在a和b表中各重覆插入一條key=2,ds='20220930'的數據):
read zhule_a;
key
ds
1
20220930
2
20220930
1
20221001
2
20221001
3
20221001

read zhule_b;

key
ds
2
20220930
3
20220930
1
20221001
2
20221001
3
20221001
4
20221001
5
20221001

 

Join/Inner Join
用法:Returns the rows that have matching column values in both the left table and the right table based on the join condition。一句話:找出兩個表中共同的部分,註意笛卡爾積下麵的性能優化
1、每張表先選出來subset,然後再join。

-- better way to perform join, select small range of data first.
SELECT A.*, B.*
FROM
(SELECT * FROM A WHERE ds='20180101') A
JOIN
(SELECT * FROM B WHERE ds='20180101') B
ON a.key = b.key;
註意:在進行各種jion操作前,一定要自查左右表是否有重覆數據,否則最終重覆的結果會以笛卡爾積的數量增長,比如左右表各有兩條重覆數據,那麼join後重覆數據會多達4條!
圖片
2、最好的情況下是大表join小表,然後利用mapjoin來實現。
官方解釋:In the map stage, MAPJOIN loads all data in the specified tables into the memory of the program that performs the JOIN operation. The tables specified for MAPJOIN must be small tables, and the total memory occupied by the table data cannot exceed 512 MB.
Limits on JOIN operations in MAPJOIN:
  • The left table in a LEFT OUTER JOIN operation must be a large table.

  • The right table in a RIGHT OUTER JOIN operation must be a large table.

  • MAPJOIN cannot be used in a FULL OUTER JOIN operation.

  • The left or right table in an INNER JOIN operation can be a large table.


SELECT  /*+ MAPJOIN(b) */
        a.*
FROM    test_a a
JOIN test_b b
ON      a.user_key = b.user_key
;
//就是在sql語句前加一個標記說這是mapjoin,把小表別名寫在括弧里
一個有趣的點:
當我們用mapjoin時,除了正常的等式,mapjoin還支持不等式,如下麵的例子:
圖片

 

Left Join

用法:A LEFT JOIN operation first takes the Cartesian product of the rows in Table A and Table B and returns all the rows of Table A and rows in Table B that meet the join condition. If the join condition finds no matching rows in Table B for a row in Table A, the row in Table A is returned in the result set with NULL values in each column from Table B.一句話:輸出左表的所有記錄,以及右表中符合關聯條件的數據。右表中不符合關聯條件的行,輸出NULL。
  1. 一定要保留左表的內容是,可以選擇用left join,例如加入key_attrs

  2. Right Join和Left Join沒有本質區別,建議定義好左表後都利用Left Join來執行

  3. 如果右表有重覆數據的情況,那麼最終left join的結果會有重覆

圖片

 

Left Semi Join

用法:A LEFT SEMI JOIN operation returns only the rows in Table A that have a matching row in Table B. 對於左表中的一條數據,如果右表存在符合關聯條件的行,則輸出左表,否則不輸出
  1. 當右表沒有重覆數據時,和Join是一致的,只會保留相同的列下來

  2. left semi join並不會返回右表B中的任何數據,所以你沒法在where條件中指定關於右表B的任何篩選條件,下麵得例子能夠有更加清晰的對比(例子引用於開源論壇):

employee (2 columns - e_id and e_name)
10, Tom
20, Jerry 
30, Emily

employee_department_mapping (2 columns - e_id and d_name)
10, IT
10, Sales
20, HR

-- inner join results
SELECT e.e_id, e.e_name, d.d_name FROM 
employee e INNER JOIN employee_department_mapping d
on e.e_id = d.e_id
-- results
10, Tom, IT
10, Tom, Sales
20, Jerry, HR

-- left semi join results
SELECT e.e_id, e.e_name, d.d_name FROM 
employee e LEFT SEMI JOIN employee_department_mapping d
on e.e_id = d.e_id
-- results
10, Tom, IT
20, Jerry, HR

 

Left Anti Join
用法:A LEFT ANTI JOIN operation returns only the rows in Table A that have no matching rows in Table B.一句話:對於左表中的一條數據,如果右表中不存在符合關聯條件的數據,則輸出左表。
  1. 最好用的場景就是找出兩表的差異部分;

  2. 演算法日常調度時可以用於每日新增修改商品的提取,將關鍵欄位放到ON條件中就行

圖片

 

Full Join

用法:A FULL JOIN operation takes the Cartesian product of the rows in Table A and Table B and returns all the rows in Table A and Table B, whether the join condition is met or not. In the result set, NULL values are returned in the columns from the table that lacks a matching row in the other table.一句話:輸出左表和右表的所有記錄,對於不符合關聯條件的數據,未關聯的另一側輸出NULL
  1. 在有增刪改情況下更新下游最新數據時,非常好用,但是知道的人比較少
舉個慄子,其中today_feat是今天新計算的feature table,yest_feat是上一個分區的feature:

SELECT  COALESCE(a.main_image_url,b.main_image_url) AS main_image_url
        ,COALESCE(a.embedding,b.embedding) AS embedding
FROM    today_feat a
FULL JOIN yest_feat b
ON      a.main_image_url = b.main_image_url

其中full jion的效果如下,正好滿足new,old,updated feature的更新,配合COALESCE很絲滑:

圖片

合理設置Mapper和Reducepriority

 

set odps.instance.priority

目前ODPS更新後只能在開發dev空間生效,通過設置優先順序能夠一定程度提升排隊任務的執行優先順序,但是目前線上正式環境不會生效了,建議大家優化好自己健康分,同時對於重要的線上調度任務設置好基線,保證產出的時效。

 

set odps.sql.mapper.split.size

官方指導:Changes the input data amount of each Map worker, which is the split size of the input file. You can use this property to indirectly control the number of workers at each Map stage (default value: 256, unit: MB)。一句話:如果小文件很多,可以調大split.size的數值,這樣可以保證在有限資源下更容易申請到Mapper,提升執行的效率。如果資源豐富,想要更多Mapper資源,那就調小split.size的數值,可以申請到更多的Mapper,提升執行效率。酌情處理喲~
舉個慄子: 

-- original sql
CREATE TABLE if not EXISTS tmp_zhl_test LIFECYCLE 1 AS 
SELECT sig, venture, seller_id, COUNT(product_id) as cnt 
FROM sku_main_image_sig
WHERE LENGTH(sig) > 10 --some bad cases may have weird sigs like '#NEXT#'
GROUP BY sig, venture, seller_id
HAVING cnt>2
;
如果是預設設置,553 mappers 和 184 reducers 被分配,大約耗時 3m18s:
圖片
在資源充沛的情況下,我們設置odps.sql.mapper.split.size=64, 可以申請到更多的Mapper去處理文件的分片,同時更多的reducer也可以被分配到,同樣的SQL代碼執行時間降為: 2m34s. 
同樣的,如果你的數據量超大,但是每條數據本身很小,同時空間資源也有限(畢竟現在資源管控比較嚴格),與其等待9999個Mapper被分配,你可以嘗試設置odps.sql.mapper.split.size=2048(甚至更大)去減少需要分配的Mapper數量,讓任務能夠快速執行:)

 

set odps.sql.reducer.instances

顯示設置reducer的數量(預設值從0到4000),不設置的話會根據任務動態分配,設置後就會分配設置數量的reducer。同樣是上面的例子,當我們設置odps.sql.reducer.instances=1000, 耗時變為2m

 

set odps.sql.mapper(reducer).memory

設置每個Map/Reducer worker的記憶體(預設值是1024,可以設置為256到12288之間的值)一般我們不需要特別設置這個值,但是當任務報錯並說「data exceeds the memory」時,可以根據個人情況來設置這個選項。

在Python UDF中使用第三方庫

在這部分主要和大家分享下如何在ODPS的python udf安裝需要的第三方庫(如numpy,opencv等),以及如果有不同依賴庫之間的版本不相容問題時的有效解決方法。

 

Upload&Call Package

  • 需要下載第三方庫的安裝包xxx.whl,可以直接下載到自己的電腦上面,這樣可以在離線環境驗證多個版本的一致性(下麵介紹)。一般來說我們需要去看安裝包需要的python版本號以及相容機器環境,一般來說都是cp37-cp37m or py2.py3-none-any在中間,然後末尾是x86_64的安裝包;

  • 本地直接將xxx.whl轉換為xxx.zip,利用命令「mv xxx.whl xxx.zip」就行

  • 將zip資源文件上傳到ODPS對應的環境

  • 在你的UDF中,利用下麵的代碼指定資源包的路徑和引用(直接copy就行)

def include_package_path(res_name, lib_name):    
    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))
    for dir_name in dir_names:
        if dir_name.endswith(lib_name):
            sys.path.insert(0, os.path.dirname(dir_name))
            break
        elif os.path.exists(os.path.join(dir_name, lib_name + '.py')):
            sys.path.insert(0, os.path.abspath(dir_name))
            break

class PostProcess(BaseUDTF):
    def __init__(self):
        include_package_path('opencv_python-3.4.0.zip','cv2')
        include_package_path('numpy-1.16.6.zip','numpy')
  • python UDF寫完後,就可以在創建函數裡面的Resources里直接將你的資源名寫進去,這樣在流程啟動後,你的資源才會被有效調用起來。

圖片
  • python UDF預設的版本是2.x的,如果你的python版本是3.x,那麼需要在ODPS運行前加入下麵的指令;同時,部分功能是需要打開沙箱的,所以如果報錯的話,可以加入第二行的沙箱命令。
set odps.sql.python.version = cp37; --use python 3.7, default is 2.x version
set odps.isolation.session.enable = true; 

 

Solve Compatibility Issue

有時候在使用多個庫時,可能會出現不同版本之間的衝突問題(比如在使用opencv庫的時候,如果對應的numpy版本不相容的話,就會報錯)。所以在上傳多個庫的資源包前,需要先確認版本間的相容性。一般非常不建議大家用不同版本去試,而應該先在本地確定版本後再上傳。可行的步驟如下:
  • 在本地可以用類似conda的工具搭建一個虛擬環境

  • 在本地用pip或者conda install來安裝你需要的三方庫

  • 查詢你下載的三方庫以及依賴庫的版本,比如python-opencv的話可以列印cv2.__version__

  • 把對應版本的xxx.whl包按照上面的方法現在下來並且上傳到ODPS資源中進行依賴

發佈任務時的一些額外建議

  • 發佈任務配置時,可以靈活使用exclude和extra來去掉或添加你想要的依賴。其中exclude可以去掉你中間產出的臨時表,而extra可以幫你增加雖然不在代碼里但是希望依賴的上游表(這在彙總不同上游表數據寫入下游對應分區並且希望同時產出下游數據時很有用)。
--exclude input or output tables (especially those tmp tables)--@exclude_input=lsiqg_iqc_sku_product_detection_result--@exclude_output=lsmp_sku_image_url_bizdate
-- include input or output tables (especially those separate venture tables)--@extra_input=lsiqg_iqc_sku_product_detection_result--@extra_output=lsmp_sku_image_url_bizdate
  • 如果在SQL代碼過程中你需要使用臨時表來過渡中間產出的數據(避免SQL嵌套過於嚴重,影響運行效率),建議一定在臨時表中加入一個時間戳,ex. lsiqg_iqc_input_tmp_${bizdate}不然在補數據或者遇到任務堵塞兩個任務同時在調度時,或產生overwrite的一系列問題。
  • 如果存在上游表存在多個分區,但是每個分區處理邏輯一樣的話(比如不同國家的分區表處理邏輯其實一樣),非常建議在第一步里就把不同分區表的數據彙總起來,可以重新增加一個分區(如venture)來存放融合後的數據。如下示例:

INSERT OVERWRITE TABLE sku_main_image_sig PARTITION (ds = '${bizdate}',venture)
SELECT  id
        ,image_url
        ,venture
FROM    (
            SELECT  id
                    ,image_url
                    ,'ID' AS venture
            FROM    auction_image_id
            WHERE   ds = MAX_PT('auction_image_id')
            UNION
            SELECT  id
                    ,image_url
                    ,'PH' AS venture
            FROM    auction_image_ph
            WHERE   ds = MAX_PT('auction_image_ph')
            UNION
            SELECT  id
                    ,image_url
                    ,'VN' AS venture
            FROM    auction_image_vn
            WHERE   ds = MAX_PT('auction_image_vn')
            UNION
            SELECT  id
                    ,image_url
                    ,'SG' AS venture
            FROM    auction_image_sg
            WHERE   ds = MAX_PT('auction_image_sg')
            UNION
            SELECT  id
                    ,image_url
                    ,'MY' AS venture
            FROM    auction_image_my
            WHERE   ds = MAX_PT('auction_image_my')
            UNION
            SELECT  id
                    ,image_url
                    ,'TH' AS venture
            FROM    auction_image_th
            WHERE   ds = MAX_PT('auction_image_th')
        ) union_table
;
  • 對於重要的數據表,一定要設置監控,防止數據丟失、不正常產出等問題,具體的方法又可以分兩類:

    • 設置任務基線(baseline)來保證任務優先順序,這樣調度的時間更有保障

    • 設置warning的簡訊/電話或者DQC的監控規則來具體監控數據

簡單的任務可以直接在任務中心查看詳情中設置:

圖片
圖片
對於更加細緻的數據層面監控可以通過DQC平臺進行配置,比如無數據產出,數據波動,數據最大/最小值監控等。
圖片

寫在最後

數據開發基本都是從陌生到熟悉,但是寫多了就會發現各種好用的工具/函數,也會發現各種坑,個人拿到數據到數據開發到數據監控的一些經驗是:
  1. 拿到數據第一時間驗證數據的重覆性,有效性;如果是組內問題就反饋,上游鏈路問題就自己過濾;

  2. 寫完數據的每一部分都先驗證合理性,這樣會提高最終數據的成功率;

  3. 一般節點上線後,會主動去觀察3-4天,確保輸出是符合預期的(如果會發現應該穩定的數據反而猛然增加or減少,那很可能是數據邏輯有問題);

  4. 定義合理的數據監控,可以避免數據為空,數據波動過大,數據欄位不合理等問題;

Enjoy Data Engineering!!

 

作者|周慧玲(逐樂)

本文來自博客園,作者:古道輕風,轉載請註明原文鏈接:https://www.cnblogs.com/88223100/p/ODPS-optimization-suggestions-for-technical-newcomers.html


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 最近筆記本重置後,台式使用“遠程桌面連接”遠程筆記本失敗了,總是提示“登錄沒有成功”。 開始自查:win10專業版,允許遠程的相關設置也都開了,連接的ip正確,也沒問題。因為我的筆記本用戶是用微軟賬戶登錄的,遠程時用戶名和密碼也要用微軟用戶名和密碼(不是那個PIN碼)。再三確認用戶名和密碼是對的後, ...
  • 問題描述 對於打開分區提示需要格式化的情況,右擊屬性查看時,文件系統變成了RAW了,沒有關係很好恢復,千萬不要格式化。 問題分析 可以看到該分區說明分區表沒有問題,這是由於DBR扇區(即啟動扇區)損壞造成的。 以上聽不懂分析沒有關係,對你的恢復影響不大。 有兩種方法恢復: 1、用軟體自動進行修複,如 ...
  • 在上篇文章 《細節拉滿,80 張圖帶你一步一步推演 slab 記憶體池的設計與實現 》中,筆者從 slab cache 的總體架構演進角度以及 slab cache 的運行原理角度為大家勾勒出了 slab cache 的總體架構視圖,基於這個視圖詳細闡述了 slab cache 的記憶體分配以及釋放原理 ...
  • DROP TABLE IF EXISTS qrtz_blob_triggers; DROP TABLE IF EXISTS qrtz_calendars; DROP TABLE IF EXISTS qrtz_cron_triggers; DROP TABLE IF EXISTS qrtz_fired ...
  • 鎖屏面試題百日百刷,每個工作日堅持更新面試題。請看到最後就能獲取你想要的,接下來的是今日的面試題: 1.解釋一下,在數據製作過程中,你如何能從Kafka得到準確的信息? 在數據中,為了精確地獲得Kafka的消息,你必須遵循兩件事: 在數據消耗期間避免重覆,在數據生產過程中避免重覆。 這裡有兩種方法, ...
  • 1. 背景 已知數據集為: 目的: 計算每個uid的連續活躍天數,並且每一段活躍期內的開始時間和結束時間 2. 步驟 第一步:處理數據集 處理數據集,使其滿足每個uid每個日期只有一條數據。 第二步:以uid為主鍵,按照日期進行排序,計算row_number. SELECT uid ,`徵信查詢日期 ...
  • 一、概述 XGBoost是一種基於決策樹的集成學習演算法,它在處理結構化數據方面表現優異。相比其他演算法,XGBoost能夠處理大量特征和樣本,並且支持通過正則化控制模型的複雜度。XGBoost也可以自動進行特征選擇並對缺失值進行處理。 二、代碼實現步驟 1、導入相關庫 import org.apach ...
  • 一、貝葉斯定理 貝葉斯定理是關於隨機事件A和B的條件概率,生活中,我們可能很容易知道P(A|B),但是我需要求解P(B|A),學習了貝葉斯定理,就可以解決這類問題,計算公式如下: P(A)是A的先驗概率 P(B)是B的先驗概率 P(A|B)是A的後驗概率(已經知道B發生過了) P(B|A)是B的後驗 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...