• Skip to primary navigation
  • Skip to main content
  • Skip to footer
Bluetab

Bluetab

an IBM Company

  • SOLUTIONS
    • DATA STRATEGY
    • Data Readiness
    • Data Products AI
  • Assets
    • TRUEDAT
    • FASTCAPTURE
    • Spark Tune
  • About Us
  • Our Offices
    • Spain
    • Mexico
    • Peru
    • Colombia
  • talent
    • Spain
    • TALENT HUB BARCELONA
    • TALENT HUB BIZKAIA
    • TALENT HUB ALICANTE
    • TALENT HUB MALAGA
  • Blog
  • EN
    • ES

Tech

MICROSOFT FABRIC: Una nueva solución de análisis de datos, todo en uno

October 16, 2023 by Bluetab

MICROSOFT FABRIC: Una nueva solución de análisis de datos, todo en uno

Deygerson Méndez

Data Engineer

En el dinámico mundo empresarial actual; la tecnología es la clave para la innovación y el éxito. Por ello, si estás buscando una forma fresca y emocionante de potenciar las capacidades de análisis de datos de tu organización, estás en el lugar correcto.

En el siguiente artículo te contaremos desde bluetab, nuestra experiencia sobre Microsoft Fabric, la nueva solución de análisis que nos ofrece este big player tecnológico. Con ella podemos abarcar todo el ciclo de vida del dato, es decir, desde el movimiento de datos pudiendo crear pipelines para la ingesta, hasta la transformación y carga de los mismos. A su vez, el análisis en tiempo real, la inteligencia empresarial, la gobernanza y el cumplimiento, todo ello en un mismo espacio de trabajo; además de contar con herramientas de inteligencia artificial integradas, que nos ayudan a generar soluciones basadas en información en un menor tiempo.

 

¿Qué es Microsoft Fabric?

La documentación oficial de Microsoft describe el servicio como “no es solo otra solución tecnológica, sino una plataforma integral diseñada para simplificar y optimizar sus procesos empresariales mediante una infraestructura moderna, la cual se presenta, como una solución altamente integrada y fácil de usar”. 

Microsoft Fabric está basado, en un modelo de Software como Servicio (SaaS) que lleva la simplicidad y la integración a un siguiente nivel. 

A la vez, ofrece un conjunto completo de servicios, que incluye un lago de datos unificado denominado OneLake, que permite mantener los datos en su lugar mientras utiliza sus herramientas de análisis preferidas, e incorpora servicios nuevos y existentes como Power BI, Azure Synapse Analytics y Azure Data Factory en un entorno unificado.

Es importante mencionar que está integración nos ofrece grandes ventajas, como, por ejemplo:

  • Amplia gama de capacidades integradas: Esto quiere decir que proporciona una suite completa de capacidades de análisis profundamente integradas, abarcando desde la ingeniería de datos, la ciencia de datos y el análisis en tiempo real.
  • Toma decisiones informadas: Gracias a la analítica avanzada de Microsoft Fabric, podrá tomar decisiones basadas en datos sólidos, impulsando así su estrategia empresarial.
  • Más eficiencia, menos esfuerzo: Al automatizar procesos repetitivos, Microsoft Fabric le libera para que pueda concentrarse en tareas más importantes y creativas.
  • Colaboración sin fronteras: La capacidad de colaborar en tiempo real entre equipos, independientemente de su ubicación, fomenta la creatividad y la innovación.
  • Gestión y gobernanza centralizadas: Con una sólida administración, Microsoft Fabric ofrece gobernanza y control en todas las experiencias.

 

Herramientas especializadas para cada necesidad:

Conviene especificar que, Microsoft Fabric nos ofrece un conjunto completo de experiencias de análisis diseñadas para trabajar conjuntamente sin problemas, cada una de ellas se adapta a un rol y tarea específica:

  • OneLake: Proporciona una ubicación unificada para almacenar todos los datos de la organización, donde se dan las experiencias. 

 

  • Synapse Data Warehousing: Ofrece un rendimiento líder en SQL y separa el proceso de almacenamiento, escalando independientemente cada componente.

Synapse Data Engineering: Proporciona una plataforma Spark de primer nivel, para transformar datos a gran escala y democratizar el uso de los datos.

  • Data Factory: Combina la simplicidad de Power Query con la potencia de Azure Data Factory, conectándote a más de 200 orígenes de datos.
  • Synapse Data Science: Permite crear, implementar y desplegar modelos de aprendizaje automático con facilidad, conectándose a Azure Machine Learning.
  • Synapse Real-Time Analytics: Puede transmitir grandes volúmenes de datos a la base de datos de KQL, con una latencia de pocos segundos, después usar un conjunto de consultas KQL para analizar y visualizar los resultados en informes de Power BI.
  • Power BI: La plataforma líder en inteligencia empresarial que permite tomar decisiones fundamentadas basadas en los datos.

Reducción de costos a través de capacidades unificadas:

En la actualidad, es común que los sistemas analíticos fusionen productos de diversos proveedores en un solo proyecto. Operando de forma independiente, implica una distribución de capacidad de cómputo en múltiples sistemas. Cuando uno de estos sistemas no se encuentra en uso, su potencial queda inhabilitado, lo que genera un notable desperdicio de recursos.

Fabric simplifica de manera significativa, la adquisición y gestión de recursos, ya que tendrás la posibilidad de adquirir un único conjunto de recursos computacionales, que potencian todas las operaciones, generando una reducción sustancial de costos, dado que cualquier unidad de cómputo sin uso puede ser aprovechada por cualquier otra operación. 

 

Impulsado por inteligencia artificial:

Gracias a la integración de Copilot (asistente de programación impulsado por inteligencia artificial desarrollado por GitHub), tendrás la capacidad de utilizar el lenguaje conversacional para desarrollar flujos, pipelines de datos, generar código, idear modelos de aprendizaje automático o visualizar los resultados obtenidos. Incluso podrás crear tus propias experiencias de lenguaje conversacional que combinen los modelos de Azure OpenAI Service.

 

Para conocer más acerca del servicio podrías ingresar al siguiente enlace: 

https://www.microsoft.com/es-es/microsoft-fabric

 

Entonces, ¿estás preparado para dar el salto? 

Aunque Microsoft Fabric se encuentra en su fase de prelanzamiento, ha sido meticulosamente diseñado para desafiar las convenciones y llevar a su empresa a un nivel completamente nuevo. 

Puedes suscribirte a la evaluación gratuita del servicio, sin necesidad de suministrar información de una tarjeta de crédito, en el siguiente enlace: https://learn.microsoft.com/es-es/fabric/get-started/fabric-trial

 

A modo de conclusión, Microsoft Fabric puede agregar valor y a la vez estarás listo para afrontar nuevos retos, crear experiencias excepcionales para tus clientes y alcanzar los objetivos en el análisis empresarial que son demandados por tu organización. 

Mediante su uso, los usuarios tendrán la capacidad de emplear un único producto que posee una estructura y experiencia cohesionadas, otorgando todas las competencias esenciales para que los desarrolladores extraigan conocimientos de los datos y los presenten a los interesados comerciales. 

Gracias a su enfoque (SaaS), todos los aspectos se fusionan y ajustan de manera automática, habilitando a los usuarios a registrarse rápidamente y empezar a obtener un valor empresarial tangible en cuestión de minutos. En Bluetab América, an IBM Company, nos encontramos entusiasmados por el potencial de esta nueva solución y estamos preparados con el mejor staff de profesionales, para ser un aliado estratégico en la implementación de este emocionante servicio.

Deygerson Méndez

Data Engineer

¿Quieres saber más de lo que ofrecemos y ver otros casos de éxito?
DESCUBRE BLUETAB

SOLUCIONES, SOMOS EXPERTOS

DATA STRATEGY
DATA FABRIC
AUGMENTED ANALYTICS

Te puede interesar

Some of the capabilities of Matillion ETL on Google Cloud

July 11, 2022
LEER MÁS

Databricks on AWS – An Architectural Perspective (part 2)

March 5, 2024
LEER MÁS

Essential features to consider when adopting a cloud paradigm

September 12, 2022
LEER MÁS

$ docker run 2021

February 2, 2021
LEER MÁS

Snowflake, el Time Travel sin DeLorean para unos datos Fail-Safe.

February 23, 2023
LEER MÁS

Using Large Language Models on Private Information

March 11, 2024
LEER MÁS

Filed Under: Blog, Tech

Azure Data Studio y Copilot

October 11, 2023 by Bluetab

Azure Data Studio y Copilot

Marco LLapapasca

Enterprise Architect

La inteligencia artificial (IA) ha dejado de ser un mero concepto futurista para convertirse en una realidad tangible que está transformando la forma en que las empresas operan y cómo los profesionales tecnológicos desarrollan soluciones. 

Esta revolución no se limita únicamente a la automatización de tareas o a la creación de asistentes virtuales; va más allá, redefiniendo paradigmas y abriendo puertas a posibilidades antes inimaginables.

En el ámbito empresarial, la IA está potenciando la toma de decisiones, optimizando procesos y creando nuevas oportunidades de negocio. Para quienes están al frente del desarrollo tecnológico, representa una herramienta que amplía la creatividad, mejora la eficiencia y redefine los límites de lo que es posible.

Desde la perspectiva de Bluetab, expertos en el manejo y análisis de datos, es evidente que la IA está reconfigurando el panorama de la tecnología de la información. Una muestra clara de esta transformación es la reciente innovación conocida como “Copilot” integrada en Azure Data Studio, una herramienta líder en la administración de bases de datos. 

Esta innovación no solo promete cambiar la forma en que desarrollamos código, sino que también augura un futuro donde la sinergia entre la IA y la gestión de datos desbloqueará potenciales que hoy apenas comenzamos a vislumbrar.

En este contexto, es esencial comprender cómo la inteligencia artificial está moldeando el mundo tecnológico y empresarial, y cómo en empresas como Bluetab estamos al frente de esta revolución, aprovechando las oportunidades y enfrentando los desafíos que presentan, con visión, talento y casos que han sido puesto a prueba.

¿Qué es Copilot?

Copilot es un asistente de programación impulsado por inteligencia artificial desarrollado por GitHub, que fue presentado al público a mediados del 2021. Este asistente ha sido diseñado con un propósito principal: ofrecer sugerencias de código en tiempo real mientras estás desarrollando un programa. Pero, ¿qué es lo interesante? Es que se basa en el contenido previamente escrito para anticiparse a tu próximo paso.

El corazón de Copilot es Codex, un sistema que opera de forma similar a GPT-3. Codex tiene la capacidad de comprender el contexto proporcionado por el código del usuario y, a partir de ello, sintetizar nuevas líneas de código que se alineen con las intenciones del programador.

La conexión con Microsoft

GitHub, la empresa detrás de Copilot, fue adquirida por Microsoft en junio de 2018. No sorprende, entonces, que Copilot haya sido integrado en la suite de aplicaciones Microsoft 365, siendo útil en herramientas como Word, Excel, PowerPoint, Outlook, Teams, entre otras.

Link: https://news.microsoft.com/es-xl/presentamos-microsoft-365-copilot-su-copiloto-para-el-trabajo/

Copilot y Azure Data Studio

El poder de Copilot no se limita a las aplicaciones de ofimática. Como hemos comentado, ahora también ha sido integrado en Azure Data Studio. Esta herramienta es una solución multiplataforma de código abierto que facilita la creación y administración de bases de datos en SQL, T-SQL, sql cmd y PowerShell. Es compatible con Windows, macOS y Linux, haciendo que la herramienta sea extremadamente versátil, ideal tanto para proyectos heredados on premise como para aquellos basados en la nube.

¿Cómo comenzar?

Si estás listo para experimentar esta integración, sigue estos pasos:

  • Instalación de Azure Data Studio:
    Comienza por descargar e instalar Azure Data Studio. Puedes hacerlo directamente desde Link: https://learn.microsoft.com/en-us/sql/azure-data-studio/download-azure-data-studio?view=sql-server-ver16&tabs=redhat-install%2Credhat-uninstall
  • Configura la de conexión.
    Una vez instalado, agregar una nueva conexión SQL. New -> New connection

Como nosotros, vas a realizar una conexión local a Microsoft SQL Server, la cadena de conexión debería lucir así: Server=localhost\SQLEXPRESS01;Database=master;Trusted_Connection=True; 

Finalmente, nos debería quedar de la siguiente forma:

  • Instalación de extensiones:
    Azure Data Studio cuenta con una variedad de extensiones que potencian su funcionalidad. Procede a instalar y configurar la extensión que necesites para tu proyecto. En nuestro caso vamos a utilizar la extensión de:

    GitHub Copilot: Ofrece sugerencias de código en tiempo real. Puedes obtener sugerencias simplemente comenzando a escribir el código que deseas, o incluso escribiendo un comentario en lenguaje natural que describa lo que deseas que haga el código.
  • Configuración de la base de datos Northwind:
    Con Azure Data Studio ya configurado, es el momento perfecto para instalar la base de datos de ejemplo Northwind. Esta base es ideal para familiarizarte con las funcionalidades del programa. Puedes encontrar las instrucciones detalladas para su instalación en Link: https://gist.github.com/jmalarcon/e98d20735d17b3160766c041060d1902

Finalmente, tendremos la base de datos Northwind instalada:

Ahora, vamos a probar Copilot.

  • Definición y prueba de recomendaciones de Copilot:
    Vamos a interpretar y definir el comentario “/* agrupar y mostrar la cantidad de productos por categoría */”. Al hacerlo, pondremos a prueba las sugerencias que Copilot nos ofrece, para evaluar su precisión y relevancia.
  • Generación automática de script:
    Es impresionante observar cómo, con la ayuda de herramientas avanzadas, se nos presenta un script generado automáticamente, manteniendo una sintaxis SQL impecable.
  • Visualización del script generado:
    Tras seguir las recomendaciones y ajustes, así es como luce nuestro script final.
  • Abordando el error de “Invalid object name ‘dbo.categoria'”:
    Al ejecutar nuestro script, nos topamos con un obstáculo: el error “Invalid object name ‘dbo.categoria’.”. Un análisis minucioso de las tablas ‘Categories’ y ‘Products’ revela discrepancias en la nomenclatura. Es esencial asegurarse de que los nombres de las tablas y columnas sean consistentes para evitar este tipo de problemas. 

¿A qué se debe esto?

Las herramientas basadas en inteligencia artificial, como Copilot, necesitan ser correctamente configuradas. En términos más sencillos, debemos “entrenarlas” o, de manera más precisa, proporcionarles la metadata de cada tabla. Al hacerlo, permitimos que la IA tome en cuenta esta información para hacer sugerencias más precisas y coherentes al momento de generar scripts.

La solución es sencilla y directa. Al ejecutar una consulta ‘SELECT’ en cada tabla involucrada, Copilot procederá automáticamente a escanear la tabla y recoger su metadata. Una vez obtenida esta información, la herramienta estará más informada y alineada con la estructura real de nuestra base de datos, permitiéndonos trabajar con mayor precisión y evitando inconvenientes similares en el futuro.

Re-evaluación y recomendaciones ajustadas:
Con las correcciones realizadas, volvemos a probar las recomendaciones. Esta vez, Copilot sugiere un script que considera las columnas correctas, demostrando su capacidad adaptativa

Resultado final:

Con las correcciones implementadas y las recomendaciones ajustadas, obtenemos un resultado final optimizado y preciso.

Estos puntos optimizados ofrecen una narrativa más clara y estructurada, facilitando la comprensión del proceso y los desafíos enfrentados.

La integración de Copilot en Azure Data Studio ha transformado el panorama del desarrollo y administración de bases de datos. Esta herramienta, que promete hacer el trabajo más intuitivo y eficiente, ha demostrado ser un aliado valioso en el ámbito tecnológico. Sin embargo, como toda herramienta, su eficacia radica en cómo se utiliza. A partir de nuestra experiencia en Bluetab, nos gustaría compartir algunas lecciones aprendidas y recomendaciones para maximizar el potencial de Copilot:

  • Verificación de nomenclatura: asegúrese siempre de revisar y validar la nomenclatura de tablas y columnas. Copilot es poderoso, pero también se basa en la consistencia de los datos con los que trabaja.
  • Pruebas continuas: no confíe ciegamente en las recomendaciones automáticas. Siempre es esencial realizar pruebas y validaciones para garantizar que el código generado sea el adecuado para su caso específico.
  • Capacitación continua: aunque Copilot facilita muchas tareas, es vital que los equipos de desarrollo continúen capacitándose y actualizándose en las mejores prácticas de SQL y administración de bases de datos.
  • Feedback activo: al ser una herramienta en constante evolución, proporcionar retroalimentación sobre su experiencia con Copilot puede ayudar a mejorar sus recomendaciones y adaptabilidad en el futuro.


En Bluetab, hemos presenciado y experimentado de primera mano cómo la integración de tecnologías avanzadas como Copilot puede potenciar la productividad de los equipos de desarrollo. Estamos comprometidos con la innovación y con brindar soluciones que estén a la vanguardia tecnológica pero, principalmente, en lograr mayores resultados en un menor tiempo. Esto le permite a nuestros clientes alcanzar retos mas complejos en los tiempos que el mercado lo demanda.

