Andare ai colloqui può essere un processo faticoso e dispendioso in termini di tempo, e i colloqui tecnici possono essere ancora più stressanti! Questo tutorial ha lo scopo di prepararti ad alcune domande comuni che incontrerai durante il colloquio con l'ingegnere dei dati. Imparerai come rispondere a domande su database, Python e SQL.
Entro la fine di questo tutorial, sarai in grado di:
- Comprendi le domande comuni per i colloqui con i data engineer
- Distinguere tra database relazionali e non relazionali
- Imposta database utilizzando Python
- Utilizza Python per eseguire query sui dati
Download gratuito: Ottieni un capitolo di esempio da Python Tricks:The Book che mostra le migliori pratiche di Python con semplici esempi che puoi applicare immediatamente per scrivere codice Pythonic più bello.
Diventare un Data Engineer
Il ruolo dell'ingegneria dei dati può essere vasto e vario. Avrai bisogno di una conoscenza pratica di più tecnologie e concetti. Gli ingegneri dei dati sono flessibili nel loro modo di pensare. Di conseguenza, possono essere esperti in più argomenti, come database, sviluppo software, DevOps e big data.
Cosa fa un ingegnere dei dati?
Dato il suo variegato set di competenze, un ruolo di ingegneria dei dati può abbracciare molte descrizioni di lavoro diverse. Un ingegnere dei dati può essere responsabile della progettazione del database, della progettazione dello schema e della creazione di più soluzioni di database. Questo lavoro potrebbe coinvolgere anche un amministratore del database.
In qualità di ingegnere dei dati , potresti fungere da ponte tra il database e i team di data science. In tal caso, sarai anche responsabile della pulizia e della preparazione dei dati. Se sono coinvolti big data, è tuo compito trovare una soluzione efficiente per quei dati. Questo lavoro può sovrapporsi al ruolo DevOps.
Dovrai anche eseguire query di dati efficienti per il reporting e l'analisi. Potrebbe essere necessario interagire con più database o scrivere stored procedure. Per molte soluzioni come siti Web o servizi ad alto traffico, potrebbe essere presente più di un database. In questi casi, il tecnico dei dati è responsabile della configurazione dei database, della loro manutenzione e del trasferimento dei dati tra di essi.
In che modo Python può aiutare i data engineer?
Python è noto per essere il coltellino svizzero dei linguaggi di programmazione. È particolarmente utile nella scienza dei dati, nei sistemi back-end e nello scripting lato server. Questo perché Python ha una tipizzazione forte, una sintassi semplice e un'abbondanza di librerie di terze parti da utilizzare. Pandas, SciPy, Tensorflow, SQLAlchemy e NumPy sono alcune delle librerie più utilizzate nella produzione in diversi settori.
Ancora più importante, Python riduce i tempi di sviluppo, il che significa meno spese per le aziende. Per un ingegnere di dati, la maggior parte dell'esecuzione del codice è legata al database, non alla CPU. Per questo motivo, ha senso sfruttare la semplicità di Python, anche a costo di prestazioni più lente rispetto a linguaggi compilati come C# e Java.
Risposte alle domande del colloquio con l'ingegnere dei dati
Ora che sai in cosa potrebbe consistere il tuo ruolo, è tempo di imparare a rispondere ad alcune domande del colloquio di data engineer! Anche se c'è molto terreno da coprire, vedrai esempi pratici di Python durante il tutorial per guidarti lungo il percorso.
Domande sui database relazionali
I database sono uno dei componenti più cruciali in un sistema. Senza di loro, non ci può essere stato e nessuna storia. Anche se potresti non aver considerato la progettazione del database come una priorità, sappi che può avere un impatto significativo sulla velocità di caricamento della tua pagina. Negli ultimi anni, diverse grandi aziende hanno introdotto diversi nuovi strumenti e tecniche:
- NoSQL
- Banca dati nella cache
- Database di grafici
- Supporto NoSQL nei database SQL
Queste e altre tecniche sono state inventate per cercare di aumentare la velocità con cui i database elaborano le richieste. Probabilmente dovrai parlare di questi concetti nel tuo colloquio con l'ingegnere dei dati, quindi esaminiamo alcune domande!
Q1:database relazionali e non relazionali
Un database relazionale è uno in cui i dati sono archiviati sotto forma di tabella. Ogni tabella ha uno schema , che sono le colonne e i tipi che deve avere un record. Ogni schema deve avere almeno una chiave primaria che identifichi in modo univoco quel record. In altre parole, non ci sono righe duplicate nel database. Inoltre, ogni tabella può essere correlata ad altre tabelle utilizzando chiavi esterne.
Un aspetto importante dei database relazionali è che una modifica in uno schema deve essere applicata a tutti i record. Questo a volte può causare rotture e grossi mal di testa durante le migrazioni. Banca dati non relazionali affrontare le cose in modo diverso. Sono intrinsecamente privi di schema, il che significa che i record possono essere salvati con schemi diversi e con una struttura nidificata diversa. I record possono ancora avere chiavi primarie, ma una modifica allo schema viene eseguita voce per voce.
Dovresti eseguire un test di confronto della velocità in base al tipo di funzione eseguita. Puoi scegliere INSERT
, UPDATE
, DELETE
o un'altra funzione. Anche la progettazione dello schema, gli indici, il numero di aggregazioni e il numero di record influenzeranno questa analisi, quindi dovrai testare a fondo. Imparerai di più su come farlo in seguito.
I database differiscono anche per la scalabilità . Un database non relazionale può essere meno complicato da distribuire. Questo perché una raccolta di record correlati può essere facilmente archiviata su un particolare nodo. D'altra parte, i database relazionali richiedono più riflessione e di solito fanno uso di un sistema master-slave.
Un esempio di SQLite
Ora che hai risposto a cosa sono i database relazionali, è tempo di approfondire un po' di Python! SQLite è un comodo database che puoi usare sul tuo computer locale. Il database è un unico file, che lo rende ideale per scopi di prototipazione. Innanzitutto, importa la libreria Python richiesta e crea un nuovo database:
import sqlite3
db = sqlite3.connect(':memory:') # Using an in-memory database
cur = db.cursor()
Ora sei connesso a un database in memoria e hai il tuo oggetto cursore pronto per l'uso.
Successivamente, creerai le seguenti tre tabelle:
- Cliente: Questa tabella conterrà una chiave primaria nonché il nome e il cognome del cliente.
- Articoli: Questa tabella conterrà una chiave primaria, il nome dell'articolo e il prezzo dell'articolo.
- Articoli acquistati :questa tabella conterrà un numero d'ordine, una data e un prezzo. Si collegherà anche alle chiavi primarie nelle tabelle Articoli e Clienti.
Ora che hai un'idea di come saranno le tue tabelle, puoi procedere e crearle:
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) )''')
Hai passato una query a cur.execute()
per creare le tue tre tabelle.
L'ultimo passaggio consiste nel popolare le tabelle con i dati:
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
Ora che ci sono alcuni record in ogni tabella, puoi utilizzare questi dati per rispondere ad altre domande del colloquio con i data engineer.
D2:Funzioni di aggregazione SQL
Funzioni di aggregazione sono quelli che eseguono un'operazione matematica su un set di risultati. Alcuni esempi includono AVG
, COUNT
, MIN
, MAX
e SUM
. Spesso avrai bisogno di GROUP BY
e HAVING
clausole a complemento di queste aggregazioni. Un'utile funzione di aggregazione è AVG
, che puoi utilizzare per calcolare la media di un determinato set di risultati:
>>> cur.execute('''SELECT itemid, AVG(price) FROM BoughtItem GROUP BY itemid''')
>>> print(cur.fetchall())
[(1, 10.2), (2, 11.73), (3, 189.995)]
Qui hai recuperato il prezzo medio per ciascuno degli articoli acquistati nel tuo database. Puoi vedere che l'articolo con un itemid
di 1
ha un prezzo medio di $ 10,20.
Per semplificare la comprensione dell'output di cui sopra, puoi visualizzare il nome dell'elemento anziché il 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)]
Ora puoi vedere più facilmente che l'articolo con un prezzo medio di $ 10,20 è la USB
.
Un'altra utile aggregazione è SUM
. Puoi utilizzare questa funzione per visualizzare l'importo totale di denaro speso da ciascun 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)]
In media, la cliente di nome Amy ha speso circa $ 180, mentre Rob ha speso solo $ 11,23!
Se al tuo intervistatore piacciono i database, potresti voler rispolverare le query nidificate, i tipi di join e i passaggi che un database relazionale esegue per eseguire la tua query.
T3:accelerare le query SQL
La velocità dipende da vari fattori, ma è principalmente influenzata da quanti di ciascuno dei seguenti sono presenti:
- Unisciti
- Aggregazioni
- Attraversamenti
- Record
Maggiore è il numero di join, maggiore è la complessità e maggiore è il numero di attraversamenti nelle tabelle. I join multipli sono piuttosto costosi da eseguire su diverse migliaia di record che coinvolgono più tabelle perché il database deve anche memorizzare nella cache il risultato intermedio! A questo punto, potresti iniziare a pensare a come aumentare le dimensioni della tua memoria.
La velocità è anche influenzata dalla presenza o meno di indici presente nella banca dati. Gli indici sono estremamente importanti e ti consentono di cercare rapidamente in una tabella e trovare una corrispondenza per alcune colonne specificate nella query.
Gli indici ordinano i record al costo di tempi di inserimento più elevati, oltre a un po' di spazio di archiviazione. È possibile combinare più colonne per creare un unico indice. Ad esempio, le colonne date
e price
potrebbero essere combinati perché la tua query dipende da entrambe le condizioni.
Q4:debug di query SQL
La maggior parte dei database include un EXPLAIN QUERY PLAN
che descrive i passaggi che il database esegue per eseguire la query. Per SQLite, puoi abilitare questa funzionalità aggiungendo EXPLAIN QUERY PLAN
davanti a un SELECT
dichiarazione:
>>> 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=?)')]
Questa query tenta di elencare il nome, il titolo dell'articolo, il prezzo originale e il prezzo acquistato per tutti gli articoli acquistati.
Ecco come appare il piano di query stesso:
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=?)
Nota che l'istruzione fetch nel tuo codice Python restituisce solo la spiegazione, ma non i risultati. Questo perché EXPLAIN QUERY PLAN
non è destinato all'uso in produzione.
Domande sui database non relazionali
Nella sezione precedente, hai esposto le differenze tra database relazionali e non relazionali e hai utilizzato SQLite con Python. Ora ti concentrerai su NoSQL. Il tuo obiettivo è metterne in evidenza i punti di forza, le differenze e i casi d'uso.
Un esempio di MongoDB
Utilizzerai gli stessi dati di prima, ma questa volta il tuo database sarà MongoDB. Questo database NoSQL è basato su documenti e si adatta molto bene. Per prima cosa, devi installare la libreria Python richiesta:
$ pip install pymongo
Potresti anche voler installare la MongoDB Compass Community. Include un IDE locale perfetto per visualizzare il database. Con esso, puoi vedere i record creati, creare trigger e agire come amministratore visivo per il database.
Nota: Per eseguire il codice in questa sezione, avrai bisogno di un server di database in esecuzione. Per ulteriori informazioni su come configurarlo, consulta Introduzione a MongoDB e Python.
Ecco come creare il database e inserire alcuni dati:
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)
Come avrai notato, MongoDB archivia i record di dati in raccolte , che sono l'equivalente di un elenco di dizionari in Python. In pratica, MongoDB memorizza i documenti BSON.
Q5:interrogazione dei dati con MongoDB
Proviamo a replicare il BoughtItem
prima la tabella, come hai fatto in SQL. A tale scopo, è necessario aggiungere un nuovo campo a un cliente. La documentazione di MongoDB specifica che l'operatore della parola chiave set può essere utilizzato per aggiornare un record senza dover scrivere tutti i campi esistenti:
# 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
}
]
},
}
)
Nota come hai aggiunto campi aggiuntivi al customer
senza definire in modo esplicito lo schema in anticipo. Bello!
In effetti, puoi aggiornare un altro cliente con uno schema leggermente modificato:
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
Analogamente a SQL, i database basati su documenti consentono anche l'esecuzione di query e aggregazioni. Tuttavia, la funzionalità può differire sia sintatticamente che nell'esecuzione sottostante. In effetti, potresti aver notato che MongoDB si riserva il $
carattere per specificare qualche comando o aggregazione sui record, come $group
. Puoi saperne di più su questo comportamento nei documenti ufficiali.
Puoi eseguire query proprio come hai fatto in SQL. Per iniziare, puoi creare un indice:
>>>>>> customers.create_index([("name", pymongo.DESCENDING)])
Questo è facoltativo, ma velocizza le query che richiedono la ricerca dei nomi.
Quindi, puoi recuperare i nomi dei clienti ordinati in ordine crescente:
>>>>>> items = customers.find().sort("name", pymongo.ASCENDING)
Puoi anche scorrere e stampare gli articoli acquistati:
>>>>>> 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}]
Puoi anche recuperare un elenco di nomi univoci nel database:
>>>>>> customers.distinct("firstname")
['Bob', 'Amy', 'Rob']
Ora che conosci i nomi dei clienti nel tuo database, puoi creare una query per recuperare informazioni su di loro:
>>>>>> 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}]}
Ecco la query SQL equivalente:
SELECT firstname, boughtitems FROM customers WHERE firstname LIKE ('Bob', 'Amy')
Nota che anche se la sintassi può differire solo leggermente, c'è una drastica differenza nel modo in cui le query vengono eseguite sotto il cofano. Questo è prevedibile a causa delle diverse strutture di query e dei casi d'uso tra i database SQL e NoSQL.
D6:NoSQL vs SQL
Se si dispone di uno schema in continua evoluzione, come le informazioni sulla regolamentazione finanziaria, NoSQL può modificare i record e nidificare le informazioni correlate. Immagina il numero di join che dovresti fare in SQL se avessi otto ordini di annidamento! Tuttavia, questa situazione è più comune di quanto pensi.
Ora, cosa succede se si desidera eseguire report, estrarre informazioni su tali dati finanziari e dedurre conclusioni? In questo caso, è necessario eseguire query complesse e SQL tende ad essere più veloce sotto questo aspetto.
Nota: I database SQL, in particolare PostgreSQL, hanno anche rilasciato una funzionalità che consente di inserire dati JSON interrogabili come parte di un record. Sebbene questo possa combinare il meglio di entrambi i mondi, la velocità potrebbe essere fonte di preoccupazione.
È più veloce interrogare dati non strutturati da un database NoSQL che interrogare campi JSON da una colonna di tipo JSON in PostgreSQL. Puoi sempre fare un test di confronto della velocità per una risposta definitiva.
Tuttavia, questa funzionalità potrebbe ridurre la necessità di un database aggiuntivo. A volte, gli oggetti in salamoia o serializzati vengono archiviati in record sotto forma di tipi binari e quindi deserializzati durante la lettura.
La velocità non è l'unica metrica, però. Dovrai anche prendere in considerazione cose come transazioni, atomicità, durabilità e scalabilità. Transazioni sono importanti nelle applicazioni finanziarie e tali caratteristiche hanno la precedenza.
Poiché esiste un'ampia gamma di database, ognuno con le proprie funzionalità, è compito del tecnico dei dati prendere una decisione informata su quale database utilizzare in ciascuna applicazione. Per ulteriori informazioni, puoi leggere le proprietà ACID relative alle transazioni del database.
Ti potrebbe anche essere chiesto quali altri database conosci nel tuo colloquio con l'ingegnere dei dati. Esistono molti altri database rilevanti utilizzati da molte aziende:
- Ricerca elastica è altamente efficiente nella ricerca di testo. Sfrutta il suo database basato su documenti per creare un potente strumento di ricerca.
- Newt DB combina ZODB e la funzione JSONB di PostgreSQL per creare un database NoSQL compatibile con Python.
- InfluxDB viene utilizzato nelle applicazioni di serie temporali per memorizzare eventi.
L'elenco potrebbe continuare, ma questo illustra come un'ampia varietà di database disponibili soddisfi tutti il loro settore di nicchia.
Domande sui database della cache
Memorizza nella cache i database conservare i dati a cui si accede di frequente. Vivono accanto ai principali database SQL e NoSQL. Il loro scopo è alleviare il carico e servire le richieste più velocemente.
Un esempio Redis
Hai trattato i database SQL e NoSQL per soluzioni di archiviazione a lungo termine, ma per quanto riguarda l'archiviazione più rapida e immediata? In che modo un tecnico dei dati può modificare la velocità con cui i dati vengono recuperati da un database?
Le applicazioni Web tipiche recuperano i dati di uso comune, come il profilo o il nome di un utente, molto spesso. Se tutti i dati sono contenuti in un database, il numero di riscontri il server di database che ottiene sarà esagerato e non necessario. Pertanto, è necessaria una soluzione di archiviazione più rapida e immediata.
Sebbene ciò riduca il carico del server, crea anche due grattacapi per l'ingegnere dei dati, il team di back-end e il team di DevOps. Innanzitutto, ora avrai bisogno di un database che abbia un tempo di lettura più veloce rispetto al tuo database SQL o NoSQL principale. Tuttavia, i contenuti di entrambi i database devono eventualmente corrispondere. (Benvenuti al problema della coerenza dello stato tra banche dati! Divertiti.)
Il secondo problema è che DevOps ora deve preoccuparsi di scalabilità, ridondanza e così via per il nuovo database della cache. Nella prossima sezione, affronterai problemi come questi con l'aiuto di Redis.
Q7:Come utilizzare i database della cache
Potresti aver ottenuto abbastanza informazioni dall'introduzione per rispondere a questa domanda! Un database di cache è una soluzione di archiviazione rapida utilizzata per archiviare dati di breve durata, strutturati o non strutturati. Può essere partizionato e ridimensionato in base alle tue esigenze, ma in genere ha dimensioni molto inferiori rispetto al tuo database principale. Per questo motivo, il database della cache può risiedere in memoria, consentendoti di ignorare la necessità di leggere da un disco.
Nota: Se hai mai usato dizionari in Python, Redis segue la stessa struttura. È un negozio chiave-valore, dove puoi SET
e GET
dati proprio come un dict
di Python .
Quando arriva una richiesta, controlli prima il database della cache, quindi il database principale. In questo modo, puoi evitare che richieste non necessarie e ripetitive raggiungano il server del database principale. Poiché un database cache ha un tempo di lettura inferiore, puoi anche beneficiare di un aumento delle prestazioni!
Puoi usare pip per installare la libreria richiesta:
$ pip install redis
Ora, considera una richiesta per ottenere il nome dell'utente dal suo 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
Questo codice controlla se il nome è in Redis usando il id
chiave. In caso contrario, il nome viene impostato con un tempo di scadenza, che utilizzi perché la cache è di breve durata.
Ora, cosa succede se il tuo intervistatore ti chiede cosa c'è che non va in questo codice? La tua risposta dovrebbe essere che non c'è gestione delle eccezioni! I database possono avere molti problemi, come connessioni interrotte, quindi è sempre una buona idea provare a catturare queste eccezioni.
Domande sui modelli di progettazione e concetti ETL
Nelle applicazioni di grandi dimensioni, utilizzerai spesso più di un tipo di database. In effetti, è possibile utilizzare PostgreSQL, MongoDB e Redis all'interno di una sola applicazione! Un problema impegnativo riguarda i cambiamenti di stato tra i database, che espongono lo sviluppatore a problemi di coerenza. Considera il seguente scenario:
- Un valore nel database n. 1 viene aggiornato.
- Lo stesso valore nel database n. 2 viene mantenuto lo stesso (non aggiornato).
- Una domanda viene eseguito sul database n. 2.
Ora, hai un risultato incoerente e obsoleto! I risultati restituiti dal secondo database non rifletteranno il valore aggiornato nel primo. Questo può accadere con due database qualsiasi, ma è particolarmente comune quando il database principale è un database NoSQL e le informazioni vengono trasformate in SQL a scopo di query.
I database possono avere lavoratori in background per affrontare tali problemi. Questi lavoratori estraggono dati da un database, trasforma in qualche modo e carica nel database di destinazione. Quando esegui la conversione da un database NoSQL a uno SQL, il processo Estrai, trasforma, carica (ETL) effettua i seguenti passaggi:
- Estratto: C'è un trigger MongoDB ogni volta che un record viene creato, aggiornato e così via. Una funzione di callback viene chiamata in modo asincrono su un thread separato.
- Trasforma: Parti del record vengono estratte, normalizzate e inserite nella struttura dati (o riga) corretta per essere inserite in SQL.
- Carica: Il database SQL viene aggiornato in batch o come record singolo per scritture ad alto volume.
Questo flusso di lavoro è abbastanza comune nelle applicazioni finanziarie, di gioco e di reporting. In questi casi, lo schema in continua evoluzione richiede un database NoSQL, ma il reporting, l'analisi e le aggregazioni richiedono un database SQL.
Q8:Sfide ETL
Esistono diversi concetti impegnativi in ETL, inclusi i seguenti:
- Big data
- Problemi con stato
- Lavoratori asincroni
- Corrispondenza del tipo
La lista continua! Tuttavia, poiché i passaggi del processo ETL sono ben definiti e logici, i tecnici dei dati e del back-end in genere si preoccuperanno maggiormente delle prestazioni e della disponibilità piuttosto che dell'implementazione.
Se la tua applicazione scrive migliaia di record al secondo in MongoDB, il tuo lavoratore ETL deve tenere il passo con la trasformazione, il caricamento e la consegna dei dati all'utente nel modulo richiesto. La velocità e la latenza possono diventare un problema, quindi questi lavoratori sono generalmente scritti in linguaggi veloci. Puoi usare il codice compilato per il passaggio di trasformazione per velocizzare le cose, poiché questa parte è solitamente legata alla CPU.
Nota: La multielaborazione e la separazione dei lavoratori sono altre soluzioni che potresti prendere in considerazione.
Se hai a che fare con molte funzioni ad alta intensità di CPU, allora potresti voler dare un'occhiata a Numba. Questa libreria compila le funzioni per renderle più veloci nell'esecuzione. Soprattutto, questo è facilmente implementabile in Python, sebbene ci siano alcune limitazioni su quali funzioni possono essere utilizzate in queste funzioni compilate.
D9:Design Pattern nei Big Data
Immagina che Amazon debba creare un sistema di raccomandazione per suggerire prodotti adatti agli utenti. Il team di scienza dei dati ha bisogno di dati e molto altro! Si rivolgono a te, l'ingegnere dei dati, e ti chiedono di creare un database di gestione temporanea separato. È lì che ripuliranno e trasformeranno i dati.
Potresti essere scioccato nel ricevere una richiesta del genere. Quando hai terabyte di dati, avrai bisogno di più macchine per gestire tutte queste informazioni. Una funzione di aggregazione del database può essere un'operazione molto complessa. Come puoi interrogare, aggregare e utilizzare dati relativamente grandi in modo efficiente?
Inizialmente Apache aveva introdotto MapReduce, che segue map, shuffle, reduce flusso di lavoro. L'idea è di mappare dati diversi su macchine separate, chiamate anche cluster. Quindi, puoi eseguire il lavoro sui dati, raggruppati per chiave e, infine, aggregare i dati nella fase finale.
Questo flusso di lavoro è ancora utilizzato oggi, ma di recente è svanito a favore di Spark. Il modello di progettazione, tuttavia, costituisce la base della maggior parte dei flussi di lavoro di big data ed è un concetto molto intrigante. Puoi leggere di più su MapReduce su IBM Analytics.
T10:Aspetti comuni del processo ETL e flussi di lavoro dei big data
Potresti pensare che questa sia una domanda piuttosto strana, ma è semplicemente un controllo delle tue conoscenze di informatica, nonché delle tue conoscenze ed esperienze di progettazione complessive.
Entrambi i flussi di lavoro seguono il Produttore-consumatore modello. Un lavoratore (il produttore) produce dati di qualche tipo e li invia a una pipeline. Questa pipeline può assumere molte forme, inclusi messaggi di rete e trigger. Dopo che il Produttore ha prodotto i dati, il Consumatore li consuma e ne fa uso. Questi lavoratori in genere lavorano in modo asincrono e vengono eseguiti in processi separati.
Puoi paragonare il Producer ai passaggi di estrazione e trasformazione del processo ETL. Allo stesso modo, nei big data, il mapper può essere visto come il Produttore, mentre il riduttore è effettivamente il Consumatore. Questa separazione delle preoccupazioni è estremamente importante ed efficace nello sviluppo e nella progettazione dell'architettura delle applicazioni.
Conclusione
Congratulazioni! Hai coperto molto terreno e hai risposto a diverse domande di interviste agli ingegneri di dati. Ora capisci un po' di più sui diversi cappelli che un ingegnere di dati può indossare, oltre a quali sono le tue responsabilità rispetto ai database, alla progettazione e al flusso di lavoro.
Forti di questa conoscenza, ora puoi:
- Utilizza Python con database SQL, NoSQL e cache
- Utilizza Python in ETL e nelle applicazioni di query
- Pianifica i progetti in anticipo, tenendo presente il design e il flusso di lavoro
Sebbene le domande del colloquio possano essere varie, sei stato esposto a più argomenti e hai imparato a pensare fuori dagli schemi in molte aree diverse dell'informatica. Ora sei pronto per una fantastica intervista!