查詢 Bigtable 外部資料表

本文說明如何使用 BigQuery 查詢儲存在 Bigtable 外部資料表中的資料。如要瞭解如何直接從 Bigtable 查詢資料,請參閱「Bigtable 適用的 GoogleSQL 總覽」。

Bigtable 是 Google 的稀疏 NoSQL 資料庫,可擴充至數十億列、數千欄和數 PB 的資料。如要瞭解 Bigtable 資料模型,請參閱「儲存空間模型」。

查詢永久外部資料表

開始之前,您或貴組織的管理員必須建立外部資料表供您使用。如需詳細資訊和必要權限,請參閱「建立 BigQuery 外部資料表」。

必要的角色

如要查詢 Bigtable 外部資料表,請確認您具備下列角色。

  • BigQuery 資料檢視者 (roles/bigquery.dataViewer)
  • BigQuery 使用者 (roles/bigquery.user)
  • Bigtable 讀取者 (roles/bigtable.reader)

視權限而定,您可以將這些角色授予自己,或要求管理員授予。如要進一步瞭解如何授予角色,請參閱「查看可針對資源授予的角色」。

如要查看查詢外部資料表所需的確切 BigQuery 權限,請展開「Required permissions」(必要權限) 部分:

所需權限

您或許還可透過自訂角色或其他預先定義的角色取得這些權限。

查詢資料表

您可以對永久外部 Bigtable 資料表執行查詢,就像對標準 BigQuery 資料表執行查詢一樣,但須遵守外部資料來源的限制。詳情請參閱「執行互動式和批次查詢」。

查詢臨時外部資料表

使用臨時資料表查詢外部資料來源,適合用於對外部資料執行一次性、臨時查詢,或用於擷取、轉換和載入 (ETL) 程序。

如要查詢外部資料來源,但不想建立永久資料表,請提供臨時資料表的資料表定義,然後在指令或呼叫中使用該資料表定義,查詢臨時資料表。您可以透過下列任一方式提供資料表定義:

系統會使用資料表定義檔案或提供的結構定義,建立臨時外部資料表,並對該資料表執行查詢。

使用臨時外部資料表時,並不會在某個 BigQuery 資料集中建立資料表。由於資料表並非永久儲存在資料集中,因此無法與他人共用。

使用臨時外部資料表而非永久外部資料表時,會有一些限制,包括:

  • 您必須具備 Bigtable 管理員 (roles/bigtable.admin) 角色。
  • 這種方法無法使用 Google Cloud 控制台推論 Bigtable 資料表的結構定義,以及自動建立資料表定義。您必須自行建立資料表定義。

必要的角色

如要查詢 Bigtable 臨時外部資料表,請確認您具備下列角色:

  • BigQuery 資料檢視者 (roles/bigquery.dataViewer)
  • BigQuery 使用者 (roles/bigquery.user)
  • Bigtable 管理員 (roles/bigtable.admin)

視權限而定,您可以將這些角色授予自己,或要求管理員授予。如要進一步瞭解如何授予角色,請參閱「查看可針對資源授予的角色」。

如要查看查詢外部資料表所需的確切 BigQuery 權限,請展開「Required permissions」(必要權限) 部分:

所需權限

您或許還可透過自訂角色或其他預先定義的角色取得這些權限。

建立及查詢資料表

如要使用臨時外部資料表查詢 Bigtable 資料,請按照下列步驟操作:

bq 指令列工具和 API 支援建立及查詢臨時外部資料表。

bq

如要使用資料表定義檔查詢臨時資料表,請輸入 bq query 指令並加上 --external_table_definition 旗標。

(選用) 提供 --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 如何隨著時間最佳化資料」。

運算

透過 BigQuery 查詢 Bigtable 資料時,您可以使用下列運算選項:

  • 叢集節點 (預設)。
  • Data Boost (預先發布版):這項無伺服器運算選項可讓您區隔數據分析流量,不會影響叢集節點處理的應用程式服務流量。

如要使用 Data Boost,您或管理員必須建立定義檔案,在 Bigtable URI 中指定 Data Boost 應用程式設定檔。詳情請參閱「建立 Bigtable 外部資料表」。

如果不使用 Data Boost,請注意,從 BigQuery 查詢 Bigtable 會耗用 Bigtable CPU 週期。使用佈建節點進行運算時,BigQuery 的 CPU 消耗量可能會影響其他並行要求 (例如即時使用者流量服務) 的延遲時間和處理量。舉例來說,Bigtable 的 CPU 使用率偏高會影響長尾查詢,並增加第 99 個百分位數的延遲時間。

因此,請務必監控 Bigtable CPU 使用率,確保用量在建議範圍內,如 Google Cloud 控制台的 Bigtable 監控資訊主頁所示。增加執行個體的節點數量,即可同時處理 BigQuery 流量和其他並行要求的流量。

查詢篩選器

查詢外部資料表時,您可以新增查詢篩選器,減少 BigQuery 資源用量。

資料列索引鍵篩選器

如果查詢含有資料列索引鍵等式篩選器,則只會讀取該特定資料列。例如,在 GoogleSQL 語法中:

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

另外也支援 rowkey > '1' 和 rowkey < '8' 等範圍篩選器,但前提是您必須使用 readRowkeyAsString 選項,把 rowkey 當做字串讀取。

依資料欄系列和限定詞篩選

您也可以選取特定資料欄系列,或資料欄系列中的特定限定詞。如要依資料欄系列篩選,請選取資料欄系列名稱,結果只會包含所選資料欄系列。在以下範例中,user_info 代表資料欄系列:

    SELECT
      rowkey AS user_id,
      user_info
    FROM
      project.dataset.table;
如要依特定限定詞篩選,必須先在外部資料表定義的 "columns" 中宣告:
CREATE OR REPLACE EXTERNAL TABLE project.dataset.table
  OPTIONS (
    format = 'CLOUD_BIGTABLE',
    uris = ['https://googleapis.com/bigtable/projects/…/instances/…/tables/…'],
    bigtable_options = '''{
  "columnFamilies": [
    {
      "familyId": "user_info",
      "columns": [
        {
          "qualifierString": "name"
        },
        {
          "qualifierString": "email"
        },
        {
          "qualifierString": "registered_at"
        }
      ]
    },
    {
      "familyId": "session_data"
    }
  ],
  "readRowkeyAsString": true,
  "timestampSuffix": "_ts"
}'''
  );

建立外部資料表後,請使用 SELECT 陳述式查詢特定限定詞。這樣一來,BigQuery 就會將篩選器推送至 Bigtable,並在從 BigQuery 執行 SELECT 陳述式時,只載入指定的限定詞,而非整個資料欄系列的資料。這可減少 BigQuery 資源消耗。

    SELECT
      rowkey AS user_id,
      user_info.email.cell[SAFE_OFFSET(0)].value as email
    FROM
      project.dataset.table;