Nuestra misión es llevar estas capacidades y conocimientos al servicio de nuestros clientes, garantizando que puedan aprovechar al máximo las ventajas que la era digital tiene para ofrecer.

Marco LLapapasca

Enterprise Architect

¿Quieres saber más de lo que ofrecemos y ver otros casos de éxito?
DESCUBRE BLUETAB

SOLUCIONES, SOMOS EXPERTOS

DATA STRATEGY
DATA FABRIC
AUGMENTED ANALYTICS

Te puede interesar

Hashicorp Boundary

December 3, 2020
LEER MÁS

¿Existe el Azar?

November 10, 2021
LEER MÁS

Container vulnerability scanning with Trivy

March 22, 2024
LEER MÁS

CDKTF: Otro paso en el viaje del DevOps, introducción y beneficios.

May 9, 2023
LEER MÁS

Serverless Microservices

October 14, 2021
LEER MÁS

De documentos en papel a datos digitales con Fastcapture y Generative AI

June 7, 2023
LEER MÁS

Filed Under: Blog, Tech

LakeHouse Streaming on AWS with Apache Flink and Hudi (Part 2)

October 4, 2023 by Bluetab

LakeHouse Streaming on AWS with Apache Flink and Hudi (Part 2)

Alberto Jaen

AWS Cloud Engineer

Alfonso Jerez

AWS Cloud Engineer

Adrián Jiménez

AWS Cloud Engineer

Introduction

This article is the second in a series of publications focusing on the creation of a LakeHouse with Hudi from a streaming ingest processed by a Flink application. The first article focuses on laying a good foundation for this platform, where Flink applications were deployed with KDA (Kinesis Data Analytics) for each type of format (MoR, CoW for Hudi and JSON) that write the result of this processing into buckets.

The input data was sent in the previous article from a local machine running a Locust application, which can present problems when scaling and processing a high volume of events. In addition, Kinesis Data Analytics applications with Flink present agility problems in their auto-scaling mode. All these new challenges will be solved in this article.

These tables will also be cataloged in Glue, a service that provides a data catalog in AWS, in order to access them and perform queries of all kinds. The query engine that will consume this metadata will be Athena, which provides a scalable, agile and serverless experience to be able to execute queries with SQL or Spark for our tables hosted in S3.

On the other hand, in this article we have also deployed the necessary components to be able to monitor our applications and thus draw conclusions about the speed at which data is ingested and the possible problems to be solved so that the processing has the required latency according to the requirements imposed.

Finally, a performance and latency comparison of the different Flink applications that write data in Hudi and JSON formats will be made in order to see the different advantages and disadvantages of these formats. 

Architecture

Below you can see the high-level architecture that will be deployed:

For a better understanding we are going to explain it from left to right. As you can see, the most notable change with respect to the first article is the inclusion of a Kubernetes cluster to be able to scale the events that will be sent as input to our streaming application. In this way, it will be possible to thoroughly test the performance of Flink applications depending on their provisioning and especially on the type of format and table in which they write to the LakeHouse. In addition, an ALB (Application Load Balancer) has been made available to access the Locust interface to define the number of users to simulate and how they should scale over time. The URL to access this will appear as output when deploying the infrastructure with Terraform.

On the other hand, significant changes have been made to the Flink KDA applications and the stream they read from. Each application now reads as EFO (Enhanced Fan Out) consumers, so that each of them has a dedicated bandwidth. The reason for this change and its details will be explained in more detail in the dedicated section for Kinesis.

Regarding the monitoring and extraction of metrics in NRT (Near Real Time), lambdas functions have been deployed that query the tables based on Athena thanks to having registered the metadata of these tables in the Glue catalog. It is important to note that the metadata of Hudi tables are registered in Glue by Flink but in the case of JSON a crawler is deployed that registers these tables in the catalog. This crawler must be executed manually for this table to be registered in Glue.

Scaling

Kinesis Stream

Since the goal is to subject the application to a considerable load of events per second, it is necessary to explain how each of the pieces of the architecture can scale according to the volume of data.

As previously mentioned, a Kinesis Stream On-Demand has been chosen to automate the scaling of the shards during load testing. It should be noted that these streams can accommodate a write rate of up to 200% of that specified by the number of shards at any given time.

Once the stream is above 100%, it will automatically increase the number of shards within 15 minutes. The only limitation is therefore not to exceed twice the supported write volume in less than that period.

On the other hand, since you will have three Flink applications reading from the same stream, read limitations will be the biggest problem. A Kinesis Stream only supports 5 GetRecord calls per shard per second. Since each application has to read the entire stream (and therefore all shards), increasing the number of shards does not help to solve this problem.

The solution is to register each application as an Enhanced Fan-Out consumer. This functionality of the Kinesis Stream provides each of these consumers with an individual limit of 5 GetRecord calls and 2MB per shard per second of reading.

This configuration is done on the consumer side, in our case via the Kinesis connector for Flink:

'scan.stream.recordpublisher' = 'EFO',
'scan.stream.efo.registration' = 'EAGER/LAZY',
'scan.stream.efo.consumername' = '{consumer_name}' 

It is worth mentioning that alternatively, it is possible to increase the read latency of our Flink applications. By default Flink performs a read every 200ms per shard, so one application completely consumes the read quota of a stream. By increasing this value to 600ms we could accommodate all three applications, at the cost of increased latency:

scan.shard.getrecords.intervalmillis = '600' 

Use will also be made of the Adaptive Reads option, which dynamically modifies the number of events collected per call depending on the size of each record. This makes it possible to take advantage of the 2 MB/s per shard available for each consumer:

'scan.shard.adaptivereads' = 'true' 

Regarding scaling in Flink KPUs (Kinesis Processing Unit), we have chosen not to make use of autoscaling, since each scaling process incurs in downtime for the application. Due to the different requirements of each of the applications, scaling actions at unexpected times could interrupt load testing. In addition, it is interesting to measure the write performance of each of the applications at equal computing capacity.

Hudi

Timeline

One of the basic systems on which Hudi’s operation and features are based is the timeline. Hudi keeps a temporary record of all the actions that have been performed on the table, as well as the status of this action.

The main actions that make up the timeline are as follows

  • Commits – atomic writing of a set of records to the table in columnar format
  • Delta Commit – similar to commit, represents a write of records in the form of logs to a Merge on Read table.
  • Compaction – compaction of log writes (delta commits) from a MoR table to columnar format
  • Cleans – deletion of old versions of files
  • Rollback – deleted from records written by a failed commit or delta commit
  • Savepoint – marks a set of files as “saved” so that they will not be deleted by the cleanup process. Allows to restore the table to a previous point in the timeline.

Any of these actions can be found in one of three states

  1. Requested – an action has been planned but not yet started
  2. Inflight – the action is in progress
  3. Completed – denotes that the action has been completed.


Table types

As hinted in the operation of the Hudi timeline, there are two types of writing supported: columnar and logs. The columnar (parquet) format constitutes the final form of a Hudi table, together with the timeline metadata. However, it is possible to make use of log writes (avro) to decrease the write latency and eventually compact to columnar format without hindering the write.

The use of these writing methods gives rise to the two types of table that Hudi makes available to us

  • Copy on Write – writes are performed exclusively in columnar format, creating a new file with the new table records. The data is available immediately but incurs higher write latency.
  • Merge on Read – makes use of writing to logs. The new records are initially written as logs, and will later be transformed to columnar format by the compaction process. We obtain lower write latency at the cost of read latency; the new logs will not be available until compaction is performed.


Query Types

In order to take advantage of the characteristics of each type of table, there are three types of queries that can be performed on a Hudi table

  • Snapshot – obtains the latest version of the table. For MoR tables this involves incurring a compaction process to get the latest records in log format. 
  • Read Optimized – for MoR tables, reads only the records already exposed in columnar format without incurring additional read latency.
  • Incremental – collects only new records since a certain commit or compact, facilitating the creation of incremental pipelines. Not supported by Athena

Integration with Glue Catalog

The Hudi connector allows a native integration with the Glue catalog in AWS. Simply add the Hive dependencies in our Flink application:

com.amazonaws.aws-java-sdk-glue
org.apache.hive.hive-common
org.apache.hive.hive-exec 

And specify the catalog configuration in the Hudi connector:

'hive_sync.enable' = 'true',
'hive_sync.db' = '{glue_database}',
'hive_sync.table' = '{table_name}',
'hive_sync.partition_fields' = '{partition_fields}',
'hive_sync.mode' = 'glue',
'hive_sync.use_jdbc' = 'false' 

With this integration, the application will automatically create the tables in the catalog. As mentioned before, there are different types of queries to query a Hudi table. Therefore, different tables will be created in the catalog to support the different queries.

For a CoW table, the table will be queried using a Snapshot query. For MoR on the other hand, two tables will be made available to support Read Optimized or Snapshot queries.

The main application of Glue is to support lambdas so that when executing queries through Athena their execution can be done in a more efficient, fast and secure way:

  • Glue Catalog: centralized storage of information about the organization, design and format of the data, used by Athena to directly perform queries to S3 without having to rely on third parties to obtain this information.
  • Schema Automation: Glue automatically tracks and catalogs data in S3, detecting and adapting schema changes. This avoids possible errors and allows the reading of new fields in case of alterations in the event schemas.

Hudi configuration

It is important to understand the configurations offered by Hudi to optimize our application, in particular for a Near Real Time application it is convenient to be aware of the available options. Although the configuration capacity is immense [1], we will try to summarize the most relevant ones for a first contact with this technology.

Partitioning

Apache Hudi offers the types of partitioning that can be found in other solutions, the main ones will be detailed and the implemented one will be justified:

  • Simple: partitioning based on a single field, in this case the field chosen is ‘ticker’ as it has been identified as the one with the lowest cardinality.
  • Compound Partitioning: partitioning based on multiple fields, it could be interesting to choose a low cardinality field (ticker) and a medium cardinality field (date).
  • Dynamic Partitioning: choice of the variable based on the values, it can be interesting when the cardinality of the variables can undergo variations and an update of the partitioning is required in an automatic and flexible way.


Indexes

Apache Hudi has multiple types of indexing [2], we will briefly discuss the most common ones:

  • Bloom Index – Makes use of a bloom filter on the key of the events, additionally it can be complemented with a filtering by key range. It works well when dealing with a table where most changes occur in the most recent partitions or for event deduplication.
  • Simple: indexing performed by the combination of FileID and RecordKey. Recommended when Upsert operations are not so frequent due to the simplicity it offers.

Both types of indexes can be used in their global form

  • Global index – They impose the uniqueness of the keys in all the partitions of the table, that is to say, they guarantee that there will be only one record with a certain key.
  • Non-global index – Key uniqueness is only required at the partition level. If the data is consistent and a key is only going to exist in one partition, this type of index offers much better performance and better scaling.

In this case, a Bloom Index has been chosen, which is the default in case it is not expressly stated:

"hoodie.index.type" = "BLOOM" 

The choice of this type of indexing is due to the fact that the use cases that have been raised require a considerably high and efficient data processing.

Types of operations

Apache Hudi offers several types of operations [3] that allow users to manage and modify large data sets. The main operations performed in Stress Tests as well as in other scenarios are detailed below:

  • Upsert – This is the default operation, and will execute an insert or an update depending on whether the record already exists after an index lookup. With this operation the table will have no duplicates for its primary key.
  • Insert – This operation ignores the index lookup when inserting events. It is the fastest but the table may contain duplicates. It is still useful if auxiliary deduplication methods are used, or simply the existence of these is tolerable in the use case.
  • Delete: Hudi offers two deletion methods. Soft Delete converts to null the values of the event except for the key. Hard Delete executes a physical deletion of the event in the table.
  • Bulk Insert Operation similar to Insert but optimized for insertion of a large volume of data, at the cost of sacrificing some guarantees in file size control. Scales well for hundreds of TBs in case of initial bootstrap of a large table.

Compaction

In the case of using a MoR table, it is possible to configure the log compaction rate to find the balance between write and read latency that best suits the use case. It is possible to specify a strategy of time or number of delta commits (or both) that execute a compaction process:

compaction.delta_commits
compaction.delta_seconds
compaction.trigger.strategy 

Asynchronous actions

Certain timeline actions such as compacting, cleaning, archiving and clustering can be performed asynchronously by the application, or even relegated to auxiliary processes to the writing application. In the case of Flink, it can help improve write latency and avoid BackPressure problems in the application:

compaction.async.enabled
hoodie.clean.async
hoodie.archive.async
hoodie.clustering.async.enabled 

Stress Tests & Insights

When deploying the applications, different tests have been performed, varying both the maximum load of events and the concurrency and exponential degree of growth of the same. This has been possible thanks to the flexibility offered by Locust being built on a Kubernetes cluster, being able to set a maximum limit of concurrency of events and an incremental of them. In the tests, a maximum limit of 5 to 15K simultaneous users (Peak Concurrency) has been established, scaling the frequency of the same in a linear way, from 5 to 20 more users per second (Spawn Rate):

The different tests have been monitored in order to draw conclusions about the performance, taking into account the specific characteristics of each of the formats. The metrics on which the analyses have been based are both the native CloudWatch Metrics (CPU & Memory Utilization, KPUs, LastCheckpoint SIze & Duration,…), as well as the metrics obtained from the Lambdas that periodically consult the number of events available in the buckets and calculate the average latency of the same.


Number of Events

When analyzing the total number of events processed, which are sent gradually, i.e., as time passes more and more events are sent per second, a fairly similar trend is identified although JSON and Hudi MoR stand out over Hudi CoW in terms of performance. It is worth noting that JSON shows a more stable and steady growth compared to Hudi MoR and CoW and this is because the latter are able to handle incremental updates in the data.

The similarity between JSON and Hudi MoR makes the choice entirely based on the characteristics of the project. In case the data is not updated JSON may be a more interesting solution mainly due to its simplicity, while if there is a high frequency of historical data update, Hudi MoR may be a better solution. This is due both to the higher efficiency in reading tasks and because of the possibility to record different versions of the data.

Latency

Due to the difficulty of standardizing the latency calculation logic between 3 different types of storage, we have chosen to simplify it by calculating it as the difference between the time of event creation and the time of processing in the respective application.

 

Similar behavior is observed between JSON and Hudi MoR, although the former in a more critical way, having a very low initial latency but as both processing time and load volume increases, this latency is negatively affected.

The choice between JSON and Hudi MoR will depend both on the fault tolerance of the application and the characteristics of each of the formats, in case the data structure is stable and does not change frequently, or does not depend on incremental updates and can deal with complete rewrites, then JSON may be a better choice.

The choice of Hudi CoW over MoR can be made when high error tolerance and high recoverability from failed or corrupted write events are required.


CPU utilization

When analyzing CPU usage, a certain homogeneity has been identified among the different tests, even when working with different workloads. JSON and Hudi MoR stand out for having the lowest CPU usage levels, both for different reasons. JSON stands out for its simplicity by directly including the new data without having to deal with data versioning, while MoR does not consume as much CPU since, due to its characteristics, the highest CPU consumption is made when performing read queries, in the write tasks it only identifies the changes that will be applied when querying them.

Remember that CloudWatch native metrics only allow us to monitor the applications, which correspond to the writing tasks. The monitoring of read tasks corresponds to the Lambdas mentioned above. 

In this case MoR is more beneficial with respect to CoW, since the higher CPU consumption in MoR occurs when querying the stored data while in CoW it occurs when updating the data.

The choice between the most efficient formats depends on the needs of the project, in case a higher fault tolerance, data versioning and higher reading efficiency are required, MoR will be chosen over JSON, between the two Hudi formats, again, the choice will depend on the characteristics of the project, if the queries require heavy and/or complex transformations, MoR would be chosen; if, on the other hand, the project requires greater data integrity and/or the data ingestion is in batch, CoW would be more interesting because when working with these volumes of data, having backup copies, in case of errors, the impact in terms of costs and recovery time is lower.


Memory Utilization

JSON again stands out for having the lowest memory usage values, although for the number of transformations that are performed, they are relatively high, especially considering that it does not have to deal with version management or data merging. These values are due to the fact that it does not have optimized compression capabilities or efficient schema management.

Regarding Hudi, similar conclusions can be drawn as in the CPU usage section, MoR has a higher memory utilization than JSON due to delta log processing and version management and a lower one to CoW since the actual data consolidation does not occur during writing.

 

Last Checkpoint Size

It is important to highlight, once again, the stability of JSON compared to Hudi applications, since it not only shows a lower value than both in the tests performed, but also a stability that is not achieved with either MoR or CoW, since, as can be seen, when monitoring the size of the Checkpoints, considerable volatility is perceived.

Perceived volatility in Hudi applications is mainly due to Checkpoint failures, which leads to a larger Checkpoint volume after the failure. In addition to this, the volatility in Checkpoint sizes may be related to the optimization and compaction operations performed internally that may lead to state compaction, which considerably reduces the size of the Checkpoint.

Development challenges

Read Throughput of Kinesis and EFO

