Vamos a explicar que es Delta Live Tables, y diferenciarlo de otros términos parecido del campo, así como la implementación de Unity Catalog, cómo es desarrollar con Delta Live Tables y las ventajas y desventajas que nos hemos encontrado.
¡Comenzamos!
Delta Live Tables busca acelerar la transformación de datos y generación de modelos, permitiendo al Data Engineer centrarse en la parte de código, apoyándose en el resto de las herramientas que tiene Databricks, como la parte de repositorio; para el versionado del código, Unity Catalog; para Data Governance o la facilidad de cambiar entre entornos desde su pipeline.
Delta Live Table es un Framework o acelerador de trabajo, que busca, que tú, como ingeniero, enfoques la mayor parte del tiempo de desarrollo en el código de transformación y modelado y no tanto en la parte de control o permisos, pero antes de meternos más en profundidad, es importante no confundirlo con otros términos del campo, como Delta Lake, Delta Table o incluso Parquet, ya que estos elementos están relacionados con el almacenamiento del dato, no con el código en sí.
Aquí nos centraremos en Delta Live Table, ya que de los otros elementos también se podría escribir un blog entero, pero un breve resumen de los otros elementos podría ser:
- Delta Lake: Es una capa de almacenamiento optimizada que proporciona las bases para la creación de Delta Tables, es decir, el sitio en el que guardas los datos o archivos.
- Delta Tables: Es el conjunto de datos/archivos que conforman una tabla, son una extensión de los archivos Parquet, a los cuales les otorga una capa extra de metadata que nos permite realizar transacciones ACID, operaciones DML o Time Travel.
- Parquet: Es el archivo base que contiene los datos en sí, que están especializados para el Big Data, por ser archivos columnares, es decir, los datos de cada columna se guardan de forma consecutiva, permitiendo una mejor compresión, pues permite tipar cada columna y no guardar la fila como un solo ente, reduciendo así el tamaño del archivo, tener metadata de cada columna, o si no se quieren leer todas las columnas, guardar en memoria solo las columnas seleccionadas.
Ahora ya metiéndonos más con Delta Live Tables, o DLT, vamos a intentar explicar cómo Databricks busca que te centres más en la parte de código apoyándose del resto de sus características.
1. Repos: para el versionado de código y tener el histórico de cambios, y poder volver atrás de ser necesario.
2. Unity Catalog: para Data Discovery y Data Governance, es decir, la parte de permisos y visibilidad del dato.
3. Databricks Workflows: para programar la orquestación.
4. Expectations: Para la parte de Data Quality.
5. Full Refresh: permite recargar y reprocesar todos los datos.
6. Dependency Managment: DLT busca las dependencias entre tablas para poder gestionar mejor la paralelización de las ingestas y que las cargas se hagan en orden.
7. Incremental Computation: DLT se encarga de gestionar los archivos cargados y de la incrementalidad de las tablas.
Documentación oficial: Delta Live Tables
¿Cómo funciona?
En Delta Live Table, los pipelines son el centro de todo, es donde se indican los notebooks a ejecutar y la orquestación de estos. En los notebooks se definan las consultas, ya sea en Python o SQL, que determinan el contenido de las tablas que se van a crear, pero el mantenimiento y la carga de estas se encarga DLT, ya que cómo tal, no puedes ejecutar el código de forma independiente, solo desde el propio pipeline, en el cual podrás ver las tablas que se definieron y el linaje entre ellas.
Es importante saber que la forma en que definas las consultas determina el tipo de tablas que se crean: Streaming Tables o Materialized Views.
- Streaming tables: están pensadas para orígenes stream o procesamientos incrementales, y principalmente para orígenes de tipo append, aunque también son el tipo de tabla, como target, que permite realizar un apply_changes(), que sería la opción de Upsert, para ingestar nuevos registros, actualizar registros existentes e incluso limpiar duplicados.
- Materialized Views: se podría resumir como las vistas normales de SQL, que definen el contenido de la tabla, pero son lo suficientemente potentes para manejar los cambios realizados en las tablas de las que depende y recalcular el contenido para mostrar siempre el dato más actualizado.
Estructura medallón
Una de las formas más comunes para almacenar el dato, es la estructura medallón, que se compone de tres capas: Bronze, Silver y Gold. Por lo que teniendo en cuenta los tipos de tabla mencionados en el anterior, una forma de definir y guardar los datos podría ser la siguiente.
- Bronze: Straming Table, va a almacenar todo el histórico de datos, por lo que ir guardando los datos según lleguen es lo ideal.
- Silver: Streaming Table, va a permitir leer los datos según lleguen a la capa Bronze, y junto al método apply_changes y las expectations (restricciones), va a permitir quitar los duplicados, actualizar los registros y limpiar los datos según las restricciones que se pongan, estilo que la PK no sea NULL o un límite de fecha.
- Gold: Materialized Views, ya que es la capa en la que se realizan los cálculos de negocios y las agregaciones, y para eso es importante tener todo el conjunto de datos para realizar los cálculos.
Creación del Pipeline de Delta Live Table
La parte que se encarga de todo el proceso son los Pipelines, que cuando los creas puedes indicar las configuraciones de este, una de las opciones es donde guardar el dato, Hive Metastore o Unity Catalog, que es la opción que vamos a utilizar nosotros y sobre la que vamos a hablar. Es importante tener en cuenta que, una vez creas el pipeline, el Catálogo, NO puedes modificarlo, pero sí el Schema (Database) en el que se guardan los datos. También puedes seleccionar el modo del Pipeline, ya sea Triggered, para ejecuciones por Lotes o Continuous, ejecuciones en Real Time.
También es la parte donde seleccionas el Source Code, que son los notebooks que crean las tablas, la configuración del Clúster que va a ejecutar dicho pipeline o incluso poner notificaciones al correo.
Una vez creado, ya verás toda la parte visual, y en la parte central, una vez ejecutados los notebooks, es donde verás las tablas y su linaje.
Nootebooks: código de cada capa
Ahora que tenemos unas nociones básicas de todo, vamos a entrar más en detalle en la parte del código para cada capa.
- Bronze: en esta capa leeremos los datos que vayan llegando al origen de datos, en nuestro caso, un Volumen de Unity Catalog, que iremos leyendo con el AutoLoader, que se encargará de ir manteniendo los archivo que ya se hayan cargado para no volver a cargarlos e ir cargando solo los nuevos.
- Silver: En esta capa también utilizaremos una Streaming Table, ya que nos permite realizar un apply_changes(), que recordemos, es una versión de Upsert para Delta Live Tables, y además usaremos expectations, que son restricciones que ponemos, para en caso de que no la cumpla, el registros se elimine, falle o simplemente salte un aviso en el pipeline. Para nuestro caso, para simplificar, creamos un diccionario para todas las tablas en el que indicamos la PK (Para actualizar registros, o eliminar duplicados), el Sequence By, que es la columna que usamos como criterio para obtener el último registro para cada PK, y las expectations, en el caso de la captura, hemos indicado dos, pero para el resto de las tablas, sólo la de valid_pk.
- Gold: en este caso, trabajaremos con Materialized Views, ya que es la capa en la que realizaremos las agrupaciones y los cálculos de agregaciones de negocio.
En base al código que acabo de mostrar, te preguntarás como sé que tipo de tabla se ha creado o como le indico si es una Materialized Views o una Streaming Table. Lo primero es fácil de ver, en la parte visual de DLT, dentro de Databricks -> Data Engineering -> Delta Live Table -> Nuestro Pipeline, te mostrará todo el linaje de las tablas, y cuando pinchas en un cuadro, que hacen referencia a las tablas que se han creado en el código, en los detalles de cada tabla, a la derecha, se indica de que tipo es.
Bronze:
Silver:
Gold:
Ahora que hemos visto dónde se puede ver el tipo de tabla, a excepción de la capa Silver, que se indica claramente con dlt.create_streaming_table(), en las capas de Bronze y Gold, no se indica que tipo de tabla es, y aun así, las ha creado de distinto tipo, y eso es porque el decorator @dlt.table(), según se defina la consulta y como se lean los datos de origen, deduce el formato de la tabla final:
- Bronze: en esta capa estamos leyendo datos con AutoLoader, por lo que está leyendo datos en forma Stream, y entonces se crea una Streaming Table.
2. Silver: en este caso, se indica claramente que es una Streaming Table a la hora de crear la tabla con el método dlt.create_streaming_table().
3. Gold: en esta capa se está utilizando el método read(), que lee todo el origen, por lo que crea una Materialized View, si utilizase el método dlt.read_stream(), crearía una Sreaming Table.
¿Como se puede saber esto? Si, por ejemplo, dentro del Notebook, clicas en el método y pulsas F12, te enseñará el Source Code y la descripción del mismo y para cada tipo de lectura:
- dlt.read()
- dlt.read_stream()
Es importante saber que una vez creas una tabla en un formato, si después cambias la consulta para que se utilice el otro, saltará un error, por lo que tendrás realizar un reproceso FULL para sobrescribir la tabla y que la vuelva a crear.
Ejecución del Pipeline
Una vez quieras ejecutar el código, es muy sencillo, desde el pipeline, arriba a la derecha hay diferentes botones, y uno de ellos es para ejecutarlo.
- Start: Permite ejecutar el pipeline de forma incremental
- Full refresh all: permite recargar y crear de 0 todas las tablas.
- Development/Production: es un botón toggle que permite seleccionar el modo de trabajo, la principal diferencia está en el tiempo de apagado y que el esquema interno de trabajo del pipeline, son distintos.
- Settings: Permite modificar algunas propiedades del pipeline, por si las quieres cambiar después de su creación, y añadir nuevos notebooks según vas desarrollando y probando.
- Schedule: permite programar la ejecución del Pipeline.
- Select tables for refresh: justo encima del gráfico de linaje, está este botón, que abre una nueva ventana, que permite seleccionar las tablas que quieres ejecutar o recargar desde 0, en los botones que aparecen abajo a la derecha.
Ventajas
Desventajas
Conclusión
Es una herramienta potente que puede ayudar a los desarrolladores a centrarse en el código y acelerar el desarrollo de las consultas, es muy visual y es sencillo de cambiar entre entornos de desarrollo de DEV y PRO, es solo un botón. Pero también nos hemos encontrado con algunas limitaciones, sobre todo a la hora de guardar los datos, ya que cuando utilizas Unity Catalog, todo el tema del almacenamiento lo gestiona el propio sistema, sólo hay dos tipos de tablas y el hecho de separar, física y visualmente, los datos y archivos de las diferentes capas, que puede llegar a hacer demasiado lioso el trabajar con los esquemas si la cantidad de tablas escala demasiado.
Por lo que, por ahora, para proyectos pequeños o medianos, diría que es una herramienta idónea y que se ha de tener en cuenta para los desarrollos de ETL, ya que busca la máxima optimización del clúster.