查询 Bigtable 数据

本文档介绍了如何查询已存储在 Bigtable 外部表中的数据。

Bigtable 是 Google 推出的一种稀疏填充的 NoSQL 数据库,可以扩展到数十亿行和数千列,支持存储 PB 级的数据。如需了解 Bigtable 数据模型,请参阅存储模型

查询永久外部表

在开始之前,您或您组织中的其他人必须创建一个外部表供您使用。如需了解详情和所需的权限,请参阅创建 BigQuery 外部表

所需的角色

如需查询 Bigtable 永久外部表,请确保您具有以下角色:

  • BigQuery Data Viewer (roles/bigquery.dataViewer)
  • BigQuery User (roles/bigquery.user)
  • Bigtable Reader (roles/bigtable.reader)

根据您的权限,您可以自行授予这些角色给自己,或者让管理员授予给您。如需详细了解如何授予角色,请参阅查看可针对资源授予的角色

如需查看查询外部表所需的确切 BigQuery 权限,请展开所需权限部分:

所需权限

您也可以使用自定义角色或其他预定义角色来获取这些权限。

查询表

您可以对永久外部 Bigtable 表运行查询,就像对标准 BigQuery 表运行查询一样,但需遵守外部数据源的限制。如需了解详情,请参阅运行交互式查询和批量查询

查询临时外部表

使用临时表查询外部数据源适用于对外部数据进行一次性临时查询,或执行提取、转换和加载 (ETL) 过程。

要在不创建永久表的情况下查询外部数据源,请为临时表提供表定义,然后在命令或调用中使用该表定义来查询临时表。您可以通过以下任一方式提供表定义:

系统会使用表定义文件或提供的架构来创建临时外部表,然后对临时外部表运行查询。

使用临时外部表时,并不会在您的某个 BigQuery 数据集中创建表。由于该表不会永久存储在数据集内,因此无法与他人共享。

使用临时外部表而不是永久外部表存在一些限制,包括:

  • 您必须具有 Bigtable Admin (roles/bigtable.admin) 角色。
  • 此方法不允许您使用 Google Cloud 控制台推断 Bigtable 表的架构并自动创建表定义。您必须自行创建表定义。

所需的角色

如需查询 Bigtable 临时外部表,请确保您具有以下角色:

  • BigQuery Data Viewer (roles/bigquery.dataViewer)
  • BigQuery User (roles/bigquery.user)
  • Bigtable 管理员 (roles/bigtable.admin)

根据您的权限,您可以自行授予这些角色给自己,或者让管理员授予给您。如需详细了解如何授予角色,请参阅查看可针对资源授予的角色

如需查看查询外部表所需的确切 BigQuery 权限,请展开所需权限部分:

所需权限

您也可以使用自定义角色或其他预定义角色来获取这些权限。

创建和查询表

如需使用临时外部表查询 Bigtable 数据,您需要执行以下操作:

bq 命令行工具和 API 支持创建和查询临时外部表。

bq

如需使用表定义文件查询临时表,请输入带 --external_table_definition 标志的 bq query 命令。

(可选)提供 --location 标志并将其值设置为您的位置

bq --location=LOCATION query \
--use_legacy_sql=false \
--external_table_definition=TABLE::DEFINITION_FILE \
'QUERY'

替换以下内容:

  • LOCATION:您所在位置的名称。--location 是可选标志。
  • TABLE:您要创建的临时表的名称。
  • DEFINITION_FILE:本地机器上表定义文件的路径。
  • QUERY:您要提交到临时表的查询。

例如,以下命令使用名为 follows_def 的表定义文件创建并查询名为 follows 的临时表。

bq query \
--use_legacy_sql=false \
--external_table_definition=follows::/tmp/follows_def \
'SELECT
  COUNT(rowkey)
 FROM
   follows'

API

  • 创建查询。如需了解如何创建查询作业,请参阅查询数据

  • (可选)在作业资源jobReference 部分的 location 属性中指定您的位置。

  • 表资源设置 ExternalDataConfiguration 以指定外部数据源属性。

Java

试用此示例之前,请按照 BigQuery 快速入门:使用客户端库中的 Java 设置说明进行操作。如需了解详情,请参阅 BigQuery Java API 参考文档

如需向 BigQuery 进行身份验证,请设置应用默认凭据。 如需了解详情,请参阅为客户端库设置身份验证

import com.google.cloud.bigquery.BigQuery;
import com.google.cloud.bigquery.BigQueryException;
import com.google.cloud.bigquery.BigQueryOptions;
import com.google.cloud.bigquery.BigtableColumn;
import com.google.cloud.bigquery.BigtableColumnFamily;
import com.google.cloud.bigquery.BigtableOptions;
import com.google.cloud.bigquery.ExternalTableDefinition;
import com.google.cloud.bigquery.QueryJobConfiguration;
import com.google.cloud.bigquery.TableResult;
import com.google.common.collect.ImmutableList;
import org.apache.commons.codec.binary.Base64;

