MaxCompute - ODPS重裝上陣 第二彈 - 新的基本數據類型與內建函數
MaxCompute(原ODPS)是阿裏雲自主研發的具有業界領先水平的分布式大數據處理平台, 尤其在集團內部得到廣泛應用,支撐了多個BU的核心業務。 MaxCompute除了持續優化性能外,也致力於提升SQL語言的用戶體驗和表達能力,提高廣大ODPS開發者的生產力。
MaxCompute基於ODPS2.0新一代的SQL引擎,顯著提升了SQL語言編譯過程的易用性與語言的表達能力。我們在此推出MaxCompute(ODPS2.0)重裝上陣係列文章
第一彈 - 善用MaxCompute編譯器的錯誤和警告
第二彈 - 新的基本數據類型與內建函數
第三彈 - 複雜類型
第四彈 - CTE,VALUES,SEMIJOIN
上次向您介紹了 編譯器的易用性改進,這次向您介紹新的基本數據類型與內建函數
原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腳本文件, 如下
運行後,可以在MaxCompute Studio的Project Explorer中找到新創建的表,察看表的詳細信息,並預覽數據,如下圖
可以看到
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特有的millisecond
, nanosecond
函數,可以取出TIMESTAMP
, DATETIME
的毫秒部分與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
- 對於INT常量,如果超過INT取值範圍,會轉為BIGINT,如果超過BIGINT取值範圍,會轉為DOUBLE
- 在原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類型處理。
最後更新:2017-10-17 17:33:51