Valores agregados en el momento de la escritura

Si deseas agregar tus datos en Bigtable en el momento de la escritura, puedes usar agrupaciones. Los agregados son celdas de tablas de Bigtable que aggregan valores de celda a medida que se escriben los datos. Cuando agregas un valor nuevo, se genera una la función de agregación combina el valor con el valor agregado que ya está en la celda. Otras bases de datos se refieren a funciones similares a las de los contadores o contadores distribuidos.

Puedes trabajar con agregados usando la CLI de cbt y las bibliotecas cliente de Bigtable para C++, Go y Java.

En este documento, se brinda una descripción general de las agregaciones y se muestra cómo crear un agregar una familia de columnas y proporciona ejemplos de cómo agregar un valor a un Agregar celda. Antes de leer este documento, debes familiarizarte con la descripción general de Bigtable y las operaciones de escritura.

Cuándo usar agregados

Los agregados de Bigtable son útiles en situaciones en las que te interesa datos de una entidad de forma agregada y no como datos individuales. Si vas a migrar a Bigtable desde bases de datos como Apache Cassandra o Redis, puedes usar los agregados de Bigtable en lugares donde antes usabas contadores en estos sistemas.

Buckets de tiempo

Puedes usar intervalos de tiempo para obtener valores agregados durante un período, como una hora, un día o una semana. En lugar de agregar datos antes o después de que se escriben en la tabla, agregas valores nuevos para agregar celdas en la tabla.

Por ejemplo, si ofreces un servicio que ayuda a organizaciones benéficas a recaudar dinero, podrías desean saber la cantidad de donaciones en línea al día de cada campaña, pero no necesitan saber el momento exacto de cada donación ni el importe por hora. En tu tabla, las claves de fila representan los IDs de organizaciones benéficas, y creas una familia de columnas agregadas llamada donations. Los calificadores de columnas de la fila son los IDs de campaña.

A medida que se recibe cada importe de donación de un día determinado para una campaña, se agrega a la suma de la celda agregada en la columna de ese día. Cada solicitud de adición para la celda usa una marca de tiempo truncada al comienzo del día, de modo que, en efecto, cada solicitud tiene la misma marca de tiempo. Truncar las marcas de tiempo garantiza que todas las donaciones de ese día se agreguen a la misma celda. El al día siguiente, todas tus solicitudes van a una nueva celda, con marcas de tiempo que son se truncará a la nueva fecha, y ese patrón continuará.

Según tu caso de uso, puedes optar por crear columnas nuevas para tus agregados nuevos. Según la cantidad de buckets que planeas acumular, puedes considerar un diseño de clave de fila diferente.

Si deseas obtener más información sobre buckets temporales, consulta Diseño de esquemas para series temporales datos categóricos.

Optimización de flujos de trabajo

Las agregaciones te permiten agregar tus datos a tu tabla de Bigtable sin necesidad de usar ningún ETL ni software de procesamiento de transmisión para agregar tus datos antes o después de escribirlos en Bigtable. Por ejemplo, si tu aplicación publicó mensajes en Pub/Sub anteriormente y, luego, usó Dataflow para leer los mensajes y agregar los datos antes de escribirlos en Bigtable, en su lugar, podrías enviar los datos directamente a las celdas de agregación en Bigtable.

Agrega familias de columnas

Para crear y actualizar celdas agregadas, debes tener una o más familias de columnas agregadas en tu tabla, es decir, familias de columnas que solo contengan celdas agregadas. Puedes crearlas cuando creas una tabla, o bien puedes agregar una familia de columnas agregadas a una tabla que ya está en uso. Cuando creas la columna debes especificar el tipo de agregación, como suma.

No puedes convertir una familia de columnas que contiene datos no agregados en un con una familia de columnas agregada. Las columnas de las familias de columnas agregadas no pueden contener celdas no agregadas, y las familias de columnas estándar no pueden contener celdas agregadas.

Para crear una tabla nueva con una familia de columnas agregada, consulta Crea una de la tabla. Cómo agregar una columna de agregación a una tabla, consulta Agregar columna familias.

Tipos de agregación

Bigtable admite los siguientes tipos de agregación:

Suma

Cuando agregas un valor a una celda de suma total (sum), el valor de la celda se y se reemplaza por la suma del valor agregado recientemente y el valor actual de la celda. El el tipo de entrada compatible con las sumas es Int64.

Mínimo

Cuando agregas un valor a una celda agregada mínima (min), el valor de la celda es reemplazado por el valor más bajo entre el valor agregado recientemente y el valor el valor de la celda. El tipo de entrada compatible con el valor mínimo es Int64.

Máximo

Cuando agregas un valor a una celda agregada máxima (max), el valor de la celda se reemplaza por el valor más alto entre el valor agregado recientemente y el valor de la celda actual. El tipo de entrada que se admite para el máximo es Int64.

HyperLogLog (HLL)

Cuando agregas un valor a una celda agregada de HLL (inthll), el valor se agrega a un conjunto probabilístico de todos los valores agregados desde el restablecimiento más reciente (ya sea el creación de la celda o eliminación de sus datos). El valor de la celda representa el estado de ese conjunto. Para obtener información más general sobre el algoritmo HLL, consulta HyperLogLog.

Puedes leer valores de HLL con la biblioteca Zetasketch. Para obtener más información, consulta el repositorio de GitHub de Zetasketch. El tipo de entrada que se admite para HLL es BYTES.

Marcas de tiempo

Una celda agregada se define por la clave de fila, la familia de columnas, el calificador de columnas y la marca de tiempo. Debes usar la misma marca de tiempo cada vez que agregues datos a la celda. Si envía un valor a la misma clave de fila, familia de columnas y calificador de columna, pero con un una marca de tiempo diferente, se crea una nueva celda agregada en la columna.

