FROM_PROTOBUF
功能概述
把 Protobuf 编码的二进制数据解析为 STRUCT,消息中的每个字段对应 STRUCT 的一个字段,嵌套消息、repeated 字段、map 字段分别转为嵌套 STRUCT、ARRAY、MAP。解析后可以像普通列一样按字段过滤、聚合,配合
LATERAL VIEW EXPLODE
LATERAL VIEW EXPLODE
展开 repeated 字段。
只需把消息整体转成 JSON 文本查看或转存时,用 PROTOBUF_TO_JSON。描述符的生成方法见 Protobuf 函数。
语法
FROM_PROTOBUF(<data>, <message_name>, <descriptor> [, <options>])
参数说明
| 选项 | 默认值 | 说明 |
|---|
mode
mode | PERMISSIVE
PERMISSIVE | PERMISSIVE
PERMISSIVE :数据损坏时该行返回 NULL;FAILFAST
FAILFAST :数据损坏时查询报错 failed to parse protobuf message
failed to parse protobuf message |
emit.default.values
emit.default.values | false
false | true
true 时未设置的字段返回 proto3 默认值(0、空串等),而不是 NULL |
unwrap.well.known.types
unwrap.well.known.types | false
false | true
true 时把 google.protobuf.Int32Value
google.protobuf.Int32Value 等包装类型展开为对应的标量 |
max.descriptor.bytes
max.descriptor.bytes | 1048576
1048576 | 描述符大小上限(字节) |
类型映射:
| Protobuf 类型 | Lakehouse 类型 |
|---|
| int32、sint32、sfixed32、uint32、fixed32 | INT |
| int64、sint64、sfixed64、uint64、fixed64 | BIGINT |
| float / double | FLOAT / DOUBLE |
| bool / string / bytes | BOOLEAN / STRING / BINARY |
| enum | STRING(枚举名) |
| 嵌套 message / repeated / map | STRUCT / ARRAY / MAP |
google.protobuf.Timestamp
google.protobuf.Timestamp | TIMESTAMP |
google.protobuf.Duration
google.protobuf.Duration | INTERVAL DAY TO SECOND |
⚠️ 注意:uint32、uint64 映射为有符号类型,超过 INT、BIGINT 上限的值会溢出为负数。递归引用自身的消息字段会被忽略,不出现在结果 STRUCT 中。
使用示例
以下示例使用这个 proto 定义编译出的描述符:
syntax = "proto3";
package test;
message SimpleMsg {
int32 id = 1;
string name = 2;
double score = 3;
bool active = 4;
int64 ts = 5;
float ratio = 6;
bytes data = 7;
}
解析一条消息:
SELECT from_protobuf(
x'082a120568656c6c6f191f85eb51b81e094020012880d095ffbc3135000020403a03010203',
'test.SimpleMsg',
x'0a89010a0a746573742e70726f746f120474657374226d0a0953696d706c654d7367120a0a026964180120012805120c0a046e616d65180220012809120d0a0573636f7265180320012801120e0a06616374697665180420012808120a0a027473180520012803120d0a05726174696f180620012802120c0a046461746118072001280c620670726f746f33'
) AS msg;
{"id":42,"name":"hello","score":3.14,"active":true,"ts":1700000000000,"ratio":2.5,"data":[01 02 03]}
取出单个字段:
SELECT msg.id, msg.name, msg.score
FROM (
SELECT from_protobuf(
x'082a120568656c6c6f191f85eb51b81e094020012880d095ffbc3135000020403a03010203',
'test.SimpleMsg',
x'0a89010a0a746573742e70726f746f120474657374226d0a0953696d706c654d7367120a0a026964180120012805120c0a046e616d65180220012809120d0a0573636f7265180320012801120e0a06616374697665180420012808120a0a027473180520012803120d0a05726174696f180620012802120c0a046461746118072001280c620670726f746f33'
) AS msg
);
💡 提示:只引用部分字段时,系统只为这些字段构建解码器,未引用的字段直接跳过,解析大消息时更快。
损坏的数据:默认
PERMISSIVE
PERMISSIVE
模式返回 NULL,
FAILFAST
FAILFAST
模式报错:
SELECT from_protobuf(
x'12646162',
'test.SimpleMsg',
x'0a89010a0a746573742e70726f746f120474657374226d0a0953696d706c654d7367120a0a026964180120012805120c0a046e616d65180220012809120d0a0573636f7265180320012801120e0a06616374697665180420012808120a0a027473180520012803120d0a05726174696f180620012802120c0a046461746118072001280c620670726f746f33',
map('mode', 'PERMISSIVE')
) AS msg;
NULL
x'12646162'
x'12646162'
声明了长度为 100 的 string 字段,实际只有 2 个字节,属于截断数据。
注意事项
- 消息类型名和描述符必须是常量。
- 默认
PERMISSIVE
PERMISSIVE
模式下,损坏的数据返回 NULL,不会中断查询。需要严格校验时用 map('mode', 'FAILFAST')
map('mode', 'FAILFAST')
。
- proto3 中未设置的字段默认返回 NULL,需要默认值时设置
emit.default.values
emit.default.values
。
相关文档