Consultar datos de Bigtable

En este documento se describe cómo usar BigQuery para consultar datos almacenados en una tabla externa de Bigtable. Para obtener información sobre cómo consultar datos directamente desde Bigtable, consulta la descripción general de GoogleSQL para Bigtable.

Bigtable es la base de datos NoSQL de Google con datos dispersos que puede escalarse a miles de millones de filas, miles de columnas y petabytes de datos. Para obtener información sobre el modelo de datos de Bigtable, consulta Modelo de almacenamiento.

Consultar tablas externas permanentes

Antes de empezar, tú o un administrador de tu organización debéis crear una tabla externa para que puedas usarla. Para obtener más información y consultar los permisos necesarios, consulta Crear una tabla externa de BigQuery.

Roles obligatorios

Para consultar tablas externas de Bigtable, asegúrate de tener los siguientes roles.

  • Lector de datos de BigQuery (roles/bigquery.dataViewer)
  • Usuario de BigQuery (roles/bigquery.user)
  • Lector de Bigtable (roles/bigtable.reader)

En función de tus permisos, puedes asignarte estos roles o pedirle a tu administrador que te los asigne. Para obtener más información sobre cómo conceder roles, consulta el artículo Ver los roles que se pueden conceder en los recursos.

Para ver los permisos exactos de BigQuery que se necesitan para consultar tablas externas, despliega la sección Permisos necesarios:

Permisos obligatorios

También puedes obtener estos permisos con roles personalizados u otros roles predefinidos.

Consultar la tabla

Puedes ejecutar una consulta en una tabla externa permanente de Bigtable exactamente igual que si fuera una tabla estándar de BigQuery, sujeta a las limitaciones de las fuentes de datos externas. Para obtener más información, consulta Ejecutar consultas interactivas y por lotes.

Consultar tablas externas temporales

Consultar una fuente de datos externa mediante una tabla temporal es útil para realizar consultas puntuales y ad hoc sobre datos externos, o para procesos de extracción, transformación y carga (ETL).

Para consultar una fuente de datos externa sin crear una tabla permanente, debes proporcionar una definición de tabla para la tabla temporal y, a continuación, usar esa definición de tabla en un comando o una llamada para consultar la tabla temporal. Puedes proporcionar la definición de la tabla de cualquiera de las siguientes formas:

El archivo de definición de tabla o el esquema proporcionado se usan para crear la tabla externa temporal y la consulta se ejecuta en la tabla externa temporal.

Cuando usas una tabla externa temporal, no creas una tabla en uno de tus conjuntos de datos de BigQuery. Como la tabla no se almacena de forma permanente en un conjunto de datos, no se puede compartir con otros usuarios.

Usar una tabla externa temporal en lugar de una permanente tiene algunas limitaciones, como las siguientes:

  • Debes tener el rol Administrador de Bigtable (roles/bigtable.admin).
  • Con este método, no puedes usar la Google Cloud consola para inferir el esquema de la tabla de Bigtable y crear automáticamente la definición de la tabla. Debes crear la definición de la tabla.

Roles obligatorios

Para consultar tablas externas temporales de Bigtable, asegúrate de tener los siguientes roles:

  • Lector de datos de BigQuery (roles/bigquery.dataViewer)
  • Usuario de BigQuery (roles/bigquery.user)
  • Administración de Bigtable (roles/bigtable.admin)

En función de tus permisos, puedes asignarte estos roles o pedirle a tu administrador que te los asigne. Para obtener más información sobre cómo conceder roles, consulta el artículo Ver los roles que se pueden conceder en los recursos.

Para ver los permisos exactos de BigQuery que se necesitan para consultar tablas externas, despliega la sección Permisos necesarios:

Permisos obligatorios

También puedes obtener estos permisos con roles personalizados u otros roles predefinidos.

Crear y consultar la tabla

Para consultar datos de Bigtable con una tabla externa temporal, debes hacer lo siguiente:

La herramienta de línea de comandos bq y la API permiten crear y consultar tablas externas temporales.

bq

Para consultar una tabla temporal con un archivo de definición de tabla, introduce el comando bq query con la marca --external_table_definition.

(Opcional) Proporcione la marca --location y asigne el valor a su ubicación.

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

Haz los cambios siguientes:

  • LOCATION: el nombre de tu ubicación. La marca --location es opcional.
  • TABLE: el nombre de la tabla temporal que vas a crear.
  • DEFINITION_FILE: la ruta al archivo de definición de tabla en tu máquina local.
  • QUERY: la consulta que envías a la tabla temporal.

