MaxCompute - ODPS重裝上陣 第三彈 - 複雜類型

摘要: MaxCompute(原ODPS)是阿里雲自主研發的具備業界領先水平的分佈式大數據處理平臺, 尤爲在集團內部獲得普遍應用,支撐了多個BU的核心業務。 MaxCompute除了持續優化性能外,也致力於提高SQL語言的用戶體驗和表達能力,提升廣大ODPS開發者的生產力。html

點此查看原文java

MaxCompute(原ODPS)是阿里雲自主研發的具備業界領先水平的分佈式大數據處理平臺, 尤爲在集團內部獲得普遍應用,支撐了多個BU的核心業務。 MaxCompute除了持續優化性能外,也致力於提高SQL語言的用戶體驗和表達能力,提升廣大ODPS開發者的生產力。數組

MaxCompute基於ODPS2.0新一代的SQL引擎,顯著提高了SQL語言編譯過程的易用性與語言的表達能力。咱們在此推出MaxCompute(ODPS2.0)重裝上陣系列文章數據結構

第一彈 - 善用MaxCompute編譯器的錯誤和警告
第二彈 - 新的基本數據類型與內建函數
第三彈 - 複雜類型
第四彈 - CTE,VALUES,SEMIJOIN分佈式

上次向您介紹了 新的基本數據類型與內建函數,此次向您介紹複雜數據類型函數

原ODPS也支持兩種複雜類型,ARRAY, MAP,可是有些場景下仍是不夠用性能

  • 場景1 
    個人項目裏,生成的一箇中間表,爲了優化性能,裏面有一列最好是個數組,由於若是把數組打散,每行上存一個元素,會由於其餘列的重複致使數據量爆炸。首先想從上游表中生成這個數組,搜索半天文檔,發現惟一的方式是把源數據列先轉STRING,再用wm_concat聚合,再用split函數打散成ARRAY<STRING>,這樣原來類型信息丟了,不過STRING彷佛也能用,好,繼續。後面的運算有個地方須要取數組最後一個元素,試圖用數組下標配合size函數,my_array[size(my_array)], 發現報告錯誤,下標必須是常量,但是個人數組不是定長的,看看有沒有函數能反轉數組呢?沒有!最後不得不放棄使用數組。。。
  • 場景2
    個人任務是爲每一個廣告生成一個曲線,表明隨着廣告商的出價由低到高,預計的impression, click次數的曲線。最天然的表達是有個數據結構,裏面存着出價,impression次數,click次數。但是ODPS不支持這樣的用法,只好encode成一個字符串,每次操做先編碼,再解碼。好麻煩,效率也不好,但是沒有辦法。。。

MaxCompute採用基於ODPS2.0的SQL引擎,大幅度改進了複雜類型並提供了配套的內建函數,基本解決了上述問題。測試

複雜類型的擴充

此文中採用MaxCompute Studio做展現 ( MaxCompute從2.8.0.2版本開始支持複雜類型,若是您的版本不夠新,請升級到最新版本 )。大數據

首先,安裝MaxCompute Studio導入測試MaxCompute項目,建立工程,創建一個新的MaxCompute腳本文件, 以下優化

image.png

運行後,能夠在MaxCompute Studio的Project Explorer中找到新建立的表,察看錶的詳細信息,並預覽數據,以下圖
image.png

能夠看到MaxCompute支持ARRAY, MAP, STRUCT類型,而且能夠任意嵌套使用。

MaxCompute Studio支持含新類型表數據的導入導出,可參考此ATA文章

  • MaxCompute支持的複雜類型見下表
