sql >> Base de Datos >  >> RDS >> Database

Preguntas de la entrevista del ingeniero de datos con Python

Ir a entrevistas puede ser un proceso agotador y lento, ¡y las entrevistas técnicas pueden ser aún más estresantes! Este tutorial tiene como objetivo prepararlo para algunas preguntas comunes que encontrará durante su entrevista con el ingeniero de datos. Aprenderá a responder preguntas sobre bases de datos, Python y SQL.

Al final de este tutorial, podrá:

  • Comprender preguntas comunes de entrevistas de ingenieros de datos
  • Distinguir entre bases de datos relacionales y no relacionales
  • Configurar bases de datos usando Python
  • Usar Python para consultar datos

Descarga gratuita: Obtenga un capítulo de muestra de Python Tricks:The Book que le muestra las mejores prácticas de Python con ejemplos simples que puede aplicar instantáneamente para escribir un código Pythonic más hermoso.


Convertirse en ingeniero de datos

El papel de la ingeniería de datos puede ser amplio y variado. Deberá tener un conocimiento práctico de múltiples tecnologías y conceptos. Los ingenieros de datos son flexibles en su forma de pensar. Como resultado, pueden dominar varios temas, como bases de datos, desarrollo de software, DevOps y big data.


¿Qué hace un ingeniero de datos?

Dado su variado conjunto de habilidades, un rol de ingeniería de datos puede abarcar muchas descripciones de trabajo diferentes. Un ingeniero de datos puede ser responsable del diseño de la base de datos, el diseño del esquema y la creación de múltiples soluciones de base de datos. Este trabajo también podría involucrar a un administrador de base de datos.

Como ingeniero de datos , podría actuar como un puente entre la base de datos y los equipos de ciencia de datos. En ese caso, también será responsable de la limpieza y preparación de datos. Si se trata de big data, entonces es su trabajo encontrar una solución eficiente para esos datos. Este trabajo puede superponerse con el rol de DevOps.

También deberá realizar consultas de datos eficientes para informes y análisis. Es posible que deba interactuar con varias bases de datos o escribir procedimientos almacenados. Para muchas soluciones, como sitios web o servicios de alto tráfico, puede haber más de una base de datos presente. En estos casos, el ingeniero de datos es responsable de configurar las bases de datos, mantenerlas y transferir datos entre ellas.



¿Cómo puede Python ayudar a los ingenieros de datos?

Python es conocido por ser la navaja suiza de los lenguajes de programación. Es especialmente útil en ciencia de datos, sistemas back-end y secuencias de comandos del lado del servidor. Esto se debe a que Python tiene una escritura fuerte, una sintaxis simple y una gran cantidad de bibliotecas de terceros para usar. Pandas, SciPy, Tensorflow, SQLAlchemy y NumPy son algunas de las bibliotecas más utilizadas en producción en diferentes industrias.

Lo que es más importante, Python reduce el tiempo de desarrollo, lo que significa menos gastos para las empresas. Para un ingeniero de datos, la mayor parte de la ejecución del código está vinculada a la base de datos, no a la CPU. Debido a esto, tiene sentido capitalizar la simplicidad de Python, incluso a costa de un rendimiento más lento en comparación con lenguajes compilados como C# y Java.




Responder a las preguntas de la entrevista del ingeniero de datos

Ahora que sabe en qué podría consistir su función, ¡es hora de aprender a responder algunas preguntas de la entrevista del ingeniero de datos! Si bien hay mucho terreno por cubrir, verá ejemplos prácticos de Python a lo largo del tutorial para guiarlo en el camino.



Preguntas sobre bases de datos relacionales

Las bases de datos son uno de los componentes más importantes de un sistema. Sin ellos, no puede haber estado ni historia. Si bien es posible que no haya considerado que el diseño de la base de datos sea una prioridad, sepa que puede tener un impacto significativo en la rapidez con la que se carga su página. En los últimos años, varias grandes corporaciones han introducido varias herramientas y técnicas nuevas:

  • No SQL
  • Caché de bases de datos
  • Bases de datos de gráficos
  • Compatibilidad con NoSQL en bases de datos SQL

