ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

StarRocks VARIANT 类型实战指南:在 Iceberg 与 Paimon 数据湖上查询半结构化数据

StarRocks VARIANT 类型实战指南:在 Iceberg 与 Paimon 数据湖上查询半结构化数据 StarRocks VARIANT 类型实战指南在 Iceberg 与 Paimon 数据湖上查询半结构化数据【免费下载链接】starrocksThe worlds fastest open query engine for sub-second analytics both on and off the data lakehouse. With the flexibility to support nearly any scenario, StarRocks provides best-in-class performance for multi-dimensional analytics, real-time analytics, and ad-hoc queries. A Linux Foundation project.项目地址: https://gitcode.com/GitHub_Trending/st/starrocksVARIANT 是 StarRocks 提供的半结构化数据类型能够以二进制格式存储整数、浮点数、字符串、布尔值、日期时间等标量类型以及结构体、映射、数组等复杂类型。本文基于 StarRocks v4.1/v4.2 的能力系统讲解 VARIANT 的查询、取值、类型互转与路径表达式语法并结合 BE 端源码be/src/exprs/variant_functions.cpp、be/src/column/variant_path_parser.cpp等揭示其底层实现原理帮助读者在数据湖分析场景中灵活驾驭形态多变、schema 频繁演进的半结构化数据。:::important VARIANT 类型仅支持 Iceberg Catalog 与 Paimon Catalog 中的表StarRocks 原生表不支持该类型。 :::从 v4.1 起StarRocks 支持查询 Parquet 格式 Iceberg 表中的半结构化数据VARIANT 类型从 v4.2 起进一步支持查询 Paimon 表中的 VARIANT 类型数据。本文介绍 VARIANT 的基本概念以及 StarRocks 如何查询 VARIANT 数据、如何通过 VARIANT 函数进行处理。VARIANT 是什么VARIANT 是一种半结构化数据类型可以存储不同数据类型schema-less的值包括标量类型整数integer、浮点数floating-point、字符串string、布尔值boolean、日期date、时间戳timestamp复杂类型结构体struct、映射map、数组array。VARIANT 数据以二进制格式编码以实现高效的存储与查询。它在 Apache Iceberg 表使用 Parquet 格式并采用 variant encoding 编码即 Parquet 格式规范中定义的 Variant Encoding 二进制布局场景下尤其有用配合灵活的 schema 演进能力可以高效存储异构数据。Parquet 的 variant encoding 又分为 shredded打散与 unshredded不打散两种形态本文后续会结合源码说明 StarRocks 对这两种形态的支持情况。从源码结构看StarRocks 在列存储层面以VariantColumnbe/src/column/variant_column.h承载 VARIANT 数据内部由_shredded_paths打散路径、多个按路径组织的_typed_columns类型化子列以及_remain_value_column未打散的余量值列协同存储这为路径查询的高性能批量访问提供了物理基础。使用 VARIANT 数据查询 Iceberg 表中的 VARIANT 数据StarRocks 支持查询以 Parquet 格式存储且使用 variant encoding 编码的 Iceberg 表。查询时VARIANT 列会被自动识别无需任何额外 DDL 或注册动作-- 查询包含 VARIANT 列的表 SELECT id, variant_col FROM iceberg_catalog.db.table_with_variants;在 BE 端Parquet 读取器会针对LogicalType::TYPE_VARIANT的列走专门的分支be/src/formats/parquet/column_reader_factory.cpp中在列类型为 VARIANT 时选择相应的 variant 列读取器be/src/formats/parquet/group_reader.cpp也会对 VARIANT 类型的 slot 与 schema 节点做特殊处理从而把 Parquet 中的 variant 编码列完整还原为VariantColumn。从 VARIANT 数据中提取值StarRocks 提供了一组函数用于从 VARIANT 数据中按路径提取强类型的值。这里以get_variant_int、get_variant_string、get_variant_bool、get_variant_double为典型代表get_variant函数家族详见函数文档。示例 1使用类型化 getter 函数提取标量值SELECT get_variant_int(variant_col, $) AS int_value, get_variant_string(variant_col, $) AS string_value, get_variant_bool(variant_col, $) AS bool_value, get_variant_double(variant_col, $) AS double_value FROM iceberg_catalog.db.table_with_variants;示例 2使用 JSON path 表达式导航嵌套结构SELECT get_variant_string(variant_col, $.user.name) AS user_name, get_variant_int(variant_col, $.user.age) AS user_age, get_variant_string(variant_col, $.address.city) AS city FROM iceberg_catalog.db.table_with_variants;示例 3访问数组元素下标从 0 开始SELECT get_variant_int(variant_col, $.scores[0]) AS first_score, get_variant_int(variant_col, $.scores[1]) AS second_score FROM iceberg_catalog.db.table_with_variants;示例 4查询嵌套 VARIANT 数据并保持 VARIANT 类型返回SELECT variant_query(variant_col, $.metadata) AS metadata, variant_query(variant_col, $.items[0]) AS first_item FROM iceberg_catalog.db.table_with_variants;示例 5检查 VARIANT 值的类型SELECT variant_typeof(variant_col) AS root_type, variant_typeof(variant_query(variant_col, $.data)) AS data_type FROM iceberg_catalog.db.table_with_variants;底层实现上述函数统一在be/src/exprs/variant_functions.cpp中实现。它们都接受两个参数——VARIANT 列与路径字符串列并委托给模板方法_do_variant_queryResultType()get_variant_string对应_do_variant_queryTYPE_VARCHARget_variant_int对应_do_variant_queryTYPE_BIGINT为统一所有整数类型返回值统一为 BIGINT见be/src/exprs/variant_functions.h中的注释get_variant_bool对应_do_variant_queryTYPE_BOOLEANget_variant_double对应_do_variant_queryTYPE_DOUBLE此外还有get_variant_date、get_variant_datetime、get_variant_time三个日期时间类 gettervariant_query对应_do_variant_queryTYPE_VARIANT即路径指向的元素仍以 VARIANT 返回variant_typeof独立实现逐行返回 VARIANT 值的类型名称。执行时若路径是常量const pathvariant_segments_prepare会在每个 fragment 初始化阶段调用VariantPathParser::parse一次性完成路径解析并把解析结果VariantPath缓存在FunctionContext中若路径不是常量则在每一行重新解析。对于常量路径 类型精确匹配 无后缀的常见形态代码还提供了一条列级批量快路径_build_typed_bulk_result/_build_typed_cast_result直接以 SIMD 批量复制类型化列数据、合并 null 掩码避免逐行解析开销。对应的单元测试位于be/test/exprs/variant_functions_test.cpp覆盖了从 JSON 文本构造 VARIANT、类型化 getter、嵌套路径查询等多种场景。将 JSON 转换为 VARIANTStarRocks 支持把 JSON 值 CAST 为 VARIANT。如果输入是 STRING需要先通过parse_json转为 JSONSELECT CAST(parse_json({id: 1, flags: {active: true}, scores: [1.5, null]}) AS VARIANT) AS variant_value;SELECT CAST(json_col AS VARIANT) AS variant_value FROM db.table_with_json;将 VARIANT 数据转换为 SQL 类型可以使用 CAST 函数将 VARIANT 数据转换为标准 SQL 类型SELECT CAST(variant_query(variant_col, $.count) AS INT) AS count, CAST(variant_query(variant_col, $.price) AS DECIMAL(10, 2)) AS price, CAST(variant_query(variant_col, $.active) AS BOOLEAN) AS is_active, CAST(variant_query(variant_col, $.name) AS STRING) AS name FROM iceberg_catalog.db.table_with_variants;复杂类型也可以从 VARIANT 转换SELECT CAST(variant_col AS STRUCTid INT, name STRING) AS user_struct, CAST(variant_col AS MAPSTRING, INT) AS config_map, CAST(variant_col AS ARRAYDOUBLE) AS values_array FROM iceberg_catalog.db.table_with_variants;从实现看be/src/exprs/cast_expr.cpp针对TYPE_VARIANT提供了完整的双向转换路径CASE_FROM_JSON_TO(TYPE_VARIANT, ...)、CASE_TO_JSON(TYPE_VARIANT, ...)以及 VARIANT 与普通类型间的cast_to逻辑因此JSON → VARIANT → SQL 类型可以在一条表达式链路里顺畅完成。将 SQL 类型转换为 VARIANT可以将 SQL 值 CAST 为 VARIANT。支持的输入类型包括BOOLEAN整数类型integer typesFLOAT / DOUBLEDECIMALSTRING / CHAR / VARCHARJSONDATE / DATETIME / TIME复杂类型ARRAY、MAP、STRUCT。注意MAP 在编码过程中键会被转换为字符串HLL、BITMAP、PERCENTILE、VARBINARY 等类型不支持转换。SELECT CAST(123 AS VARIANT) AS v_int, CAST(3.14 AS VARIANT) AS v_double, CAST(CAST(12.34 AS DECIMAL(10, 2)) AS VARIANT) AS v_decimal, CAST(hello AS VARIANT) AS v_string, CAST(PARSE_JSON({k:1}) AS VARIANT) AS v_json;VARIANT 函数VARIANT 函数用于查询和提取 VARIANT 列中的数据。三个核心函数如下每个函数的完整语法、参数与示例详见各自文档函数作用文档variant_query按路径表达式查询 VARIANT 值返回 VARIANT 类型variant_queryget_variant从 VARIANT 中按路径提取强类型值int、bool、double、stringget_variantvariant_typeof返回 VARIANT 值的类型名称variant_typeof函数签名速览来自 get_variant.mdBIGINT get_variant_int(variant_expr, path) DOUBLE get_variant_double(variant_expr, path) VARCHAR get_variant_string(variant_expr, path) BOOLEAN get_variant_bool(variant_expr, path)返回值语义若路径对应的元素不存在、路径无效、或值无法转换为目标类型相关函数返回 NULL。variant_query同理元素不存在或路径非法时返回 NULL见 variant_query.md。VARIANT 路径表达式VARIANT 函数使用 JSON path 表达式在数据结构中导航语法与 JSON path 类似$表示 VARIANT 值的根.用于访问对象字段[index]用于访问数组元素下标从 0 开始包含特殊字符如点号的字段名可以用引号括起来$.field.name。路径表达式示例$ -- 根元素 $.field -- 对象字段访问 $.nested.field -- 嵌套字段访问 $.field.with.dots -- 带引号的字段名 $[0] -- 第一个数组元素 $.array[1] -- 数组字段的第二个元素 $.users[0].name -- 嵌套数组访问 $.config[key] -- Map 风格访问源码级语法说明上述路径由 BE 端的VariantPathParserbe/src/column/variant_path_parser.h解析每个路径被拆分为一组VariantSegment其中kObject表示对象键key字段kArray表示数组下标index字段。解析器支持$根标记parse_root.点号键parse_object_key未加引号的键仅允许字母数字与下划线[a-zA-Z0-9_][数字]数组下标parse_array_index[key]或[key]带引号键parse_quoted_key且支持\n、\t、\r、\、\、\\等转义序列路径必须以$开头否则解析直接报错Status::InvalidArgument(Path must start with $)。从测试用例be/test/exprs/variant_functions_test.cpp可以看到$.commit、$.did、$.time_us等路径会被逐段解析后经VariantPathReader在VariantColumn上定位并读取目标值。数据类型转换从采用 variant encoding 的 Parquet 文件读取数据时支持以下类型转换Parquet Variant 类型StarRocks VARIANT 类型INT8, INT16, INT32, INT64int8, int16, int32, int64FLOAT, DOUBLEfloat, doubleBOOLEANbooleanSTRINGstringDATEDateTIMESTAMP, TIMESTAMP_NTZTimestampDECIMALDecimal, float, doubleSTRUCTObjectMAPObjectARRAYArray可以看到Parquet 侧的 STRUCT、MAP 在 StarRocks VARIANT 中统一呈现为 Object而 DECIMAL 可以按需转换为 StarRocks 的 Decimal、float 或 double这为异构数据源的数据落地提供了较大的灵活性。限制与注意事项使用 VARIANT 类型时请注意以下边界与限制VARIANT 支持从使用 variant encodingParquet 格式的 Iceberg 表读取数据也支持使用 StarRocks 文件写入器file writers写 Parquet 文件写入采用 unshredded variant encoding。VARIANT 同样支持从 Paimon 表读取数据Paimon 的 VARIANT 列要求使用 Parquet但仅限由原生读取器native reader读取的 split即仅追加表append-only tables与已合并的主键数据compacted primary-key data。未合并的主键数据uncompacted primary-key data读取需要 JNI reader目前尚不支持此类查询会在计划阶段plan-time直接报错。单个 VARIANT 值的大小上限为16 MB。目前读与写均仅支持 unshredded variant 值。VARIANT 可以由 JSON 值或受支持的 SQL 类型包括 ARRAY、MAP、STRUCTCAST 而来。嵌套结构的最大深度取决于底层 Parquet 文件的结构。需要特别留意的是即使 StarRocks 当前读写仅支持 unshredded variant其内存列结构VariantColumn仍内置了 shredded打散形态的存储与路径索引能力_shredded_paths、按路径组织的类型化子列以便在查询时对常见路径进行列级批量访问优化这一实现细节可以解释为何常量路径 精确类型匹配的查询能够走 SIMD 批量快路径。不过在实际使用中仍应以上述官方限制为准来规划写入链路。小结VARIANT 为 StarRocks 的数据湖分析场景补上了无固定 schema的一环对 IcebergParquet variant encoding与 Paimon 表你可以直接以 VARIANT 列读取半结构化数据再通过variant_query、get_variant家族与variant_typeof按 JSON path 提取强类型值或借助 CAST 在 JSON、VARIANT 与标准 SQL 类型含 ARRAY/MAP/STRUCT之间自由转换。结合 BE 端variant_functions.cpp的批量快路径与variant_path_parser的路径解析实现既保证了查询的易用性也为高频路径访问保留了列式优化的空间。上手时建议从 Iceberg Catalog 中一个带 variant 编码列的 Parquet 表开始先用variant_typeof观察根类型再用get_variant_*逐字段抽取目标值最后按需 CAST 为分析所需的 SQL 类型。【免费下载链接】starrocksThe worlds fastest open query engine for sub-second analytics both on and off the data lakehouse. With the flexibility to support nearly any scenario, StarRocks provides best-in-class performance for multi-dimensional analytics, real-time analytics, and ad-hoc queries. A Linux Foundation project.项目地址: https://gitcode.com/GitHub_Trending/st/starrocks创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表