MaxCompute - ODPS重裝上陣 第二彈 - 新的基本數據類型與內建函數

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

點此查看原文java

 

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

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

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

上次向您介紹了 [編譯器的易用性改進] https://yq.aliyun.com/articles/225028),此次向您介紹新的基本數據類型與內建函數編程

原ODPS只有六種基本數據類型, bigint, double, decimal, string, datetime, boolean。通常用起來也還夠用,可是在某些場景下就不夠了數組

  • 場景1 
    一個項目須要將原來在SQL SERVER上面運行的ETL系統,最近由於數據量暴漲,須要遷移到MaxCompute。發現某些表用了VARCHAR,有的用了INT。這些類型也被系統的多處SQL腳本用到還參與了運算。遷移到ODPS上時候,用STRING代替VARCHAR,用BIGINT代替INT ( 注1 )。

遷移完成後發現數據和原有系統對不上,是否是VARCHAR的截斷,INT的溢出行爲致使數據不一樣呢?仍是什麼其餘緣由,面對着現存系統,沒辦法,只好一點點看代碼,跑數據,作分析。原本覺得挺輕鬆的項目,花了幾周時間才搞定。。。編程語言

  • 場景2
    個人項目須要存放二進制數據到表中,由於是語音識別項目,每小段採集的音頻若是做爲一個字段存下去,而後用個UDF處理起來很方便。但是,ODPS沒有BINARY數據類型,好吧,就存成STRING好了。但是編寫寫UDF時候好麻煩,爲了存進去,必須將byte[]編碼成string, 讀的時候又必須解碼,代碼寫了一大堆,運行速度也慢了好多。。。

MaxCompute採用基於ODPS2.0的SQL引擎,大幅度擴充了基本類型並提供了配套的內建函數,基本解決了上述問題。分佈式

基本類型的擴充

此文中採用MaxCompute Studio做展現,首先,安裝MaxCompute Studio導入測試MaxCompute項目,建立工程,創建一個新的MaxCompute腳本文件, 以下函數

screenshot.png

運行後,創建另外一個文件插入數據,以下:
screenshot.png

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

能夠看到

  • 建立表的時候,首先指定使用MaxCompute新類型系統,由於兼容性的考慮,須要您主動打開這個設定。也能夠在MaxCompute Studio中缺省指定,以下圖
    screenshot.png

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

若是不使用MaxCompute Studio,能夠在腳本中指定,set odps.sql.type.system.odps2=true;。Studio實際上在後臺也是使用這個開關來控制是否啓用新類型。odps.sql.type.system.odps2設定爲true的時候,除了可使用新類型,也控制其它方面的一些行爲改變。將在相關部分說明。

若是須要在MaxCompute 項目中缺省打開,能夠聯繫您的項目管理員,在項目模板中設定。

  • 擴充後MaxCompute支持的基本數據類型以下表,新增類型有TINYINT, SMALLINT, INT, FLOAT, VARCHAR, TIMESTAMP, BINARY。
類型 是否新增 常量定義 描述
TINYINT 1Y, -127Y 8位有符號整形, 範圍-128到127
SMALLINT 32767S, -100S 16位有符號整形, 範圍-32768到32767
INT 1000, -15645787 ( 注1 ) 32位有符號整形, 範圍-2^31到2^31 - 1
BIGINT 100000000000L, -1L 64位有符號整形, 範圍-2^63 + 1到2^63 - 1
FLOAT 32位二進制浮點型
DOUBLE 3.1415926 1E+7 64位二進制浮點型
DECIMAL 3.5BD, 99999999999.9999999BD 10進制精確數字類型,整形部分範圍-10^36+1到10^36-1, 小數部分精確到10^-18
VARCHAR 無 ( 注2 ) 變長字符類型,n爲長度,取值範圍1到65535
STRING "abc", 'bcd', "alibaba" 'inc' ( 注3 ) 字符串類型,目前長度限制爲8M
BINARY 二進制數據類型,目前長度限制爲8M
DATETIME DATETIME '2017-11-11 00:00:00' 日期時間類型,範圍從0001年1月1日到9999年12月31日, 精確到毫秒
TIMESTAMP TIMESTAMP '2017-11-11 00:00:00.123456789' 與時區無關的時間戳類型,範圍從0001年1月1日到9999年12月31日 23.59:59.999999999, 精確到納秒 ( 注4 )
BOOLEAN TRUE,FALSE boolean類型, 取值TRUE或FALSE