Estas y otras técnicas se inventaron para intentar aumentar la velocidad a la que las bases de datos procesan las solicitudes. Es probable que necesite hablar sobre estos conceptos en su entrevista con el ingeniero de datos, ¡así que repasemos algunas preguntas!


P1:Bases de datos relacionales frente a no relacionales

Una base de datos relacional es aquel en el que los datos se almacenan en forma de tabla. Cada tabla tiene un esquema , que son las columnas y los tipos que debe tener un registro. Cada esquema debe tener al menos una clave principal que identifique de forma única ese registro. En otras palabras, no hay filas duplicadas en su base de datos. Además, cada tabla se puede relacionar con otras tablas mediante claves foráneas.

Un aspecto importante de las bases de datos relacionales es que un cambio en un esquema debe aplicarse a todos los registros. Esto a veces puede causar roturas y grandes dolores de cabeza durante las migraciones. Bases de datos no relacionales abordar las cosas de otra manera. Son inherentemente sin esquema, lo que significa que los registros se pueden guardar con diferentes esquemas y con una estructura anidada diferente. Los registros aún pueden tener claves primarias, pero el cambio en el esquema se realiza entrada por entrada.

Deberá realizar una prueba de comparación de velocidad según el tipo de función que se esté realizando. Puede elegir INSERT , UPDATE , DELETE , u otra función. El diseño del esquema, los índices, la cantidad de agregaciones y la cantidad de registros también afectarán este análisis, por lo que deberá realizar una prueba exhaustiva. Aprenderá más sobre cómo hacer esto más adelante.

Las bases de datos también difieren en escalabilidad . Una base de datos no relacional puede ser un dolor de cabeza menor para distribuir. Esto se debe a que una colección de registros relacionados se puede almacenar fácilmente en un nodo en particular. Por otro lado, las bases de datos relacionales requieren más reflexión y, por lo general, utilizan un sistema maestro-esclavo.



Un ejemplo de SQLite

Ahora que ha respondido qué son las bases de datos relacionales, ¡es hora de profundizar en Python! SQLite es una base de datos conveniente que puede usar en su máquina local. La base de datos es un único archivo, lo que la hace ideal para la creación de prototipos. Primero, importe la biblioteca Python requerida y cree una nueva base de datos:

import sqlite3

db = sqlite3.connect(':memory:')  # Using an in-memory database
cur = db.cursor()

Ahora está conectado a una base de datos en memoria y tiene su objeto de cursor listo para usar.

A continuación, creará las siguientes tres tablas:

  1. Cliente: Esta tabla contendrá una clave principal, así como el nombre y apellido del cliente.
  2. Artículos: Esta tabla contendrá una clave principal, el nombre del artículo y el precio del artículo.
  3. Artículos comprados :Esta tabla contendrá un número de pedido, fecha y precio. También se conectará a las claves principales en las tablas Artículos y Clientes.

Ahora que tiene una idea de cómo se verán sus tablas, puede continuar y crearlas:

cur.execute('''CREATE TABLE IF NOT EXISTS Customer (
                id integer PRIMARY KEY,
                firstname varchar(255),
                lastname varchar(255) )''')
cur.execute('''CREATE TABLE IF NOT EXISTS Item (
                id integer PRIMARY KEY,
                title varchar(255),
                price decimal )''')
cur.execute('''CREATE TABLE IF NOT EXISTS BoughtItem (
                ordernumber integer PRIMARY KEY,
                customerid integer,
                itemid integer,
                price decimal,
                CONSTRAINT customerid
                    FOREIGN KEY (customerid) REFERENCES Customer(id),
                CONSTRAINT itemid
                    FOREIGN KEY (itemid) REFERENCES Item(id) )''')

Ha pasado una consulta a cur.execute() para crear tus tres tablas.

El último paso es llenar sus tablas con datos:

