Bigtable 데이터 쿼리

이 문서에서는 Bigtable 외부 테이블에 저장된 데이터를 쿼리하는 방법을 설명합니다.

Bigtable은 수십억 개의 행, 수천 개의 열, 수 페타바이트의 데이터까지 확장할 수 있으며 데이터 밀도가 낮은 Google의 NoSQL 데이터베이스입니다. Bigtable 데이터 모델에 대한 자세한 내용은 스토리지 모델을 참조하세요.

영구 외부 테이블 쿼리

시작하기 전에 사용자 또는 조직의 사용자가 사용할 외부 테이블을 만들어야 합니다. 자세한 내용과 필요한 권한은 BigQuery 외부 테이블 만들기를 참조하세요.

필요한 역할

Bigtable 영구 외부 테이블을 쿼리하려면 다음 역할이 있어야 합니다.

  • BigQuery 데이터 뷰어(roles/bigquery.dataViewer)
  • BigQuery 사용자(roles/bigquery.user)
  • Bigtable 리더(roles/bigtable.reader)

권한에 따라 이러한 역할을 직접 부여하거나 관리자에게 부여를 요청할 수 있습니다. 역할 부여에 대한 자세한 내용은 리소스에 대해 부여할 수 있는 역할 보기를 참조하세요.

외부 테이블을 쿼리하는 데 필요한 정확한 BigQuery 권한을 보려면 필수 권한 섹션을 확장하세요.

필수 권한

커스텀 역할이나 다른 사전 정의된 역할을 사용하여 이 권한을 부여받을 수도 있습니다.

테이블 쿼리

표준 BigQuery 테이블과 마찬가지로 영구 외부 Bigtable 테이블에 대한 쿼리를 다음과 같이 정확하게 실행할 수 있으며, 외부 데이터 소스에 대한 제한사항이 적용됩니다. 자세한 내용은 대화형 및 일괄 쿼리 실행을 참조하세요.

임시 외부 테이블 쿼리

임시 테이블을 사용하여 외부 데이터 소스를 쿼리하면 외부 데이터를 대상으로 하는 일회성 임시 쿼리 또는 ETL(추출, 변환, 로드) 프로세스에 유용합니다.

영구 테이블을 만들지 않고 외부 데이터 소스를 쿼리하려면 임시 테이블에 대한 테이블 정의를 제공한 후 명령어 또는 호출에서 해당 테이블 정의를 사용하여 임시 테이블을 쿼리합니다. 다음과 같은 방법으로 테이블 정의를 제공할 수 있습니다.

테이블 정의 파일이나 제공된 스키마는 임시 외부 테이블을 만드는 데 사용되며, 임시 외부 테이블을 대상으로 쿼리가 실행됩니다.

임시 외부 테이블을 사용하는 경우, BigQuery 데이터 세트 중 하나에 테이블을 만들지 마세요. 테이블이 데이터 세트에 영구적으로 저장되지 않으므로, 다른 사용자와 테이블을 공유할 수 없습니다.

영구 외부 테이블 대신 임시 외부 테이블을 사용하면 다음과 같은 제한사항이 있습니다.

  • Bigtable 관리자(roles/bigtable.admin) 역할이 있어야 합니다.
  • 이 접근 방식에서는 Google Cloud 콘솔을 사용하여 Bigtable 테이블의 스키마를 추론하고 테이블 정의를 자동으로 만들 수 없습니다. 테이블 정의를 직접 만들어야 합니다.

필요한 역할

Bigtable 임시 외부 테이블을 쿼리하려면 다음 역할이 있어야 합니다.

  • BigQuery 데이터 뷰어(roles/bigquery.dataViewer)
  • BigQuery 사용자(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는 쿼리에서 참조하는 column family만 읽는 방식으로 최대한 적은 양의 데이터를 읽으려고 합니다. 동시 로드의 범위는 Bigtable 클러스터의 노드 수와 테이블의 분할 수에 따라 다릅니다.

Bigtable은 로드를 기준으로 분할을 자동 병합합니다. 테이블을 자주 읽지 않는 경우 시간 경과에 따라 분할 수가 감소하고 쿼리 성능이 차츰 저하됩니다. row key를 기준으로 테이블 분할에 대한 자세한 내용은 테이블 관리하기를 참조하세요.

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가 문자열로 읽히는 경우에만 해당됩니다.