Esecuzione di query sui dati di Cloud Bigtable

Questa pagina descrive come utilizzare BigQuery per eseguire query sui dati archiviati in Cloud Bigtable.

Cloud Bigtable è il database NoSQL di Google a bassa densità che può scalare fino a miliardi di righe, migliaia di colonne e piccole quantità di dati. Cloud Bigtable ha un modello di dati simile a Apache HBase e fornisce una libreria client compatibile con HBase. Per informazioni sul modello dei dati di Cloud Bigtable, consulta la sezione Modello di archiviazione.

Aree geografiche e zone supportate

L'esecuzione di query sui dati in Cloud Bigtable è disponibile in tutte le zone di Cloud Bigtable supportate. Qui puoi trovare l'elenco delle zone. Per le istanze multi-cluster, BigQuery instrada il traffico in base alle impostazioni del profilo dell'app di Cloud Bigtable.

Recupero dell'URI Cloud Bigtable

Per creare una tabella esterna per un'origine dati Cloud Bigtable, devi fornire l'URI Cloud Bigtable. Per recuperare l'URI Cloud Bigtable:

  1. Apri la console di Cloud Bigtable.

    Apri la console di Cloud Bigtable

  2. Recupera i seguenti dettagli sull'origine dati Cloud Bigtable:

    • ID progetto
    • ID istanza Cloud Bigtable
    • Il nome della tabella Cloud Bigtable
    • L'ID del tuo profilo dell'app Cloud Bigtable
  3. Scrivi l'URI Cloud Bigtable utilizzando il seguente formato, dove:

    • project_id è il progetto che contiene la tua istanza di Cloud Bigtable
    • instance_id è l'ID istanza Cloud Bigtable
    • table_name è il nome della tabella su cui stai eseguendo query
    • app_profile è l'ID profilo dell'app che vuoi utilizzare.

    https://googleapis.com/bigtable/projects/project_id/instances/instance_id/tables/table_name[/appProfiles/app_profile]

Controlli e ambiti di accesso

Controlli di accesso per le tabelle esterne permanenti

Puoi condividere l'accesso a una tabella esterna permanente collegata a un'origine dati Cloud Bigtable. Non puoi condividere l'accesso a una tabella esterna temporanea.

Puoi condividere l'accesso a una tabella esterna permanente con utenti (inclusi gli account di servizio) o gruppi. Per eseguire una query sulla tabella esterna, i tuoi utenti o gruppi devono essere concessi (come minimo)

  • Il ruolo bigquery.dataViewer a livello di set di dati o superiore per accedere al set di dati che contiene la tabella esterna
  • Il ruolo bigquery.user a livello di progetto o superiore per eseguire job di query
  • Il ruolo bigtable.reader in Cloud Bigtable, che fornisce accesso in sola lettura ai metadati e alle tabelle

Ambiti per le istanze Compute Engine

Quando crei un'istanza Compute Engine, puoi specificare un elenco di ambiti per l'istanza. Gli ambiti controllano l'accesso dell'istanza ai prodotti Google Cloud, incluso Cloud Bigtable. Le applicazioni in esecuzione sulla VM utilizzano l'account di servizio per le chiamate alle API Google Cloud.

Se configuri un'istanza di Compute Engine da eseguire come account di servizio e tale account accede a una tabella esterna collegata a un'origine dati di Cloud Bigtable, devi aggiungere l'ambito di accesso ai dati di sola lettura (https://www.googleapis.com/auth/bigtable.data.readonly) di Cloud Bigtable all'istanza. Per saperne di più, consulta Creazione di un'istanza di Compute Engine per Cloud Bigtable.

Per informazioni sull'applicazione di ambiti a un'istanza Compute Engine, consulta Modifica dell'account di servizio e degli ambiti di accesso per un'istanza. Per ulteriori informazioni sugli account di servizio Compute Engine, consulta Account di servizio.

Tabelle esterne permanenti e temporanee

Puoi eseguire query su un'origine dati esterna in BigQuery utilizzando una tabella permanente o una tabella temporanea. Una tabella permanente è una tabella creata in un set di dati che è collegata alla tua origine dati esterna. Poiché la tabella è permanente, puoi utilizzare i controlli di accesso per condividere la tabella con altri che hanno anche accesso all'origine dati esterna sottostante e puoi eseguire query sulla tabella in qualsiasi momento.