cur.execute('''INSERT INTO Customer(firstname, lastname)
               VALUES ('Bob', 'Adams'),
                      ('Amy', 'Smith'),
                      ('Rob', 'Bennet');''')
cur.execute('''INSERT INTO Item(title, price)
               VALUES ('USB', 10.2),
                      ('Mouse', 12.23),
                      ('Monitor', 199.99);''')
cur.execute('''INSERT INTO BoughtItem(customerid, itemid, price)
               VALUES (1, 1, 10.2),
                      (1, 2, 12.23),
                      (1, 3, 199.99),
                      (2, 3, 180.00),
                      (3, 2, 11.23);''') # Discounted price 

Ahora que hay algunos registros en cada tabla, puede usar estos datos para responder algunas preguntas más de la entrevista del ingeniero de datos.



P2:Funciones de agregación de SQL

Funciones de agregación son aquellos que realizan una operación matemática sobre un conjunto de resultados. Algunos ejemplos incluyen AVG , COUNT , MIN , MAX y SUM . A menudo, necesitará GROUP BY y HAVING cláusulas para complementar estas agregaciones. Una función de agregación útil es AVG , que puede usar para calcular la media de un conjunto de resultados determinado:

>>>
>>> cur.execute('''SELECT itemid, AVG(price) FROM BoughtItem GROUP BY itemid''')
>>> print(cur.fetchall())
[(1, 10.2), (2, 11.73), (3, 189.995)]

Aquí, ha obtenido el precio promedio de cada uno de los artículos comprados en su base de datos. Puede ver que el elemento con un itemid de 1 tiene un precio promedio de $10.20.

Para que el resultado anterior sea más fácil de entender, puede mostrar el nombre del elemento en lugar del itemid :

>>>
>>> cur.execute('''SELECT item.title, AVG(boughtitem.price) FROM BoughtItem as boughtitem
...             INNER JOIN Item as item on (item.id = boughtitem.itemid)
...             GROUP BY boughtitem.itemid''')
...
>>> print(cur.fetchall())
[('USB', 10.2), ('Mouse', 11.73), ('Monitor', 189.995)]

Ahora ves más fácilmente que el artículo con un precio promedio de $10.20 es el USB .

Otra agregación útil es SUM . Puede usar esta función para mostrar la cantidad total de dinero que gastó cada cliente:

>>>
>>> cur.execute('''SELECT customer.firstname, SUM(boughtitem.price) FROM BoughtItem as boughtitem
...             INNER JOIN Customer as customer on (customer.id = boughtitem.customerid)
...             GROUP BY customer.firstname''')
...
>>> print(cur.fetchall())
[('Amy', 180), ('Bob', 222.42000000000002), ('Rob', 11.23)]

En promedio, el cliente llamado Amy gastó alrededor de $180, mientras que Rob solo gastó $11,23.

Si a su entrevistador le gustan las bases de datos, es posible que desee repasar las consultas anidadas, los tipos de unión y los pasos que sigue una base de datos relacional para realizar su consulta.



P3:Acelerando consultas SQL

La velocidad depende de varios factores, pero se ve afectada principalmente por la cantidad de cada uno de los siguientes elementos:

  • Únete
  • Agregaciones
  • Recorridos
  • Registros

Cuanto mayor sea el número de uniones, mayor será la complejidad y mayor el número de recorridos en las tablas. Las uniones múltiples son bastante costosas de realizar en varios miles de registros que involucran varias tablas porque la base de datos también necesita almacenar en caché el resultado intermedio. En este punto, puede comenzar a pensar en cómo aumentar el tamaño de su memoria.

La velocidad también se ve afectada si hay o no índices presentes en la base de datos. Los índices son extremadamente importantes y le permiten buscar rápidamente en una tabla y encontrar una coincidencia para alguna columna especificada en la consulta.

Los índices ordenan los registros a costa de un mayor tiempo de inserción, así como algo de almacenamiento. Se pueden combinar varias columnas para crear un solo índice. Por ejemplo, las columnas date y price pueden combinarse porque su consulta depende de ambas condiciones.



