查询 protobuf 数据

本文档提供了一些示例,演示了如何读取和查询存储在 Bigtable 中的协议缓冲区 (protobuf) 数据。

在阅读本页面内容之前,请先熟悉以下内容:

示例数据

以下示例使用存储专辑和艺术家信息的 Music 表。数据存储在名为 album_details 的列族中,并具有列限定符 album。列限定符包含 protobuf 消息。

protobuf 架构是在以下 proto 文件中定义的:

  • artist.proto

    syntax = "proto3";
    
    package package_name;
    
    message Artist {
     string name = 1;
    }
    
  • album.proto

    syntax = "proto3";
    
    package package_name;
    
    import "artist.proto";
    
    message Album {
     string title = 1;
     Artist artist = 2;
     int32 release_year = 3;
    }
    

因此,Bigtable 会为此表创建一个架构软件包,其中包含以下针对这些 protobuf 定义的描述符集:

file {
  name: "artist.proto"
  package: "package_name"
  message_type {
    name: "Artist"
    field {
      name: "name"
      number: 1
      label: LABEL_OPTIONAL
      type: TYPE_STRING
      json_name: "name"
    }
  }
  syntax: "proto3"
}
file {
  name: "album.proto"
  package: "package_name"
  dependency: "artist.proto"
  message_type {
    name: "Album"
    field {
      name: "title"
      number: 1
      label: LABEL_OPTIONAL
      type: TYPE_STRING
      json_name: "title"
    }
    field {
      name: "artist"
      number: 2
      label: LABEL_OPTIONAL
      type: TYPE_MESSAGE
      type_name: ".package_name.Artist"
      json_name: "artist"
    }
    field {
      name: "release_year"
      number: 3
      label: LABEL_OPTIONAL
      type: TYPE_INT32
      json_name: "releaseYear"
    }
  }
  syntax: "proto3"
}

示例查询

以下示例展示了如何使用 GoogleSQL 查询 Bigtable 和 BigQuery 外部表的 protobuf 数据。

将列转换为 protobuf 消息

您可以使用 CAST 运算符将 BYTES 值解释为 protobuf 消息。为此,您必须按照以下格式提供 protobuf 消息的完整名称:SCHEMA_BUNDLE_ID.FULLY_QUALIFIED_MESSAGE_NAME

替换以下内容:

  • SCHEMA_BUNDLE_ID:您在创建架构包时为其分配的唯一 ID。
  • FULLY_QUALIFIED_MESSAGE_NAME:消息的完整名称,必须包含在 proto 文件中定义的软件包名称,例如 package_name.message_name

以下示例查询将 album 列转换为 Album protobuf 消息。此消息在 package_name 软件包中定义,并且是名为 bundle_name 的架构软件包的一部分:

SELECT
  CAST(album_details['album'] AS bundle_name.package_name.Album).title
FROM
  Music;

访问嵌套字段

您可以使用点表示法访问 protobuf 消息中的嵌套字段。

以下查询从 Album 消息中的嵌套 Artist 消息检索艺术家的姓名:

SELECT
  CAST(album_details['album'] AS bundle_name.package_name.Album).artist.name
FROM
  Music;

根据 protobuf 字段进行过滤

您可以使用 WHERE 子句根据 protobuf 消息中字段的值过滤行。

以下查询会选择音乐人 Dana A. 的所有专辑:

SELECT
  *
FROM
  Music
WHERE
  CAST(album_details['album'] AS bundle_name.package_name.Album).artist.name = 'Dana A.';

汇总 protobuf 字段

您可以在 protobuf 消息中使用 SUMAVGMINMAXCOUNT 等聚合函数来处理数字字段。

以下查询会计算表中所有专辑的平均发行年份:

SELECT
  AVG(CAST(album_details['album'] AS bundle_name.package_name.Album).release_year)
FROM
  Music;

按 protobuf 字段排序

您可以使用 ORDER BY 子句根据 protobuf 消息中的字段对结果集进行排序。

以下查询会检索所有专辑,并按发行年份以降序对其进行排序:

SELECT
  *
FROM
  Music
ORDER BY
  CAST(album_details['album'] AS bundle_name.package_name.Album).release_year DESC;

与 BigQuery 外部表搭配使用

您可以创建外部表,以便从 BigQuery 查询存储在 Bigtable 中的 protobuf 数据。创建外部表时,您需要将列类型指定为 JSON,将其编码指定为 PROTO_BINARY,并将其与架构包相关联。此过程会将 protobuf 消息字节转换为等效的 JSON 数据,从而让您可以直接查询其字段。

以下是用于创建基于 Music 表的 BigQuery 外部表的表定义文件示例:

{
    "sourceFormat": "BIGTABLE",
    "sourceUris": [
        "https://googleapis.com/bigtable/projects/PROJECT_ID/instances/INSTANCE_ID/tables/Music"
    ],
    "bigtableOptions": {
        "columnFamilies" : [
            {
                "familyId": "album_details",
                "columns": [
                    {
                        "qualifierString": "album",
                        "type": "JSON",
                        "encoding": "PROTO_BINARY",
                        "protoConfig": {
                            "schemaBundleId": "bundle_name",
                            "protoMessageName": "package_name.Album"
                        }
                    }
                ]
            }
        ]
    }
}

创建外部表后,您可以在 BigQuery 中将 protobuf 数据作为 JSON 列进行查询。

以下查询从 BigQuery 外部表中检索 2022 年发行的所有专辑的标题:

SELECT JSON_VALUE(value, '$.title') AS title
FROM
`PROJECT_ID.DATASET.TABLE_NAME` AS t,
UNNEST(t.album_details.album.cell)
WHERE INT64(JSON_EXTRACT(value, '$.releaseYear')) = 2022;

后续步骤