# Cloud BigTable Vamos a usar un dataset público de los buses de Nueva York, donde hay más de 300 buses y 5,800 vehículos siguiendo las rutas. ![](https://i.imgur.com/vZz1mcU.png) Este archivo está en formato SequenceFile que es un archivo plano, binario con pares key/value. Es muy usado por MapReduce en Apache Hadoop. ![](https://i.imgur.com/1A1ZbA6.png) El dataset contiene Nombre Destino, id vehículo, latitud, longitud, tiempo de llegada esperado, tiempo de llegada planificado. Este dataset se construyó con snapshots tomados cada 10 minutos en Junio 2017. ![](https://i.imgur.com/PxrpYEF.png) El esquema tendrá como row key: [compañía bus/línea bus/Timestamp redondeado a la hora/ID vehículo] Tendremos una familia de columnas, por simplicidad. Mire este link para saber más sobre el diseño de los esquemas [Link](https://cloud.google.com/bigtable/docs/schema-design) **Crear instancia, tabla y familia** En un nuevo proyecto, activa el cloud shell y setea las siguientes variables de entorno, reemplazando ID_PROYECTO con el tuyo: ``` INSTANCE_ID="bus-instance" CLUSTER_ID="bus-cluster" TABLE_ID="bus-data" CLUSTER_NUM_NODES=3 CLUSTER_ZONE="us-central1-c" GOOGLE_CLOUD_PROJECT="ID_PROYECTO" ```` Primero, vamos a habilitar las APIs que usaremos con el siguiente comando (Esto también lo puedes hacer por consola, buscando las dos APIs y poniendo Enable): ``` gcloud services enable bigtable.googleapis.com bigtableadmin.googleapis.com ``` Para crear una instancia usaremos el comando gcloud de la siguiente manera: ``` gcloud bigtable instances create $INSTANCE_ID \ --cluster-config=id=$CLUSTER_ID,zone=$CLUSTER_ZONE,nodes=$CLUSTER_NUM_NODES \ --display-name=$INSTANCE_ID ``` Por consola Web sería, ir en menú de navegación a BigTable y crear instancia, luego: ![Screenshot 2024-09-25 at 15.15.35](https://hackmd.io/_uploads/r1QeVCWCC.png) ![Screenshot 2024-09-25 at 15.16.22](https://hackmd.io/_uploads/Hkqe4AW0R.png) ![Screenshot 2024-09-25 at 15.16.56](https://hackmd.io/_uploads/rybbERW0R.png) ![Screenshot 2024-09-25 at 15.17.22](https://hackmd.io/_uploads/S1tbEAZC0.png) Cloud BigTable tiene un archivo de configuración, le pondremos la configuración del proyecto e instancia y luego crearemos una tabla y una familia de columnas, llamada cf. ``` echo project = $GOOGLE_CLOUD_PROJECT > ~/.cbtrc echo instance = $INSTANCE_ID >> ~/.cbtrc cbt createtable $TABLE_ID cbt createfamily $TABLE_ID cf ``` Por consola esto sería ir a Tablas -> +CREAR TABLA: ![Screenshot 2024-09-25 at 15.19.55](https://hackmd.io/_uploads/SJIuNCWRR.png) Y luego llenar los datos: ![Screenshot 2024-09-25 at 15.21.20](https://hackmd.io/_uploads/SJxaNCZRA.png) **Importar datos** El dataset utilizado está en Cloud Storage en gs://cloud-bigtable-public-datasets/bus-data Para importarlo usaremos un trabajo de Dataflow, por lo que habilitamos la API de la siguiente manera: ``` gcloud services enable dataflow.googleapis.com ```` Además, agregaremos permisos en el servicio IAM para que nuestro proyecto puedo leer datos de Cloud Storage, donde está el dataset. Para esto en el menu de navegador selecciona IAM > IAM. ![Screenshot 2024-09-25 at 15.22.37](https://hackmd.io/_uploads/HkRgrCZCC.png) Edita los permisos de Compute Engine default service account: ![Screenshot 2024-09-25 at 15.25.24](https://hackmd.io/_uploads/rkeHjSCZ00.png) Y agrega los roles de Trabajador deDataflow, Usuario de Bigtable, Visualizador de objetos de Storage, Creador de objetos de Storage. Luego presiona Guardar. ![Screenshot 2024-09-25 at 15.29.32](https://hackmd.io/_uploads/ByTsURW00.png) El comando que utilizaremos para lanzar el trabajo en Dataflow es: ``` NUM_WORKERS=$(expr 3 \* $CLUSTER_NUM_NODES) gcloud beta dataflow jobs run import-bus-data-$(date +%s) \ --gcs-location gs://dataflow-templates/latest/GCS_SequenceFile_to_Cloud_Bigtable \ --num-workers=$NUM_WORKERS --max-workers=$NUM_WORKERS --region 'us-central1' \ --parameters bigtableProject=$GOOGLE_CLOUD_PROJECT,bigtableInstanceId=$INSTANCE_ID,bigtableTableId=$TABLE_ID,sourcePattern=gs://cloud-bigtable-public-datasets/bus-data/* ```` Puedes monitorear el avance del trabajo en la consola de Dataflow, seleccionándolo del menu de navegación. Veremos algo como esto: ![Screenshot 2024-09-25 at 15.31.46](https://hackmd.io/_uploads/BkSmvCZAR.png) Este trabajo también lo podemos lanzar por interfaz gráfica, accediendo a Dataflow, + CREAR TRABAJO A PARTIR DE UNA PLANTILLA, llenar los datos y luego EJECUTAR TRABAJO. La plantilla es SequenceFile Files on Cloud Storage to Cloud BigTable. ![Screenshot 2024-09-25 at 16.08.30](https://hackmd.io/_uploads/SJC1gyfA0.png) ![Screenshot 2024-09-25 at 16.08.42](https://hackmd.io/_uploads/SJExx1GRR.png) Si haz hecho los pasos por consola y por interfaz gráfica a la vez, antes de pasar a la siguiente sección borra una de las instancias que hemos creado. **Consultar los datos** Vamos a crear una pequeña aplicación en Python para conectarnos a Cloud BigTable y consultar los datos, mediante un lookup de una key de fila y un scan en un rango de key de filas. Primero crearemos una carpeta y un archivo llamado requirements.txt: ``` mkdir querycbt cd querycbt nano requirements.txt ```` El archivo requirements.txt tendrá lo siguiente, que son las librerías que ocupará el programa de python. ``` protobuf==3.20.1 google-cloud==0.34.0 google-cloud-bigtable==2.10.0 google-cloud-core==2.3.0 ``` Luego crearemos un Virtual Environment de Python [Link creación ambientes virtuales](https://packaging.python.org/en/latest/guides/installing-using-pip-and-virtual-environments/) ``` python3 -m pip install --user virtualenv python3 -m venv env source env/bin/activate python3 -m pip install -r requirements.txt ``` [Link ejemplos leer de BigTable en Python](https://github.com/googleapis/python-bigtable/blob/HEAD/samples/snippets/reads/read_snippets.py) Luego crearemos el archivo main.py. El archivo tendrá lo siguiente: ```python= import argparse import datetime from google.cloud import bigtable from google.cloud.bigtable import column_family from google.cloud.bigtable import row_filters from google.cloud.bigtable.row_set import RowSet # Funcion que imprime los resultados de una fila, # recuerde que una fila en cloud BigTable es tridimensional. # Recuerde ademas que los datos no estan en texto plano def print_row(row): print("Reading data for {}:".format(row.row_key.decode("utf-8"))) for cf, cols in sorted(row.cells.items()): print("Column Family {}".format(cf)) for col, cells in sorted(cols.items()): for cell in cells: labels = ( " [{}]".format(",".join(cell.labels)) if len(cell.labels) else "" ) print( "\t{}: {} @{}{}".format( col.decode("utf-8"), cell.value.decode("utf-8"), cell.timestamp, labels, ) ) print("") # En esta función esta la conexion y las consultas def main(project_id, instance_id, table_id): # Conexion a la base de datos client = bigtable.Client(project=project_id, admin=True) # Obtencion de instancia y tabla instance = client.instance(instance_id) table = instance.table(table_id) # Lookup: el lookup busca la fila asociada a una clave de fila row_key = "MTA/M86-SBS/1496275200000/NYCT_5824" # Este comando lee la fila completa que coincida con row_key row1= table.read_row(row_key.encode("utf-8")) #Este comando aplica filtros para mejorar rendimiento # No lee la fila completa sino solo lasa columnas indicadas row2 = table.read_row(row_key.encode("utf-8"), filter_ = row_filters.ColumnQualifierRegexFilter("VehicleLocation.*".encode("utf-8"))) print("Lookup 1") print_row(row1) print("\nLookup 2\n") print_row(row2) # Scan: entrega todas lasa filas desde la fila de inicio # hasta la del final print("\nScan\n") key_start = "MTA/M86-SBS/1496275200000".encode("utf-8") key_end = "MTA/M86-SBS/1496300000000".encode("utf-8") # El scan no devuelve una fila, sino un RowSet row_set = RowSet() row_set.add_row_range_from_keys(start_key=key_start, end_key=key_end) rows =table.read_rows(row_set=row_set) # Imprimo todas las filas for row in rows: print_row(row) # MAIN Recibe y parsea Argumentos if __name__ == "__main__": parser = argparse.ArgumentParser( description=__doc__, formatter_class=argparse.ArgumentDefaultsHelpFormatter ) parser.add_argument("project_id", help="Your Cloud Platform project ID.") parser.add_argument( "instance_id", help="ID of the Cloud Bigtable instance to connect to." ) parser.add_argument( "table_id", help="Table to create and destroy." ) args = parser.parse_args() main(args.project_id, args.instance_id, args.table_id) ``` Vamos a ir haciendo las consultas una a una, comentando las otras para tener orden en los resultados. Ejecuto el programa en python con: ``` python3 main.py GOOGLE_PROJECT_ID bus-instance bus-data ``` Los resultados serán de la siguiente forma: ![](https://i.imgur.com/imtP7He.png) En el siguiente link pueden encontrar la documentación completa de Cloud BigTable para seguir experimentando [Link](https://cloud.google.com/bigtable/docs/samples/). **Recuerda borrar la instancia de Bigtable y apagar el proyecto.** ``` gcloud bigtable instances delete $INSTANCE_ID ```