P4:Depuración de consultas SQL

La mayoría de las bases de datos incluyen un EXPLAIN QUERY PLAN que describe los pasos que toma la base de datos para ejecutar la consulta. Para SQLite, puede habilitar esta funcionalidad agregando EXPLAIN QUERY PLAN delante de un SELECT declaración:

>>>
>>> cur.execute('''EXPLAIN QUERY PLAN SELECT customer.firstname, item.title, 
...                item.price, boughtitem.price FROM BoughtItem as boughtitem
...                INNER JOIN Customer as customer on (customer.id = boughtitem.customerid)
...                INNER JOIN Item as item on (item.id = boughtitem.itemid)''')
...
>>> print(cur.fetchall())
[(4, 0, 0, 'SCAN TABLE BoughtItem AS boughtitem'), 
(6, 0, 0, 'SEARCH TABLE Customer AS customer USING INTEGER PRIMARY KEY (rowid=?)'), 
(9, 0, 0, 'SEARCH TABLE Item AS item USING INTEGER PRIMARY KEY (rowid=?)')]

Esta consulta intenta enumerar el nombre, el título del artículo, el precio original y el precio de compra de todos los artículos comprados.

Así es como se ve el plan de consulta en sí:

SCAN TABLE BoughtItem AS boughtitem
SEARCH TABLE Customer AS customer USING INTEGER PRIMARY KEY (rowid=?)
SEARCH TABLE Item AS item USING INTEGER PRIMARY KEY (rowid=?)

Tenga en cuenta que la declaración de búsqueda en su código de Python solo devuelve la explicación, pero no los resultados. Eso es porque EXPLAIN QUERY PLAN no está destinado a ser utilizado en producción.




Preguntas sobre bases de datos no relacionales

En la sección anterior, expuso las diferencias entre las bases de datos relacionales y no relacionales y usó SQLite con Python. Ahora te vas a centrar en NoSQL. Su objetivo es resaltar sus fortalezas, diferencias y casos de uso.


Un ejemplo de MongoDB

Utilizará los mismos datos que antes, pero esta vez su base de datos será MongoDB. Esta base de datos NoSQL está basada en documentos y se escala muy bien. Lo primero es lo primero, deberá instalar la biblioteca de Python necesaria:

$ pip install pymongo

También es posible que desee instalar MongoDB Compass Community. Incluye un IDE local que es perfecto para visualizar la base de datos. Con él, puede ver los registros creados, crear disparadores y actuar como administrador visual de la base de datos.

Nota: Para ejecutar el código de esta sección, necesitará un servidor de base de datos en ejecución. Para obtener más información sobre cómo configurarlo, consulte Introducción a MongoDB y Python.

Así es como crea la base de datos e inserta algunos datos:

import pymongo

client = pymongo.MongoClient("mongodb://localhost:27017/")

# Note: This database is not created until it is populated by some data
db = client["example_database"]

customers = db["customers"]
items = db["items"]

customers_data = [{ "firstname": "Bob", "lastname": "Adams" },
                  { "firstname": "Amy", "lastname": "Smith" },
                  { "firstname": "Rob", "lastname": "Bennet" },]
items_data = [{ "title": "USB", "price": 10.2 },
              { "title": "Mouse", "price": 12.23 },
              { "title": "Monitor", "price": 199.99 },]

customers.insert_many(customers_data)
items.insert_many(items_data)

Como habrás notado, MongoDB almacena registros de datos en colecciones , que son el equivalente a una lista de diccionarios en Python. En la práctica, MongoDB almacena documentos BSON.



P5:Consulta de datos con MongoDB

Intentemos replicar el BoughtItem tabla primero, como lo hizo en SQL. Para hacer esto, debe agregar un nuevo campo a un cliente. La documentación de MongoDB especifica que el operador de palabra clave set puede usarse para actualizar un registro sin tener que escribir todos los campos existentes:

# Just add "boughtitems" to the customer where the firstname is Bob
bob = customers.update_many(
        {"firstname": "Bob"},
        {
            "$set": {
                "boughtitems": [
                    {
                        "title": "USB",
                        "price": 10.2,
                        "currency": "EUR",
                        "notes": "Customer wants it delivered via FedEx",
                        "original_item_id": 1
                    }
                ]
            },
        }
    )

Observe cómo agregó campos adicionales al customer sin definir explícitamente el esquema de antemano. ¡Ingenioso!

De hecho, puede actualizar otro cliente con un esquema ligeramente alterado:

amy = customers.update_many(
        {"firstname": "Amy"},
        {
            "$set": {
                "boughtitems":[
                    {
                        "title": "Monitor",
                        "price": 199.99,
                        "original_item_id": 3,
                        "discounted": False
                    }
                ]
            } ,
        }
    )
print(type(amy))  # pymongo.results.UpdateResult

Al igual que SQL, las bases de datos basadas en documentos también permiten ejecutar consultas y agregaciones. Sin embargo, la funcionalidad puede diferir tanto sintácticamente como en la ejecución subyacente. De hecho, es posible que haya notado que MongoDB reserva el $ carácter para especificar algún comando o agregación en los registros, como $group . Puede obtener más información sobre este comportamiento en los documentos oficiales.

Puede realizar consultas tal como lo hizo en SQL. Para empezar, puede crear un índice:

>>>
>>> customers.create_index([("name", pymongo.DESCENDING)])

Esto es opcional, pero acelera las consultas que requieren búsquedas de nombres.

Luego, puede recuperar los nombres de los clientes ordenados en orden ascendente:

>>>
>>> items = customers.find().sort("name", pymongo.ASCENDING)

También puede iterar e imprimir los artículos comprados:

>>>
>>> for item in items:
...     print(item.get('boughtitems'))    
...
None
[{'title': 'Monitor', 'price': 199.99, 'original_item_id': 3, 'discounted': False}]
[{'title': 'USB', 'price': 10.2, 'currency': 'EUR', 'notes': 'Customer wants it delivered via FedEx', 'original_item_id': 1}]

Incluso puede recuperar una lista de nombres únicos en la base de datos:

>>>
>>> customers.distinct("firstname")
['Bob', 'Amy', 'Rob']

Ahora que conoce los nombres de los clientes en su base de datos, puede crear una consulta para recuperar información sobre ellos:

>>>
>>> for i in customers.find({"$or": [{'firstname':'Bob'}, {'firstname':'Amy'}]}, 
...                                  {'firstname':1, 'boughtitems':1, '_id':0}):
...     print(i)
...
{'firstname': 'Bob', 'boughtitems': [{'title': 'USB', 'price': 10.2, 'currency': 'EUR', 'notes': 'Customer wants it delivered via FedEx', 'original_item_id': 1}]}
{'firstname': 'Amy', 'boughtitems': [{'title': 'Monitor', 'price': 199.99, 'original_item_id': 3, 'discounted': False}]}

Aquí está la consulta SQL equivalente:

SELECT firstname, boughtitems FROM customers WHERE firstname LIKE ('Bob', 'Amy')

Tenga en cuenta que aunque la sintaxis puede diferir solo ligeramente, hay una diferencia drástica en la forma en que se ejecutan las consultas debajo del capó. Esto es de esperar debido a las diferentes estructuras de consulta y casos de uso entre las bases de datos SQL y NoSQL.



P6:NoSQL frente a SQL

Si tiene un esquema que cambia constantemente, como la información regulatoria financiera, entonces NoSQL puede modificar los registros y anidar la información relacionada. ¡Imagínese la cantidad de uniones que tendría que hacer en SQL si tuviera ocho órdenes de anidamiento! Sin embargo, esta situación es más común de lo que piensas.

Ahora, ¿qué sucede si desea ejecutar informes, extraer información sobre esos datos financieros e inferir conclusiones? En este caso, necesita ejecutar consultas complejas y SQL tiende a ser más rápido en este sentido.