Quando esegui una query su un'origine dati esterna utilizzando una tabella temporanea, devi inviare un comando che include una query e creare una tabella non permanente collegata all'origine dati esterna. Quando utilizzi una tabella temporanea, non crei una tabella in uno dei tuoi set di dati BigQuery. Poiché la tabella non è archiviata in modo permanente in un set di dati, non può essere condivisa con altri. Esecuzione di query su un'origine dati esterna mediante una tabella temporanea è utile per query una tantum e ad hoc su dati esterni o per processi di estrazione, trasformazione e caricamento (ETL).

Utilizzo dei profili app Bigtable

Un profilo dell'applicazione Bigtable, o profilo app, archivia le impostazioni che indicano all'istanza Bigtable come gestire le richieste in entrata da un'applicazione. Quando BigQuery si connette a un'istanza Bigtable, può specificare un profilo app e BigQuery utilizza questo profilo per le richieste di BigQuery.

Per scoprire come funzionano i profili delle app Bigtable, consulta l'articolo Informazioni sui profili delle app.

Esecuzione di query sui dati Cloud Bigtable utilizzando tabelle esterne permanenti

Per eseguire una query su un'origine dati Cloud Bigtable utilizzando una tabella permanente, crea una tabella in un set di dati BigQuery collegato all'origine dati di Cloud Bigtable. I dati non vengono archiviati nella tabella BigQuery. Poiché la tabella è permanente, puoi utilizzare i controlli di accesso a livello di set di dati per condividere la tabella con altre persone che hanno anche accesso all'origine dati Cloud Bigtable sottostante.

Quando crei una tabella esterna permanente in BigQuery collegata a un'origine dati Cloud Bigtable, puoi specificare lo schema della tabella in due modi:

  • Se utilizzi l'API o lo strumento a riga di comando bq, crei un file di definizione della tabella che definisce lo schema e i metadati per l'origine dati esterna.
  • Se utilizzi Google Cloud Console, inserisci la famiglia di colonne e i qualificatori di Cloud Bigtable manualmente.

