JSON格式导入

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进行匹配,得到最终数据123beijing

    若JSON数据如下:

    { "id": 123, "name" : "beijing"}

    则Doris使用id, city进行匹配,得到最终数据123null

  • 指定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"]。则匹配到的元素为123null

    Doris当前不区分JSON数据中表示的Null值,和匹配失败时产生的Null值。假设JSON数据为:

    { "id": 123, "name" : null }

    则使用以下两种JSON Path会获得相同的结果:123null

    • ["$.id", "$.name"]
    • ["$.id", "$.info"]
  • 完全匹配失败

    为防止一些参数设置错误导致的误操作。Doris在尝试匹配一行数据时,如果所有列都匹配失败,则会认为这个是一个错误行。假设JSON数据为:

    { "id": 123, "city" : "beijing" }

    如果JSON Path错误的写为(或者不指定JSON Path时,表中的列不包含idcity):

    ["$.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中的元素。示例如下:

    表中包含两列:idcity。JSON数据为:

    { "id": 123, "name" : { "id" : "321", "city" : "shanghai" }}

    则Doris会使用id, city进行匹配,得到最终数据123null

  • 指定JSON Root

    通过JSON_Root指定JSON数据的根节点。Doris将通过JSON Root抽取根节点的元素进行解析。默认为空。

    指定Json root -H "json_root: $.name"。则匹配到的元素为:

    { "id" : "321", "city" : "shanghai" }

    该元素会被当作新JSON进行后续导入操作,得到最终数据321shanghai

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