Nota: Las bases de datos SQL, particularmente PostgreSQL, también han lanzado una función que permite insertar datos JSON consultables como parte de un registro. Si bien esto puede combinar lo mejor de ambos mundos, la velocidad puede ser motivo de preocupación.

Es más rápido consultar datos no estructurados desde una base de datos NoSQL que consultar campos JSON desde una columna de tipo JSON en PostgreSQL. Siempre puedes hacer una prueba de comparación de velocidad para obtener una respuesta definitiva.

No obstante, esta característica podría reducir la necesidad de una base de datos adicional. A veces, los objetos decapados o serializados se almacenan en registros en forma de tipos binarios y luego se deserializan al leerlos.

Sin embargo, la velocidad no es la única métrica. También querrá tener en cuenta cosas como transacciones, atomicidad, durabilidad y escalabilidad. Transacciones son importantes en las aplicaciones financieras, y tales características tienen prioridad.

Dado que existe una amplia gama de bases de datos, cada una con sus propias características, es trabajo del ingeniero de datos tomar una decisión informada sobre qué base de datos usar en cada aplicación. Para obtener más información, puede leer sobre las propiedades de ACID relacionadas con las transacciones de la base de datos.

También se le puede preguntar qué otras bases de datos conoce en su entrevista de ingeniero de datos. Hay varias otras bases de datos relevantes que utilizan muchas empresas:

  • Búsqueda elástica es muy eficiente en la búsqueda de texto. Aprovecha su base de datos basada en documentos para crear una poderosa herramienta de búsqueda.
  • Newt DB combina ZODB y la función PostgreSQL JSONB para crear una base de datos NoSQL compatible con Python.
  • InfluxDB se utiliza en aplicaciones de series temporales para almacenar eventos.

La lista continúa, pero esto ilustra cómo una amplia variedad de bases de datos disponibles se adaptan a su industria de nicho.




Preguntas sobre bases de datos de caché

Bases de datos de caché mantener los datos de acceso frecuente. Conviven con las principales bases de datos SQL y NoSQL. Su objetivo es aliviar la carga y atender las solicitudes más rápido.


Un ejemplo de Redis

Ha cubierto bases de datos SQL y NoSQL para soluciones de almacenamiento a largo plazo, pero ¿qué pasa con el almacenamiento más rápido e inmediato? ¿Cómo puede un ingeniero de datos cambiar la rapidez con la que se recuperan los datos de una base de datos?

Las aplicaciones web típicas recuperan datos de uso común, como el perfil o el nombre de un usuario, muy a menudo. Si todos los datos están contenidos en una base de datos, entonces el número de accesos el servidor de la base de datos será exagerado e innecesario. Como tal, se necesita una solución de almacenamiento más rápida e inmediata.

Si bien esto reduce la carga del servidor, también crea dos dolores de cabeza para el ingeniero de datos, el equipo de back-end y el equipo de DevOps. Primero, ahora necesitará alguna base de datos que tenga un tiempo de lectura más rápido que su base de datos SQL o NoSQL principal. Sin embargo, los contenidos de ambas bases de datos eventualmente deben coincidir. (Bienvenido al problema de la consistencia del estado entre bases de datos! Disfruta.)

El segundo dolor de cabeza es que DevOps ahora debe preocuparse por la escalabilidad, la redundancia, etc., para la nueva base de datos de caché. En la siguiente sección, se sumergirá en problemas como estos con la ayuda de Redis.



P7:Cómo usar bases de datos de caché

¡Es posible que haya obtenido suficiente información de la introducción para responder a esta pregunta! Una base de datos de caché es una solución de almacenamiento rápido que se utiliza para almacenar datos de corta duración, estructurados o no estructurados. Se puede particionar y escalar según sus necesidades, pero normalmente es mucho más pequeño que su base de datos principal. Debido a esto, su base de datos de caché puede residir en la memoria, lo que le permite evitar la necesidad de leer desde un disco.