Per eseguire query sui dati Cloud Bigtable utilizzando una tabella esterna permanente, devi:

  • Crea un file di definizione della tabella (per l'API o lo strumento a riga di comando bq).
  • Creare una tabella in BigQuery collegata all'origine dati esterna
  • Eseguire query sui dati utilizzando la tabella permanente

Creazione e query di una tabella esterna permanente

Per creare e configurare una tabella permanente:

console

Al momento non è possibile eseguire query sui dati da Cloud Bigtable utilizzando Google Cloud Console.

bq

Puoi creare una tabella nello strumento a riga di comando bq utilizzando il comando bq mk. Quando utilizzi lo strumento a riga di comando bq per creare una tabella collegata a un'origine dati esterna, puoi identificare lo schema della tabella utilizzando un file di definizione della tabella.

  1. Utilizza il comando bq mk per creare una tabella permanente.

    bq mk \
    --external_table_definition=definition_file \
    dataset.table
    

    Dove:

    • definition_file è il percorso del file di definizione della tabella sulla tua macchina locale.
    • dataset è il nome del set di dati che contiene la tabella.
    • table è il nome della tabella che stai creando.

    Successivamente, puoi eseguire una query sulla tabella come se fosse una tabella BigQuery nativa, soggetta alle limitazioni sulle origini dati esterne.

Server

  • Per la proprietà sourceUris nella risorsa tabella, puoi specificare esattamente un URI Cloud Bigtable e deve essere un URL HTTPS valido e completamente specificato.

  • Specifica le proprietà del formato dati impostando la proprietà sourceFormat. Per Cloud Bigtable, specifica "BIGTABLE".

Java

Prima di provare questo esempio, segui le istruzioni di configurazione di Java nella Guida di BigQuery per l'utilizzo delle librerie client. Per ulteriori informazioni, consulta la documentazione di riferimento dell'API Java di 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.TableId;
import com.google.cloud.bigquery.TableInfo;
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 permanent table
public class QueryExternalBigtablePerm {

  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 bigqueryDatasetName = "MY_DATASET_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);
    queryExternalBigtablePerm(bigqueryDatasetName, bigqueryTableName, sourceUri, query);
  }

  public static void queryExternalBigtablePerm(
      String datasetName, 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();

      TableId tableId = TableId.of(datasetName, tableName);
      // Create a permanent table linked to the Bigtable table
      ExternalTableDefinition externalTable =
          ExternalTableDefinition.newBuilder(sourceUri, options).build();
      bigquery.create(TableInfo.of(tableId, externalTable));

      // Example query
      TableResult results = bigquery.query(QueryJobConfiguration.of(query));

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

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

Esecuzione di query sui dati Cloud Bigtable utilizzando tabelle esterne temporanee

Per eseguire una query su un'origine dati esterna senza creare una tabella permanente, esegui un comando per combinare:

Il file di definizione della tabella o lo schema fornito vengono utilizzati per creare la tabella esterna temporanea e la query viene eseguita su questa tabella. Le query su un'origine dati esterna mediante una tabella temporanea sono supportate dallo strumento a riga di comando bq e dall'API.

Quando utilizzi una tabella esterna temporanea, non crei una tabella in uno dei tuoi set di dati BigQuery. Poiché la tabella non è archiviata in modo permanente in un set di dati, non può essere condivisa con altri. Esecuzione di query su un'origine dati esterna tramite una tabella temporanea è utile per query una tantum ad hoc su dati esterni o per processi di estrazione, trasformazione e caricamento (ETL).

Creazione e query di una tabella esterna temporanea

Per eseguire query sui dati Cloud Bigtable utilizzando una tabella esterna temporanea, devi:

La creazione e l'esecuzione di query di una tabella esterna temporanea sono attualmente supportate dallo strumento a riga di comando bq e dall'API.

bq

Per eseguire una query su una tabella temporanea utilizzando un file di definizione della tabella, inserisci il comando bq query con il flag --external_table_definition.

(Facoltativo) Fornisci il flag --location e imposta il valore sulla tua località.

bq --location=location query \
--use_legacy_sql=false \
--external_table_definition=table::definition_file \
'query'

Dove:

  • location è il nome della tua località. Il flag --location è facoltativo.
  • table è il nome della tabella temporanea che stai creando.
  • definition_file è il percorso del file di definizione della tabella sulla macchina locale.
  • query è la query che stai inviando alla tabella temporanea.

Ad esempio, il seguente comando crea ed esegue query su una tabella temporanea denominata follows utilizzando un file di definizione della tabella denominato follows_def.

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

Server

  • Crea una query. Consulta Esecuzione di query sui dati per informazioni sulla creazione di un job di query.

  • (Facoltativo) Specifica la tua località nella proprietà location nella sezione jobReference della risorsa lavorativa.

  • Specifica le proprietà dell'origine dati esterna impostando ExternalDataConfiguration per la risorsa tabella.

Java

Prima di provare questo esempio, segui le istruzioni di configurazione di Java nella Guida di BigQuery per l'utilizzo delle librerie client. Per ulteriori informazioni, consulta la documentazione di riferimento dell'API Java di 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());
    }
  }
}

Considerazioni sul rendimento

Le prestazioni delle query rispetto alle origini dati esterne di Cloud Bigtable dipendono da tre fattori:

  • Il numero di righe
  • La quantità di dati letti
  • La misura del parallelismo

BigQuery cerca di leggere il minor numero possibile di dati leggendo soltanto le famiglie di colonne a cui viene fatto riferimento nella query. La portata del processo di parallelizzazione dipende dal numero di nodi presenti nel cluster Cloud Bigtable e dal numero di suddivisioni presenti nella tabella.

Tieni presente che Cloud Bigtable suddivide automaticamente le suddivisioni in base al carico. Se la tabella non viene letta di frequente, il numero di suddivisioni nel tempo verrà ridotto e una diminuzione graduale delle prestazioni delle query. Per ulteriori informazioni sulla suddivisione di una tabella per chiave di riga, consulta Gestione delle tabelle.