In order not to exceed the read limit on the Kinesis Stream we have chosen to subscribe the consumers as Enhanced Fan-Out. In some tests in conjunction with Autoscaling this has given problems with the Flink Kinesis connector being unable to close connections when scaling the cluster.

Hudi configuration

Hudi’s configuration has been another sticking point during development. Under high loads the compaction and cleanup processes are more likely to cause backpressure problems and cause application errors. Although configuring these processes to occur asynchronously can alleviate this problem, conflicts and misalignment between processes can arise under high loads. A balance between these configurations and the application’s cluster capacity are key to the smooth operation of the application.

Format heterogeneity

When analyzing the performance of the 3 applications, there is an additional difficulty due to the nature of the format types, which has an impact both on the architecture and on the development of the logics.

The different behavior of the formats in the ingest complicates the development oflogics when calculating latency. MoR writes to logs after compaction, so the data is not immediately available as is the case with CoW or JSON.  This implies that the common measurable metric for all formats is read availability, which is not the main purpose of a MoR table.  

Synchronization with the Glue Catalog

One of the great advantages we have found with Hudi is its ability to synchronize with the Glue catalog, creating the tables and keeping them updated without the need for a crawler. This allows for a cleaner application and architecture than in the case of JSON, for which it must be run manually when deploying applications.

Conclusions

The test results show considerable differences between the JSON, Hudi MoR and CoW formats in terms of efficiency, responsiveness and resource utilization. We proceed to analyze each of the aspects in more detail:

  • Processing Efficiency: JSON and Hudi MoR stand out in most metrics, showing optimal performance in terms of Latency, CPU & Memory Utilization. However, JSON behavior is more stable and predictable, although MoR has advantages over JSON, for example, in incremental update management.
  • Resilience and Fault Tolerance: fault tolerance is a very important factor in the decision on the choice between Hudi and JSON. In the case of MoR and CoW, it will depend on the degree of criticality, since at a general level the performance in writing tasks for MoR is superior.
  • Resource Usage: JSON is shown to be the most lightweight, with low CPU and memory utilization, due to its inherent simplicity. Whereas Hudi MoR and CoW, due to the nature of their design and data management, require more resources, especially in operations involving version management and data compaction.

Finally, it is interesting to identify in which use cases or projects each of the formats may be more recommendable depending on their characteristics and the network flags that may be established:

  • JSON: Recommended for applications with stable data structures that do not require incremental updates and where simplicity and stability are key.
  • Hudi MoR: Suitable for projects that require efficient management of incremental updates and where latency and writing efficiency are crucial.
  • Hudi CoW: Ideal for contexts where data integrity is essential, and robust error recovery is needed, especially in batch ingest scenarios. 

References

[1] Hudi Tables Configuration. [link]

[2] Index Types in Hudi. [link]

[3] Hudi Operation Types. [link]

Autores

Alberto Jaen

AWS Cloud Engineer

I started my career with the development, maintenance and administration of multidimensional databases and Data Lakes. From there I started to be interested in data platforms and cloud architectures, being certified 3 times in AWS and 2 with Hashicorp.

I am currently working as a Cloud Engineer developing Data Lakes and DataWarehouses with AWS for a client related to the organization of sporting events worldwide.

Alfonso Jerez

AWS Cloud Engineer

Passionate about data and new technologies, specialized as AWS Cloud Engineer in DataWarehouses optimization and Data Lakes ingestion and transformation processes. Motivated by continuous improvement and automation of service integration.

Actively collaborating with the Cloud Practice group in research and blog development of cutting-edge and innovative technologies such as this one, thus fostering continuous learning.

Adrián Jiménez

AWS Cloud Engineer

Dedicated to constantly learning new technologies and their application, enjoying using them to solve technological challenges. I develop my career as a Cloud Engineer designing, implementing and maintaining infrastructure in AWS.

I actively collaborate in the Cloud Practice, where we research and experiment with new technologies, seeking solutions to the challenges faced by our clients.

Navigation

¿Quieres saber más de lo que ofrecemos y ver otros casos de éxito?
DESCUBRE BLUETAB

SOLUCIONES, SOMOS EXPERTOS

DATA STRATEGY
DATA FABRIC
AUGMENTED ANALYTICS

Te puede interesar

Data Mesh

July 27, 2022
LEER MÁS

Workshop Ingeniería del caos sobre Kubernetes con Litmus

July 7, 2021
LEER MÁS

Big Data and loT

February 10, 2021
LEER MÁS

MICROSOFT FABRIC: Una nueva solución de análisis de datos, todo en uno

October 16, 2023
LEER MÁS

Incentives and Business Development in Telecommunications

October 9, 2020
LEER MÁS

Databricks on AWS – An Architectural Perspective (part 1)

March 5, 2024
LEER MÁS

Filed Under: Outstanding, Practices, Tech

El futuro del Cloud y GenIA en el Next ’23

September 19, 2023 by Bluetab

El futuro del Cloud y GenIA en el Next ’23

Lucas Calvo

Cloud Engineer

Javi Perez

Cloud Engineer

Gabriel Gallardo

Cloud Engineer

Este año desde Bluetab hemos ido al Google Cloud Next, la conferencia anual organizada por Google Cloud, uno de nuestros partners de referencia además de uno de los principales proveedores Cloud del mundo. Este evento está orientado para dar a conocer todos sus nuevos anuncios de productos así como casos de usos de éxito que se han realizado con distintos clientes sobre su plataforma. 

En esta ocasión, hemos viajado hasta San Francisco para ver todas las últimas novedades que nos presenta Google, así como tener la oportunidad de debatir sobre distintas áreas como la inteligencia artificial, aprendizaje automático, análisis de datos y otros temas relacionados con los servicios de Google Cloud con los principales ingenieros que los desarrollan.

Tal y como viene siendo costumbre este año los anuncios más importantes han venido relacionados con la Generative AI, esta revolución tecnológica que nos ha abierto un mundo de posibilidades y avances. Comenzando por la parte clásica, a medida que seguimos generando más datos y explorando sistemas cada vez más complejos con datos que tienen un mayor grado de actualización para garantizar que las recomendaciones y los resultados sean reflejos precisos del mundo en evolución que nos rodea, debemos disponer de una capacidad de cómputo escalable que proporciona una gran conectividad. Orquestar las cargas de trabajo actuales a gran escala siempre ha requerido un esfuerzo manual para gestionar los fallos. Sin embargo, hoy somos capaces de simplificar los esfuerzos que conlleva la gestión de estas cargas de trabajo, sobre todo las destinadas a IA con la integración de las TPU en la nube en GKE, el servicio Kubernetes más escalable y líder del sector en la actualidad. 

Este ha sido uno de los anuncios más importantes del Next’23, ya que ahora los clientes pueden mejorar la productividad del desarrollo de IA aprovechando GKE para gestionar la orquestación de cargas de trabajo de IA a gran escala en las nuevas Cloud TPU v5e, así como en Cloud TPU v4. Esta nueva generación tiene hasta 2,5 veces más rendimiento en comparación con Cloud TPU v4, pero lo realmente importante es la nueva tecnología Multi Slicing que permite realizar entrenamientos distribuidos más allá de los límites físicos de una TPU, escalando a cientos de pods con estos dispositivos.

Igualmente, merece la pena destacar la mejor en las instancias de cómputo para las cargas de trabajo no relacionadas con la IA, pero que tienen igual o mayor importancia para nuestros, para ello Google presente su nueva familia de VMs basadas respectivamente en procesadores de AMD (C3D) o ARM (C3A) que se suman a las instancias A3 donde disfrutaremos de las nuevos GPUs de Nvidia: las H100. Todo aderezado con las nuevas reservas, ahora en versión preliminar, que son una nueva función de Compute Engine que permite reservar capacidad para una fecha futura.

Aunque estas nuevas ventajas  abren las posibilidades a un nuevo mundo en la nube, la realidad sigue siendo que trabajar con Large Language Models es complicado, no solo se necesita losl últimos avances en hardware, sino también el tiempo a invertir para obtener un resultado de calidad. Google se ha puesto las pilas para solventar esta problemática, y ofrecer a nuestros clientes el nuevo concepto de “Model Garden” que Microsoft anunció en su conferencia anual Build y que también AWS está trabajando para incorporar en Amazon JumpStart. Esta nueva capacidad permite elegir con qué Modelo Fundacional queremos trabajar en un click, solo necesitamos entender qué tipo de Prompt Engineering estamos trabajando para comenzar a construir nuestras soluciones de Information Retrieval con Vertex AI Search and Conversation. Pero Google Cloud no se queda en el “Model Garden” donde podremos encontrar los últimos LLM como son: Llama 2 y Code Llama de Meta, Falcon LLM del Technology Innovation Institute y Claude 2 de Anthropic, sino que también podremos personalizarlo con las características más relevantes que nosotros creamos conveniente para el caso de uso que estamos trabajando, lo cual nos permite generar un flujo de trabajo de tipo Reinforcement Learning with Human Feedback (RLHF), aumentando la confianza en nuestras aplicaciones conversacionales y de búsqueda mediante la IA generativa.

Con los nuevos productos de Vertex AI, la base de datos original de la organización se convierte en la pieza fundamental para que la IA generativa se capaz de buscar la información que es relevante para la persona que le está preguntado acerca de una cuestión de negocio, y para que la experiencia sea más sencilla posible se presentaron las nuevas extensiones Vertex AI permiten a los modelos realizar acciones y recuperar información específica en tiempo real y actuar en nombre de los usuarios a través de Google y aplicaciones de terceros como Datastax, MongoDB y Redis, sin olvidar los nuevos conectores que ayudan a ingerir datos de otras aplicaciones empresariales como Salesforce, Confluence y JIRA.

Finalmente, se ha presentado la evolución del Vertex AI Feature Store para su uso tiempo real mediante la búsqueda vectorial y semántica con BigQuery, que mejora su integración de machine learning mediante BigQuery ML, e incorpora la facilidad de uso de notebooks con Colab para crear nuevos modelos a medidas pero con todas las funciones de seguridad y cumplimiento de normativas que una organización require. Es decir, un nuevo mundo de posibilidades para integrar la Generative AI con tu negocio.

Y es a nivel empresarial donde más destaca su anuncio más esperado, la presentación global de Duet AI dentro de Google Workspaces y Google Cloud Services. Aún tendremos que esperar algunos días para que se vayan actualizando todos los servicios con nueva capacidad de IA generativa que nos permitirá realizar una búsqueda avanzado entre todos los documentos que almacenemos en Google Drive para encontrar aquellos que son realmente interesantes par la tarea que estamos haciendo, o ser capaces de escribir actas de forma automática mediante Chat y preguntar por el propio contenido de la reunión, así como crear nuevos presentaciones en base a breves pero concisas descripciones, ahora tiempo de tener que empezar de cero sin una buena base. Duet AI proporciona un asistente de IA generativa entrenada específicamente, por ejemplo, en la documentación de GKE para ayudar a los equipos de la plataforma a reducir el tiempo que tardan en aprender y gestionar Kubernetes, no solo a la hora de desplegar una nueva aplicación, sino también a la hora de encontrar los bugs y depurar su origen, o incluso registrar nuestros findings de seguridad para identificar las fallas que puedan existir en nuestras aplicaciones. Con Duet AI, se podría incluso llevar a plantear una migración de código legacy, o documentar aquellas partes del código que se quedan huérfanas de forma automática. Además, este anuncio no solo se queda ahí ya que Duet permitirá a usuarios sin conocimientos realizar consultas para monitorizar sus aplicaciones con lenguaje natural, evitando así el uso de otros lenguajes más complejos como Promql.

Por la parte más tradicional de data también hemos tenido distintos anuncios como  el nuevo producto que se ha lanzado de BigQuery, BigQuery Studio que nos ofrece un espacio único para el trabajo de ingeniería de datos facilitando que todos los profesionales aceleren los datos hacia los flujos de trabajo de IA . Podríamos destacar entre sus características más importantes que es un espacio de trabajo unificado usando SQL y notebooks en el cual se permite el uso múltiples lenguajes de programación (SQL, Python, Spark, Javascript y lenguaje natural), además ofrece control de versiones e historial de revisiones centralizado y un asistente de código y chat impulsado por IA que nos permitirá mejorar la productividad. Otra parte importante que hay que señalar en BigQuery Studio es que permite realizar de forma sencilla y automática el profiling, la calidad y el linaje para todos los assets de datos coordinado con herramientas como dataplex.

Además en esta edición, se han presentado nuevas funcionalidades para poder llevar BigLake a una plataforma lakehouse gestionada. Entre las nuevas características encontramos la integración con formatos de datos abiertos (Apache Iceberg, Delta y Hudi) permitiendo un control de acceso detallado y rendimiento de forma integrada. Otra de las novedades que se ha incluido BigLake son las tablas gestionadas que usan formato abierto Apache Iceberg y permiten uso de streaming sobre ellas con alto rendimiento así como todas las ventajas que ofrece Apache Iceberg. Con el servicio de BigLake se puede afrontar los nuevos retos que plantean arquitecturas orientadas al Data Mesh de una forma mucho más sencilla y dando la posibilidad de compartir nuestros set de datos dentro de toda la organización.

También en la parte de contenedores y orquestación ha habido algunos puntos importantes, con anuncios en sus productos estrellas y diferenciales en el mercado como es GKE y Cloud Run. Desde hace unos años Google está apostando cada vez más a soluciones de orquestación de contenedores totalmente administradas, ya lo vimos con autopilot en 2021 y Cloud Run y ahora además está queriendo hacer más sencillo el uso de Kubernetes integrándose con Duet para realizar recomendaciones y configuraciones de aplicaciones y servicios con lenguaje natural.

Todas las novedades las podemos resumir en el siguiente post

https://cloud.google.com/blog/topics/google-cloud-next/next-2023-wrap-up

Conclusiones

  • El Next’23 nos ha permitido charlar con los profesionales de Google y  compartir ideas y conocimientos con los distintos partner que han asistido al evento lo que nos permite debatir nuevas visiones y confirmar que desde Bluetab estamos realizando los pasos correctos. Como siempre, las sesiones son de gran utilidad y abarcan las nuevas características y funcionalidades que podemos esperar en los próximos meses para Kubernetes.
  • Después de volver de Next’23 reafirmamos que Google sigue siendo una de las mejores soluciones en el mercado de la analítica avanzada con uno de los anuncios más importantes del Next, Duet. Google es uno de los primeros proveedores cloud que han integrado la parte de Generative AI en su plataforma y esto es gracias a Duet que es una asistente que te ayudará a enfrentarte con los distintos retos que puedan surgir en Google Cloud. 
  • Pero no todo va a ser inteligencia artificial, uno de los puntos que más hay que trabajar y más importantes para una organización es la parte de FinOps, muchas veces el gran olvidado. En este Next hemos visto distintas soluciones aportadas por clientes para una optimización de costes y distintas estrategias para el gobierno y el control de estos. Aún así todas las soluciones pasan por realizar distintos desarrollos exportando los datos de la facturación a Bigquery y creando Dashboard en Looker, una solución de momento que no es totalmente administrada. En este apartado hay mucho trabajo por hacer para que la parte de FinOps sea mucho más proactiva y podamos hacer recomendaciones en tiempo real a los desarrolladores para disminuir el gasto en la organización.

 

Ha sido un placer vivir esta experiencia con todos los desarrolladores e ingenieros de Google y con el resto de compañeros. Además solo nos queda agradecer al equipo de partners de Google España por su dedicación y seguro que nos vemos en la próxima edición. Hasta entonces, sigamos explorando nuevas ideas y tecnologías.

¡Nos vemos en Las Vegas!”

Lucas Calvo

Cloud Engineer

Javi Perez

Cloud Engineer

Gabriel Gallardo

Cloud Engineer

¿Quieres saber más de lo que ofrecemos y ver otros casos de éxito?
DESCUBRE BLUETAB

SOLUCIONES, SOMOS EXPERTOS

DATA STRATEGY
DATA FABRIC
AUGMENTED ANALYTICS

Te puede interesar

IBM to acquire Bluetab

July 9, 2021
LEER MÁS

Databricks on Azure – An Architecture Perspective (part 1)

February 15, 2022
LEER MÁS

Oscar Hernández, new CEO of Bluetab LATAM.

May 16, 2024
LEER MÁS

Starburst: Construyendo un futuro basado en datos.

May 25, 2023
LEER MÁS

Cómo depurar una Lambda de AWS en local

October 8, 2020
LEER MÁS

CLOUD SERVICE DELIVERY MODELS

June 27, 2022
LEER MÁS

Filed Under: Blog, Tech

De documentos en papel a datos digitales con Fastcapture y Generative AI

June 7, 2023 by Bluetab

De documentos en papel a datos digitales con Fastcapture y Generative AI

Resumen

Los avances en Generative AI y en los grandes modelos de lenguaje, LLMs por sus siglas en inglés (Large Language Models), permiten transferir el pre-entrenamiento de estos modelos en una tarea simple, como predecir las palabras que faltan en una frase a tareas más complejas, como procesar documentos en papel para extraer sus datos de forma automática. Esta transferencia del entrenamiento funciona tan bien que es posible plantear desarrollar casos de uso que cierren el gap entre la digitalización y las actividades que requieren documentos en papel.