類型 定義示例 構造示例 訪問示例
ARRAY array<int>
array<struct<a:int, b:string>>
array(1, 2, 3)
array(array(1, 2), array(3, 4))
a[1]
a[x][y]
MAP map<string, string>,
map<tinyint, array<string>>
map("k1", "v1", "k2", "v2"),
map(1Y, array('a', 'b'), 2Y, array('x', 'y'))
m['k1'],
m[2Y][id]
STRUCT struct<x:int, y:int>,
struct<a:array<int>, b:map<int, int>>
named_struct('x', 1, 'y', 2)
named_struct('a', array(1, 2), 'b', map(1, 7, 2, 8)
s.x
s.b[1]

複雜類型構造與操做函數

返回類型 簽名 註釋
MAP<K, V> map(K key1, V value1, K key2, V value2, ...) 使用給定key/value對創建map, 全部key類型一致,必須是基本類型,全部value類型一致,可爲任意類型
ARRAY<K> map_keys(Map<K, V> m) 將參數中的map的全部key做爲數組返回,輸入NULL,返回NULL
ARRAY<V> map_values(MAP<K, V> m) 將參數中的map的全部value做爲數組返回,輸入NULL,返回NULL
int size(MAP<K, V>) 取得給定MAP元素數目
TABLE<K, V> explode(MAP<K, V>) 表生成函數,將給定MAP展開,每一個key/value一行,每行兩列分別對應key和value
ARRAY<T> array(T value1, T value2, ...) 使用給定value構造ARRAY,全部value類型一致
int size(ARRAY<T>) 取得給定ARRAY元素數目
boolean array_contains(ARRAY<T> a, value v) 檢測給定ARRAY a中是否包含v
ARRAY<T> sort_array(ARRAY<T>) 對給定數組排序
ARRAY<T> collect_list(T col) 聚合函數,在給定group內,將col指定的表達式聚合爲一個數組
ARRAY<T> collect_set(T col) 聚合函數,在給定group內,將col指定的表達式聚合爲一個無重複元素的集合數組
TABLE<T> explode(ARRAY<T>) 表生成函數,將給定ARRAY展開,每一個value一行,每行一列對應相應數組元素
TABLE (int, T) posexplode(ARRAY<T>) 表生成函數,將給定ARRAY展開,每一個value一行,每行兩列分別對應數組從0開始的下標和數組元素
STRUCT<col1:T1, col2:T2, ...> struct(T1 value1, T2 value2, ...) 使用給定value列表創建struct, 各value可爲任意類型,生成struct的field的名稱依次爲col1, col2, ...
STRUCT<name1:T1, name2:T2, ...> named_struct(name1, value1, name2, value2, ...) 使用給定name/value列表創建struct, 各value可爲任意類型,生成struct的field的名稱依次爲name1, name2, ...
TABLE (f1 T1, f2 T2, ...) inline(ARRAY<STRUCT<f1:T1, f2:T2, ...>>) 表生成函數,將給定struct數組展開,每一個元素對應一行,每行每一個struct元素對應一列

在UDF中使用複雜類型

原ODPS不支持在UDF中訪問任何複雜類型。MaxCompute Java UDF支持全部複雜類型,Python UDF也會在不久的未來支持。

JAVA UDF中複雜類型的表示方法

ODPS的UDF分爲三大類:UDF,UDAF,UDTF,其中:

  1. UDAF和UDTF經過@Resolve annotation來指定sinature,在MaxCompute 2.0上線後,用戶將能夠在Resolve annotation中。如 @Resolve("array<string>,struct<a1:bigint,b1:string>,string->map<string,bigint>,struct<b1:bigint, b2:binary>")
  2. UDF經過evaluate方法的signature來映射UDF的輸入輸出類型,此時參考MaxCompute類型與java類型的映射關係。其中array對應java.util.List, map對應java.util.Map,struct對應com.aliyun.odps.data.Struct 。須要注意的是,com.aliyun.odps.data.Struct從反射是看不出field name和field type的,因此須要用 @Resolve annotation來輔助,即若是須要再UDF中使用struct,要求在UDF class上也標註上@Resolve註解,這個註解只會影響參數或返回值中包含com.aliyun.odps.data.Struct的重載。目前class上只能提供一個@Resolve annotation,所以一個UDF中帶有struct 參數或返回值的重載只能有一個。這個是目前的一個限制,咱們正在改進,後續將會取消這一限制。

實際用例

如如下代碼,定義了一個有三個overloads的UDF,其中第一個用了array做爲參數,第二個用了map做爲參數,第三個用了struct。因爲第三個overloads用了struct做爲參數或者返回值,所以要求必需要對UDF class打上@Resolve annotation,來指定struct的具體類型。

@Resolve("struct<a:bigint>,string->string")
public class UdfArray extends UDF {
  public String evaluate(List<String> vals, Long len) {
    return vals.get(len.intValue());
  }

  public String evaluate(Map<String,String> map, String key) {
    return map.get(key);
  }

  public String evaluate(Struct struct, String key) {
    return struct.getFieldValue("a") + key;
  }
}

用戶能夠直接將複雜類型傳入UDF中:

create function my_index as 'UdfArray' using 'myjar.jar';
select id, my_index(array('red', 'yellow', 'green'), colorOrdinal) as color_name from colors;

小節

MaxCompute豐富了複雜類型的支持,能夠更好的適應各類應用場景。MaxCompute仍將在兼容性,表達能力等多方面持續改進類型系統。從本系列的下一篇起,開始介紹MaxCompute在SQL語言其餘方面的改進!

相關文章
相關標籤/搜索