Una solicitud de agregado que se envía a una celda de agregación debe incluir una marca de tiempo.

Tipo de entrada

El tipo de entrada del valor en la solicitud de adición debe coincidir con el tipo de entrada con el que se creó la familia de columnas. Por ejemplo, si envías un valor de cadena a una familia de columnas configurada para Int64, se rechazará la solicitud.

AddToCell

Una solicitud de adición envía una mutación AddToCell en la API de datos de Bigtable. En cambio, una solicitud de escritura no agregada envía una mutación SetCell. Para obtener más información, consulta la referencia de la API de Data. Las operaciones AddToCell están sujetas a las mismas operaciones límites que otras mutaciones de la tabla.

En una tabla replicada, una celda agregada converge en el mismo valor final en a todos los clústeres con el retraso de replicación actual. El valor final es el agregado de todas las mutaciones de AddToCell enviadas a esa celda en todos los clústeres desde la última operación de eliminación o desde que se creó la celda.

Recolección de elementos no utilizados

Las celdas de agregación se tratan como a cualquier otra celda durante la recolección de elementos no utilizados: si se trata de se marca para su eliminación, esta se replica en todos los clústeres del instancia. Para obtener más información, consulta Replicación y recolección de basura. Si una solicitud de agregado enviados a una celda de agregado que se haya quitado a través de la recolección de elementos no utilizados, una nueva se crea una celda de agregación.

Agrega ejemplos de solicitudes

En los siguientes ejemplos, se muestra cómo agregar un valor a una celda agregada. Los ejemplos se suman a una suma en una familia de columnas que espera el tipo de entrada Int64.

cbt

cbt addtocell TABLE_ID ROW_KEY FAMILY_NAME:COLUMN_QUALIFER=VALUE@TIMESTAMP

Reemplaza lo siguiente:

  • TABLE_ID: el identificador permanente de la tabla
  • ROW_KEY: Es la clave de fila.
  • FAMILY_NAME: Es el nombre de la familia de columnas agregadas.
  • COLUMN_QUALIFIER: Un identificador para la columna
  • VALUE: Es el valor que se agregará a la celda.
  • TIMESTAMP: Una marca de tiempo de Unix en microsegundos, como 1710868850000000.

Ejemplo:

cbt addtocell mobile-data device-1 updates:week12=100@1710868850000000

Go

Si deseas obtener información sobre cómo instalar y usar la biblioteca cliente de Bigtable, consulta las bibliotecas cliente de Bigtable.

Para autenticarte en Bigtable, configura las credenciales predeterminadas de la aplicación. Si deseas obtener más información, consulta Configura la autenticación para bibliotecas cliente.

import (
	"context"
	"fmt"
	"io"
	"time"

	"cloud.google.com/go/bigtable"
)

func writeAggregate(w io.Writer, projectID, instanceID string, tableName string) error {
	// projectID := "my-project-id"
	// instanceID := "my-instance-id"
	// tableName := "mobile-time-series"

	ctx := context.Background()
	client, err := bigtable.NewClient(ctx, projectID, instanceID)
	if err != nil {
		return fmt.Errorf("bigtable.NewClient: %w", err)
	}
	defer client.Close()
	tbl := client.Open(tableName)
	columnFamilyName := "view_count"
	viewTimestamp, err := time.Parse(time.RFC3339, "2024-03-13T12:41:34Z")
	if err != nil {
		return err
	}
	hourlyBucket := viewTimestamp.Truncate(time.Hour)

	mut := bigtable.NewMutation()
	mut.AddIntToCell(columnFamilyName, "views", bigtable.Time(hourlyBucket), 1)

	rowKey := "page#index.html"
	if err := tbl.Apply(ctx, rowKey, mut); err != nil {
		return fmt.Errorf("Apply: %w", err)
	}

	fmt.Fprintf(w, "Successfully wrote row: %s\n", rowKey)
	return nil
}

Java

Si deseas obtener información sobre cómo instalar y usar la biblioteca cliente de Bigtable, consulta las bibliotecas cliente de Bigtable.

Para autenticarte en Bigtable, configura las credenciales predeterminadas de la aplicación. Si deseas obtener más información, consulta Configura la autenticación para bibliotecas cliente.


import com.google.cloud.bigtable.data.v2.BigtableDataClient;
import com.google.cloud.bigtable.data.v2.models.RowMutation;
import java.time.Instant;
import java.time.temporal.ChronoUnit;

public class WriteAggregate {
  private static final String COUNT_COLUMN_FAMILY_NAME = "view_count";
  private static final long MICROS_PER_MILLI = 1000;

  public static void writeAggregate(String projectId, String instanceId, String tableId) {
    // String projectId = "my-project-id";
    // String instanceId = "my-instance-id";
    // String tableId = "page-view-counter";

    try (BigtableDataClient dataClient = BigtableDataClient.create(projectId, instanceId)) {

      String rowKey = "page#index.html";
      Instant viewTimestamp = Instant.parse("2024-03-13T12:41:34.123Z");

      // Bucket the views for an hour into a single count, giving us an hourly view count for a
      // given page.
      Instant hourlyBucket = viewTimestamp.truncatedTo(ChronoUnit.HOURS);
      long hourlyBucketMicros = hourlyBucket.toEpochMilli() * MICROS_PER_MILLI;

      RowMutation rowMutation =
          RowMutation.create(tableId, rowKey)
              .addToCell(COUNT_COLUMN_FAMILY_NAME, "views", hourlyBucketMicros, 1);

      dataClient.mutateRow(rowMutation);
      System.out.printf("Successfully wrote row %s", rowKey);

    } catch (Exception e) {
      System.out.println("Error during WriteAggregate: \n" + e.toString());
    }
  }
}

¿Qué sigue?