Interroger des données Bigtable

Ce document explique comment interroger des données stockées dans une table externe Bigtable.

Bigtable est la base de données NoSQL partiellement remplie de Google qui peut contenir jusqu'à plusieurs milliards de lignes, des milliers de colonnes et des pétaoctets de données. Pour en savoir plus sur le modèle de données de Bigtable, consultez la section Modèle de stockage.

Interroger des tables externes permanentes

Avant de commencer, vous ou une personne de votre organisation devez créer une table externe que vous pourrez utiliser. Pour en savoir plus et connaître les autorisations requises, consultez la section Créer une table externe BigQuery.

Rôles requis

Pour interroger des tables externes Bigtable permanentes, assurez-vous de disposer des rôles suivants :

  • Lecteur de données BigQuery (roles/bigquery.dataViewer)
  • Utilisateur BigQuery (roles/bigquery.user)
  • Lecteur Bigtable (roles/bigtable.reader)

Selon vos autorisations, vous pouvez vous attribuer ces rôles ou demander à votre administrateur de vous les accorder. Pour en savoir plus sur l'attribution de rôles, consultez la page Afficher les rôles pouvant être attribués sur des ressources.

Pour afficher les autorisations BigQuery exactes requises pour interroger des tables externes, développez la section Autorisations requises :

Autorisations requises

Vous pouvez également obtenir ces autorisations avec des rôles personnalisés ou d'autres rôles prédéfinis.

Interroger la table

Vous pouvez exécuter une requête sur une table Bigtable externe permanente exactement comme s'il s'agissait d'une table BigQuery standard, conformément aux limites sur les sources de données externes. Pour en savoir plus, consultez la section Exécuter des requêtes interactives et par lot.

Interroger des tables externes temporaires

L'interrogation d'une source de données externe à l'aide d'une table temporaire est utile pour les requêtes ad hoc ponctuelles qui sont exécutées sur des données externes ou pour les processus d'extraction, de transformation et de chargement (ETL, Extract-Transform-Load).

Pour interroger une source de données externe sans créer de table permanente, vous devez fournir une définition de table pour la table temporaire, puis l'utiliser dans une commande ou un appel pour interroger la table temporaire. Vous pouvez fournir la définition de la table de l'une des manières suivantes :

Le fichier de définition de table ou le schéma fourni est utilisé pour créer la table externe temporaire, sur laquelle la requête s'exécute.

En cas d'utilisation d'une table externe temporaire, vous ne créez pas de table dans l'un de vos ensembles de données BigQuery. La table n'étant pas stockée de manière permanente dans un ensemble de données, elle ne peut pas être partagée avec d'autres utilisateurs.

L'utilisation d'une table externe temporaire au lieu d'une table externe permanente présente certaines limites, parmi lesquelles :

  • Vous devez disposer du rôle Administrateur Bigtable (roles/bigtable.admin).
  • Cette approche ne vous permet pas d'utiliser la console Google Cloud pour déduire le schéma de la table Bigtable et de créer automatiquement la définition de table. Vous devez créer vous-même la définition de table.

Rôles requis

Pour interroger des tables externes Bigtable temporaires, assurez-vous de disposer des rôles suivants :

  • Lecteur de données BigQuery (roles/bigquery.dataViewer)
  • Utilisateur BigQuery (roles/bigquery.user)
  • Bigtable Admin (roles/bigtable.admin)

Selon vos autorisations, vous pouvez vous attribuer ces rôles ou demander à votre administrateur de vous les accorder. Pour en savoir plus sur l'attribution de rôles, consultez la page Afficher les rôles pouvant être attribués sur des ressources.

Pour afficher les autorisations BigQuery exactes requises pour interroger des tables externes, développez la section Autorisations requises :

Autorisations requises

Vous pouvez également obtenir ces autorisations avec des rôles personnalisés ou d'autres rôles prédéfinis.

Créer et interroger la table

Pour interroger des données Bigtable à l'aide d'une table externe temporaire, vous devez exécuter les opérations suivantes :

Il est possible de créer et d'interroger une table externe temporaire avec l'outil de ligne de commande bq et l'API.

bq

Pour interroger une table temporaire à l'aide d'un fichier de définition de table, saisissez la commande bq query avec l'option --external_table_definition.

(Facultatif) Spécifiez l'option --location et définissez la valeur correspondant à votre emplacement.

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

Remplacez l'élément suivant :

  • LOCATION : nom de votre emplacement. L'option --location est facultative ;
  • TABLE : nom de la table temporaire que vous créez.
  • DEFINITION_FILE : chemin d'accès au fichier de définition de table sur votre ordinateur local.
  • QUERY : requête que vous soumettez à la table temporaire.

Par exemple, la commande suivante permet de créer et d'interroger une table temporaire nommée follows à l'aide du fichier de définition de table follows_def.

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

API

  • Créez une requête. Consultez la page Interroger des données pour en savoir plus sur la création d'une tâche de requête.

  • (Facultatif) Spécifiez votre emplacement dans la propriété location de la section jobReference de la ressource de tâche.

  • Spécifiez les propriétés de la source de données externe en définissant le paramètre ExternalDataConfiguration pour la ressource de table.

Java

Avant d'essayer cet exemple, suivez les instructions de configuration pour Java du guide de démarrage rapide de BigQuery : Utiliser les bibliothèques clientes. Pour en savoir plus, consultez la documentation de référence de l'API BigQuery pour Java.

Pour vous authentifier auprès de BigQuery, configurez le service Identifiants par défaut de l'application. Pour en savoir plus, consultez la page Configurer l'authentification pour les bibliothèques clientes.

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

Considérations sur les performances

Les performances des requêtes exécutées sur des sources de données externes Bigtable dépendent des trois facteurs suivants :

  • Nombre de lignes
  • Quantité de données lues
  • Ampleur de la parallélisation

BigQuery tente de lire le moins de données possible en se limitant aux familles de colonnes référencées dans la requête. L'ampleur de la parallélisation dépend du nombre de nœuds présents dans le cluster Bigtable et du nombre de divisions que comporte la table.

Notez que Bigtable fusionne automatiquement les divisions en fonction de la charge. Si la table n'est pas lue fréquemment, le nombre de divisions diminue au fil du temps et les performances des requêtes se dégradent progressivement. Pour savoir comment diviser une table en fonction d'une clé de ligne, consultez la page Gérer des tables.

En interrogeant Bigtable à partir de BigQuery, vous consommez des cycles de processeur Bigtable. Cela peut influer sur la latence et le débit des autres requêtes simultanées telles que la diffusion du trafic utilisateur en direct. Par exemple, une utilisation intensive du processeur sur Bigtable influe sur les requêtes en longue traîne et augmente la latence au 99e centile.

Vous devez surveiller l'utilisation du processeur Bigtable pour vérifier que vous vous trouvez dans les limites recommandées, telles qu'indiquées dans le tableau de bord de surveillance Cloud Bigtable de la console Google Cloud. L'augmentation du nombre de nœuds de votre instance vous permet de gérer à la fois le trafic BigQuery et le trafic provenant d'autres requêtes simultanées.

Filtres de requête

Les requêtes associées à un filtre d'égalité de ligne ne permettent de lire qu'une ligne spécifique. L'exemple suivant utilise la syntaxe GoogleSQL :

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

Les filtres de plage tels que rowkey > '1' et rowkey < '8' sont également acceptés, mais seulement lorsque la clé de ligne est lue sous forme de chaîne avec l'option readRowkeyAsString.