Hemos desarrollado un proyecto para modernizar la tecnología de AI de Fastcapture, nuestro IDP (Intelligent Document Processing), con Generative AI y LLMs. Hemos conectado Fastcapture con Hugging Face, un hub de la comunidad Open Source de AI. Los resultados que hemos obtenido están muy por encima de un F1 score de 0.9.

 

Introducción

Estamos viviendo una era de disrupciones. Esta situación está produciendo un momento de constantes avances tecnológicos. Me voy a fijar en 2 de ellos, la digitalización y el desarrollo de aplicaciones con inteligencia artificial (AI).

La pandemia COVID-19 ha sido terrible. Ahora bien, una de sus consecuencias ha sido la aceleración de la digitalización. El crecimiento de usuarios digitales ha sido de 2 dígitos en la gran mayoría de las empresas. Sin embargo, muchas actividades en las empresas siguen requiriendo documentos en papel. Un informe del US Bureau of Labor Statistics indica que las compañías americanas se gastaron $5,3Bn en cargar manualmente los documentos durante el año 2021.

Los avances en AI, y en particular los avances en Generative AI y en los grandes modelos de lenguaje han alcanzado un momento que, a parte de la aparición de aplicaciones sorprendentes como ChatGPT, permite el desarrollo de casos de uso de tratamiento de textos e imágenes con unos niveles de precisión muy elevados >0.9.

Juntando estas piezas, hoy es realmente posible plantear automatizar el procesamiento de documentos en papel a escala para convertirlos en datos digitales listos para ser consumidos y analizados en cualquier otra actividad de la empresa. 

 

El problema

Muchas actividades en las empresas siguen requiriendo documentos en papel. Facturas, contratos, informes. Estos documentos contienen datos relevantes y disponer de una versión digital es clave para la digitalización de las empresas. 

Una forma de convertir los documentos en papel en datos digitales es mediante cargas manuales. También se pueden convertir en datos digitales utilizando aplicaciones del tipo de un IDP. Un IDP consiste en un grupo de pipelines con pasos para procesar los documentos y convertirlos en datos digitales. El primer paso es la conversión del documento en texto con un modelo OCR (Optical Character Recognition). 

A continuación vienen los pasos para tratar el texto. Los pasos de tratamiento del texto pueden utilizar modelos de AI. Típicamente estos modelos de AI están basados en una arquitectura RNN (Recurrent Neural Network). Los modelos RNN tratan la secuencia de palabras en orden, una a una. Estos modelos se enfrentan a 2 dificultades a la hora de realizar su tarea. La primera es su capacidad de tratamiento del contexto. Según se van alejando las palabras y las frases, el modelo empieza a perder su capacidad para relacionarlas. La segunda es la dificultad que tienen para escalar y, por lo tanto, para ser entrenados en grandes volúmenes de textos. Estas 2 dificultades suponen un techo para la precisión del IDP y por lo tanto para su capacidad de automatizar la conversión de documentos en papel en datos digitales.

 

La solución propuesta

Los LLM se basan en la arquitectura de los Transformers. Esta arquitectura propuesta en el paper “Attention is all you need” Vaswani et al. 2017 fué totalmente revolucionaria. Trata la secuencia a través del mecanismo de atención mediante matrices. El mecanismo de atención permite realizar un mejor procesamiento del contexto. 

Todas las palabras se encuentran a la misma distancia entre sí medida en número de operaciones matemáticas. Y permite escalar el entrenamiento de forma horizontal. Los modelos basados en esta arquitectura se pueden entrenar con cantidades de textos muy grandes. 

En el paper “Improving Language Understanding by Generative Pre-Training” Radford et al. 2018 proponen un nuevo framework de 2 fases para entrenar los LLMs. Un pre-entrenamiento no supervisado sobre un objetivo sencillo, predecir la siguiente palabra de un texto, y con grandes volúmenes de textos. Y un fine-tune para adaptar el modelo a resolver una tarea NLP concreta como extraer datos relevantes de un documento, y con pocos ejemplos. 

Esta combinación es ideal para transferir el pre-entrenamiento de un modelo con grandes cantidades de textos a tareas para las que se disponen de pocos ejemplos. 

Nuestra aproximación consiste en utilizar LLMs pre-entrenados disponibles en la comunidad Open Source y realizar un fine-tune para convertir los documentos en papel en datos digitales. 

Hemos conectado nuestro IDP Fastcapture con el hub de Hugging Face donde residen LLMs pre-entrenados Open Source para acceder a ellos y generar versiones especializadas mediante un fine-tune en nuestro hub privado sin enviar los datos al hub público.

 

Cómo incorporar los LLMs en un IDP

La estrategia que hemos seguido para incorporar los LLMs en nuestro IDP Fastcapture se ha basado en 3 pilares, aprender a través de I+D, apoyarnos en la comunidad Open Source de AI y construir sobre lo que ya teníamos.

Estos han sido los pasos clave del proyecto:

  1. La selección del LLM pre-entrenado
  2. El diseño del contexto del Transformer
  3. Utilizar entornos multi-GPU para realizar el fine-tune y el servicing

 

La selección del LLM pre-entrenado

La comunidad Open Source de AI da acceso a LLMs pre-entrenados con un nivel de calidad enterprise-grade. Nuestro caso de uso requiere un modelo tipo encoder con capacidades multi idioma. De esta manera un único modelo será capaz de extraer datos relevantes de documentos del mismo tipo con diferente idioma.

Nos decantamos por el modelo pre-entrenado XLM-R propuesto en el paper “Unsupervised Cross-lingual Representation Learning at Scale” Conneau et al. 2020. El modelo XLM-R ha sido pre-entrenado en 2.5TB de textos con 100 idiomas. Hemos utilizado las siguientes tallas:

Modelo

Número de parámetros

XLM-RLarge

550M

XLM-RXL

3.5B



Diseño del contexto del Transformer

Diseñar cómo usar el contexto del LLM es un factor importante a la hora de conseguir niveles de performance de 0.9.

Los documentos están organizados en páginas y frases. Lo que queremos es que el LLM analice frase a frase en búsqueda de datos relevantes. Los tipos de documentos que manejamos son más bien telegráficos, con poco texto. Esto suele ser una tónica habitual al tratar documentos en papel en el mundo empresarial. 

Para dar una mejor oportunidad al LLM de hacer su tarea ubicamos la frase de interés a la derecha del contexto y completamos el contexto por la izquierda con las frases predecesoras que quepan.

El siguiente esquema muestra el diseño al que nos referimos.

Fine-tune y servicing en un entorno multi-GPU

Realizar un fine-tune de un LLM requiere utilizar GPU’s (Graphics Processing Units). El modelo XLM-RLarge puede entrenarse sin utilizar un framework que optimice el uso de la memoria o que distribuya el modelo entre diferentes GPUs. 

Sin embargo la versión XLM-RXL es tan grande que al realizar el algoritmo de gradient descent no cabe y requiere utilizar frameworks de optimización y/o que distribuyan el modelo en el entorno multi-GPU.

El proyecto lo hemos realizado en una máquina virtual con 4 GPUs NVIDIA a10g, y hemos utilizado el framework propuesto en el paper “ZeRO: Memory Optimizations Toward Training Trillion Parameter Models” Rajbhandari et al. 2020. ZeRO optimiza el uso de la memoria para almacenar el estado del modelo a la hora de entrenar y permite distribuir los gradientes y los parámetros entre las GPUs.

Utilizar entornos multi-GPU y frameworks de optimización como ZeRO, a parte de poder escalar el proceso de fine-tuning, permite gestionar los recursos computacionales que requieren modelos extra grandes. 

 

Resultados

En el proyecto hemos utilizado 2 juegos de datos, uno de factura y otro de informes económicos.

 

El impacto de la talla en el performance depende del caso de uso

Las siguientes gráficas muestran el F1 score de las 2 tallas, L y XL, en cada uno de los juegos de datos.

Gráfica 1. F1 score fine-tune facturas XLM-RLarge
Gráfica 2. F1 score fine-tune facturas XLM-RXL
Gráfica 3. F1 score fine-tune informes XLM-RLarge
Gráfica 4. F1 score fine-tune informes XLM-RXL

Estas gráficas ayudan a visualizar la diferencia de performance entre las tallas L y XL en los 2 juegos de datos y poder decidir qué modelo utilizar en el IDP. En el caso de las facturas la talla XL obtiene un score medio 8 puntos básicos mejor que la talla L, mientras que en el caso de los informes económicos la diferencia del score medio es de 1 punto básico. 

Al elegir el tamaño de modelo adecuado para cada caso de uso hay que considerar varios factores como el performance del modelo, los recursos de computación y el trade-off entre precisión y complejidad. En algunos casos, un modelo más pequeño puede proporcionar resultados suficientemente precisos con menores requisitos de computación y menor complejidad de mantenimiento. 

La importancia de diseñar el contexto al trabajar con LLMs

El diseño del contexto es clave para cualquier caso de uso con LLMs. La siguiente gráfica muestra el resultado de un fine-tune del modelo XLM-RLarge sin utilizar el contexto con diseño de ventana. El F1 score medio es 3 puntos básicos inferior sin utilizar el diseño de contexto con ventana.

Gráfica 3. F1 score fine-tune informes XLM-RLarge
sin el diseño de contexto con ventana

Referencias

Ashish Vaswani, Noam Shazeer, Niki Parmar, Jakob Uszkoreit, Llion Jones, Aidan N. Gomez, Lukasz Kaiser, and Illia Polosukhin. 2017. Attention is all you need. arXiv:1706.03762 

Alec Radford, Karthik Narasimhan, Tim Salimans, Ilya Sutskever. Improving Language Understanding by Generative Pre-Training. 2018. 

Alexis Conneau, Kartikay Khandelwal, Naman Goyal, Vishrav Chaudhary, Guillaume Wenzek, Francisco Guzman, Edouard Grave, Myle Ott, Luke Zettlemoyer, Veselin Stoyanov. Unsupervised Cross-lingual Representation Learning at Scale. 2020. arXiv:1911.02116v2.

Samyam Rajbhandari∗ , Jeff Rasley∗ , Olatunji Ruwase, Yuxiong He. ZeRO: Memory Optimizations Toward Training Trillion Parameter Models. 2020. arXiv:1910.02054v3

¿Quieres saber más de lo que ofrecemos y ver otros casos de éxito?
DESCUBRE BLUETAB

SOLUCIONES, SOMOS EXPERTOS

DATA STRATEGY
DATA FABRIC
AUGMENTED ANALYTICS

Te puede interesar

5 common errors in Redshift

December 15, 2020
LEER MÁS

Bluetab is certified under the AWS Well-Architected Partner Program

October 19, 2020
LEER MÁS

Spying on your Kubernetes with Kubewatch

September 14, 2020
LEER MÁS

Desplegando una plataforma CI/CD escalable con Jenkins y Kubernetes

September 22, 2021
LEER MÁS

Data Governance: trend or need?

October 13, 2022
LEER MÁS

Snowflake Advanced Storage Guide

October 3, 2022
LEER MÁS

Filed Under: Blog, Outstanding, Tech

Starburst: Construyendo un futuro basado en datos.

May 25, 2023 by Bluetab

Starburst: Construyendo un futuro basado en datos.

Lucas Calvo

Cloud Engineer

Introducción

En este nuevo artículo vamos a hablar de uno de nuestros partners: Starburst[1]. Starburst es la versión empresarial de Trino[2] realizando nuevas integraciones, mejoras de rendimiento, una capa de seguridad y restando complejidad a la gestión con una interfaz de usuario muy fácil de usar y que te permite realizar distintas configuraciones.

Para los que no conocéis Trino, es un motor de consulta SQL distribuido open-source creado en 2012 por Facebook bajo el nombre Presto. Está diseñado para consultar grandes conjuntos de datos distribuidos en una o más fuentes de datos heterogéneas. Esto significa que podemos consultar datos que residen en diferentes sistemas de almacenamiento como HDFS, AWS S3, Google Cloud Storage o Azure Blob Storage. Trino también tiene la capacidad de federar diferentes fuentes de datos como MySQL, PostgreSQL, Cassandra, Kafka.

Con las nuevas necesidades que van saliendo de arquitecturas orientadas al Data Mesh[3], plataformas analíticas como Starburst son cada vez más importantes y nos permiten centralizar y federar distintas fuentes de datos para así tener solo un punto de entrada a nuestra información. Con esta mentalidad, podemos hacer que nuestros usuarios accedan a la plataforma de Starburst con distintos roles y distinta granularidad de acceso para que puedan consultar los distintos dominios que poseen las empresas. Además Starburst no solo se queda en la consulta de datos, sino que nos permite conectarnos con herramientas analíticas como puedes ser DBT[4] o Jupyter Notebook[5] o herramientas de reporting como Power BI[6] para sacarle más rendimiento a todos nuestros datos. Pero Starburst no solo se queda en eso, sino que nos puede ayudar en la migraciones de datos hacia el Cloud, ya que fácilmente podemos conectarnos a las fuentes de datos y sacar toda la información para volcarlas en cualquier almacenamiento del Cloud.

Como podéis observar, Starburst es capaz de analizar todos sus datos, dentro y alrededor de tu Data Lake, y se conecta a todo un ecosistema de herramientas. Por eso vamos a realizar una serie de artículos para tratar los puntos más relevantes como son el despliegue y configuración de la plataforma, integración con otras herramientas y gobierno y administración de usuarios. En este primer artículo, nos vamos a centrar en el despliegue de Starburst en Kubernetes, así como la configuración que se tiene que realizar para conectar con los distintos componentes de GCP. Además hemos añadido una capa de monitorización con Prometheus[7] y Grafana[8], donde hemos publicado un dashboard con distintas métricas importantes por si cualquier compañía quiere centralizar las métricas en Grafana. Para todo ello, nos vamos a apoyar de un repositorio que hemos creado con el levantamiento de la infraestructura y la instalación de Starburst.

¿Qué necesitas para entender este artículo?

  • Algunos conceptos sobre Terraform[9].
  • Algunos conceptos de Kubernetes.
  • Algunos conceptos de Helm.
  • Algunos conceptos de Prometheus.
  • Algunos conceptos de Grafana.
  • Un cuenta en GCP.
  • Una licencia de Starburst

Arquitectura

Como se puede observar en el diagrama, estos son los componentes que se van a desplegar para la configuración de Starburst. Como pieza central del despliegue, utilizaremos Google Kubernetes Engine. Este es el servicio administrado de orquestación de contenedores de Google. Utilizaremos Kubernetes ya que nos facilitará la gestión de Starburst y aprovecharemos las ventajas del autoscaling de Kubernetes para ampliar el número de workers de Starburst y escalar en más nodos para poder así tener más recursos de computación si tenemos algún pico de trabajo o de usuarios.

Como configuración inicial de nuestro cluster de GKE, comenzaremos con un único nodepool para facilitar el despliegue. Un nodepool es una agrupación de nodos dentro de un cluster con la misma configuración y especificaciones de tipo de máquina. En nuestro caso, nuestro nodepool se llamará `default-node-pool` y el tipo de instancia utilizada será `e2-standard-16`, que es la recomendada por Starburst, ya que el tipo de carga de trabajo necesita nodos con bastante memoria. Además de la instalación de Starburst, también desplegaremos en el cluster tanto Prometheus como Grafana.

Como hemos explicado anteriormente, Starburst está basado en Trino, que es un motor de consulta distribuido. Los principales componentes de Trino son el Coordinator y los Workers. El Coordinator de Trino es el componente responsable de analizar las sentencias, planificar las consultas y gestionar los nodos Workers de Trino. El Coordinator realiza un seguimiento de la actividad de cada Worker y orquesta la ejecución de una consulta. Los Workers son el componente responsable de ejecutar tareas y procesar datos. Los nodos Workers obtienen datos de los conectores e intercambian datos intermedios entre sí. El Coordinator es responsable de obtener los resultados de los Workers y devolver los resultados finales al cliente.

Como componentes transversales de nuestra arquitectura, también desplegaremos una red con una subnet para realizar el despliegue de nuestro cluster de GKE, así como un bucket en Cloud Storage para realizar pruebas de escritura de datos desde Starburst.

Además, como componente fuera de la arquitectura, tendremos jmeter[10], la herramienta con la que realizaremos pruebas de performance para probar la elasticidad de Starburst y poder probar el autoescalado de nuestro cluster.

Despliegue de la infraestructura

Una vez explicada la arquitectura vamos a proceder a realizar el despliegue de todos los componentes. Para ello, nos vamos a ayudar de Terraform como herramienta de IaC. Como partes importantes de este despliegue, tendremos la parte más de infraestructura tradicional que son las VPC, el cluster de GKE y la parte de Cloud Storage como hemos hablado antes, además de los componentes que desplegamos en Kubernetes de una forma totalmente automatizada que son Grafana y Prometheus.

Vamos a empezar con la explicación de la infraestructura más clásica. Para este despliegue haremos uso de dos módulos que están subidos al github:

  • Módulo de GKE[11].
  • Módulo de VPC[12].