Nota: Si alguna vez ha usado diccionarios en Python, entonces Redis sigue la misma estructura. Es una tienda de clave-valor, donde puede SET y GET datos como un Python dict .

Cuando llega una solicitud, primero verifica la base de datos de caché, luego la base de datos principal. De esta manera, puede evitar que las solicitudes innecesarias y repetitivas lleguen al servidor de la base de datos principal. Dado que una base de datos de caché tiene un tiempo de lectura más bajo, ¡también se beneficia de un aumento en el rendimiento!

Puede usar pip para instalar la biblioteca requerida:

$ pip install redis

Ahora, considere una solicitud para obtener el nombre del usuario de su ID:

import redis
from datetime import timedelta

# In a real web application, configuration is obtained from settings or utils
r = redis.Redis()

# Assume this is a getter handling a request
def get_name(request, *args, **kwargs):
    id = request.get('id')
    if id in r:
        return r.get(id)  # Assume that we have an {id: name} store
    else:
        # Get data from the main DB here, assume we already did it
        name = 'Bob'
        # Set the value in the cache database, with an expiration time
        r.setex(id, timedelta(minutes=60), value=name)
        return name

Este código verifica si el nombre está en Redis usando el id llave. De lo contrario, el nombre se establece con un tiempo de caducidad, que se utiliza porque la memoria caché es de corta duración.

Ahora, ¿qué sucede si su entrevistador le pregunta qué tiene de malo este código? ¡Su respuesta debería ser que no hay manejo de excepciones! Las bases de datos pueden tener muchos problemas, como conexiones interrumpidas, por lo que siempre es una buena idea intentar detectar esas excepciones.




Preguntas sobre patrones de diseño y conceptos ETL

En aplicaciones grandes, a menudo usará más de un tipo de base de datos. De hecho, ¡es posible usar PostgreSQL, MongoDB y Redis en una sola aplicación! Un problema desafiante es lidiar con cambios de estado entre bases de datos, lo que expone al desarrollador a problemas de consistencia. Considere el siguiente escenario:

  1. Un valor en la base de datos #1 se actualiza.
  2. Ese mismo valor en la base de datos #2 se mantiene igual (no actualizada).
  3. Una consulta se ejecuta en la base de datos #2.

Ahora, ¡tienes un resultado inconsistente y desactualizado! Los resultados devueltos por la segunda base de datos no reflejarán el valor actualizado en la primera. Esto puede suceder con dos bases de datos cualquiera, pero es especialmente común cuando la base de datos principal es una base de datos NoSQL y la información se transforma en SQL para fines de consulta.

Las bases de datos pueden tener trabajadores de fondo para abordar tales problemas. Estos trabajadores extraen datos de una base de datos, transformar de alguna manera, y cargar en la base de datos de destino. Cuando está convirtiendo de una base de datos NoSQL a una base de datos SQL, el proceso de extracción, transformación y carga (ETL) sigue los siguientes pasos:

  1. Extracto: Hay un disparador de MongoDB cada vez que se crea, actualiza un registro, etc. Una función de devolución de llamada se llama de forma asíncrona en un subproceso separado.
  2. Transformar: Se extraen partes del registro, se normalizan y se colocan en la estructura de datos (o fila) correcta para insertarse en SQL.
  3. Cargar: La base de datos SQL se actualiza por lotes o como un único registro para escrituras de gran volumen.

Este flujo de trabajo es bastante común en aplicaciones financieras, de juegos y de informes. En estos casos, el esquema en constante cambio requiere una base de datos NoSQL, pero los informes, análisis y agregaciones requieren una base de datos SQL.


P8:Desafíos de ETL

Hay varios conceptos desafiantes en ETL, incluidos los siguientes:

  • Grandes datos
  • Problemas de estado
  • Trabajadores asincrónicos
  • Coincidencia de tipos

¡La lista continua! Sin embargo, dado que los pasos del proceso ETL están bien definidos y son lógicos, los ingenieros de datos y de back-end generalmente se preocuparán más por el rendimiento y la disponibilidad que por la implementación.

