Ejemplo: aplicación “Hello World” en Go

En este ejemplo, se usa una aplicación muy simple llamada “hello world” escrita en Go y se demuestra cómo hacer las siguientes tareas:

  • Conectarse a una instancia de Cloud Bigtable.
  • Crear una tabla nueva.
  • Escribir datos en la tabla.
  • Volver a leer datos.
  • Borrar la tabla.

Ejecuta la muestra

En este ejemplo, se usa el paquete de Cloud Bigtable de la biblioteca cliente de Google Cloud para Go a fin de comunicarse con Cloud Bigtable.

Para ejecutar este programa de muestra, sigue las instrucciones que se indican en GitHub.

Usa la biblioteca cliente de Cloud con Cloud Bigtable

La aplicación de muestra se conecta con Cloud Bigtable y demuestra algunas operaciones simples.

Importa la biblioteca cliente

En esta muestra, se usan las siguientes importaciones:

import (
	"context"
	"flag"
	"fmt"
	"log"

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

Cómo conectarse a Cloud Bigtable para administrar las tablas

Para administrar las tablas, conéctate a Cloud Bigtable mediante bigtable.NewAdminClient().

adminClient, err := bigtable.NewAdminClient(ctx, *project, *instance)
if err != nil {
	log.Fatalf("Could not create admin client: %v", err)
}

Crea una tabla

Crea una tabla con AdminClient.CreateTable() y obtén información sobre la tabla con AdminClient.TableInfo(). Crea una familia de columnas con AdminClient.CreateColumnFamily().

tables, err := adminClient.Tables(ctx)
if err != nil {
	log.Fatalf("Could not fetch table list: %v", err)
}

if !sliceContains(tables, tableName) {
	log.Printf("Creating table %s", tableName)
	if err := adminClient.CreateTable(ctx, tableName); err != nil {
		log.Fatalf("Could not create table %s: %v", tableName, err)
	}
}

tblInfo, err := adminClient.TableInfo(ctx, tableName)
if err != nil {
	log.Fatalf("Could not read info for table %s: %v", tableName, err)
}

if !sliceContains(tblInfo.Families, columnFamilyName) {
	if err := adminClient.CreateColumnFamily(ctx, tableName, columnFamilyName); err != nil {
		log.Fatalf("Could not create column family %s: %v", columnFamilyName, err)
	}
}

Cómo conectarse a Cloud Bigtable para administrar los datos

Para administrar los datos, conéctate a Cloud Bigtable mediante bigtable.NewClient().

client, err := bigtable.NewClient(ctx, *project, *instance)
if err != nil {
	log.Fatalf("Could not create data operations client: %v", err)
}

Escribe filas en una tabla

Abre la tabla en la que desees escribir. Usa bigtable.NewMutation() a fin de crear una mutación en una sola fila y, luego, usa Mutation.Set() para establecer valores en la fila. Genera una clave de fila única para cada fila. Repite estos pasos para crear varias mutaciones. Por último, usa Table.ApplyBulk() para aplicar todas las mutaciones a tu tabla.

tbl := client.Open(tableName)
muts := make([]*bigtable.Mutation, len(greetings))
rowKeys := make([]string, len(greetings))

log.Printf("Writing greeting rows to table")
for i, greeting := range greetings {
	muts[i] = bigtable.NewMutation()
	muts[i].Set(columnFamilyName, columnName, bigtable.Now(), []byte(greeting))

	// Each row has a unique row key.
	//
	// Note: This example uses sequential numeric IDs for simplicity, but
	// this can result in poor performance in a production application.
	// Since rows are stored in sorted order by key, sequential keys can
	// result in poor distribution of operations across nodes.
	//
	// For more information about how to design a Bigtable schema for the
	// best performance, see the documentation:
	//
	//     https://cloud.google.com/bigtable/docs/schema-design
	rowKeys[i] = fmt.Sprintf("%s%d", columnName, i)
}

rowErrs, err := tbl.ApplyBulk(ctx, rowKeys, muts)
if err != nil {
	log.Fatalf("Could not apply bulk row mutation: %v", err)
}
if rowErrs != nil {
	for _, rowErr := range rowErrs {
		log.Printf("Error writing row: %v", rowErr)
	}
	log.Fatalf("Could not write some rows")
}

Lee una fila por su clave

Obtén una fila directamente mediante su clave con Table.ReadRow().

log.Printf("Getting a single greeting by row key:")
row, err := tbl.ReadRow(ctx, rowKeys[0], bigtable.RowFilter(bigtable.ColumnFilter(columnName)))
if err != nil {
	log.Fatalf("Could not read row with key %s: %v", rowKeys[0], err)
}
log.Printf("\t%s = %s\n", rowKeys[0], string(row[columnFamilyName][0].Value))

Analiza todas las filas de una tabla

Usa Table.ReadRows() para escanear todas las filas de una tabla. Cierra el cliente de datos cuando termines de usarlo.

log.Printf("Reading all greeting rows:")
err = tbl.ReadRows(ctx, bigtable.PrefixRange(columnName), func(row bigtable.Row) bool {
	item := row[columnFamilyName][0]
	log.Printf("\t%s = %s\n", item.Row, string(item.Value))
	return true
}, bigtable.RowFilter(bigtable.ColumnFilter(columnName)))

if err = client.Close(); err != nil {
	log.Fatalf("Could not close data operations client: %v", err)
}

Borra una tabla

Borra una tabla con AdminClient.DeleteTable(). Cierra el cliente de administración cuando termines de usarlo.

log.Printf("Deleting the table")
if err = adminClient.DeleteTable(ctx, tableName); err != nil {
	log.Fatalf("Could not delete table %s: %v", tableName, err)
}

if err = adminClient.Close(); err != nil {
	log.Fatalf("Could not close admin client: %v", err)
}

Revisión general

Este es el ejemplo completo sin comentarios.


package main

import (
	"context"
	"flag"
	"fmt"
	"log"

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

const (
	tableName        = "Hello-Bigtable"
	columnFamilyName = "cf1"
	columnName       = "greeting"
)

var greetings = []string{"Hello World!", "Hello Cloud Bigtable!", "Hello golang!"}

func sliceContains(list []string, target string) bool {
	for _, s := range list {
		if s == target {
			return true
		}
	}
	return false
}

func main() {
	project := flag.String("project", "", "The Google Cloud Platform project ID. Required.")
	instance := flag.String("instance", "", "The Google Cloud Bigtable instance ID. Required.")
	flag.Parse()

	for _, f := range []string{"project", "instance"} {
		if flag.Lookup(f).Value.String() == "" {
			log.Fatalf("The %s flag is required.", f)
		}
	}

	ctx := context.Background()

	adminClient, err := bigtable.NewAdminClient(ctx, *project, *instance)
	if err != nil {
		log.Fatalf("Could not create admin client: %v", err)
	}

	tables, err := adminClient.Tables(ctx)
	if err != nil {
		log.Fatalf("Could not fetch table list: %v", err)
	}

	if !sliceContains(tables, tableName) {
		log.Printf("Creating table %s", tableName)
		if err := adminClient.CreateTable(ctx, tableName); err != nil {
			log.Fatalf("Could not create table %s: %v", tableName, err)
		}
	}

	tblInfo, err := adminClient.TableInfo(ctx, tableName)
	if err != nil {
		log.Fatalf("Could not read info for table %s: %v", tableName, err)
	}

	if !sliceContains(tblInfo.Families, columnFamilyName) {
		if err := adminClient.CreateColumnFamily(ctx, tableName, columnFamilyName); err != nil {
			log.Fatalf("Could not create column family %s: %v", columnFamilyName, err)
		}
	}

	client, err := bigtable.NewClient(ctx, *project, *instance)
	if err != nil {
		log.Fatalf("Could not create data operations client: %v", err)
	}

	tbl := client.Open(tableName)
	muts := make([]*bigtable.Mutation, len(greetings))
	rowKeys := make([]string, len(greetings))

	log.Printf("Writing greeting rows to table")
	for i, greeting := range greetings {
		muts[i] = bigtable.NewMutation()
		muts[i].Set(columnFamilyName, columnName, bigtable.Now(), []byte(greeting))

		rowKeys[i] = fmt.Sprintf("%s%d", columnName, i)
	}

	rowErrs, err := tbl.ApplyBulk(ctx, rowKeys, muts)
	if err != nil {
		log.Fatalf("Could not apply bulk row mutation: %v", err)
	}
	if rowErrs != nil {
		for _, rowErr := range rowErrs {
			log.Printf("Error writing row: %v", rowErr)
		}
		log.Fatalf("Could not write some rows")
	}

	log.Printf("Getting a single greeting by row key:")
	row, err := tbl.ReadRow(ctx, rowKeys[0], bigtable.RowFilter(bigtable.ColumnFilter(columnName)))
	if err != nil {
		log.Fatalf("Could not read row with key %s: %v", rowKeys[0], err)
	}
	log.Printf("\t%s = %s\n", rowKeys[0], string(row[columnFamilyName][0].Value))

	log.Printf("Reading all greeting rows:")
	err = tbl.ReadRows(ctx, bigtable.PrefixRange(columnName), func(row bigtable.Row) bool {
		item := row[columnFamilyName][0]
		log.Printf("\t%s = %s\n", item.Row, string(item.Value))
		return true
	}, bigtable.RowFilter(bigtable.ColumnFilter(columnName)))

	if err = client.Close(); err != nil {
		log.Fatalf("Could not close data operations client: %v", err)
	}

	log.Printf("Deleting the table")
	if err = adminClient.DeleteTable(ctx, tableName); err != nil {
		log.Fatalf("Could not delete table %s: %v", tableName, err)
	}

	if err = adminClient.Close(); err != nil {
		log.Fatalf("Could not close admin client: %v", err)
	}
}