Estos dos módulos están invocados en el `main.tf` del repositorio y hacen uso del provider de Google para el despliegue:


```tf
provider "google" {
  project = var.project_id
  region  = var.region
}

provider "google-beta" {
  project = var.project_id
  region  = var.region
}


module "network" {
  source = "git@github.com:lucasberlang/gcp-network.git?ref=v1.0.0"

  project_id         = var.project_id
  description        = var.description
  enable_nat_gateway = true
  offset             = 1

  intra_subnets = [
    {
      subnet_name           = "private-subnet01"
      subnet_ip_cidr        = "10.0.0.0/24"
      subnet_private_access = false
      subnet_region         = var.region
    }
  ]

  secondary_ranges = {
    private-subnet01 = [
      {
        range_name    = "private-subnet01-01"
        ip_cidr_range = var.ip_range_pods
      },
      {
        range_name    = "private-subnet01-02"
        ip_cidr_range = var.ip_range_services
      },
    ]
  }

  labels = var.labels
}

resource "google_storage_bucket" "gcs_starburst" {
  name          = var.name
  location      = "EU"
  force_destroy = var.force_destroy
}

module "gke-starburst" {
  source = "git@github.com:lucasberlang/gcp-gke.git?ref=v1.1.0"

  project_id              = var.project_id
  name                    = "starburst"
  regional                = true
  region                  = var.region
  network                 = module.network.network_name
  subnetwork              = "go-euw1-bt-stb-private-subnet01-dev"
  ip_range_pods           = "private-subnet01-01"
  ip_range_services       = "private-subnet01-02"
  enable_private_endpoint = false
  enable_private_nodes    = false
  master_ipv4_cidr_block  = "172.16.0.0/28"
  workload_identity       = false
  kubernetes_version      = var.kubernetes_version
  
  gce_persistent_disk_csi_driver = true

  master_authorized_networks = [
    {
      cidr_block   = module.network.intra_subnet_ips.0
      display_name = "VPC"
    },
    {
      cidr_block   = "0.0.0.0/0"
      display_name = "shell"
    }
  ]

  cluster_autoscaling = {
    enabled             = true,
    autoscaling_profile = "BALANCED",
    max_cpu_cores       = 300,
    max_memory_gb       = 940,
    min_cpu_cores       = 24,
    min_memory_gb       = 90,
  }


  node_pools = [
    {
      name         = "default-node-pool"
      machine_type = "e2-standard-16"
      auto_repair  = false
      auto_upgrade = false
    },
  ]
  
  node_labels = {
    "starburstpool" = "default-node-pool"
  }

  istio     = var.istio
  dns_cache = var.dns_cache
  labels    = var.labels
}
```
 

Lo único importante a tener en cuenta, es que vamos a desplegar una red con una única subred y que el cluster de GKE está habilitado con el autoescalado para poder incrementar el número de nodos cuando haya una carga de trabajo. Asimismo, es importante tener en cuenta que se ha añadido una etiqueta a todos los nodos que es `”starburstpool” = “default-node-pool”` para aislar el propio despliegue de Starburst del que más tarde haremos uso. Aparte de estos componentes también desplegamos una Cloud Storage para luego configurar el conector de Hive.

Por otra parte, como hemos comentado, también haremos el despliegue de Grafana y Prometheus. Para ello haremos uso del provider de Helm y de Kubernetes de Terraform. 

El despliegue de estos componentes lo tenemos en el archivo `helm.tf`:

```tf
resource "kubernetes_namespace" "prometheus" {
  metadata {
    name = "prometheus"
  }
}

resource "kubernetes_namespace" "grafana" {
  metadata {
    name = "grafana"
  }
}

resource "helm_release" "grafana" {
  chart      = "grafana"
  name       = "grafana"
  namespace  = kubernetes_namespace.grafana.metadata.0.name
  repository = "https://grafana.github.io/helm-charts"

  values = [
    file("templates/grafana.yaml")
  ]
}

resource "kubernetes_secret" "grafana-secrets" {
  metadata {
    name      = "grafana-credentials"
    namespace = kubernetes_namespace.grafana.metadata.0.name
  }
  data = {
    adminUser     = "admin"
    adminPassword = "admin"
  }
}

resource "helm_release" "prometheus" {
  chart      = "prometheus"
  name       = "prometheus"
  namespace  = kubernetes_namespace.prometheus.metadata.0.name
  repository = "https://prometheus-community.github.io/helm-charts"

  values = [
    file("templates/prometheus.yaml")
  ]
}
```
 

Hay varias cosas que tenemos que tener en cuenta, estas son las configuraciones que hemos añadido en los values de cada chart. 

Primero vamos con los valores de Prometheus que hemos configurado. Hemos añadido una configuración extra para que recoja las métricas de Starburst una vez que se levante. Esto lo hemos hecho en la siguiente parte de la configuración:

```yaml
extraScrapeConfigs: |
  - job_name: starburst-monitor
    scrape_interval: 5s
    static_configs:
      - targets: 
        - 'prometheus-coordinator-starburst-enterprise.default.svc.cluster.local:8081'
        - 'prometheus-worker-starburst-enterprise.default.svc.cluster.local:8081'
    metrics_path: /metrics
    scheme: http
```
 

Lo único a tener en cuenta son los targets que hemos añadido, que básicamente son los servicios tanto del Coordinator como de los Workers de Starburst para que recoja todas las métricas.

En la parte de Grafana hemos añadido tanto la configuración de Prometheus, como un dashboard que hemos creado custom para Starburst. 

La configuración que hemos añadida es la siguiente:

```yaml
datasources:
 datasources.yaml:
   apiVersion: 1
   datasources:
   - name: Prometheus
     type: prometheus
     url: http://prometheus-server.prometheus.svc.cluster.local
     isDefault: true


dashboards:
  default:
    Starburst-cluster:
      gnetId: 18767
      revision: 1
      datasource: Prometheus
```
 

En la carpeta infra del repositorio de Github, podrás encontrar todo el código necesario para realizar dicho despliegue.

Instalación y configuración de Starburst

Una vez que tengamos toda la infraestructura levantada, vamos a proceder a desplegar Starburst en nuestro cluster de GKE. Para ello, vamos a desplegar estos componentes:

  • Postgres Database on Kubernetes
  • Hive Metastore Service
  • Starburst Enterprise

El servicio de Hive Mestastore es necesario para configurar el conector de Hive para así poder acceder o escribir a los datos que se guardan en Google Cloud Storage. Como backend de nuestro servicio de Metastore, vamos a desplegar un base de datos PostgreSQL, para así poder guardar toda la información de la metadata en esta base de datos. Además tendremos que configurar el servicio de Hive para pasarle las credenciales de Google Cloud y que tenga permisos para poder leer y escribir de GCS. Por lo tanto, vamos a proceder primero a declarar algunas variables de entorno que necesitaremos para descargar los charts del repositorio privado de Starburst y algunas variables de configuración más que necesitaremos para realizar el despliegue.

Esta serían las variables que vamos a necesitar en nuestro despliegue:

```bash
export admin_usr=     # Choose an admin user name you will use to login to Starburst & Ranger. Do NOT use 'admin'
export admin_pwd=     # Choose an admin password you will use to login to Starburst & Ranger. MUST be a minimum of 8 characters and contain at least one uppercase, lowercase and numeric value.

export registry_pwd= #Credentials harbor registry
export registry_usr= #Credentials harbor registry
export starburst_license=starburstdata.license #License Starburst
# Zone where the cluster will be deployed. e.g. us-east4-b
export zone="europe-west1"
# Google Cloud Project ID where the cluster is being deployed
export google_cloud_project=
# Google Service account name. The service account is used to access services like GCS and BigQuery, so you should ensure that it has the relevant permissions for these
# Give your cluster a name
export cluster_name=

# These next values are automatically set based on your input values
# We'll automatically get the domain for the zone you are selecting. Comment this out if you don't need DNS
#export google_cloud_dns_zone_name=$(gcloud dns managed-zones describe ${google_cloud_dns_zone:?Zone not set} --project ${google_cloud_project_dns:?Project ID not set} | grep dnsName | awk '{ print $2 }' | sed 's/.$//g')

# This is the public URL to access Starburst
export starburst_url=${cluster_name:?Cluster Name not set}-starburst.${google_cloud_dns_zone_name}
# This is the public URL to access Ranger
export ranger_url=${cluster_name:?Cluster Name not set}-ranger.${google_cloud_dns_zone_name}

# Insights DB details
# These are the defaults if you choose to deploy your postgresDB to the K8s cluster
# You can adjust these to connect to an external DB, but be advised that the nodes in the K8s cluster must have access to the URL
export database_connection_url=jdbc:postgresql://postgresql:5432/insights
export database_username=
export database_password=

# Data Products. Leave the password unset as below, if you are connecting directly to the coordinator on port 8080
export data_products_enabled=true
export data_products_jdbc_url=jdbc:trino://coordinator:8080
export data_products_username=${admin_usr}
export data_products_password=

# Starburst Access Control
export starburst_access_control_enabled=true
export starburst_access_control_authorized_users=${admin_usr}

# These last remaining values are static
export xtra_args_hive="--set objectStorage.gs.cloudKeyFileSecret=service-account-key"
export xtra_args_starburst="--values starburst.catalog.yaml"
export xtra_args_ranger=""
```
 

Una vez definidas nuestras variables de entorno procederemos a crearnos un secreto de Kubernetes para configurar las credenciales con las que Hive se va a conectar a GCS.

```bash
kubectl create secret generic service-account-key --from-file key.json
```
 

Para ello, como paso previo, nos hemos creado una service account con permisos en Cloud Storage y en Bigquery y nos hemos descargado las credenciales de esa service account. También como paso previo, añadiremos los repositorio de Helm con el siguiente comando:

```bash
helm repo add --username ${registry_usr} --password ${registry_pwd} starburstdata https://harbor.starburstdata.net/chartrepo/starburstdata
helm repo add bitnami https://charts.bitnami.com/bitnami
```
 

Una vez que tenemos la configuración previa hecha, vamos a proceder a desplegar el servicio de PostgreSQL primero, y posteriormente, el Hive Metastore. Para ello haremos uso de Helm. Para el despliegue de PostgreSQL usaremos el siguiente comando:

```bash
helm upgrade postgres bitnami/postgresql --install --values postgres.yaml \
    --version 12.1.6 \
    --set primary.nodeSelector.starburstpool=default-node-pool \
    --set readReplicas.nodeSelector.starburstpool=default-node-pool
```
 

Hay varios factores a tener en cuenta en el comando anterior. El primero es que el despliegue de PostgreSQL lo haremos en los nodos que tengan el tag `starburstpool=default-node-pool`, que es nuestro worker pool por defecto. Usaremos la versión 12.1.6 de PostgreSQL y la configuración que hemos añadido en postgres es la siguiente:

```yaml
fullnameOverride: postgresql

global:
  postgresql:
    auth:
      database: postgres
      username: postgres
      postgresPassword: ****
  storageClass: "standard"
primary:
  initdb:
    scripts:
      init.sql: |
        create database hive;
        create database ranger;
        create database insights;
        create database datacache;

service:
  type: ClusterIP
``` 

Esta información se encuentra en el archivo `postgres.yaml` y nos configurará el usuario y contraseña de PostgreSQL, y nos creará 4 bases de datos que usa internamente Starburst como backend. En nuestro caso, como podéis observar, hemos configurado el servicio de backend en el mismo cluster que la configuración de Starburst, pero esto se puede configurar fuera del cluster de Kubernetes para entornos productivos. Básicamente podríamos tener un servicio gestionado como es Cloud Sql para así evitar problemas en producción.

Ahora vamos a proceder con el despliegue del servicio de Hive Metastore, esto lo haremos con el siguiente comando:

```bash
helm upgrade hive starburstdata/starburst-hive --install --values hive.yaml \
    --set registryCredentials.username=${registry_usr:?Value not set} \
    --set registryCredentials.password=${registry_pwd:?Value not set} \
    --set nodeSelector.starburstpool=default-node-pool  \
    --set objectStorage.gs.cloudKeyFileSecret=service-account-key
``` 

Aquí tenemos que tener en cuenta varias cosas importantes, la primera es que como en el servicio de PostgreSQL el despliegue se va a realizar en los nodos con el tag `starburstpool=default-node-pool`. El segundo punto importante es que hemos realizado la configuración de las credenciales de Google para que funcione el conector de hive, esto lo hemos realizado con el siguiente comando:

`--set objectStorage.gs.cloudKeyFileSecret=service-account-key` 

Con esta acción,  montamos el fichero de credenciales como un archivo en el despliegue de Hive para que tenga visibilidad en las credenciales. Los valores extras que hemos añadido a la configuración de hive se encuentran en el archivo `hive.yaml` y son los siguientes:

```yaml
database:
  external:
    driver: org.postgresql.Driver
    jdbcUrl: jdbc:postgresql://postgresql:5432/hive
    user: #user postgres
    password: #password postgres
  type: external

expose:
  type: clusterIp

image:
  repository: harbor.starburstdata.net/starburstdata/hive

registryCredentials:
  enabled: true
  registry: harbor.starburstdata.net/starburstdata
```
 

Una vez que tenemos desplegado tanto el servicio de Postgres como el de Hive Metastore, podemos proceder a desplegar Starburst. Primero necesitaremos realizar una serie de pasos previos. El primero será crearnos un secreto de Kubernetes con la licencia de Starburst, el segundo será crearnos un secreto con las variables de entornos que hemos definido antes, esto lo haremos con un pequeño script para quitar complejidad y que nos coja las variables que ya hemos definido. 

Con el siguiente comando procederemos a realizar los pasos anteriores:

```bash
kubectl create secret generic starburst --from-file ${starburst_license}
chmod 755 load_secrets.sh && . ./load_secrets.sh
kubectl apply -f secrets.yaml
```
 

Una vez que tenemos las configuraciones previas vamos a proceder a desplegar Starburst con el siguiente comando:

```bash
helm upgrade starburst-enterprise starburstdata/starburst-enterprise --install --values starburst.yaml \
    --set sharedSecret="$(openssl rand 64 | base64)" \
    --set coordinator.resources.requests.memory=$(echo $(( $(kubectl get nodes --selector='starburstpool=default-node-pool' -o jsonpath='{.items[0].status.allocatable.memory}' | awk -F "Ki" '{ print $1 }')*10/100 ))Ki) \
    --set coordinator.resources.requests.cpu=$(echo $(( $(kubectl get nodes --selector='starburstpool=default-node-pool' -o jsonpath='{.items[0].status.allocatable.cpu}' | awk -F "m" '{ print $1 }')*10/100 ))m) \
    --set coordinator.resources.limits.memory=$(echo $(( $(kubectl get nodes --selector='starburstpool=default-node-pool' -o jsonpath='{.items[0].status.allocatable.memory}' | awk -F "Ki" '{ print $1 }')*10/100 ))Ki) \
    --set coordinator.resources.limits.cpu=$(echo $(( $(kubectl get nodes --selector='starburstpool=default-node-pool' -o jsonpath='{.items[0].status.allocatable.cpu}' | awk -F "m" '{ print $1 }')*10/100 ))m) \
    --set worker.resources.requests.memory=$(echo $(( $(kubectl get nodes --selector='starburstpool=default-node-pool' -o jsonpath='{.items[0].status.allocatable.memory}' | awk -F "Ki" '{ print $1 }') - 10500000 ))Ki) \
    --set worker.resources.requests.cpu=$(echo $(( $(kubectl get nodes --selector='starburstpool=default-node-pool' -o jsonpath='{.items[0].status.allocatable.cpu}' | awk -F "m" '{ print $1 }') - 3500 ))m) \
    --set worker.resources.limits.memory=$(echo $(( $(kubectl get nodes --selector='starburstpool=default-node-pool' -o jsonpath='{.items[0].status.allocatable.memory}' | awk -F "Ki" '{ print $1 }') - 10500000 ))Ki) \
    --set worker.resources.limits.cpu=$(echo $(( $(kubectl get nodes --selector='starburstpool=default-node-pool' -o jsonpath='{.items[0].status.allocatable.cpu}' | awk -F "m" '{ print $1 }') - 3500 ))m) \
    --set coordinator.nodeSelector.starburstpool=default-node-pool 
```
 

Aquí como podéis observar, hay varias cosas a tener en cuenta. La primera es que todos los componentes de Starburst que se despliegan lo hacen en los nodos con el tag `starburstpool=default-node-pool`. Esto simplemente lo hemos hecho para quitar complejidad a la demo.  En entornos productivos, una buena práctica sería tener un nodepool para el Coordinator y otro nodepool para los Workers de Starburst.

Otra cosa a tener en cuenta es la configuración de la memoria y cpu que se hace tanto en los Workers como en el Coordinator. Como buenas prácticas, Starburst recomienda que haya un pod worker por cada nodo que se despliega en nuestro cluster de Kubernetes. Para ello lo que hemos hecho es ajustar la memoria y cpu de nuestros pods al tamaño de máquina que tenemos. Por último están los valores de configuración que hemos utilizado en el despliegue de Starburst, estos se pueden encontrar en el archivo `starburst.yaml` y son los siguientes:

```yaml
catalogs:
  hive: |
    connector.name=hive
    hive.security=starburst
    hive.metastore.uri=thrift://hive:9083
    hive.gcs.json-key-file-path=/gcs-keyfile/key.json
    hive.gcs.use-access-token=false
  postgres: |
    connector.name=postgresql
    connection-url=jdbc:postgresql://postgresql:5432/insights
    connection-user=******
    connection-password=******
  bigquery: |
      connector.name=bigquery
      bigquery.project-id=******
      bigquery.credentials-file=/gcs-keyfile/key.json
prometheus:
  enabled: true
  agent:
    version: "0.16.1"
    port: 8081
    config: "/etc/starburst/telemetry/prometheus.yaml"
  rules:
    - pattern: trino.execution<name=QueryManager><>(running_queries|queued_queries)
      name: $1
      attrNameSnakeCase: true
      type: GAUGE
    - pattern: 'trino.execution<name=QueryManager><>FailedQueries\.TotalCount'
      name: 'starburst_failed_queries'
      type: COUNTER
    - pattern: 'trino.execution<name=QueryManager><>(running_queries)'
      name: 'starburst_running_queries'
    - pattern: 'trino.execution<name=QueryManager><>StartedQueries\.FiveMinute\.Count'
      name: 'starburst_started_queries'
    - pattern: 'trino.execution<name=SqlTaskManager><>InputPositions\.FiveMinute\.Count'
      name: 'starburst_input_rows'
    - pattern: 'trino.execution<name=SqlTaskManager><>InputDataSize\.FiveMinute\.Count'
      name: 'starburst_input_data_bytes'
    - pattern: 'trino.execution<name=QueryManager><>UserErrorFailures\.FiveMinute\.Count'
      name: 'starburst_failed_queries_user'
    - pattern: 'trino.execution<name=QueryManager><>ExecutionTime\.FiveMinutes\.P50'
      name: 'starburst_latency_p50'
    - pattern: 'trino.execution<name=QueryManager><>WallInputBytesRate\.FiveMinutes\.P90'
      name: 'starburst_latency_p90'
    - pattern: 'trino.failuredetector<name=HeartbeatFailureDetector><>ActiveCount'
      name: 'starburst_active_node'
    - pattern: 'trino.memory<type=ClusterMemoryPool, name=general><>FreeDistributedBytes'
      name: 'starburst_free_memory_pool'
    - pattern: 'trino.memory<name=ClusterMemoryManager><>QueriesKilledDueToOutOfMemory'
      name: 'starburst_queries_killed_due_to_out_of_memory'
    - pattern: 'java.lang<type=Memory><HeapMemoryUsage>committed'
      name: 'starburst_heap_size_usage'
    - pattern: 'java.lang<type=Threading><>ThreadCount'
      name: 'starburst_thread_count'
coordinator:
  envFrom:
  - secretRef:
      name: environment-vars
  additionalProperties: |
    starburst.data-product.enabled=${ENV:data_products_enabled}
    data-product.starburst-jdbc-url=${ENV:data_products_jdbc_url}
    data-product.starburst-user=${ENV:data_products_username}
    data-product.starburst-password=
    query.max-memory=1PB
    starburst.access-control.enabled=${ENV:starburst_access_control_enabled}
    starburst.access-control.authorized-users=${ENV:starburst_access_control_authorized_users}
  etcFiles:
    properties:
      config.properties: |
        coordinator=true
        node-scheduler.include-coordinator=false
        http-server.http.port=8080
        discovery-server.enabled=true
        discovery.uri=http://localhost:8080
        usage-metrics.cluster-usage-resource.enabled=true
        http-server.authentication.allow-insecure-over-http=true
        web-ui.enabled=true
        http-server.process-forwarded=true
        insights.persistence-enabled=true
        insights.metrics-persistence-enabled=true
        insights.jdbc.url=${ENV:database_connection_url}
        insights.jdbc.user=${ENV:database_username}
        insights.jdbc.password=${ENV:database_password}
      password-authenticator.properties: |
        password-authenticator.name=file
  nodeSelector:
    starburstpool: default-node-pool
  resources:
    limits:
      cpu: 2
      memory: 12Gi
    requests:
      cpu: 2
      memory: 12Gi

expose:
  type: clusterIp
  ingress:
    serviceName: starburst
    servicePort: 8080
    host: 
    path: "/"
    pathType: Prefix
    tls:
      enabled: true
      secretName: tls-secret-starburst
    annotations:
      kubernetes.io/ingress.class: nginx
      cert-manager.io/cluster-issuer: letsencrypt

registryCredentials:
  enabled: true
  password: ******
  registry: harbor.starburstdata.net/starburstdata
  username: ******

starburstPlatformLicense: starburst

userDatabase:
  enabled: true
  users:
  - password: ******
    username: ******

worker:
  envFrom:
  - secretRef:
      name: environment-vars
  autoscaling:
    enabled: true
    maxReplicas: 10
    minReplicas: 3
    targetCPUUtilizationPercentage: 40
  deploymentTerminationGracePeriodSeconds: 30
  nodeSelector:
    starburstpool: default-node-pool
  resources:
    limits:
      cpu: 8
      memory: 40Gi
    requests:
      cpu: 8
      memory: 40Gi
  starburstWorkerShutdownGracePeriodSeconds: 120
  tolerations:
    - key: "kubernetes.azure.com/scalesetpriority"
      operator: "Exists"
      effect: "NoSchedule"

additionalVolumes:
  - path: /gcs-keyfile/key.json
    subPath: key.json
    volume:
      configMap:
        name: "sa-key"
```
 

En esta configuración hay varios valores a tener en cuenta, como son catalogs, prometheus, worker y additionalVolumes.

Vamos a empezar explicando la parte de catalogs. Para los que no lo sepan, un catálogo en Starburst es la configuración que permite acceder a unas fuentes de datos determinadas. Cada clúster de Starburst puede tener configurados múltiples catálogos y, por tanto, permitir el acceso a diversas fuentes de datos. En nuestro caso hemos definido el catálogo de Hive, PostgreSQL y Bigquery para poder acceder a dichas fuentes de datos:

```yaml
catalogs:
  hive: |
    connector.name=hive
    hive.security=starburst
    hive.metastore.uri=thrift://hive:9083
    hive.gcs.json-key-file-path=/gcs-keyfile/key.json
    hive.gcs.use-access-token=false
  postgres: |
    connector.name=postgresql
    connection-url=jdbc:postgresql://postgresql:5432/insights
    connection-user=******
    connection-password=******
  bigquery: |
      connector.name=bigquery
      bigquery.project-id=******
      bigquery.credentials-file=/gcs-keyfile/key.json
```
 

La segunda configuración a tener en cuenta es la de Prometheus, esto lo realizamos para exponer ciertas métricas a Prometheus y poder sacar información relevante en un dashboard de Grafana. Para ello tenemos la siguiente configuración:

```yaml
prometheus:
  enabled: true
  agent:
    version: "0.16.1"
    port: 8081
    config: "/etc/starburst/telemetry/prometheus.yaml"
  rules:
    - pattern: trino.execution<name=QueryManager><>(running_queries|queued_queries)
      name: $1
      attrNameSnakeCase: true
      type: GAUGE
    - pattern: 'trino.execution<name=QueryManager><>FailedQueries\.TotalCount'
      name: 'starburst_failed_queries'
      type: COUNTER
    - pattern: 'trino.execution<name=QueryManager><>(running_queries)'
      name: 'starburst_running_queries'
    - pattern: 'trino.execution<name=QueryManager><>StartedQueries\.FiveMinute\.Count'
      name: 'starburst_started_queries'
    - pattern: 'trino.execution<name=SqlTaskManager><>InputPositions\.FiveMinute\.Count'
      name: 'starburst_input_rows'
    - pattern: 'trino.execution<name=SqlTaskManager><>InputDataSize\.FiveMinute\.Count'
      name: 'starburst_input_data_bytes'
    - pattern: 'trino.execution<name=QueryManager><>UserErrorFailures\.FiveMinute\.Count'
      name: 'starburst_failed_queries_user'
    - pattern: 'trino.execution<name=QueryManager><>ExecutionTime\.FiveMinutes\.P50'
      name: 'starburst_latency_p50'
    - pattern: 'trino.execution<name=QueryManager><>WallInputBytesRate\.FiveMinutes\.P90'
      name: 'starburst_latency_p90'
    - pattern: 'trino.failuredetector<name=HeartbeatFailureDetector><>ActiveCount'
      name: 'starburst_active_node'
    - pattern: 'trino.memory<type=ClusterMemoryPool, name=general><>FreeDistributedBytes'
      name: 'starburst_free_memory_pool'
    - pattern: 'trino.memory<name=ClusterMemoryManager><>QueriesKilledDueToOutOfMemory'
      name: 'starburst_queries_killed_due_to_out_of_memory'
    - pattern: 'java.lang<type=Memory><HeapMemoryUsage>committed'
      name: 'starburst_heap_size_usage'
    - pattern: 'java.lang<type=Threading><>ThreadCount'
      name: 'starburst_thread_count'
```
 

En la configuración de los workers, vamos a activar el autoescalado de estos pods. Para ello vamos a realizar una configuración para que haya un mínimo de 3 pods workers que se traducirán en 3 nodos en nuestro cluster de GKE y un máximo de 10 pods. Para el autoescalado vamos a usar la métrica de consumo de CPU. 

Los valores son los siguientes:

```yaml
worker:
  envFrom:
  - secretRef:
      name: environment-vars
  autoscaling:
    enabled: true
    maxReplicas: 10
    minReplicas: 3
    targetCPUUtilizationPercentage: 40
```
 

Por último, añadiremos un volumen adicional a nuestro despliegue para poder montar las credenciales de Google cloud tanto en el coordinator como en los workers.

Esto lo haremos de la siguiente forma:

```yaml
additionalVolumes:
  - path: /gcs-keyfile/key.json
    subPath: key.json
    volume:
      configMap:
        name: "sa-key"
```
 

Con todos estos pasos, tendríamos nuestro cluster de Starburst ya operativo.

Consultas en GCP y autoescalado de Starburst

Una vez realizado el levantamiento del cluster de Starburst, vamos a realizar algunas consultas para probar su rendimiento y funcionamiento. Para ello vamos a realizar consultas de lectura en el esquema de TPCH[13] y después vamos a escribir la salida de estas consultas en el bucket de Google que hemos creado en los pasos de despliegue. 

Las consultas que vamos a ejecutar se encuentran en la carpeta de queries en los archivos `tpch.sql` y `gcs_storage.sql`.

Para lanzar las consultas será tan sencillo como irnos al apartado de consultas de la interfaz web y ejecutar las primeras consultas del archivo `tpch.sql`:

```sql
 CREATE SCHEMA hive.logistic WITH (location = 'gs://starburst-bluetab-test/logistic');

CREATE VIEW "hive"."logistic"."shipping_priority" SECURITY DEFINER AS
SELECT
  l.orderkey
, SUM((l.extendedprice * (1 - l.discount))) revenue
, o.orderdate
, o.shippriority
FROM
  tpch.tiny.customer c
, tpch.tiny.orders o
, tpch.tiny.lineitem l
WHERE ((c.mktsegment = 'BUILDING') AND (c.custkey = o.custkey) AND (l.orderkey = o.orderkey))
GROUP BY l.orderkey, o.orderdate, o.shippriority
ORDER BY revenue DESC, o.orderdate ASC;


CREATE VIEW "hive"."logistic"."minimum_cost_supplier" SECURITY DEFINER AS
SELECT
  s.acctbal
, s.name SupplierName
, n.name Nation
, p.partkey
, p.mfgr
, s.address
, s.phone
, s.comment
FROM
  tpch.tiny.part p
, tpch.tiny.supplier s
, tpch.tiny.partsupp ps
, tpch.tiny.nation n
, tpch.tiny.region r
WHERE ((p.partkey = ps.partkey) AND (s.suppkey = ps.suppkey) AND (p.size = 15) AND (p.type LIKE '%BRASS') AND (s.nationkey = n.nationkey) AND (n.regionkey = r.regionkey) AND (r.name = 'EUROPE') AND (ps.supplycost = (SELECT MIN(ps.supplycost)
FROM
  tpch.tiny.partsupp ps
, tpch.tiny.supplier s
, tpch.tiny.nation n
, tpch.tiny.region r
WHERE ((p.partkey = ps.partkey) AND (s.suppkey = ps.suppkey) AND (s.nationkey = n.nationkey) AND (n.regionkey = r.regionkey) AND (r.name = 'EUROPE'))
)))
ORDER BY s.acctbal DESC, n.name ASC, s.name ASC, p.partkey ASC;



select
  cst.name as CustomerName,
  cst.address,
  cst.phone,
  cst.nationkey,
  cst.acctbal as BookedOrders,
  cst.mktsegment,
  nat.name as Nation,
  reg.name as Region
from tpch.sf1.customer as cst
join tpch.sf1.nation as nat on nat.nationkey = cst.nationkey
join tpch.sf1.region as reg on reg.regionkey = nat.regionkey
where reg.regionkey = 1;

select
  nat.name as Nation,
  avg(cst.acctbal) as average_booking
from tpch.sf100.customer as cst
join tpch.sf100.nation as nat on nat.nationkey = cst.nationkey
join tpch.sf100.region as reg on reg.regionkey = nat.regionkey
where reg.regionkey = 1
group by nat.name;
```
 

En estas pruebas crearemos una serie de vistas y haremos unos selects con varios cruces sobre las tablas de customer(15000000 rows), nation(25 rows) y region(5 rows) del esquema sf100 para comprobar que todo funciona correctamente y ver que tenemos nuestra plataforma operativa. Una vez comprobado que todo es correcto, probaremos a escribir algunos resultados en el bucket que hemos creado.

Para ello lanzaremos las consultas que se encuentran en el archivo `gcs_storage.sql`:

