全部產品
Search
文件中心

:MaxCompute JSON類型使用指南

更新時間:Jun 19, 2024

MaxCompute當前支援JSON資料類型,提高了表中帶有JSON類型資料的計算和分析的效能,本文為您介紹JSON類型的使用方法。

JSON類型簡介

背景資訊

半結構化資料介於結構和非結構化資料之間,資料中有一定的Schema,但是Schema靈活,沒有強約束,通常資料的Schema是自描述的。典型的例子就是JSON資料。MaxCompute中已經支援Schema Evolution、JSON STRING或複雜類型內建函數、Lambda等工作來增強SQL對半結構化資料的支援,在這種模型下,系統仍然要求使用者將半結構化資料通過正常化的處理後,匯入到有Schema的結構化表中。當業務資料變化時,需要使用者顯式執行Schema Evolution DDL語句對錶結構進行修改。image.png

上述模式存在強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 BYGROUP 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類型。

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,像建立基礎資料型別 (Elementary Data Type)一樣建立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

  • member accessor:$.phone,特殊字元可以使用如 $."sf*"

  • wildcard member accessor:$.*

  • element accessor:$[1, 2, 4 to 7]

  • wildcard element accessor:$[*]

mode

可選值為:laxstrict,預設使用lax模式。

  • lax:lax模式包含了wrapper和unwrapper過程。例如'lax $.phones.phonetype'

    以上述JSON資料為例,為您展示以下運算式的結果:

    • $[0] : wrap object [{....}] ,表示訪問第0號資料,返回{....}

    • $[1] : wrap object [{....}] ,表示訪問第1號資料,返回NULL

    • $.name.* : "name" 下是"Molly" ,期望是object,返回NULL

    • $.name[*] : "name" 下是"Molly" ,期望是array,此時會進行wrap成["Molly"],返回["Molly"]

    • $.phones.phonetype:phones的value是array,會對array進行unwrap成2個object,繼續擷取object中的phonetype,最終返回["work","cell"]

    • $.phones[*].phonetype:準確擷取phonetype的value,返回["work","cell"]

  • strict:strict模式嚴格要求JSON Path路徑與實際的類型一致,否則會返回NULL。例如'strict $.phones.phonetype'

    以上述JSON資料為例,為您展示以下運算式的結果:

    • strict $.phones.phonetype:由於phones的子節點是array,期望是object,返回NULL

    • strict $.address:由於沒有address變數,也會返回NULL

重要

目前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   |
+-----+