// Sample to queries an external bigtable data source using a temporary table
public class QueryExternalBigtableTemp {

  public static void main(String[] args) {
    // TODO(developer): Replace these variables before running the sample.
    String projectId = "MY_PROJECT_ID";
    String bigtableInstanceId = "MY_INSTANCE_ID";
    String bigtableTableName = "MY_BIGTABLE_NAME";
    String bigqueryTableName = "MY_TABLE_NAME";
    String sourceUri =
        String.format(
            "https://googleapis.com/bigtable/projects/%s/instances/%s/tables/%s",
            projectId, bigtableInstanceId, bigtableTableName);
    String query = String.format("SELECT * FROM %s ", bigqueryTableName);
    queryExternalBigtableTemp(bigqueryTableName, sourceUri, query);
  }

  public static void queryExternalBigtableTemp(String tableName, String sourceUri, String query) {
    try {
      // Initialize client that will be used to send requests. This client only needs to be created
      // once, and can be reused for multiple requests.
      BigQuery bigquery = BigQueryOptions.getDefaultInstance().getService();

      BigtableColumnFamily.Builder statsSummary = BigtableColumnFamily.newBuilder();

      // Configuring Columns
      BigtableColumn connectedCell =
          BigtableColumn.newBuilder()
              .setQualifierEncoded(Base64.encodeBase64String("connected_cell".getBytes()))
              .setFieldName("connected_cell")
              .setType("STRING")
              .setEncoding("TEXT")
              .build();
      BigtableColumn connectedWifi =
          BigtableColumn.newBuilder()
              .setQualifierEncoded(Base64.encodeBase64String("connected_wifi".getBytes()))
              .setFieldName("connected_wifi")
              .setType("STRING")
              .setEncoding("TEXT")
              .build();
      BigtableColumn osBuild =
          BigtableColumn.newBuilder()
              .setQualifierEncoded(Base64.encodeBase64String("os_build".getBytes()))
              .setFieldName("os_build")
              .setType("STRING")
              .setEncoding("TEXT")
              .build();

      // Configuring column family and columns
      statsSummary
          .setColumns(ImmutableList.of(connectedCell, connectedWifi, osBuild))
          .setFamilyID("stats_summary")
          .setOnlyReadLatest(true)
          .setEncoding("TEXT")
          .setType("STRING")
          .build();

      // Configuring BigtableOptions is optional.
      BigtableOptions options =
          BigtableOptions.newBuilder()
              .setIgnoreUnspecifiedColumnFamilies(true)
              .setReadRowkeyAsString(true)
              .setColumnFamilies(ImmutableList.of(statsSummary.build()))
              .build();

      // Configure the external data source and query job.
      ExternalTableDefinition externalTable =
          ExternalTableDefinition.newBuilder(sourceUri, options).build();
      QueryJobConfiguration queryConfig =
          QueryJobConfiguration.newBuilder(query)
              .addTableDefinition(tableName, externalTable)
              .build();

      // Example query
      TableResult results = bigquery.query(queryConfig);

      results
          .iterateAll()
          .forEach(row -> row.forEach(val -> System.out.printf("%s,", val.toString())));

      System.out.println("Query on external temporary table performed successfully.");
    } catch (BigQueryException | InterruptedException e) {
      System.out.println("Query not performed \n" + e.toString());
    }
  }
}

性能考虑因素

针对 Bigtable 外部数据源进行的查询的性能取决于三个因素:

  • 行数
  • 读取的数据量
  • 并行化程度

BigQuery 会尝试仅读取查询中引用的列族,从而尽可能减少读取数据量。并行化程度取决于您在 Bigtable 集群中拥有的节点数量以及您在自己的表中的拆分次数。

请注意,Bigtable 会根据负载自动合并拆分。如果读取该表的频率较低,则随着时间的推移,拆分次数会减少,查询性能会逐渐降低。如需详细了解如何按行键拆分表,请参阅管理表

通过 BigQuery 查询 Bigtable 表时会消耗 Bigtable 的 CPU 周期。BigQuery 的 CPU 消耗可能会影响其他并发请求(例如实时用户流量传送)的延迟时间和吞吐量。例如,Bigtable 上的高 CPU 使用率会影响长尾查询,并增加第 99 百分位的延迟时间。

您应该监控 Bigtable 的 CPU 使用率,以验证此数据是否处于 Google Cloud 控制台内 Bigtable 监控信息中心所注明的推荐范围内。通过增加实例的节点数量,您将能够处理 BigQuery 流量以及来自其他并发请求的流量。

查询过滤器

采用行相等性过滤器的查询仅读取该特定行。例如,在 GoogleSQL 语法中:

SELECT
  COUNT(follows.column.name)
FROM
  `dataset.table`
WHERE
  rowkey = "alice";

系统也支持 rowkey > '1'rowkey < '8' 等范围过滤器,但只有在使用 readRowkeyAsString 选项以字符串形式读取 rowkey 时才能提供此支持。