{"type":"elementor","siteurl":"https://bluetab.net/es/wp-json/","elements":[{"id":"1a82503","elType":"widget","isInner":false,"isLocked":false,"settings":{"code_language":"python","code_block":"```sql\n CREATE SCHEMA hive.logistic WITH (location = 'gs://starburst-bluetab-test/logistic');\n\nCREATE VIEW \"hive\".\"logistic\".\"shipping_priority\" SECURITY DEFINER AS\nSELECT\n  l.orderkey\n, SUM((l.extendedprice * (1 - l.discount))) revenue\n, o.orderdate\n, o.shippriority\nFROM\n  tpch.tiny.customer c\n, tpch.tiny.orders o\n, tpch.tiny.lineitem l\nWHERE ((c.mktsegment = 'BUILDING') AND (c.custkey = o.custkey) AND (l.orderkey = o.orderkey))\nGROUP BY l.orderkey, o.orderdate, o.shippriority\nORDER BY revenue DESC, o.orderdate ASC;\n\n\nCREATE VIEW \"hive\".\"logistic\".\"minimum_cost_supplier\" SECURITY DEFINER AS\nSELECT\n  s.acctbal\n, s.name SupplierName\n, n.name Nation\n, p.partkey\n, p.mfgr\n, s.address\n, s.phone\n, s.comment\nFROM\n  tpch.tiny.part p\n, tpch.tiny.supplier s\n, tpch.tiny.partsupp ps\n, tpch.tiny.nation n\n, tpch.tiny.region r\nWHERE ((p.partkey = ps.partkey) AND (s.suppkey = ps.suppkey) AND (p.size = 15) AND (p.type LIKE '%BRASS') AND (s.nationkey = n.nationkey) AND (n.regionkey = r.regionkey) AND (r.name = 'EUROPE') AND (ps.supplycost = (SELECT MIN(ps.supplycost)\nFROM\n  tpch.tiny.partsupp ps\n, tpch.tiny.supplier s\n, tpch.tiny.nation n\n, tpch.tiny.region r\nWHERE ((p.partkey = ps.partkey) AND (s.suppkey = ps.suppkey) AND (s.nationkey = n.nationkey) AND (n.regionkey = r.regionkey) AND (r.name = 'EUROPE'))\n)))\nORDER BY s.acctbal DESC, n.name ASC, s.name ASC, p.partkey ASC;\n\n\n\nselect\n  cst.name as CustomerName,\n  cst.address,\n  cst.phone,\n  cst.nationkey,\n  cst.acctbal as BookedOrders,\n  cst.mktsegment,\n  nat.name as Nation,\n  reg.name as Region\nfrom tpch.sf1.customer as cst\njoin tpch.sf1.nation as nat on nat.nationkey = cst.nationkey\njoin tpch.sf1.region as reg on reg.regionkey = nat.regionkey\nwhere reg.regionkey = 1;\n\nselect\n  nat.name as Nation,\n  avg(cst.acctbal) as average_booking\nfrom tpch.sf100.customer as cst\njoin tpch.sf100.nation as nat on nat.nationkey = cst.nationkey\njoin tpch.sf100.region as reg on reg.regionkey = nat.regionkey\nwhere reg.regionkey = 1\ngroup by nat.name;\n```\n","_title":"","_margin":{"unit":"px","top":"","right":"","bottom":"","left":"","isLinked":true},"_margin_tablet":{"unit":"px","top":"","right":"","bottom":"","left":"","isLinked":true},"_margin_mobile":{"unit":"px","top":"","right":"","bottom":"","left":"","isLinked":true},"_padding":{"unit":"px","top":"","right":"","bottom":"","left":"","isLinked":true},"_padding_tablet":{"unit":"px","top":"","right":"","bottom":"","left":"","isLinked":true},"_padding_mobile":{"unit":"px","top":"","right":"","bottom":"","left":"","isLinked":true},"_element_width":"","_element_width_tablet":"","_element_width_mobile":"","_element_custom_width":{"unit":"%","size":"","sizes":[]},"_element_custom_width_tablet":{"unit":"px","size":"","sizes":[]},"_element_custom_width_mobile":{"unit":"px","size":"","sizes":[]},"_element_vertical_align":"","_element_vertical_align_tablet":"","_element_vertical_align_mobile":"","_position":"","_offset_orientation_h":"start","_offset_x":{"unit":"px","size":"0","sizes":[]},"_offset_x_tablet":{"unit":"px","size":"","sizes":[]},"_offset_x_mobile":{"unit":"px","size":"","sizes":[]},"_offset_x_end":{"unit":"px","size":"0","sizes":[]},"_offset_x_end_tablet":{"unit":"px","size":"","sizes":[]},"_offset_x_end_mobile":{"unit":"px","size":"","sizes":[]},"_offset_orientation_v":"start","_offset_y":{"unit":"px","size":"0","sizes":[]},"_offset_y_tablet":{"unit":"px","size":"","sizes":[]},"_offset_y_mobile":{"unit":"px","size":"","sizes":[]},"_offset_y_end":{"unit":"px","size":"0","sizes":[]},"_offset_y_end_tablet":{"unit":"px","size":"","sizes":[]},"_offset_y_end_mobile":{"unit":"px","size":"","sizes":[]},"_z_index":"","_z_index_tablet":"","_z_index_mobile":"","_element_id":"","_css_classes":"","motion_fx_motion_fx_scrolling":"","motion_fx_translateY_effect":"","motion_fx_translateY_direction":"","motion_fx_translateY_speed":{"unit":"px","size":4,"sizes":[]},"motion_fx_translateY_affectedRange":{"unit":"%","size":"","sizes":{"start":0,"end":100}},"motion_fx_translateX_effect":"","motion_fx_translateX_direction":"","motion_fx_translateX_speed":{"unit":"px","size":4,"sizes":[]},"motion_fx_translateX_affectedRange":{"unit":"%","size":"","sizes":{"start":0,"end":100}},"motion_fx_opacity_effect":"","motion_fx_opacity_direction":"out-in","motion_fx_opacity_level":{"unit":"px","size":10,"sizes":[]},"motion_fx_opacity_range":{"unit":"%","size":"","sizes":{"start":20,"end":80}},"motion_fx_blur_effect":"","motion_fx_blur_direction":"out-in","motion_fx_blur_level":{"unit":"px","size":7,"sizes":[]},"motion_fx_blur_range":{"unit":"%","size":"","sizes":{"start":20,"end":80}},"motion_fx_rotateZ_effect":"","motion_fx_rotateZ_direction":"","motion_fx_rotateZ_speed":{"unit":"px","size":1,"sizes":[]},"motion_fx_rotateZ_affectedRange":{"unit":"%","size":"","sizes":{"start":0,"end":100}},"motion_fx_scale_effect":"","motion_fx_scale_direction":"out-in","motion_fx_scale_speed":{"unit":"px","size":4,"sizes":[]},"motion_fx_scale_range":{"unit":"%","size":"","sizes":{"start":20,"end":80}},"motion_fx_transform_origin_x":"center","motion_fx_transform_origin_y":"center","motion_fx_devices":["desktop","tablet","mobile"],"motion_fx_range":"","motion_fx_motion_fx_mouse":"","motion_fx_mouseTrack_effect":"","motion_fx_mouseTrack_direction":"","motion_fx_mouseTrack_speed":{"unit":"px","size":1,"sizes":[]},"motion_fx_tilt_effect":"","motion_fx_tilt_direction":"","motion_fx_tilt_speed":{"unit":"px","size":4,"sizes":[]},"sticky":"","sticky_on":["desktop","tablet","mobile"],"sticky_offset":0,"sticky_offset_tablet":"","sticky_offset_mobile":"","sticky_effects_offset":0,"sticky_effects_offset_tablet":"","sticky_effects_offset_mobile":"","sticky_parent":"","_animation":"","_animation_tablet":"","_animation_mobile":"","animation_duration":"","_animation_delay":"","_transform_rotate_popover":"","_transform_rotateZ_effect":{"unit":"px","size":"","sizes":[]},"_transform_rotateZ_effect_tablet":{"unit":"deg","size":"","sizes":[]},"_transform_rotateZ_effect_mobile":{"unit":"deg","size":"","sizes":[]},"_transform_rotate_3d":"","_transform_rotateX_effect":{"unit":"px","size":"","sizes":[]},"_transform_rotateX_effect_tablet":{"unit":"deg","size":"","sizes":[]},"_transform_rotateX_effect_mobile":{"unit":"deg","size":"","sizes":[]},"_transform_rotateY_effect":{"unit":"px","size":"","sizes":[]},"_transform_rotateY_effect_tablet":{"unit":"deg","size":"","sizes":[]},"_transform_rotateY_effect_mobile":{"unit":"deg","size":"","sizes":[]},"_transform_perspective_effect":{"unit":"px","size":"","sizes":[]},"_transform_perspective_effect_tablet":{"unit":"px","size":"","sizes":[]},"_transform_perspective_effect_mobile":{"unit":"px","size":"","sizes":[]},"_transform_translate_popover":"","_transform_translateX_effect":{"unit":"px","size":"","sizes":[]},"_transform_translateX_effect_tablet":{"unit":"px","size":"","sizes":[]},"_transform_translateX_effect_mobile":{"unit":"px","size":"","sizes":[]},"_transform_translateY_effect":{"unit":"px","size":"","sizes":[]},"_transform_translateY_effect_tablet":{"unit":"px","size":"","sizes":[]},"_transform_translateY_effect_mobile":{"unit":"px","size":"","sizes":[]},"_transform_scale_popover":"","_transform_keep_proportions":"yes","_transform_scale_effect":{"unit":"px","size":"","sizes":[]},"_transform_scale_effect_tablet":{"unit":"px","size":"","sizes":[]},"_transform_scale_effect_mobile":{"unit":"px","size":"","sizes":[]},"_transform_scaleX_effect":{"unit":"px","size":"","sizes":[]},"_transform_scaleX_effect_tablet":{"unit":"px","size":"","sizes":[]},"_transform_scaleX_effect_mobile":{"unit":"px","size":"","sizes":[]},"_transform_scaleY_effect":{"unit":"px","size":"","sizes":[]},"_transform_scaleY_effect_tablet":{"unit":"px","size":"","sizes":[]},"_transform_scaleY_effect_mobile":{"unit":"px","size":"","sizes":[]},"_transform_skew_popover":"","_transform_skewX_effect":{"unit":"px","size":"","sizes":[]},"_transform_skewX_effect_tablet":{"unit":"deg","size":"","sizes":[]},"_transform_skewX_effect_mobile":{"unit":"deg","size":"","sizes":[]},"_transform_skewY_effect":{"unit":"px","size":"","sizes":[]},"_transform_skewY_effect_tablet":{"unit":"deg","size":"","sizes":[]},"_transform_skewY_effect_mobile":{"unit":"deg","size":"","sizes":[]},"_transform_flipX_effect":"","_transform_flipY_effect":"","_transform_rotate_popover_hover":"","_transform_rotateZ_effect_hover":{"unit":"px","size":"","sizes":[]},"_transform_rotateZ_effect_hover_tablet":{"unit":"deg","size":"","sizes":[]},"_transform_rotateZ_effect_hover_mobile":{"unit":"deg","size":"","sizes":[]},"_transform_rotate_3d_hover":"","_transform_rotateX_effect_hover":{"unit":"px","size":"","sizes":[]},"_transform_rotateX_effect_hover_tablet":{"unit":"deg","size":"","sizes":[]},"_transform_rotateX_effect_hover_mobile":{"unit":"deg","size":"","sizes":[]},"_transform_rotateY_effect_hover":{"unit":"px","size":"","sizes":[]},"_transform_rotateY_effect_hover_tablet":{"unit":"deg","size":"","sizes":[]},"_transform_rotateY_effect_hover_mobile":{"unit":"deg","size":"","sizes":[]},"_transform_perspective_effect_hover":{"unit":"px","size":"","sizes":[]},"_transform_perspective_effect_hover_tablet":{"unit":"px","size":"","sizes":[]},"_transform_perspective_effect_hover_mobile":{"unit":"px","size":"","sizes":[]},"_transform_translate_popover_hover":"","_transform_translateX_effect_hover":{"unit":"px","size":"","sizes":[]},"_transform_translateX_effect_hover_tablet":{"unit":"px","size":"","sizes":[]},"_transform_translateX_effect_hover_mobile":{"unit":"px","size":"","sizes":[]},"_transform_translateY_effect_hover":{"unit":"px","size":"","sizes":[]},"_transform_translateY_effect_hover_tablet":{"unit":"px","size":"","sizes":[]},"_transform_translateY_effect_hover_mobile":{"unit":"px","size":"","sizes":[]},"_transform_scale_popover_hover":"","_transform_keep_proportions_hover":"yes","_transform_scale_effect_hover":{"unit":"px","size":"","sizes":[]},"_transform_scale_effect_hover_tablet":{"unit":"px","size":"","sizes":[]},"_transform_scale_effect_hover_mobile":{"unit":"px","size":"","sizes":[]},"_transform_scaleX_effect_hover":{"unit":"px","size":"","sizes":[]},"_transform_scaleX_effect_hover_tablet":{"unit":"px","size":"","sizes":[]},"_transform_scaleX_effect_hover_mobile":{"unit":"px","size":"","sizes":[]},"_transform_scaleY_effect_hover":{"unit":"px","size":"","sizes":[]},"_transform_scaleY_effect_hover_tablet":{"unit":"px","size":"","sizes":[]},"_transform_scaleY_effect_hover_mobile":{"unit":"px","size":"","sizes":[]},"_transform_skew_popover_hover":"","_transform_skewX_effect_hover":{"unit":"px","size":"","sizes":[]},"_transform_skewX_effect_hover_tablet":{"unit":"deg","size":"","sizes":[]},"_transform_skewX_effect_hover_mobile":{"unit":"deg","size":"","sizes":[]},"_transform_skewY_effect_hover":{"unit":"px","size":"","sizes":[]},"_transform_skewY_effect_hover_tablet":{"unit":"deg","size":"","sizes":[]},"_transform_skewY_effect_hover_mobile":{"unit":"deg","size":"","sizes":[]},"_transform_flipX_effect_hover":"","_transform_flipY_effect_hover":"","_transform_transition_hover":{"unit":"px","size":"","sizes":[]},"motion_fx_transform_x_anchor_point":"","motion_fx_transform_x_anchor_point_tablet":"","motion_fx_transform_x_anchor_point_mobile":"","motion_fx_transform_y_anchor_point":"","motion_fx_transform_y_anchor_point_tablet":"","motion_fx_transform_y_anchor_point_mobile":"","_background_background":"","_background_color":"","_background_color_stop":{"unit":"%","size":0,"sizes":[]},"_background_color_b":"#f2295b","_background_color_b_stop":{"unit":"%","size":100,"sizes":[]},"_background_gradient_type":"linear","_background_gradient_angle":{"unit":"deg","size":180,"sizes":[]},"_background_gradient_position":"center center","_background_image":{"url":"","id":"","size":""},"_background_image_tablet":{"url":"","id":"","size":""},"_background_image_mobile":{"url":"","id":"","size":""},"_background_position":"","_background_position_tablet":"","_background_position_mobile":"","_background_xpos":{"unit":"px","size":0,"sizes":[]},"_background_xpos_tablet":{"unit":"px","size":0,"sizes":[]},"_background_xpos_mobile":{"unit":"px","size":0,"sizes":[]},"_background_ypos":{"unit":"px","size":0,"sizes":[]},"_background_ypos_tablet":{"unit":"px","size":0,"sizes":[]},"_background_ypos_mobile":{"unit":"px","size":0,"sizes":[]},"_background_attachment":"","_background_repeat":"","_background_repeat_tablet":"","_background_repeat_mobile":"","_background_size":"","_background_size_tablet":"","_background_size_mobile":"","_background_bg_width":{"unit":"%","size":100,"sizes":[]},"_background_bg_width_tablet":{"unit":"px","size":"","sizes":[]},"_background_bg_width_mobile":{"unit":"px","size":"","sizes":[]},"_background_video_link":"","_background_video_start":"","_background_video_end":"","_background_play_once":"","_background_play_on_mobile":"","_background_privacy_mode":"","_background_video_fallback":{"url":"","id":"","size":""},"_background_slideshow_gallery":[],"_background_slideshow_loop":"yes","_background_slideshow_slide_duration":5000,"_background_slideshow_slide_transition":"fade","_background_slideshow_transition_duration":500,"_background_slideshow_background_size":"","_background_slideshow_background_size_tablet":"","_background_slideshow_background_size_mobile":"","_background_slideshow_background_position":"","_background_slideshow_background_position_tablet":"","_background_slideshow_background_position_mobile":"","_background_slideshow_lazyload":"","_background_slideshow_ken_burns":"","_background_slideshow_ken_burns_zoom_direction":"in","_background_hover_background":"","_background_hover_color":"","_background_hover_color_stop":{"unit":"%","size":0,"sizes":[]},"_background_hover_color_b":"#f2295b","_background_hover_color_b_stop":{"unit":"%","size":100,"sizes":[]},"_background_hover_gradient_type":"linear","_background_hover_gradient_angle":{"unit":"deg","size":180,"sizes":[]},"_background_hover_gradient_position":"center center","_background_hover_image":{"url":"","id":"","size":""},"_background_hover_image_tablet":{"url":"","id":"","size":""},"_background_hover_image_mobile":{"url":"","id":"","size":""},"_background_hover_position":"","_background_hover_position_tablet":"","_background_hover_position_mobile":"","_background_hover_xpos":{"unit":"px","size":0,"sizes":[]},"_background_hover_xpos_tablet":{"unit":"px","size":0,"sizes":[]},"_background_hover_xpos_mobile":{"unit":"px","size":0,"sizes":[]},"_background_hover_ypos":{"unit":"px","size":0,"sizes":[]},"_background_hover_ypos_tablet":{"unit":"px","size":0,"sizes":[]},"_background_hover_ypos_mobile":{"unit":"px","size":0,"sizes":[]},"_background_hover_attachment":"","_background_hover_repeat":"","_background_hover_repeat_tablet":"","_background_hover_repeat_mobile":"","_background_hover_size":"","_background_hover_size_tablet":"","_background_hover_size_mobile":"","_background_hover_bg_width":{"unit":"%","size":100,"sizes":[]},"_background_hover_bg_width_tablet":{"unit":"px","size":"","sizes":[]},"_background_hover_bg_width_mobile":{"unit":"px","size":"","sizes":[]},"_background_hover_video_link":"","_background_hover_video_start":"","_background_hover_video_end":"","_background_hover_play_once":"","_background_hover_play_on_mobile":"","_background_hover_privacy_mode":"","_background_hover_video_fallback":{"url":"","id":"","size":""},"_background_hover_slideshow_gallery":[],"_background_hover_slideshow_loop":"yes","_background_hover_slideshow_slide_duration":5000,"_background_hover_slideshow_slide_transition":"fade","_background_hover_slideshow_transition_duration":500,"_background_hover_slideshow_background_size":"","_background_hover_slideshow_background_size_tablet":"","_background_hover_slideshow_background_size_mobile":"","_background_hover_slideshow_background_position":"","_background_hover_slideshow_background_position_tablet":"","_background_hover_slideshow_background_position_mobile":"","_background_hover_slideshow_lazyload":"","_background_hover_slideshow_ken_burns":"","_background_hover_slideshow_ken_burns_zoom_direction":"in","_background_hover_transition":{"unit":"px","size":"","sizes":[]},"_border_border":"","_border_width":{"unit":"px","top":"","right":"","bottom":"","left":"","isLinked":true},"_border_width_tablet":{"unit":"px","top":"","right":"","bottom":"","left":"","isLinked":true},"_border_width_mobile":{"unit":"px","top":"","right":"","bottom":"","left":"","isLinked":true},"_border_color":"","_border_radius":{"unit":"px","top":"","right":"","bottom":"","left":"","isLinked":true},"_border_radius_tablet":{"unit":"px","top":"","right":"","bottom":"","left":"","isLinked":true},"_border_radius_mobile":{"unit":"px","top":"","right":"","bottom":"","left":"","isLinked":true},"_box_shadow_box_shadow_type":"","_box_shadow_box_shadow":{"horizontal":0,"vertical":0,"blur":10,"spread":0,"color":"rgba(0,0,0,0.5)"},"_box_shadow_box_shadow_position":" ","_border_hover_border":"","_border_hover_width":{"unit":"px","top":"","right":"","bottom":"","left":"","isLinked":true},"_border_hover_width_tablet":{"unit":"px","top":"","right":"","bottom":"","left":"","isLinked":true},"_border_hover_width_mobile":{"unit":"px","top":"","right":"","bottom":"","left":"","isLinked":true},"_border_hover_color":"","_border_radius_hover":{"unit":"px","top":"","right":"","bottom":"","left":"","isLinked":true},"_border_radius_hover_tablet":{"unit":"px","top":"","right":"","bottom":"","left":"","isLinked":true},"_border_radius_hover_mobile":{"unit":"px","top":"","right":"","bottom":"","left":"","isLinked":true},"_box_shadow_hover_box_shadow_type":"","_box_shadow_hover_box_shadow":{"horizontal":0,"vertical":0,"blur":10,"spread":0,"color":"rgba(0,0,0,0.5)"},"_box_shadow_hover_box_shadow_position":" ","_border_hover_transition":{"unit":"px","size":"","sizes":[]},"_mask_switch":"","_mask_shape":"circle","_mask_image":{"url":"","id":"","size":""},"_mask_notice":"","_mask_size":"contain","_mask_size_tablet":"","_mask_size_mobile":"","_mask_size_scale":{"unit":"%","size":100,"sizes":[]},"_mask_size_scale_tablet":{"unit":"px","size":"","sizes":[]},"_mask_size_scale_mobile":{"unit":"px","size":"","sizes":[]},"_mask_position":"center center","_mask_position_tablet":"","_mask_position_mobile":"","_mask_position_x":{"unit":"%","size":0,"sizes":[]},"_mask_position_x_tablet":{"unit":"px","size":"","sizes":[]},"_mask_position_x_mobile":{"unit":"px","size":"","sizes":[]},"_mask_position_y":{"unit":"%","size":0,"sizes":[]},"_mask_position_y_tablet":{"unit":"px","size":"","sizes":[]},"_mask_position_y_mobile":{"unit":"px","size":"","sizes":[]},"_mask_repeat":"no-repeat","_mask_repeat_tablet":"","_mask_repeat_mobile":"","hide_desktop":"","hide_tablet":"","hide_mobile":"","_attributes":"","custom_css":""},"defaultEditSettings":{"defaultEditRoute":"content"},"elements":[],"widgetType":"elementor-syntax-highlighter","editSettings":{"defaultEditRoute":"content","panel":{"activeTab":"content","activeSection":"content_section"}},"htmlCache":"\t\t<div class=\"elementor-widget-container\">\n\t\t\t<pre><code class='language-python'>```sql\n CREATE SCHEMA hive.logistic WITH (location = 'gs://starburst-bluetab-test/logistic');\n\nCREATE VIEW &quot;hive&quot;.&quot;logistic&quot;.&quot;shipping_priority&quot; SECURITY DEFINER AS\nSELECT\n  l.orderkey\n, SUM((l.extendedprice * (1 - l.discount))) revenue\n, o.orderdate\n, o.shippriority\nFROM\n  tpch.tiny.customer c\n, tpch.tiny.orders o\n, tpch.tiny.lineitem l\nWHERE ((c.mktsegment = 'BUILDING') AND (c.custkey = o.custkey) AND (l.orderkey = o.orderkey))\nGROUP BY l.orderkey, o.orderdate, o.shippriority\nORDER BY revenue DESC, o.orderdate ASC;\n\n\nCREATE VIEW &quot;hive&quot;.&quot;logistic&quot;.&quot;minimum_cost_supplier&quot; SECURITY DEFINER AS\nSELECT\n  s.acctbal\n, s.name SupplierName\n, n.name Nation\n, p.partkey\n, p.mfgr\n, s.address\n, s.phone\n, s.comment\nFROM\n  tpch.tiny.part p\n, tpch.tiny.supplier s\n, tpch.tiny.partsupp ps\n, tpch.tiny.nation n\n, tpch.tiny.region r\nWHERE ((p.partkey = ps.partkey) AND (s.suppkey = ps.suppkey) AND (p.size = 15) AND (p.type LIKE '%BRASS') AND (s.nationkey = n.nationkey) AND (n.regionkey = r.regionkey) AND (r.name = 'EUROPE') AND (ps.supplycost = (SELECT MIN(ps.supplycost)\nFROM\n  tpch.tiny.partsupp ps\n, tpch.tiny.supplier s\n, tpch.tiny.nation n\n, tpch.tiny.region r\nWHERE ((p.partkey = ps.partkey) AND (s.suppkey = ps.suppkey) AND (s.nationkey = n.nationkey) AND (n.regionkey = r.regionkey) AND (r.name = 'EUROPE'))\n)))\nORDER BY s.acctbal DESC, n.name ASC, s.name ASC, p.partkey ASC;\n\n\n\nselect\n  cst.name as CustomerName,\n  cst.address,\n  cst.phone,\n  cst.nationkey,\n  cst.acctbal as BookedOrders,\n  cst.mktsegment,\n  nat.name as Nation,\n  reg.name as Region\nfrom tpch.sf1.customer as cst\njoin tpch.sf1.nation as nat on nat.nationkey = cst.nationkey\njoin tpch.sf1.region as reg on reg.regionkey = nat.regionkey\nwhere reg.regionkey = 1;\n\nselect\n  nat.name as Nation,\n  avg(cst.acctbal) as average_booking\nfrom tpch.sf100.customer as cst\njoin tpch.sf100.nation as nat on nat.nationkey = cst.nationkey\njoin tpch.sf100.region as reg on reg.regionkey = nat.regionkey\nwhere reg.regionkey = 1\ngroup by nat.name;\n```\n </code></pre><script>\nif (!document.getElementById('syntaxed-prism')) {\n\tvar my_awesome_script = document.createElement('script');\n\tmy_awesome_script.setAttribute('src','https://bluetab.net/wp-content/plugins/syntax-highlighter-for-elementor/assets/prism2.js');\n\tmy_awesome_script.setAttribute('id','syntaxed-prism');\n\tdocument.body.appendChild(my_awesome_script);\n} else {\n\twindow.Prism && Prism.highlightAll();\n}\n</script>\t\t</div>\n\t\t"}]} 

