首页 前端知识 ClickHouse 官方文档:处理 JSON 数据 (2/2)

ClickHouse 官方文档:处理 JSON 数据 (2/2)

2025-03-14 12:03:41 前端知识 前端哥 699 932 我要收藏

图片

本文字数:15445;估计阅读时间:39分钟

作者: ClickHouse team

本文在公众号【ClickHouseInc】首发

ClickHouse 官方文档:处理 JSON 数据 (1/2)

导出 JSON 数据和元信息  

用于导入的几乎所有 JSON 格式都可以用于导出。最常用的导出格式是 JSONEachRow:

SELECT * FROM sometable FORMAT JSONEachRow
复制
    {"path":"Bob_Dolman","month":"2016-11-01","hits":245}
    {"path":"1-krona","month":"2017-01-01","hits":4}
    {"path":"Ahmadabad-e_Kalij-e_Sofla","month":"2017-01-01","hits":3}
    复制

    此外,可以使用 JSONCompactEachRow 格式,通过省略列名来减少存储空间占用:

    SELECT * FROM sometable FORMAT JSONCompactEachRow
    复制
      ["Bob_Dolman", "2016-11-01", 245]
      ["1-krona", "2017-01-01", 4]
      ["Ahmadabad-e_Kalij-e_Sofla", "2017-01-01", 3]
      复制

      将数据类型导出为字符串  

      ClickHouse 会严格按照标准遵循数据类型导出 JSON。但在某些场景中,如果需要将所有值导出为字符串,可以使用 JSONStringsEachRow 格式:

      SELECT * FROM sometable FORMAT JSONStringsEachRow
      复制
        {"path":"Bob_Dolman","month":"2016-11-01","hits":"245"}
        {"path":"1-krona","month":"2017-01-01","hits":"4"}
        {"path":"Ahmadabad-e_Kalij-e_Sofla","month":"2017-01-01","hits":"3"}
        复制

        在此示例中,数值列 hits 被编码为字符串。此功能适用于所有 JSON* 格式,用户可以使用 JSONStrings\* 或 JSONCompactStrings\* 格式:

        SELECT * FROM sometable FORMAT JSONCompactStringsEachRow
        复制
          ["Bob_Dolman", "2016-11-01", "245"]
          ["1-krona", "2017-01-01", "4"]
          ["Ahmadabad-e_Kalij-e_Sofla", "2017-01-01", "3"]
          复制

          导出数据及元信息  

          通用 JSON 格式(广泛应用于各种应用程序)不仅会导出结果数据,还包含列类型和查询统计信息:

          SELECT * FROM sometable FORMAT JSON
          复制
            {
            "meta":
            [
            {
            "name": "path",
            "type": "String"
            },
            ],
            "data":
            [
            {
            "path": "Bob_Dolman",
            "month": "2016-11-01",
            "hits": 245
            },
            ],
            "rows": 3,
            "statistics":
            {
            "elapsed": 0.000497457,
            "rows_read": 3,
            "bytes_read": 87
            }
            }
            复制

            JSONCompact 格式提供相同的元信息,但对数据部分采用紧凑格式:

            SELECT * FROM sometable FORMAT JSONCompact
            复制
            {
            "meta":
            [
            {
            "name": "path",
            "type": "String"
            },
            ],
            "data":
            [
            ["Bob_Dolman", "2016-11-01", 245],
            ["1-krona", "2017-01-01", 4],
            ["Ahmadabad-e_Kalij-e_Sofla", "2017-01-01", 3]
            ],
            "rows": 3,
            "statistics":
            {
            "elapsed": 0.00074981,
            "rows_read": 3,
            "bytes_read": 87
            }
            }
            复制

            如果需要将所有值导出为字符串,可以选择 JSONStrings 或 JSONCompactStrings 格式变体。

            紧凑格式导出 JSON 数据  

            导出 JSON 数据及其结构的更高效方式是使用 JSONCompactEachRowWithNamesAndTypes 格式:

            SELECT * FROM sometable FORMAT JSONCompactEachRowWithNamesAndTypes
            复制
            ["path", "month", "hits"]
            ["String", "Date", "UInt32"]
            ["Bob_Dolman", "2016-11-01", 245]
            ["1-krona", "2017-01-01", 4]
            ["Ahmadabad-e_Kalij-e_Sofla", "2017-01-01", 3]
            复制

            该格式采用紧凑的 JSON 表示,并附加两行头部信息,分别包含列名和列类型。此格式非常适合导入到其他 ClickHouse 实例或应用程序。

            将 JSON 数据导出到文件  

            可以使用 INTO OUTFILE 子句将 JSON 数据保存到文件中:

            SELECT * FROM sometable INTO OUTFILE 'out.json' FORMAT JSONEachRow
            复制
            36838935 rows in set. Elapsed: 2.220 sec. Processed 36.84 million rows, 1.27 GB (16.60 million rows/s., 572.47 MB/s.)
            复制

            ClickHouse 在 2 秒内成功导出了约 3700 万条记录至 JSON 文件。此外,还可以通过 COMPRESSION 子句启用实时压缩:

            SELECT * FROM sometable INTO OUTFILE 'out.json.gz' FORMAT JSONEachRow
            复制
            36838935 rows in set. Elapsed: 22.680 sec. Processed 36.84 million rows, 1.27 GB (1.62 million rows/s., 56.02 MB/s.)
            复制

            尽管压缩过程耗时更长,但生成的文件大小显著减小:

            2.2G out.json
            576M out.json.gz
            复制

            处理其他 JSON 格式  

            在前面的示例中,我们使用 JSONEachRow(NDJSON)格式加载 JSON 数据。以下是其他常见 JSON 格式的加载方法。

            JSON 对象数组  

            常见的一种 JSON 数据格式是数组形式的 JSON 对象列表,如以下示例:

            > cat list.json
            [
            {
            "path": "Akiba_Hebrew_Academy",
            "month": "2017-08-01",
            "hits": 241
            },
            {
            "path": "Aegithina_tiphia",
            "month": "2018-02-01",
            "hits": 34
            },
            ...
            ]
            复制

            可以为此类数据定义一个表:

            CREATE TABLE sometable
            (
            `path` String,
            `month` Date,
            `hits` UInt32
            )
            ENGINE = MergeTree
            ORDER BY tuple(month, path)
            复制

            导入 JSON 对象列表时,可以使用 JSONEachRow 格式(从本地文件 list.json 加载数据):

            INSERT INTO sometable
            FROM INFILE 'list.json'
            FORMAT JSONEachRow
            复制

            使用 FROM INFILE 子句从本地文件加载数据,导入成功:

            SELECT *
            FROM sometable
            复制
            ┌─path──────────────────────┬──────month─┬─hits─┐
            1971-72_Utah_Stars_season 2016-10-01 1
            Akiba_Hebrew_Academy 2017-08-01 241
            Aegithina_tiphia 2018-02-01 34
            └───────────────────────────┴────────────┴──────┘
            复制

            处理 NDJSON(行分隔 JSON)  

            许多应用会将日志记录为 JSON 格式,每行表示一个独立的 JSON 对象,如以下文件所示:

            cat object-per-line.json
            复制
            {"path":"1-krona","month":"2017-01-01","hits":4}
            {"path":"Ahmadabad-e_Kalij-e_Sofla","month":"2017-01-01","hits":3}
            {"path":"Bob_Dolman","month":"2016-11-01","hits":245}
            复制

            JSONEachRow 格式也适用于此类文件:

            INSERT INTO sometable FROM INFILE 'object-per-line.json' FORMAT JSONEachRow;
            SELECT * FROM sometable;
            复制
            ┌─path──────────────────────┬──────month─┬─hits─┐
            Bob_Dolman 2016-11-01 245
            1-krona 2017-01-01 4
            Ahmadabad-e_Kalij-e_Sofla 2017-01-01 3
            └───────────────────────────┴────────────┴──────┘
            复制

            JSON 对象键  

            在某些场景下,JSON 对象列表可能以对象属性的形式编码,而非数组元素(例如 objects.json 文件):

            cat objects.json
            复制
            {
            "a": {
            "path":"April_25,_2017",
            "month":"2018-01-01",
            "hits":2
            },
            "b": {
            "path":"Akahori_Station",
            "month":"2016-06-01",
            "hits":11
            },
            ...
            }
            复制

            ClickHouse 支持使用 JSONObjectEachRow 格式加载此类数据:

            INSERT INTO sometable FROM INFILE 'objects.json' FORMAT JSONObjectEachRow;
            SELECT * FROM sometable;
            复制
            ┌─path────────────┬──────month─┬─hits─┐
            Abducens_palsy 2016-05-01 28
            Akahori_Station 2016-06-01 11
            April_25,_2017 2018-01-01 2
            └─────────────────┴────────────┴──────┘
            复制

            指定父对象键值  

            如果需要将父对象的键值保存到表中,可以使用以下选项定义目标列名:

            SET format_json_object_each_row_column_for_object_name = 'id'
            复制

            随后,可以通过 file() 函数检查从原始 JSON 文件加载的数据:

            SELECT * FROM file('objects.json', JSONObjectEachRow)
            复制
            ┌─id─┬─path────────────┬──────month─┬─hits─┐
            a April_25,_2017 2018-01-01 2
            b Akahori_Station 2016-06-01 11
            c Abducens_palsy 2016-05-01 28
            └────┴─────────────────┴────────────┴──────┘
            复制

            可以看到,id 列已成功填充对应的键值。

            JSON 数组  

            为了节省空间,JSON 文件有时会以数组而非对象的形式编码。在这种情况下,处理的是 JSON 数组列表:

            cat arrays.json
            复制
            ["Akiba_Hebrew_Academy", "2017-08-01", 241],
            ["Aegithina_tiphia", "2018-02-01", 34],
            ["1971-72_Utah_Stars_season", "2016-10-01", 1]
            复制

            ClickHouse 会按数组值的顺序映射到列,使用 JSONCompactEachRow 格式加载此类数据:

            SELECT * FROM sometable
            复制
            ┌─c1────────────────────────┬─────────c2─┬──c3─┐
            Akiba_Hebrew_Academy 2017-08-01 241
            Aegithina_tiphia 2018-02-01 34
            1971-72_Utah_Stars_season 2016-10-01 1
            └───────────────────────────┴────────────┴─────┘
            复制

            从 JSON 数组中导入单独的列  

            在某些情况下,数据按列而非按行编码,此时父 JSON 对象包含列及其值。以下是一个示例文件:

            cat columns.json
            复制
            {
            "path": ["2007_Copa_America", "Car_dealerships_in_the_USA", "Dihydromyricetin_reductase"],
            "month": ["2016-07-01", "2015-07-01", "2015-07-01"],
            "hits": [178, 11, 1]
            }
            复制

            ClickHouse 使用 JSONColumns 格式解析此类数据:

            SELECT * FROM file('columns.json', JSONColumns)
            复制
            ┌─path───────────────────────┬──────month─┬─hits─┐
            2007_Copa_America 2016-07-01 178
            Car_dealerships_in_the_USA 2015-07-01 11
            Dihydromyricetin_reductase 2015-07-01 1
            └────────────────────────────┴────────────┴──────┘
            复制

            对于列数组而非对象的场景,还可以使用更紧凑的 JSONCompactColumns 格式:

            SELECT * FROM file('columns-array.json', JSONCompactColumns)
            复制
            ┌─c1──────────────┬─────────c2─┬─c3─┐
            Heidenrod 2017-01-01 10
            Arthur_Henrique 2016-11-01 12
            Alan_Ebnother 2015-11-01 66
            └─────────────────┴────────────┴────┘
            复制

            将 JSON 对象保存为字符串而不解析  

            在处理结构不同的 JSON 列表时,您可能希望将 JSON 对象以字符串形式保存,而不对其进行解析。例如,以下是一个包含多个不同结构 JSON 对象的父列表:

            cat custom.json
            复制
            [
            {"name": "Joe", "age": 99, "type": "person"},
            {"url": "/my.post.MD", "hits": 1263, "type": "post"},
            {"message": "Warning on disk usage", "type": "log"}
            ]
            复制

            可以将原始 JSON 对象存储到以下表结构中:

            CREATE TABLE events
            (
            `data` String
            )
            ENGINE = MergeTree
            ORDER BY ()
            复制

            通过使用 JSONAsString 格式,可以将文件中的数据加载到表中,并保留 JSON 对象的原始格式而不进行解析:

            INSERT INTO events (data)
            FROM INFILE 'custom.json'
            FORMAT JSONAsString
            复制

            同时,可以使用 JSON 函数查询已保存的对象:

            SELECT
            JSONExtractString(data, 'type') AS type,
            data
            FROM events
            复制
            ┌─type───┬─data─────────────────────────────────────────────────┐
            │ person │ {"name": "Joe", "age": 99, "type": "person"} │
            │ post │ {"url": "/my.post.MD", "hits": 1263, "type": "post"} │
            log │ {"message": "Warning on disk usage", "type": "log"} │
            └────────┴──────────────────────────────────────────────────────┘
            复制

            需要注意,JSONAsString 格式同样适用于每行包含一个 JSON 对象的文件(通常使用 JSONEachRow 格式)。

            嵌套对象的架构  

            处理嵌套 JSON 对象时,可定义复杂类型的架构(如 Array、Object 数据类型或 Tuple)以加载数据:

            SELECT *
            FROM file('list-nested.json', JSONEachRow, 'page Tuple(path String, title String, owner_id UInt16), month Date, hits UInt32')
            LIMIT 1
            复制
            ┌─page───────────────────────────────────────────────┬──────month─┬─hits─┐
            │ ('Akiba_Hebrew_Academy','Akiba Hebrew Academy',12) │ 2017-08-01241
            └────────────────────────────────────────────────────┴────────────┴──────┘
            复制

            访问嵌套 JSON 对象  

            我们可以通过启用以下设置选项来引用嵌套的 JSON 键:

            SET input_format_import_nested_json = 1
            复制

            这使得我们可以使用点表示法来引用嵌套的 JSON 键(需使用反引号括起来):

            SELECT *
            FROM file('list-nested.json', JSONEachRow, '`page.owner_id` UInt32, `page.title` String, month Date, hits UInt32')
            LIMIT 1
            复制
            ┌─page.owner_id─┬─page.title───────────┬──────month─┬─hits─┐
            12 Akiba Hebrew Academy 2017-08-01 241
            └───────────────┴──────────────────────┴────────────┴──────┘
            复制

            这种方式允许将嵌套的 JSON 对象展平,或提取部分嵌套值作为单独的列保存。

            跳过未知列的行为  

            默认情况下,ClickHouse 在导入 JSON 数据时会跳过未知列。例如,尝试将一个缺少 month 列的表导入原始文件:

            CREATE TABLE shorttable
            (
            `path` String,
            `hits` UInt32
            )
            ENGINE = MergeTree
            ORDER BY path
            复制

            即使原始 JSON 数据包含 3 列,仍可成功插入表中:

            INSERT INTO shorttable FROM INFILE 'list.json' FORMAT JSONEachRow;
            SELECT * FROM shorttable
            复制
            ┌─path──────────────────────┬─hits─┐
            1971-72_Utah_Stars_season │ 1
            │ Aegithina_tiphia │ 34
            │ Akiba_Hebrew_Academy │ 241
            └───────────────────────────┴──────┘
            复制

            导入过程中,未知列会被自动忽略。若希望禁用该行为,可以设置 input_format_skip_unknown_fields 选项:

            SET input_format_skip_unknown_fields = 0;
            INSERT INTO shorttable FROM INFILE 'list.json' FORMAT JSONEachRow;
            复制
            Ok.
            Exception on client:
            Code: 117. DB::Exception: Unknown field found while parsing JSONEachRow format: month: (in file/uri /data/clickhouse/user_files/list.json): (at row 1)
            复制

            当 JSON 数据与表列结构不匹配时,ClickHouse 将抛出异常。

            BSON 文件的导入与导出  

            ClickHouse 支持 BSON 文件的数据导入与导出,这是一种被 MongoDB 等数据库管理系统广泛使用的格式。

            要导入 BSON 数据,可使用 BSONEachRow 格式。以下示例展示了从 BSON 文件导入数据的过程:

            SELECT * FROM file('data.bson', BSONEachRow)
            复制
            ┌─path──────────────────────┬─month─┬─hits─┐
            │ Bob_Dolman │ 17106245
            1-krona │ 171674
            │ Ahmadabad-e_Kalij-e_Sofla │ 171673
            └───────────────────────────┴───────┴──────┘
            复制

            同样,可以使用相同的格式将数据导出为 BSON 文件:

            SELECT *
            FROM sometable
            INTO OUTFILE 'out.bson'
            FORMAT BSONEachRow
            复制

            数据导出成功后,将存储于 out.bson 文件中。

            ClickHouse 中的其他 JSON 建模方法  

            以下是 ClickHouse 中建模 JSON 的一些替代方案。这些方法主要是为了完整性记录,但通常不推荐使用,且不适用于大多数场景。

            使用 Nested  

            Nested 类型适用于建模静态且变化较少的对象,是 Tuple 和 Array(Tuple) 的替代方案。尽管如此,我们通常不建议在 JSON 数据中使用 Nested 类型,因为它的行为可能令人困惑。但 Nested 的一个显著优势是其子列可以用作排序键。

            以下示例展示了使用 Nested 类型建模静态对象的方式。以下是一个简单的 JSON 日志条目:

            {
            "timestamp": 897819077,
            "clientip": "45.212.12.0",
            "request": {
            "method": "GET",
            "path": "/french/images/hm_nav_bar.gif",
            "version": "HTTP/1.0"
            },
            "status": 200,
            "size": 3305
            }
            复制

            flatten_nested 设置  

            flatten_nested 控制 Nested 的行为,有两种主要模式:

            flatten_nested=1  

            当设置为 1(默认值)时,不支持任意级别的嵌套。此时,可将嵌套数据视为多个长度相同的 Array 列。字段 method、path 和 version 会作为独立的 Array 列,但其长度必须相同:

            SHOW CREATE TABLE http
            CREATE TABLE http
            (
            `timestamp` Int32,
            `clientip` IPv4,
            `request.method` Array(LowCardinality(String)),
            `request.path` Array(String),
            `request.version` Array(LowCardinality(String)),
            `status` UInt16,
            `size` UInt32
            )
            ENGINE = MergeTree
            ORDER BY (status, timestamp)
            复制

            我们可以向表中插入数据,

            SET input_format_import_nested_json = 1;
            INSERT INTO http
            FORMAT JSONEachRow
            {"timestamp":897819077,"clientip":"45.212.12.0","request":[{"method":"GET","path":"/french/images/hm_nav_bar.gif","version":"HTTP/1.0"}],"status":200,"size":3305}
            复制

            这里有几个需要注意的点:

            1. 启用 input_format_import_nested_json 设置,才能以嵌套结构插入 JSON。未启用时,需展平 JSON:  

            INSERT INTO http FORMAT JSONEachRow
            {"timestamp":897819077,"clientip":"45.212.12.0","request":{"method":["GET"],"path":["/french/images/hm_nav_bar.gif"],"version":["HTTP/1.0"]},"status":200,"size":3305}
            复制

            2. 嵌套字段 method、path 和 version 必须以 JSON 数组的形式传递:  

            {
            "@timestamp": 897819077,
            "clientip": "45.212.12.0",
            "request": {
            "method": [
            "GET"
            ],
            "path": [
            "/french/images/hm_nav_bar.gif"
            ],
            "version": [
            "HTTP/1.0"
            ]
            },
            "status": 200,
            "size": 3305
            }
            复制

            3. 可以使用点符号访问嵌套列:

            SELECT clientip, status, size, `request.method` FROM http WHERE has(request.method, 'GET');
            ┌─clientip────┬─status─┬─size─┬─request.method─┐
            45.212.12.02003305 │ ['GET'] │
            └─────────────┴────────┴──────┴────────────────┘
            1 row in set. Elapsed: 0.002 sec.
            复制

            由于子列为 Array 类型,可以使用完整的 Array 函数集,包括 ARRAY JOIN 子句——当列包含多个值时,这非常实用。

            flatten_nested=0  

            当设置为 0 时,允许任意嵌套级别。嵌套列被视为元组数组,与 Array(Tuple) 等效:

            这是推荐的 Nested 使用方式,只需将嵌套对象表示为列表即可:

            注意以下几点:

            CREATE TABLE http
            (
            `timestamp` Int32,
            `clientip` IPv4,
            `request` Nested(method LowCardinality(String), path String, version LowCardinality(String)),
            `status` UInt16,
            `size` UInt32
            )
            ENGINE = MergeTree
            ORDER BY (status, timestamp)
            SHOW CREATE TABLE http
            -- note Nested type is preserved.
            CREATE TABLE default.http
            (
            `timestamp` Int32,
            `clientip` IPv4,
            `request` Nested(method LowCardinality(String), path String, version LowCardinality(String)),
            `status` UInt16,
            `size` UInt32
            )
            ENGINE = MergeTree
            ORDER BY (status, timestamp)
            INSERT INTO http
            FORMAT JSONEachRow
            {"timestamp":897819077,"clientip":"45.212.12.0","request":[{"method":"GET","path":"/french/images/hm_nav_bar.gif","version":"HTTP/1.0"}],"status":200,"size":3305}
            复制

            1. 无需启用 input_format_import_nested_json 设置。  

            2. Nested 类型在 SHOW CREATE TABLE 中显示为 Array(Tuple)。  

            3. 插入时需要将嵌套对象作为数组处理:  

            {
            "timestamp": 897819077,
            "clientip": "45.212.12.0",
            "request": [
            {
            "method": "GET",
            "path": "/french/images/hm_nav_bar.gif",
            "version": "HTTP/1.0"
            }
            ],
            "status": 200,
            "size": 3305
            }
            复制

            列同样可以通过点符号再次访问:

            SELECT clientip, status, size, `request.method` FROM http WHERE has(request.method, 'GET');
            ┌─clientip────┬─status─┬─size─┬─request.method─┐
            45.212.12.02003305 │ ['GET'] │
            └─────────────┴────────┴──────┴────────────────┘
            1 row in set. Elapsed: 0.002 sec.
            复制

            示例 

            上述数据的更大示例可以在 s3 的公共存储桶中获取,路径为:s3://datasets-documentation/http/。

            SELECT *
            FROM s3('https://datasets-documentation.s3.eu-west-3.amazonaws.com/http/documents-01.ndjson.gz', 'JSONEachRow')
            LIMIT 1
            FORMAT PrettyJSONEachRow
            {
            "@timestamp": "893964617",
            "clientip": "40.135.0.0",
            "request": {
            "method": "GET",
            "path": "\/images\/hm_bg.jpg",
            "version": "HTTP\/1.0"
            },
            "status": "200",
            "size": "24736"
            }
            1 row in set. Elapsed: 0.312 sec.
            复制

            基于 JSON 的限制和输入格式,我们通过以下查询插入此示例数据集,并将 flatten_nested 设置为 0:

            以下语句将插入 1000 万行数据,可能需要几分钟执行。如有必要,可以通过 LIMIT 限制行数:

            INSERT INTO http
            SELECT `@timestamp` AS `timestamp`, clientip, [request], status,
            size FROM s3('https://datasets-documentation.s3.eu-west-3.amazonaws.com/http/documents-01.ndjson.gz',
            'JSONEachRow');
            复制

            查询这些数据时,需要以数组的形式访问 request 字段。以下是我们对固定时间段内的错误和 HTTP 方法的汇总结果:  

            SELECT status, request.method[1] as method, count() as c
            FROM http
            WHERE status >= 400
            AND toDateTime(timestamp) BETWEEN '1998-01-01 00:00:00' AND '1998-06-01 00:00:00'
            GROUP by method, status
            ORDER BY c DESC LIMIT 5;
            ┌─status─┬─method─┬─────c─┐
            404GET11267
            404 │ HEAD │ 276
            500GET160
            500 │ POST │ 115
            400GET81
            └────────┴────────┴───────┘
            5 rows in set. Elapsed: 0.007 sec.
            复制

            使用成对数组(Pairwise Arrays)  

            成对数组是一种在 JSON 灵活性与性能之间的折中方法。其优点是可以在根级别动态添加新字段,但其查询语法较为复杂,且不支持嵌套结构。

            以下为一个成对数组表的示例:

            CREATE TABLE http_with_arrays (
            keys Array(String),
            values Array(String)
            )
            ENGINE = MergeTree ORDER BY tuple();
            复制

            要插入数据,需要将 JSON 构造为键值对列表,并使用 JSONExtractKeysAndValues 函数完成:

            SELECT
            arrayMap(x -> (x.1), JSONExtractKeysAndValues(json, 'String')) AS keys,
            arrayMap(x -> (x.2), JSONExtractKeysAndValues(json, 'String')) AS values
            FROM s3('https://datasets-documentation.s3.eu-west-3.amazonaws.com/http/documents-01.ndjson.gz', 'JSONAsString')
            LIMIT 1
            FORMAT Vertical
            Row 1:
            ──────
            keys: ['@timestamp','clientip','request','status','size']
            values: ['893964617','40.135.0.0','{"method":"GET","path":"/images/hm_bg.jpg","version":"HTTP/1.0"}','200','24736']
            1 row in set. Elapsed: 0.416 sec.
            复制

            请注意,request 列依然是一个嵌套结构,存储为字符串。我们可以向根级别添加新的键值,同时 JSON 本身也允许插入任意差异。要将数据插入本地表,请执行以下操作:

            INSERT INTO http_with_arrays
            SELECT
            arrayMap(x -> (x.1), JSONExtractKeysAndValues(json, 'String')) AS keys,
            arrayMap(x -> (x.2), JSONExtractKeysAndValues(json, 'String')) AS values
            FROM s3('https://datasets-documentation.s3.eu-west-3.amazonaws.com/http/documents-01.ndjson.gz', 'JSONAsString')
            0 rows in set. Elapsed: 12.121 sec. Processed 10.00 million rows, 107.30 MB (825.01 thousand rows/s., 8.85 MB/s.)
            复制

            查询此结构需要结合 indexOf 函数,通过键名获取值数组对应的索引。例如:values[indexOf(keys, 'status')]。对于嵌套 JSON,例如 request 列,可结合 simpleJSONExtractString 提取值。

            SELECT toUInt16(values[indexOf(keys, 'status')]) as status,
            simpleJSONExtractString(values[indexOf(keys, 'request')], 'method') as method,
            count() as c
            FROM http_with_arrays
            WHERE status >= 400
            AND toDateTime(values[indexOf(keys, '@timestamp')]) BETWEEN '1998-01-01 00:00:00' AND '1998-06-01 00:00:00'
            GROUP by method, status ORDER BY c DESC LIMIT 5;
            ┌─status─┬─method─┬─────c─┐
            404GET11267
            404 │ HEAD │ 276
            500GET160
            500 │ POST │ 115
            400GET81
            └────────┴────────┴───────┘
            5 rows in set. Elapsed: 0.383 sec. Processed 8.22 million rows, 1.97 GB (21.45 million rows/s., 5.15 GB/s.)
            Peak memory usage: 51.35 MiB.
            复制

             

             征稿启示

            面向社区长期正文,文章内容包括但不限于关于 ClickHouse 的技术研究、项目实践和创新做法等。建议行文风格干货输出&图文并茂。质量合格的文章将会发布在本公众号,优秀者也有机会推荐到 ClickHouse 官网。请将文章稿件的 WORD 版本发邮件至:Tracy.Wang@clickhouse.com

            转载请注明出处或者链接地址:https://www.qianduange.cn//article/23653.html
            标签
            clickhouse
            评论
            会员中心 联系我 留言建议 回顶部
            浏览器升级提示:您的浏览器版本较低,建议您立即升级为知了极速浏览器,极速、安全、简约,上网速度更快!立即下载
            复制成功!