Si su aplicación está escribiendo miles de registros por segundo en MongoDB, entonces su trabajador de ETL debe seguir transformando, cargando y entregando los datos al usuario en el formulario solicitado. La velocidad y la latencia pueden convertirse en un problema, por lo que estos trabajadores suelen estar escritos en lenguajes rápidos. Puede usar código compilado para el paso de transformación para acelerar las cosas, ya que esta parte generalmente está vinculada a la CPU.

Nota: El procesamiento múltiple y la separación de trabajadores son otras soluciones que quizás desee considerar.

Si está lidiando con muchas funciones de uso intensivo de la CPU, es posible que desee consultar Numba. Esta biblioteca compila funciones para hacerlas más rápidas en la ejecución. Lo mejor de todo es que esto se implementa fácilmente en Python, aunque existen algunas limitaciones sobre qué funciones se pueden usar en estas funciones compiladas.



P9:Patrones de diseño en Big Data

Imagina que Amazon necesita crear un sistema de recomendación para sugerir productos adecuados a los usuarios. ¡El equipo de ciencia de datos necesita datos y muchos! Acuden a usted, el ingeniero de datos, y le piden que cree un almacén de base de datos provisional independiente. Ahí es donde limpiarán y transformarán los datos.

Es posible que se sorprenda al recibir tal solicitud. Cuando tenga terabytes de datos, necesitará varias máquinas para manejar toda esa información. Una función de agregación de base de datos puede ser una operación muy compleja. ¿Cómo puede consultar, agregar y hacer uso de datos relativamente grandes de manera eficiente?

Apache había introducido inicialmente MapReduce, que sigue el map, shuffle, reduce flujo de trabajo. La idea es mapear diferentes datos en máquinas separadas, también llamadas clústeres. Luego, puede trabajar con los datos, agruparlos por clave y, finalmente, agregar los datos en la etapa final.

Este flujo de trabajo todavía se usa hoy en día, pero se ha ido desvaneciendo recientemente a favor de Spark. Sin embargo, el patrón de diseño forma la base de la mayoría de los flujos de trabajo de big data y es un concepto muy intrigante. Puede leer más sobre MapReduce en IBM Analytics.



P10:Aspectos comunes del proceso ETL y flujos de trabajo de Big Data

Es posible que le parezca una pregunta bastante extraña, pero es simplemente una verificación de sus conocimientos de informática, así como de su conocimiento y experiencia general en diseño.

Ambos flujos de trabajo siguen el Productor-Consumidor patrón. Un trabajador (el Productor) produce datos de algún tipo y los envía a una canalización. Esta canalización puede tomar muchas formas, incluidos mensajes de red y disparadores. Después de que el Productor genera los datos, el Consumidor los consume y hace uso de ellos. Estos trabajadores suelen trabajar de forma asincrónica y se ejecutan en procesos independientes.

Puede comparar el Productor con los pasos de extracción y transformación del proceso ETL. De manera similar, en big data, el mapeador puede ser visto como el Productor, mientras que el reductor es efectivamente el Consumidor. Esta separación de preocupaciones es extremadamente importante y eficaz en el diseño de arquitectura y desarrollo de aplicaciones.




Conclusión

¡Felicidades! Ha cubierto mucho terreno y ha respondido varias preguntas de entrevistas de ingenieros de datos. Ahora comprende un poco más sobre los diferentes roles que puede usar un ingeniero de datos, así como cuáles son sus responsabilidades con respecto a las bases de datos, el diseño y el flujo de trabajo.

Con este conocimiento, ahora puede:

  • Utilice Python con SQL, NoSQL y bases de datos de caché
  • Usar Python en ETL y aplicaciones de consulta
  • Planifique proyectos con anticipación, teniendo en cuenta el diseño y el flujo de trabajo

Si bien las preguntas de la entrevista pueden variar, ha estado expuesto a múltiples temas y ha aprendido a pensar fuera de la caja en muchas áreas diferentes de la informática. ¡Ahora estás listo para tener una entrevista increíble!