En esta prueba lo más relevante es que vamos a escribir los datos de la tablas customer(15000000 rows), orders(150000000 rows), supplier(1000000 rows), nation(25 rows) y region(5 rows) en nuestro bucket de GCS.

Como comentamos anteriormente, Starburst no solo es una herramienta que te permite lanzar consultas para analizar datos, sino que también te puede ayudar en las migraciones de datos de tu compañía, volcando la información de tu base de datos a tu plataforma de la nube. Una cosa muy importante a tener en cuenta es que Starburst te permite trabajar con distintos tipos de fichero, pudiendo escribir tus tablas finales en ORC, Parquet o formatos como Delta o Hudi dándote una libertad muy amplia en las migraciones al cloud.

Como última prueba para ver que todo está funcionando correctamente, vamos a lanzar una consulta para federar distintos datos de diversas fuentes. En nuestro caso, federaremos datos de la anterior tabla que hemos creado en Google Cloud Storage llamada customer con una tabla llamada nation, que nos crearemos en el PostgreSQL que hemos configurado en nuestro despliegue, y la tabla region que está en el esquema tcph. Esta consulta la podemos encontrar en el archivo `federate.sql`:

create schema postgres.logistic;
create table postgres.logistic.nation as select * from tpch.sf1.nation;

select
  cst.name as CustomerName,
  cst.address,
  cst.phone,
  cst.nationkey,
  cst.acctbal as BookedOrders,
  cst.mktsegment,
  nat.name as Nation,
  reg.name as Region
from hive.datalake.customer as cst
join postgres.logistic.nation as nat on nat.nationkey = cst.nationkey
join tpch.sf1.region as reg on reg.regionkey = nat.regionkey
where reg.regionkey = 1;
 

Este tipo de consultas es uno de los puntos fuertes que tiene Starburst, poder federar consultas que se encuentren en distintos silos de información sin la necesidad de migrar los datos y pudiendo atacar a distintos Cloud o a información que se tenga en el onpremise. 

Una vez que hemos probado que tanto las consultas como la escritura en GCS funcionan correctamente, vamos a realizar unos test de performance para simular usuarios en paralelo y ver como autoescala nuestra plataforma. Vamos a configurar JMeter para estas pruebas. Para ello hemos tenido que configurar el conector jdbc de trino para que mande consultas a nuestro cluster.

Vamos a simular 20 usuarios en paralelo, y cada uno lanzará una secuencia de 5 consultas. Esto significa que habrá 20 consultas en paralelo al mismo tiempo, simulando un escenario real, ya que generalmente no se lanzarán consultas de todos los usuarios en el mismo momento. Las consultas que vamos a ejecutar son las siguiente:

```sql
select
  cst.name as CustomerName,
  cst.address,
  cst.phone,
  cst.nationkey,
  cst.acctbal as BookedOrders,
  cst.mktsegment,
  nat.name as Nation,
  reg.name as Region
from tpch.sf1.customer as cst
join tpch.sf1.nation as nat on nat.nationkey = cst.nationkey
join tpch.sf1.region as reg on reg.regionkey = nat.regionkey
where reg.regionkey = 1;

SELECT
  s.acctbal
, s.name SupplierName
, n.name Nation
, p.partkey
, p.mfgr
, s.address
, s.phone
, s.comment
FROM
  tpch.tiny.part p
, tpch.tiny.supplier s
, tpch.tiny.partsupp ps
, tpch.tiny.nation n
, tpch.tiny.region r
WHERE ((p.partkey = ps.partkey) AND (s.suppkey = ps.suppkey) AND (p.size = 15) AND (p.type LIKE '%BRASS') AND (s.nationkey = n.nationkey) AND (n.regionkey = r.regionkey) AND (r.name = 'EUROPE') AND (ps.supplycost = (SELECT MIN(ps.supplycost)
FROM
  tpch.tiny.partsupp ps
, tpch.tiny.supplier s
, tpch.tiny.nation n
, tpch.tiny.region r
WHERE ((p.partkey = ps.partkey) AND (s.suppkey = ps.suppkey) AND (s.nationkey = n.nationkey) AND (n.regionkey = r.regionkey) AND (r.name = 'EUROPE'))
)))
ORDER BY s.acctbal DESC, n.name ASC, s.name ASC, p.partkey ASC;

SELECT
count(*)
FROM
  tpch.sf1.customer c
, tpch.sf1.orders o
, tpch.sf1.lineitem l
WHERE ((c.mktsegment = 'BUILDING') AND (c.custkey = o.custkey) AND (l.orderkey = o.orderkey))
GROUP BY l.orderkey, o.orderdate, o.shippriority
ORDER BY o.orderdate ASC;
```
 

Si nos fijamos, en nuestro cluster de Kubernetes podemos ver que se están levantando más workers de Starburst por el momento de alta demanda en nuestra simulación:

Esto es una de las características más cómodas e importantes que nos da Starburst, ya que hace que nuestra plataforma de analítica de datos sea 100% elástica y podamos ir adaptándonos a los picos de demanda que tengamos.

Métricas

Por último, Starburst nos proporciona una interfaz donde visualizar ciertas métricas del consumo de nuestro cluster, como puede ser la memoria, la cpu o las consultas realizadas en tiempo real en nuestro cluster.

Además de estas métricas, hemos añadido también a nuestra configuración el despliegue de Prometheus y Grafana para integrarnos con las herramientas más comunes dentro de cualquier organización. Las métricas que hemos añadido a Grafana son consumo de memoria de nuestro cluster de Starburst, consultas realizadas por los usuarios, consultas con errores, memoria total de nuestro cluster de Kubernetes y Workers activos. Una vez integradas dichas métricas, el dashboard que tendríamos sería el siguiente:

Una vez integrado con Grafana, podríamos crearnos alertas de envío de mensajes por si hay algún problema en nuestro cluster de Starburst, y así tener todo el flujo de operaciones cubierto para evitarnos dolores de cabeza si hubiera algún tipo de incidencia o indisponibilidad.

El dashboard está publicado en Grafana[14] para que cualquier persona pueda hacer uso de él.

Conclusiones

Desde hace ya unos años, las grandes corporaciones se enfrentan a un desafío común cuando intentan compartir y analizar información entre departamentos ya que cada departamento almacena y gestiona sus datos de manera aislada. Estos silos dificultan el acceso y la integración de datos, lo que impide una visión completa y unificada de la información empresarial. La falta de interoperabilidad entre los silos de datos obstaculiza la toma de decisiones informada, ralentiza los procesos analíticos y limita la capacidad de las organizaciones para obtener una ventaja competitiva. Si tu organización se encuentra en una situación similar, Starburst es tu herramienta.

Starburst te facilita el acceso y análisis a todos estos silos de información y da la capacidad de federar datos de diversas fuentes y ubicaciones, ya sea datos en el Cloud o en tu datacenter onpremise. Permite realizar consultas en tiempo real sin necesidad de mover o transformar los datos previamente. Esto agiliza el proceso analítico y brinda a las organizaciones una visión 360 de sus datos. Además, no solo te ayuda a la hora de consultar datos de distintas fuentes, sino que también te puede ayudar en tus migraciones al Cloud, ya que te permite consultar cualquier origen y volcar dicha información en un almacenamiento como S3 o GCS en formato de ficheros abierto, como puede ser Parquet.

Una de las principales ventajas de Starburst, es que te permite desplegar la infraestructura en Kubernetes para aprovechar así todo su potencial. Kubernetes te da la capacidad de adaptarse dinámicamente a la carga de trabajo. Con esta función, los clústeres de Starburst pueden aumentar o disminuir automáticamente el número de Workers según la demanda. Esto permite optimizar el uso de recursos y garantizar un rendimiento óptimo, ya que los pods adicionales se crean cuando la carga aumenta y se eliminan cuando disminuye. Esto dentro de cualquier organización es un punto muy importante, ya que mejora la eficiencia operativa al minimizar el tiempo de inactividad y los costos innecesarios, al tiempo que asegura una disponibilidad constante y una respuesta ágil a los picos de trabajo. Además, una cosa a tener en cuenta es que puedes realizar la instalación de Starburst tanto en cualquiera de los Cloud, como en onpremise.

Además, también te permite tener un roleado y gobierno de los usuarios dentro de tu plataforma, dando una granularidad a nivel de acceso a los datos a cada usuario, permitiéndote crear roles para ciertos esquemas, tablas o hasta columnas y filas dentro de una tabla.

Los que trabajamos con datos sabemos de la dificultad de trabajar con multitud de fuentes de datos, entornos diversos, herramientas de todo tipo, etc. Uno de los puntos más diferenciales de Starburst es tener la capacidad de consultar los datos desde su almacenamiento, eliminando duplicidad de información, pudiendo así tener una mejor eficiencia en cuanto al storage, y facilitando también el gobierno de estos datos.

En conclusión, Starburst es una herramienta a tener en cuenta si quieres llevar a tu organización al siguiente nivel en el mundo de los datos, o si te estás planteando una estrategia de datos con una visión y una filosofía más orientada al data mesh.

Referencias

[1] Qué es Starburst.[link] 

[2] Qué es Trino. [link]

[3] Principios del Data Mesh. [link]

[4] Introducción  a DBT. [link]

[5] Introducción a Jupyter Notebook. [link]

[6] Introducción a Power BI. [link]

[7] Qué es Prometheus.. [link]

[8] Qué es Grafana. [link]

[9] Qué es Terraform. [link]

[10] Qué es Jmeter.[link]

[11] Módulo de GKE.[link]

[12] Módulo de VPC.[link]

[13] Qué es TPCH.[link]

[14] Dashboard Grafana.[link]

[15] Repositorio de Github con el despliegue.[link]

Navegación

Lucas Calvo

Cloud Engineer

¿Quieres saber más de lo que ofrecemos y ver otros casos de éxito?
DESCUBRE BLUETAB

SOLUCIONES, SOMOS EXPERTOS

DATA STRATEGY
DATA FABRIC
AUGMENTED ANALYTICS

Te puede interesar

MDM as a Competitive Advantage in Organizations

June 18, 2024
LEER MÁS

Cómo preparar la certificación AWS Data Analytics – Specialty

November 17, 2021
LEER MÁS

LakeHouse Streaming on AWS with Apache Flink and Hudi (Part 2)

October 4, 2023
LEER MÁS

Bank Fraud detection with automatic learning

September 17, 2020
LEER MÁS

How much is your customer worth?

October 1, 2020
LEER MÁS

Basic AWS Glue concepts

July 22, 2020
LEER MÁS

Filed Under: Blog, Practices, Tech

  • « Go to Previous Page
  • Page 1
  • Page 2
  • Page 3
  • Page 4
  • Interim pages omitted …
  • Page 7
  • Go to Next Page »

Footer

LegalPrivacy Cookies policy

Patron

Sponsor

© 2025 Bluetab Solutions Group, SL. All rights reserved.