L'esecuzione di query su Cloud Bigtable da BigQuery utilizza i cicli di CPU Cloud Bigtable. Il consumo della CPU da parte di BigQuery può influire sulla latenza e sulla velocità effettiva per altre richieste in parallelo, ad esempio la gestione del traffico degli utenti in tempo reale. Ad esempio, un elevato utilizzo della CPU in Cloud Bigtable influisce sulle query long-tail e aumenta la latenza al 99° percentile.

Dovresti monitorare l'utilizzo della CPU di Cloud Bigtable per verificare che rientri nei limiti consigliati, come indicato nella dashboard di monitoraggio di Cloud Bigtable in Google Cloud Console. L'aumento del numero di nodi per l'istanza consente di gestire meglio il traffico BigQuery e il traffico da altre richieste in parallelo.

Schema generato

Per impostazione predefinita, BigQuery espone i valori in una famiglia di colonne come un array di colonne e al suo interno un array di valori scritti in timestamp diversi. Questo schema conserva il layout naturale dei dati in Cloud Bigtable, ma le query SQL possono essere difficili. È possibile promuovere colonne in sottocampi all'interno della famiglia di colonne principali e leggere solo il valore più recente di ciascuna cella. Rappresenta entrambi gli array nello schema predefinito come valori scalari.

Esempio

I tuoi profili utente sono memorizzati in un social network fittizio. Un modello di dati per questa potrebbe essere una famiglia di colonne profile con singole colonne per gender, age e email:

rowkey | profile:gender| profile:age| profile:email
-------| --------------| -----------| -------------
alice  | female        | 30         | alice@gmail.com

Con lo schema predefinito, una query SQL standard per conteggiare il numero di utenti di sesso maschile più di 30 è:

SELECT
  COUNT(1)
FROM
  `dataset.table`
OMIT
  RECORD IF NOT SOME(profile.column.name = "gender"
    AND profile.column.cell.value = "male")
  OR NOT SOME(profile.column.name = "age"
    AND INTEGER(profile.column.cell.value) > 30)

L'esecuzione di query sui dati è meno complessa se gender e age vengono esposti come campi secondari. Per esporli come sottocampi, elenca gender e age come colonne denominate nella famiglia di colonne profile durante la definizione della tabella. Puoi anche fornire a BigQuery i valori più recenti della famiglia di colonne poiché è ancora disponibile. In genere, interessa solo l'ultimo valore (e forse l'unico).

Dopo aver esposto le colonne come sottocampi, la query SQL standard per conteggiare il numero di utenti maschili oltre 30 è:

SELECT
  COUNT(1)
FROM
  `dataset.table`
WHERE
  profile.gender.cell.value="male"
  AND profile.age.cell.value > 30

Nota come gender e age vengono utilizzati direttamente come campi. La configurazione JSON per questa configurazione è:

  "bigtableOptions": {
    "readRowkeyAsString": "true",
    "columnFamilies": [
      {
          "familyId": "profile",
          "onlyReadLatest": "true",
          "columns": [
              {
                  "qualifierString": "gender",
                  "type": "STRING"
              },
              {
                  "qualifierString": "age",
                  "type": "INTEGER"
              }
          ]
      }
    ]
  }

Codifica valore

Cloud Bigtable archivia i dati come byte non elaborati, indipendentemente dalla codifica dei dati. Tuttavia, i valori dei byte sono di uso limitato nell'analisi delle query SQL. Cloud Bigtable offre due tipi di decodifica scalare di base: testo e HBase-binary.

Il formato del testo presuppone che tutti i valori vengano memorizzati come stringhe di testo alfanumeriche. Ad esempio, un numero intero 768 verrà memorizzato come stringa "768". La codifica binaria presuppone che la classe di metodi Bytes.toBytes di HBase sia stata utilizzata per codificare i dati e applica un metodo di decodifica appropriato.

Filtri di query

Le query con un filtro di uguaglianza di riga leggono solo quella riga specifica. Ad esempio, nella sintassi SQL standard:

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

Sono supportati anche i filtri per intervalli come rowkey > '1' e rowkey < '8', ma solo quando la chiave riga è letta come stringa con l'opzione readRowkeyAsString.