新的隱式轉換規則表以下表 ( 注5 )

| | boolean | tinyint | smallint | int | bigint | float | double | decimal | string | varchar | timestamp | binary | 
|--------------|---------|---------|----------|-------|--------|-------|--------|---------|--------|---------|-----------|--------| 
| boolean to | TRUE | FALSE | FALSE | FALSE | FALSE | FALSE | FALSE | FALSE | FALSE | FALSE | FALSE | FALSE | 
| tinyint to | FALSE | TRUE | TRUE | TRUE | TRUE | TRUE | TRUE | TRUE | TRUE | TRUE | FALSE | FALSE | 
| smallint to | FALSE | FALSE | TRUE | TRUE | TRUE | TRUE | TRUE | TRUE | TRUE | TRUE | FALSE | FALSE | 
| int to | FALSE | FALSE | FALSE | TRUE | TRUE | TRUE | TRUE | TRUE | TRUE | TRUE | FALSE | FALSE | 
| bigint to | FALSE | FALSE | FALSE | FALSE | TRUE | TRUE | TRUE | TRUE | TRUE | TRUE | FALSE | FALSE | 
| float to | FALSE | FALSE | FALSE | FALSE | FALSE | TRUE | TRUE | TRUE | TRUE | TRUE | FALSE | FALSE | 
| double to | FALSE | FALSE | FALSE | FALSE | FALSE | FALSE | TRUE | TRUE | TRUE | TRUE | FALSE | FALSE | 
| decimal to | FALSE | FALSE | FALSE | FALSE | FALSE | FALSE | FALSE | TRUE | TRUE | TRUE | FALSE | FALSE | 
| string to | FALSE | FALSE | FALSE | FALSE | FALSE | FALSE | TRUE | TRUE | TRUE | TRUE | FALSE | FALSE | 
| varchar to | FALSE | FALSE | FALSE | FALSE | FALSE | FALSE | TRUE | TRUE | TRUE | TRUE | FALSE | FALSE | 
| timestamp to | FALSE | FALSE | FALSE | FALSE | FALSE | FALSE | FALSE | FALSE | TRUE | TRUE | TRUE | FALSE | 
| binary to | FALSE | FALSE | FALSE | FALSE | FALSE | FALSE | FALSE | FALSE | FALSE | FALSE | FALSE | TRUE |

此外,還新增了DECIMAL類型與DATETIME的常量定義方式, 100BD就是數值爲100的DECIMAL,datetime '2017-11-11 00:00:00'就是個datetime類型的常量。常量定義的方便之處在於能夠直接用到values子句和values表中,之後會單獨介紹。

內建函數的擴充

任何編程語言,包括SQL,無論語言自己多強大,如過沒有豐富的函數後者類庫支持,在應用的時候仍是會很不方便,MaxCompute配合新數據類型,大大豐富了內建函數,以下:

  • 數學函數
    log2, log10, bin, hex, unhex, degrees, radians, sign, e, pi, factorial, cbrt, shiftleft, shiftright, shiftrightunsigned
  • 日期函數
    unix_timestamp, year, quarter, month, day, dayofmonth, hour, minute, second, millisecond, nanosecond, from_utc_timestamp, current_timestamp, add_months, last_day, next_day, months_between
  • 字符串函數
    concat_ws, lpad, rpad, replace, soundex, substring_index, base64, unbase64
  • 聚合函數
    corr

這些函數大部分與Hive的內建函數兼容,用法能夠直接參考Hive的文檔。與Hive不一樣的是MaxCompute提供的這些函數都是用本地代碼實現的高效版本。

新增的TIMESTAMP數據類型支持納秒級別的精度,與之配合,新增了MaxCompute特有的millisecondnanosecond函數,能夠取出TIMESTAMPDATETIME的毫秒部分與TIMESTAMP的納秒部分。

如本系列上一篇中提到的,MaxCompute支持新的強制轉換寫法,例如,要強制bigint變量爲轉換爲string,能夠直接寫string(a_bigint), 和寫成cast(a_bigint as string)是等效的。具體用哪一種形式徹底取決於您的偏好。

須要注意的是全部用來支持新類型的函數,例如current_timestamp,也須要設定set odps.sql.type.system.odps2=true;,不然會報告編譯錯誤。

分區類型的擴充

分區類型的支持也進行了擴充,目前分區類型支持TINYINT, SMALLINT, INT, BIGINT, VARCHAR與STRING ( 注6 )