Por ejemplo, el siguiente comando crea y consulta una tabla temporal llamada follows mediante un archivo de definición de tabla llamado follows_def.

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

API

  • Crea una consulta. Consulta Consultar datos para obtener información sobre cómo crear un trabajo de consulta.

  • (Opcional) Especifica tu ubicación en la propiedad location de la sección jobReference del recurso Job.

  • Especifique las propiedades de la fuente de datos externa configurando el ExternalDataConfiguration del recurso de tabla.

Java

Antes de probar este ejemplo, sigue las Javainstrucciones de configuración de la guía de inicio rápido de BigQuery con bibliotecas de cliente. Para obtener más información, consulta la documentación de referencia de la API Java de BigQuery.

Para autenticarte en BigQuery, configura las credenciales predeterminadas de la aplicación. Para obtener más información, consulta el artículo Configurar la autenticación para bibliotecas de cliente.

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());
    }
  }
}

Consideraciones sobre el rendimiento.

El rendimiento de las consultas a fuentes de datos externas de Bigtable depende de tres factores:

  • Número de filas
  • Cantidad de datos leídos
  • El grado de paralelización

BigQuery intenta leer la menor cantidad de datos posible leyendo solo las familias de columnas a las que se hace referencia en la consulta. El grado de paralelización depende del número de nodos que tengas en tu clúster de Bigtable y del número de divisiones que tenga tu tabla.

Ten en cuenta que Bigtable combina automáticamente las divisiones en función de la carga. Si tu tabla no se lee con frecuencia, habrá menos divisiones con el tiempo y una degradación gradual del rendimiento de las consultas. Para obtener más información, consulta Cómo optimiza BigQuery tus datos a lo largo del tiempo.

Computación

Cuando consultas tus datos de Bigtable desde BigQuery, tienes las siguientes opciones de cálculo:

  • Nodos de clúster, que es el valor predeterminado.
  • Data Boost (vista previa), una opción de computación sin servidor que te permite aislar el tráfico de analíticas sin que afecte al tráfico de servicio de la aplicación que gestionan los nodos de tus clústeres.

Para usar Data Boost, tú o tu administrador debéis crear un archivo de definición que especifique un perfil de aplicación de Data Boost en el URI de Bigtable. Para obtener más información, consulta Crear una tabla externa de Bigtable.

Si no usas Data Boost, ten en cuenta que consultar Bigtable desde BigQuery consume ciclos de CPU de Bigtable. El consumo de CPU por parte de BigQuery al usar nodos aprovisionados para el cálculo puede afectar a la latencia y al rendimiento de otras solicitudes simultáneas, como el servicio de tráfico de usuarios activos. Por ejemplo, un uso elevado de la CPU en Bigtable afecta a las consultas de cola larga y aumenta la latencia en el percentil 99.

Por lo tanto, debes monitorizar el uso de CPU de Bigtable para verificar que te encuentras dentro de los límites recomendados, tal como se indica en el panel de control de monitorización de Bigtable de la Google Cloud consola. Si aumenta el número de nodos de su instancia, podrá gestionar tanto el tráfico de BigQuery como el de otras solicitudes simultáneas.

Filtros de consulta

Puedes añadir filtros de consulta al consultar una tabla externa para reducir el uso de recursos de BigQuery.

Filtro de clave de fila

Las consultas con un filtro de igualdad de clave de fila solo leen esa fila específica. Por ejemplo, en la sintaxis de GoogleSQL:

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

También se admiten filtros de intervalo, como rowkey > '1' y rowkey < '8', pero solo cuando rowkey se lee como una cadena con la opción readRowkeyAsString.

Filtrar por familia de columnas y calificador

También puedes seleccionar una familia de columnas específica o un calificador específico dentro de una familia de columnas. Para filtrar por familia de columnas, selecciona el nombre de la familia de columnas. El resultado incluirá solo la familia de columnas seleccionada. En el siguiente ejemplo, user_info representa una familia de columnas:

    SELECT
      rowkey AS user_id,
      user_info
    FROM
      project.dataset.table;
Para filtrar por un calificador específico, primero debe declararlo en "columns" en la definición de la tabla externa:
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"
}'''
  );

Una vez creada la tabla externa, usa una instrucción SELECT para consultar un calificador específico. De esta forma, BigQuery envía el filtro a Bigtable y solo carga los calificadores especificados al ejecutar una instrucción SELECT desde BigQuery, no los datos de toda la familia de columnas. De esta forma, se reduce el consumo de recursos de BigQuery.

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