Mas leido
Building Stories
Modo Rua: Redefiniendo el desarrollo de aplicaciones mediante iteración centrada en el usuario Ago 23
Building Stories
NuStories: Adaptación de productos para clientes fanáticos en varios países Oct 30
Culture & Values
Cómo los valores y la cultura de Nu dan forma a los productos que creamos Ago 7
Carreras
Reunimos a grandes mentes de diversos orígenes que permiten la discusión y el debate y mejoran la resolución de problemas.
Conoce más sobre nuestras carreras



En Ciencia de Datos, la gestión efectiva de consultas es fundamental. Sumérgete en la estrategia de Nubank, donde se aprovecha el poder de Scala y Spark para asegurar transformaciones de datos eficientes.
Descubre cómo la intrincada arquitectura de datos de Nubank, que incluye extracción, transformación y carga, funciona de manera fluida con Scala para mantener la consistencia y gobernanza de los datos.
Esta guía ofrece una inmersión profunda en los matices de la codificación y ejemplos del mundo real, mostrando las enormes capacidades de Scala y Spark para manejar consultas complejas.
Una breve introducción a la estructura de datos de Nubank
Antes de profundizar en la parte de programación, es crucial entender la estructura de datos de Nubank. En resumen, nuestra arquitectura de datos se compone de tres partes estándar:
Descubre las oportunidades
El papel de Scala y Spark
Scala y Spark entran en juego durante la etapa de transformación. Con la gran cantidad de transformaciones que ocurren, es imperativo gestionar nuestras consultas de manera efectiva, asegurando la consistencia y gobernanza de los datos. Aquí es donde Scala y Spark brillan.
Profundizando en el aspecto de la codificación, es importante mencionar que utilizamos Databricks, que es similar a Jupyter. Es un entorno de ejecución con el formato de un cuaderno de notas.
Un ejemplo práctico con Scala y Spark
Vamos a demostrar una consulta simple construida utilizando una ‘Tabla Base’. Esta tabla consta de detalles de transacciones, como la fecha de solicitud y la información del cliente.
Aunque el código inicial consta de solo unas pocas líneas, el poder de Scala y Spark nos permite reescribir las transformaciones como cadenas basadas en funciones puras. Este enfoque estructurado ayuda a gestionar consultas complejas de manera más eficiente.
MetaDatos: un ingrediente esencial y aprovechando el poder de Scala
Cuando se manejan grandes cantidades de datos, los metadatos se vuelven cruciales. Estos proporcionan información sobre la consulta, su autor, la descripción y más.
Aunque es posible mantener un repositorio de metadatos separado, integrar la consulta con sus metadatos es más eficiente, simplificando el proceso de transformación y gestión de datos.
La propuesta única de Scala es su capacidad para combinar la programación orientada a objetos con la programación funcional de manera fluida.
Para estructurar mejor nuestros metadatos, introducimos ‘Spark Query’, un Trait en Scala (similar a una interfaz en Java o una clase abstracta en otros lenguajes). Esto nos permite definir una consulta con sus metadatos asociados.
Por ejemplo, una ‘Spark Query’ puede tener:
Preparando el escenario
Imagina el desafío: tienes una consulta y necesitas integrarla en tu estructura predefinida. Esto requiere que crees un objeto para la consulta previamente definida. Para efectos de este tutorial, podemos llamarlo CompletedPixTransactions..
Creando nuestro objeto
Para implementar un hilo en Scala, usamos la palabra clave extends. Después de extender nuestro hilo, definiremos todos los elementos necesarios dentro. Dado que Scala cuenta con capacidades impresionantes de inferencia de tipos, no es necesario especificar explícitamente el tipo para todo. Por ejemplo, si tableName es una cadena de texto, simplemente definimos nuestra cadena.
Para este ejercicio, nuestro tableName se llamará CompletedPixMovements. Aquí es donde residirán nuestros datos. Para proporcionar una breve descripción o lo que llamaríamos un ExampleDataset, considérelo como una instantánea de nuestro proyecto en curso. El equipo propietario (llamémoslo OwnerTeam) no necesita ser entendido en profundidad para este contexto. Nuestros datos pertenecen a Brasil, por lo que, naturalmente, todo nuestro contenido está en portugués.
Después de evaluar nuestra consulta, concluimos que su nivel de QualityAssurance es alto, lo que indica un concepto de negocio bien escrito y preciso. En cuanto a nuestras entradas, lo hemos mantenido simple utilizando solo una tabla: PixMovements.
Construyendo metadatos y la consulta
Ahora viene la parte crucial. ¿Cómo redactamos nuestra consulta? Recuperaremos nuestra consulta previamente escrita y la integraremos dentro de nuestra estructura de encapsulación. Con Scala, al construir un objeto de esta manera, hay libertad para añadir detalles suplementarios. Si se desea, se puede agregar un metadato de frecuencia para indicar la frecuencia de ejecución de la consulta.
Funciones únicas exclusivas de esta consulta de Spark también pueden estar anidadas dentro. Esto mejora la claridad, ya que al escribir la consulta, estas funciones pueden ser referenciadas directamente.
El siguiente paso es extraer nuestros datos de entrada del dataframe, aplicar las transformaciones necesarias como antes, y evitar cualquier función de visualización ya que nuestra principal preocupación es la ejecución de la consulta, no su visualización o mecanismo de guardado.
Con una ejecución exitosa, este enfoque nos ayuda a encapsular tanto nuestra consulta como sus metadatos asociados dentro de un solo objeto estandarizado.
Ejecución y resultados
El proceso para ejecutar esta consulta encapsulada es bastante intuitivo. Primero, especifica la entrada de tu consulta, que típicamente es un mapa, luego accede a los datos dentro de la tabla usando el nombre del mapa. Este objeto puede entonces llamar a la consulta definida e introducir los datos en ella. Si se ejecuta correctamente, deberías ver resultados similares a los de antes.
Para guardar los resultados en una tabla—un procedimiento estándar en las pipelines—puedes utilizar los comandos de Spark. El nombre de la tabla está predefinido dentro de nuestro objeto como TableName. Al ejecutar, los resultados de la consulta serán almacenados en esta tabla especificada.
En resumen, hemos encapsulado exitosamente una consulta básica y sus metadatos en un objeto estandarizado, ofreciendo un método claro y robusto para gestionar consultas de Spark con Scala.
Un paso más allá: múltiples consultas
Los entornos de producción reales no lidian con una sola consulta, sino potencialmente con cientos. Manejar tal volumen requiere un enfoque más avanzado.
En nuestro segmento inicial, aprendimos cómo elaborar una consulta de Spark utilizando la API de Scala, enfatizando funciones puras y capas de gobernanza mejoradas. A medida que avanzamos, profundizaremos en aprovechar el poder combinado de la programación orientada a objetos y el lenguaje funcional con Scala.
Dentro de nuestra consulta de Spark, poseemos un atributo llamado QueryInputs. Este atributo contiene una lista que detalla las entradas para una consulta específica.
Por ejemplo, si queremos determinar el número de entradas para una consulta dada, podríamos hacerlo fácilmente llamando al método .size en nuestra lista.
Creando la función getNumberOfInputs
Para demostrar, podemos crear una función llamada getNumberOfInputs que obtenga el número de entradas. Cuando esta función se aplica a una lista de consultas, produciría una lista de enteros que representa la cantidad de entradas para cada consulta.
Esta transformación es posible utilizando el operador map. El operador map aplica una función dada a cada elemento de una lista de entrada, creando una nueva lista que contiene los elementos devueltos por la función.
Entendiendo la operación reduce:
Otra operación crucial en la programación funcional es reduce. El objetivo de reduce es tomar una lista de elementos y condensarla en un solo valor.
Por ejemplo, dada una lista de números, uno podría usar reduce para calcular el promedio o la suma de la lista. La función que acepta el método reduce típicamente toma dos argumentos y retorna un solo resultado.
Para visualizarlo, imagina aplicar una función secuencialmente a pares de elementos en una lista, reduciéndola gradualmente hasta obtener un único resultado acumulado.
Sumando las entradas
Para poner esto en perspectiva, consideremos un escenario donde tenemos una lista de enteros que representa las entradas de consultas. Podríamos definir una función, sumNumberOfInputs, que calcule la suma de dos enteros.
Cuando esta función se aplica sobre nuestra lista utilizando reduce, acumularía el número total de entradas a través de todas las consultas.
Identificando consultas del equipo de ingenieros PIX
Para aislar las consultas creadas por el equipo de Ingenieros PIX, empleamos la operación filter. Esta operación procesa una lista, reteniendo solo los elementos que cumplen con una condición dada.
En nuestro caso, definimos una función, isFromTeamPixEngineers, que verifica si una consulta dada se origina de este equipo específico.
Aislamiento de consultas de baja calidad
De nuestra lista filtrada de consultas de los Ingenieros PIX, podríamos querer discernir cuáles de ellas son de baja calidad. Podemos introducir otra condición de filtrado, verificando el atributo QualityAssurance de cada consulta en busca del valor ‘bajo’.
Un requisito común en los entornos ETL es identificar dependencias. Supongamos que queremos identificar qué conjuntos de datos dependen del conjunto de datos Meetup PixMovements. Podemos crear otra función de filtro para examinar nuestra lista y encontrar consultas que dependan de este conjunto de datos específico.
Este ejercicio es fundamental, especialmente al considerar los efectos en cadena de alterar una consulta fundamental.
Desafiando las normas: exigiendo más de Scala
Después de establecer un sistema de consultas robusto, ¿qué sigue? Aquí hay algunas provocaciones:
Implementación de pruebas rigurosas
Estas son prácticas que hemos integrado en nuestra gobernanza de datos en Nubank, asegurando control y consistencia.
Capacidades avanzadas de Scala
La flexibilidad de Scala ofrece posibilidades aún más avanzadas:
Por ejemplo, con solo unas pocas líneas de código, podemos crear un dataframe, que nos permite analizar la distribución de datos, como el número de conjuntos de datos por país o por equipo propietario, en tiempo real.
Dominar Scala y Spark resulta fundamental para optimizar las transformaciones y la gestión de datos. Como ilustra la metodología de Nubank, integrar ambas herramientas ofrece una solución integral a los desafíos de la gobernanza de datos.
Con características como la encapsulación de consultas y metadatos, la visualización de dependencias y el tratamiento de metadatos como datos reales, Scala se convierte en un activo invaluable para los profesionales de datos. A medida que los ecosistemas de datos continúan creciendo y volviéndose más complejos, adoptar estas estrategias se vuelve crucial para las empresas que buscan eficiencia, claridad y una gobernanza de datos robusta.
Mira lo que compartimos sobre este tema en Meetup a continuación:
Descubre las oportunidades