另外原ODPS在動態分區的時候,若是分區列的類型與對應SELECT列表中的列的類型不嚴格一致,會報錯。MaxCompute支持隱式類型轉換
例如:

set odps.sql.type.system.odps2=true;
create table parttable(a int, b double) partitioned by (p string);
insert into parttable partition(p) (p, a) select key, value, current_timestmap() from src;
select * from parttable;

返回

a b p
0 NULL 2017-01-23 22:30:47.130406621
0 NULL 2017-01-23 22:30:47.130406621

能夠看到分區列p的值爲從timestamp類型隱含轉換而來。

使用UDF

目前,MaxCompute2.0的JAVA UDF已經支持了新類型,Python UDF會盡快實現。JAVA UDF使用新類型的方法以下:

  1. UDAF和UDTF經過@Resolve註解來獲取signature,MaxCompute2.0支持在註解中使用新類型,如 @Resolve("smallint->varchar(10)")
  2. UDF經過反射分析evaluate來獲取signature,此時max compute內置類型與JAVA類型符合一一映射關係
max compute type java type
tinyint java.lang.Byte
smallint java.lang.Short
int java.lang.Integer
bigint java.lang.Long
float java.lang.Float
double java.lang.Double
decimal java.math.BigDecimal
boolean java.lang.Boolean
string java.lang.String
varchar com.aliyun.odps.data.Varchar
binary com.aliyun.odps.data.Binary
datetime java.util.Date
timestamp java.sql.Timestamp
array java.util.List
map java.util.Map
struct com.aliyun.odps.data.Struct

須要注意的是這裏,array類型對應的java類型是List,而不是數組

小結

MaxCompute大大擴充了基本數據類型與內建函數,能夠更好的適應豐富的應用場景。不過,不少比較複雜的場景僅使用基本類型仍然很麻煩,請期待MaxCompute重裝上陣下一篇,複雜類型的支持

標註

  • 注1
  1. 對於INT常量,若是超過INT取值範圍,會轉爲BIGINT,若是超過BIGINT取值範圍,會轉爲DOUBLE
  2. 在原ODPS下,由於歷史緣由,SQL腳本中的全部int類型都被轉換爲bigint,例如
create table a_bigint_table(a int); -- 這裏的int實際看成bigint處理
select cast(id as int) from mytable; -- 這裏的int實際看成bigint處理

爲了與ODPS原有模式兼容,MaxCompute在沒有設定odps.sql.type.system.odps2爲true的狀況下,仍然保留此轉換,可是會報告一個警告提示int被看成bigint處理了,若是您的腳本有此種狀況,建議所有改寫爲bigint,避免混淆。

  • 注2 VARCHAR類型常量可經過STRING常量的隱式轉換表示
  • 注3 STRING常量支持鏈接, 例如'abc' 'xyz'會解析爲'abcxyz',不一樣部分能夠寫在不一樣行上
  • 注4 受底層系統限制,目前調用current_timestamp還達不到納秒精度,例如
meta_dev>set odps.sql.type.system.odps2=true;select nanosecond(current_timestamp());

輸出爲相似

+------+
| _c0  |
+------+
| 877000000 |
+------+

Timestamp常量與外部數據導入能夠支持納秒精度。

  • 注5 在原ODPS下,由於歷史緣由,DOUBLE能夠隱式的轉換爲BIGINT,這個轉換潛在可能有數據丟失,通常數據庫系統都不容許。爲了與ODPS原有模式兼容,MaxCompute在沒有設定odps.sql.type.system.odps2爲true的狀況下,仍然容許此轉換,可是會報告警告;在設定odps.sql.type.system.odps2爲true的狀況下,不容許此隱式類型轉換。
  • 注6 在原ODPS下,由於歷史緣由,雖然能夠指定分區類型爲BIGINT,可是除了表的schema表示其爲BIGINT, 任何其餘狀況都被處理爲STRING。例如:
create table parttest (a bigint) partitioned by (pt bigint);
insert into parttest partition(pt) select 1, 2 from dual;
insert into parttest partition(pt) select 1, 10 from dual;
select * from parttest where pt >= 2;

返回的結果只有一行,由於10被按照字符串和2比,沒能返回。爲了與ODPS原有模式兼容,MaxCompute在沒有設定odps.sql.type.system.odps2爲true的狀況下,仍然如此處理;在設定odps.sql.type.system.odps2爲true的狀況下,BIGINT類型的分區嚴格按照BIGINT類型處理。

相關文章
相關標籤/搜索