Doris支持導入JSON格式的數據。本文為您介紹進行JSON格式數據導入時的參數說明和注意事項。
支持的導入方式
目前只有以下導入方式支持JSON格式的數據導入:
將本地JSON格式的文件通過Stream Load方式導入。
通過Routine Load訂閱并消費Kafka中的JSON格式消息。
暫不支持其他方式的JSON格式數據導入。
支持的JSON格式
當前僅支持以下兩種JSON格式:
以Array表示的多行數據
以Array為根節點的JSON格式。Array中的每個元素表示要導入的一行數據,通常是一個Object。示例如下:
[ { "id": 123, "city" : "beijing"}, { "id": 456, "city" : "shanghai"}, ... ]
這種方式通常用于Stream Load導入方式,以便在一批導入數據中表示多行數據。
重要必須配合設置strip_outer_array=true使用。Doris在解析時會將數組展開,然后依次解析其中的每一個 Object作為一行數據。
以Object表示的單行數據
以Object為根節點的JSON格式。整個Object即表示要導入的一行數據。示例如下:
{ "id": 123, "city" : "beijing"}
{ "id": 123, "city" : { "name" : "beijing", "region" : "haidian" }}
這種方式通常用于Routine Load導入方式,如表示Kafka中的一條消息,即一行數據。
以固定分隔符分隔的多行Object數據
Object表示的一行數據,即表示要導入的一行數據,示例如下:
{ "id": 123, "city" : "beijing"} { "id": 456, "city" : "shanghai"} ...
這種方式通常用于Stream Load導入方式,以便在一批導入數據中表示多行數據。
重要必須配合設置read_json_by_line=true使用,特殊分隔符還需要指定line_delimiter參數,默認\n。Doris在解析時會按照分隔符分隔,然后解析其中的每一行Object作為一行數據。
JSON參數
streaming_load_json_max_mb參數
一些數據格式,如JSON,無法進行拆分處理,必須讀取全部數據到內存后才能開始解析,因此,這個值用于限制此類格式數據單次導入最大數據量。
默認值為100,單位MB,詳情請參見BE參數配置修改此參數。
fuzzy_parse參數
在Stream Load中,可以添加fuzzy_parse參數來加速JSON數據的導入效率。
這個參數通常用于導入以Array表示的多行數據這種格式,所以一般要配合strip_outer_array=true使用。
這個功能要求Array中的每行數據的字段順序完全一致。Doris僅會根據第一行的字段順序做解析,然后以下標的形式訪問之后的數據,該方式可以提升3~5倍的導入效率。
JSON Path
Doris支持通過JSON Path抽取JSON中指定的數據。
因為對于Array類型的數據,Doris會先進行數組展開,最終按照Object格式進行單行處理,故以單個Object格式的JSON數據進行如下說明。
不指定JSON Path
如果沒有指定JSON Path,則Doris會默認使用表中的列名查找Object中的元素。示例如下:
表中包含兩列
id, city
。Json數據如下:{ "id": 123, "city" : "beijing"}
則Doris會使用
id, city
進行匹配,得到最終數據123
和beijing
。若JSON數據如下:
{ "id": 123, "name" : "beijing"}
則Doris使用
id, city
進行匹配,得到最終數據123
和null
。指定JSON Path
通過一個JSON數據的形式指定一組JSON Path。數組中的每個元素表示一個要抽取的列。示例如下:
["$.id", "$.name"]
["$.id.sub_id", "$.name[0]", "$.city[0]"]
Doris會使用指定的JSON Path進行數據匹配和抽取。
匹配非基本類型
前面的示例最終匹配到的數值都是基本類型,如整型、字符串等。Doris當前暫不支持復合類型,如Array、Map等。所以當匹配到一個非基本類型時,Doris會將該類型轉換為JSON格式的字符串,并以字符串類型進行導入,示例如下:
JSON數據為:
{ "id": 123, "city" : { "name" : "beijing", "region" : "haidian" }}
JSON Path為
["$.city"]
。則匹配到的元素為:{ "name" : "beijing", "region" : "haidian" }
該元素會被轉換為字符串進行后續導入操作:
"{'name':'beijing','region':'haidian'}"
匹配失敗
當匹配失敗時,將會返回Null。示例如下:
JSON數據為:
{ "id": 123, "name" : "beijing"}
JSON Path為
["$.id", "$.info"]
。則匹配到的元素為123
和null
。Doris當前不區分JSON數據中表示的Null值,和匹配失敗時產生的Null值。假設JSON數據為:
{ "id": 123, "name" : null }
則使用以下兩種JSON Path會獲得相同的結果:
123
和null
。["$.id", "$.name"]
["$.id", "$.info"]
完全匹配失敗
為防止一些參數設置錯誤導致的誤操作。Doris在嘗試匹配一行數據時,如果所有列都匹配失敗,則會認為這個是一個錯誤行。假設JSON數據為:
{ "id": 123, "city" : "beijing" }
如果JSON Path錯誤的寫為(或者不指定JSON Path時,表中的列不包含
id
和city
):["$.ad", "$.infa"]
則會導致完全匹配失敗,則該行會標記為錯誤行,而不是產出
null, null
。
JSON Path和Columns
JSON Path用于指定如何對JSON格式中的數據進行抽取,而Columns指定列的映射和轉換關系。兩者可以配合使用。
相當于通過JSON Path,將一個JSON格式的數據,按照JSON Path中指定的列順序進行了列的重排。之后,可以通過Columns,將這個重排后的源數據和表的列進行映射。舉例如下:
數據內容
{"k1" : 1, "k2": 2}
表結構
k2 int, k1 int
導入語句1(以Stream Load為例)
curl -v --location-trusted -u root: -H "format: json" -H "jsonpaths: [\"$.k2\", \"$.k1\"]" -T example.json http://127.0.0.1:8030/api/db1/tbl1/_stream_load
導入語句1中,僅指定了JSON Path,沒有指定Columns。其中JSON Path的作用是將JSON數據按照JSON Path中字段的順序進行抽取,之后會按照表結構的順序進行寫入。最終導入的數據結果如下:
+------+------+ | k1 | k2 | +------+------+ | 2 | 1 | +------+------+
實際的k1列導入了JSON數據中的k2列的值。因為JSON中字段名稱并不等同于表結構中字段的名稱,所以需要顯式的指定這兩者之間的映射關系。
導入語句2
curl -v --location-trusted -u root: -H "format: json" -H "jsonpaths: [\"$.k2\", \"$.k1\"]" -H "columns: k2, k1" -T example.json http://127.0.0.1:8030/api/db1/tbl1/_stream_load
相比如導入語句1,這里增加了Columns字段,用于描述列的映射關系,按k2,k1的順序。即按JSON Path中字段的順序抽取后,指定第一列為表中k2列的值,而第二列為表中k1列的值。最終導入的數據結果如下:
+------+------+ | k1 | k2 | +------+------+ | 1 | 2 | +------+------+
如其他導入一樣,可以在Columns中進行列的轉換操作。示例如下:
curl -v --location-trusted -u root: -H "format: json" -H "jsonpaths: [\"$.k2\", \"$.k1\"]" -H "columns: k2, tmp_k1, k1 = tmp_k1 * 100" -T example.json http://127.0.0.1:8030/api/db1/tbl1/_stream_load
上述示例會將k1的值乘以100后導入。最終導入的數據結果如下:
+------+------+ | k1 | k2 | +------+------+ | 100 | 2 | +------+------+
JSON Root
Doris支持通過JSON Root抽取JSON中指定的數據。
對于Array類型的數據,Doris會先進行數組展開,最終按照Object格式進行單行處理。所以示例都以單個Object格式的JSON數據進行說明。
不指定JSON Root
如果沒有指定JSON Root,則Doris會默認使用表中的列名查找Object中的元素。示例如下:
表中包含兩列:
id
和city
。JSON數據為:{ "id": 123, "name" : { "id" : "321", "city" : "shanghai" }}
則Doris會使用
id, city
進行匹配,得到最終數據123
和null
。指定JSON Root
通過JSON_Root指定JSON數據的根節點。Doris將通過JSON Root抽取根節點的元素進行解析。默認為空。
指定
Json root -H "json_root: $.name"
。則匹配到的元素為:{ "id" : "321", "city" : "shanghai" }
該元素會被當作新JSON進行后續導入操作,得到最終數據
321
和shanghai
。
NULL和Default值
示例數據如下:
[ {"k1": 1, "k2": "a"}, {"k1": 2}, {"k1": 3, "k2": "c"}, ]
表結構為:
k1 int null, k2 varchar(32) null default "x"
。導入語句如下:
curl -v --location-trusted -u root: -H "format: json" -H "strip_outer_array: true" -T example.json http://127.0.0.1:8030/api/db1/tbl1/_stream_load
您可能期望的導入結果如下,即對于缺失的列,填寫默認值。
+------+------+ | k1 | k2 | +------+------+ | 1 | a | +------+------+ | 2 | x | +------+------+ | 3 | c | +------+------+
但實際的導入結果如下,即對于缺失的列,補上了NULL。
+------+------+ | k1 | k2 | +------+------+ | 1 | a | +------+------+ | 2 | NULL | +------+------+ | 3 | c | +------+------+
這是因為通過導入語句中的信息,Doris并未獲取“缺失的列是表中的k2列”的信息。如果要對以上數據按照期望結果導入,則導入語句如下:
curl -v --location-trusted -u root: -H "format: json" -H "strip_outer_array: true" -H "jsonpaths: [\"$.k1\", \"$.k2\"]" -H "columns: k1, tmp_k2, k2 = ifnull(tmp_k2, 'x')" -T example.json http://127.0.0.1:8030/api/db1/tbl1/_stream_load