MaxCompute當前支持JSON數據類型,提高了表中帶有JSON類型數據的計算和分析的性能,本文為您介紹JSON類型的使用方法。
JSON類型簡介
背景信息
半結構化數據介于結構和非結構化數據之間,數據中有一定的Schema,但是Schema靈活,沒有強約束,通常數據的Schema是自描述的。典型的例子就是JSON數據。MaxCompute中已經支持Schema Evolution、JSON STRING或復雜類型內置函數、Lambda等工作來增強SQL對半結構化數據的支持,在這種模型下,系統仍然要求用戶將半結構化數據通過規范化的處理后,導入到有Schema的結構化表中。當業務數據變化時,需要用戶顯式執行Schema Evolution DDL語句對表結構進行修改。
上述模式存在強Schema約束,無法將半結構化數據快速導入到系統中,數據導入時不符合Schema規范的數據只能丟棄,無法全量保存。針對以上問題,我們設計了一種新的數據類型JSON,既可以支持無強Schema約束的半結構化數據,又能夠充分利用列存儲的優化,同時滿足高靈活性和高性能的要求。
基本原理
JSON數據類型作為一種新的數據類型,使用方法和其他類型相似。我們無需管理Schema信息,插入JSON數據后,由MaxCompute自動進行公共Schema提取并進行優化,盡可能列存以提高性能。以下面測試數據為例:
CREATE TABLE json_table
(
json_val json
);
CREATE TABLE string_table
(
string_val STRING
);
INSERT INTO string_table VALUES
('{"a":1, "b":2}')
,('{"a":"key", "b":2}')
,('{"c":3}');
INSERT INTO json_table
SELECT json_parse(string_val)
FROM string_table;
在寫入數據時MaxCompute會自動提取出公共Schema<"a":binary, "b":bigint, "c":bigint>
,當讀取數據時可以根據Schema進行列裁剪,減少讀的數據,提高效率。例如:
SELECT json_val["b"]
,json_val["c"]
FROM json_table
;
-- 在讀表時進行列裁剪只保留b, c變量
+-----+-----+
| _c0 | _c1 |
+-----+-----+
| 2 | NULL |
| 2 | NULL |
| NULL | 3 |
+-----+-----+
對于非公共Schema部分,MaxCompute采用BINARY進行存儲,相較于原始STRING可以減少存儲空間。同時相比于用戶自定義UDF,新的JSON數據類型對于STRING和JSON相互轉換效率也有較大提高。
JSON類型使用
當前在新版的MaxCompute項目中,odps.sql.type.json.enable
參數默認為true,而在存量MaxCompute項目中,odps.sql.type.json.enable
參數默認為false。因此,若您是存量MaxCompute項目,在使用JSON數據類型時,需執行set odps.sql.type.json.enable=true;
,開啟對JSON類型特性的支持。您可以執行setproject;
代碼,確認odps.sql.type.json.enable
的參數值。
使用限制
目前支持的開發工具包括odpscmd客戶端,Studio和DataWorks,暫不支持Dataphin等外圍生態。如果需要跟外部系統做組合使用時,請先確認后再使用。使用odpscmd客戶端和Studio時需要關注以下內容。
使用odpscmd客戶端
使用Studio
需要將客戶端升級到V0.46.5及以上版本,否則無法使用
desc json_table
命令且無法通過Tunnel下載JSON類型數據。需要將客戶端安裝路徑下的conf\odps_config.ini文件中的參數
use_instance_tunnel
設置為false,否則查詢會報錯。
Studio只支持查詢JSON類型的操作,不支持上傳、下載JSON類型數據。
如果表存在其他引擎讀取情況,比如Hologres等,目前不支持讀取JSON數據類型。
暫不支持對一張表新增JSON列。
暫不支持對JSON類型的比較操作,也不支持對JSON類型進行
ORDER BY
、GROUP BY
或作為JOIN
的key等。目前JSON NUMBER的整數和小數分別使用BIGINT和DOUBLE類型進行存儲。當整數部分超出BIGINT范圍時會溢出,小數轉為DOUBLE時會損失精度。
生成JSON類型數據所用的字符串里不支持UNICODE
\u0000
。Java UDF和Python UDF暫不支持JSON類型。
目前JSON類型不支持Cluster表。
Java SDK V0.44.0以下版本和PyODPS V0.11.4.1以下版本均不支持JSON數據類型。
Delta Table類型的表暫不支持JSON類型。
JSON數據類型可以被嵌套使用,最多支持不超過20層的嵌套。
LITERAL常量
JSON類型完全按照JSON標準定義,支持BOOLEAN、NUMBER、STRING、NULL、ARRAY、OBJECT。其中NUMBER采用BIGINT和DOUBLE存儲,超過限制會有精度損失,同時注意json 'null'
和sql null
是不同的。
JSON 'null'
JSON '123'
JSON '123.34'
JSON 'true'
JSON '{"id":123,"name":"MaxCompute"}'
JSON '[12, 34]'
常量必須符合JSON標準定義,比如JSON '{id:123,"name":"MaxCompute"}'
為非法JSON STRING,id
必須包含在""
中。
JSON類型定義
無需指定Schema,像創建基本數據類型一樣創建JSON即可。
CREATE TABLE mf_json_table (json_val JSON);
JSON類型數據生成
有多種方式可以生成JSON類型數據:
JSON Literal
insert into mf_json_table values (json '123');
JSON函數
--json_object和json_array是MaxCompute的內置函數 insert into mf_json_table select json_object("key",123, "value", "abc"); select * from mf_json_table; --返回結果 +----------+ | json_val | +----------+ | 123 | | {"key":123,"value":"abc"} | +----------+ insert into mf_json_table select json_array("key",234, "value", "abc"); select * from mf_json_table; --返回結果 +----------+ | json_val | +----------+ | 123 | | ["key",234,"value","abc"] | | {"key":123,"value":"abc"} | +----------+
類型轉換
cast轉換需要留意與json_parse的區別,具體參見復雜類型函數說明:
insert into mf_json_table select cast("abc" as json); select * from mf_json_table; --返回 +----------+ | json_val | +----------+ | 123 | | "abc" | | ["key",234,"value","abc"] | | {"key":123,"value":"abc"} | +----------+
JSON訪問
JSON類型數據可以通過索引方式、json_extract、get_json_object函數訪問,返回JSON類型。
索引方式訪問
索引訪問方式為strict模式,包括下標index訪問和fieldName訪問。如果JSON Path和實際結構不一致,則返回NULL。
json_val['a'] [0][1]
相當于json_extract(json_val, 'strict $.a[0][1]')
。
--返回123
SELECT v['id']
FROM VALUES (JSON '{"id":123}') as t(v);
--返回12
SELECT v[0]
FROM VALUES (JSON '[12, 34]') as t(v);
--返回1
select v['x']['a'] from values (json '{"x": {"a": 1, "b": 2}}') as t(v);
--返回NULL
SELECT v[0]
FROM VALUES (JSON '{"id":123}') as t(v);
--返回NULL
SELECT v['not_exists']
FROM VALUES (JSON '{"id":123}') as t(v);
JSON函數訪問
例如通過json_extract/get_json_object函數訪問。
--通過get_json_object函數訪問,返回'MaxCompute'
SELECT GET_JSON_OBJECT(v, '$.x.name')
FROM VALUES (JSON '{"x": {"id": 1001, "name": "MaxCompute"}}') as t(v);
--返回結果
+-----+
| _c0 |
+-----+
| MaxCompute |
+-----+
--通過json_extract函數訪問,返回JSON 'MaxCompute'
SELECT JSON_EXTRACT(v, '$.x.name')
FROM VALUES (JSON '{"x": {"id": 1001, "name": "MaxCompute"}}') as t(v);
--返回結果
+-----+
| _c0 |
+-----+
| "MaxCompute" |
+-----+
新的JSON類型采用了更為規范的JSON Path解析,與MaxCompute舊函數get_json_object的JSON Path不同,可能存在兼容性問題,因此新的SQL推薦使用json_extract函數,更多JSON內置函數請參見復雜類型函數。
JSON Path規范
JSON Path用于指定JSON中某一節點的位置,方便查找節點、獲取想要的數據,常作為JSON函數的參數,新的JSON類型中采用的JSON Path解析器與PostgreSQL一致,屬于PostgreSQL的子集。示例如下:
JSON數據:
{ "name": "Molly", "phones": [ { "phonetype": "work", "phone#": "650-506-7000" }, { "phonetype": "cell", "phone#": "650-555-5555" } ] }
JSON Path示例:
$.phones[1]."phone#'
的結果為:"650-555-5555"。
下表中以上述JSON數據為例為您介紹JSON Path的相關規范:
變量 | 訪問運算符 |
accessor |
|
mode | 可選值為:lax、strict,默認使用lax模式。
重要 目前lax模式不支持列裁剪優化,strict模式支持。 |
JSON類型實踐示例
--若您的項目odps.sql.type.json.enable參數值為false,需執行以下命令
set odps.sql.type.json.enable=true;
create table json_table(json_val json);
create table mf_string_table(string_val string);
insert into mf_string_table values('{"a":1, "b":2}');
insert into json_table select json_parse(string_val)
from mf_string_table
where json_valid(string_val);
select * from json_table where json_val is not null;
--返回結果
+----------+
| json_val |
+----------+
| {"a":1,"b":2} |
+----------+
select json_val['b'] from json_table where json_val is not null;
--返回結果
+-----+
| _c0 |
+-----+
| 2 |
+-----+