sql >> Database teknologi >  >> RDS >> Database

Dataingeniørinterviewspørgsmål med Python

At gå til samtaler kan være en tidskrævende og trættende proces, og tekniske samtaler kan være endnu mere stressende! Denne tutorial har til formål at forberede dig på nogle almindelige spørgsmål, du vil støde på under dit dataingeniørinterview. Du lærer, hvordan du besvarer spørgsmål om databaser, Python og SQL.

I slutningen af ​​dette selvstudie vil du være i stand til:

  • Forstå almindelige dataingeniørinterviewspørgsmål
  • Skelne mellem relationelle og ikke-relationelle databaser
  • Opsæt databaser ved hjælp af Python
  • Brug Python til at forespørge data

Gratis download: Få et eksempelkapitel fra Python Tricks:The Book, der viser dig Pythons bedste praksis med enkle eksempler, som du kan anvende med det samme for at skrive smukkere + Pythonic kode.


Bliv dataingeniør

Dataingeniørrollen kan være omfattende og varieret. Du skal have et praktisk kendskab til flere teknologier og koncepter. Dataingeniører er fleksible i deres tankegang. Som et resultat kan de være dygtige til flere emner, såsom databaser, softwareudvikling, DevOps og big data.


Hvad laver en dataingeniør?

På grund af dets varierede kvalifikationssæt kan en dataingeniørrolle spænde over mange forskellige jobbeskrivelser. En dataingeniør kan være ansvarlig for databasedesign, skemadesign og oprettelse af flere databaseløsninger. Dette arbejde kan også involvere en databaseadministrator.

Som dataingeniør , kan du fungere som en bro mellem databasen og datavidenskabsteamene. I så fald er du også ansvarlig for datarensning og forberedelse. Hvis big data er involveret, så er det din opgave at komme med en effektiv løsning til disse data. Dette arbejde kan overlappe med DevOps-rollen.

Du skal også lave effektive dataforespørgsler til rapportering og analyse. Du skal muligvis interagere med flere databaser eller skrive Stored Procedures. For mange løsninger, såsom websteder eller tjenester med høj trafik, kan der være mere end én database til stede. I disse tilfælde er dataingeniøren ansvarlig for at oprette databaserne, vedligeholde dem og overføre data mellem dem.



Hvordan kan Python hjælpe dataingeniører?

Python er kendt for at være programmeringssprogenes schweiziske hærkniv. Det er især nyttigt inden for datavidenskab, backend-systemer og server-side scripting. Det er fordi Python har stærk indtastning, enkel syntaks og en overflod af tredjepartsbiblioteker at bruge. Pandaer, SciPy, Tensorflow, SQLAlchemy og NumPy er nogle af de mest udbredte biblioteker i produktion på tværs af forskellige industrier.

Det vigtigste er, at Python reducerer udviklingstiden, hvilket betyder færre udgifter for virksomhederne. For en dataingeniør er det meste kodeudførelse databasebundet, ikke CPU-bundet. På grund af dette giver det mening at udnytte Pythons enkelhed, selv på bekostning af langsommere ydeevne sammenlignet med kompilerede sprog som C# og Java.




Besvarelse af dataingeniørinterviewspørgsmål

Nu hvor du ved, hvad din rolle kan bestå af, er det tid til at lære, hvordan du besvarer nogle dataingeniørinterviewspørgsmål! Selvom der er en masse jord at dække, vil du se praktiske Python-eksempler gennem hele selvstudiet for at guide dig på vej.



Spørgsmål om relationelle databaser

Databaser er en af ​​de mest afgørende komponenter i et system. Uden dem kan der ikke være nogen stat og ingen historie. Selvom du måske ikke har anset databasedesign for at være en prioritet, skal du vide, at det kan have en betydelig indflydelse på, hvor hurtigt din side indlæses. I de sidste par år har flere store virksomheder introduceret flere nye værktøjer og teknikker:

  • NoSQL
  • Cachedatabaser
  • Grafdatabaser
  • NoSQL-understøttelse i SQL-databaser

Disse og andre teknikker blev opfundet for at forsøge at øge hastigheden, hvormed databaser behandler anmodninger. Du bliver sandsynligvis nødt til at tale om disse begreber i dit dataingeniørinterview, så lad os gennemgå nogle spørgsmål!


Spørgsmål 1:Relationelle vs ikke-relationelle databaser

En relationel database er en, hvor data gemmes i form af en tabel. Hver tabel har et skema , som er de kolonner og typer, en post skal have. Hvert skema skal have mindst én primær nøgle, der unikt identificerer denne post. Med andre ord er der ingen duplikerede rækker i din database. Desuden kan hver tabel relateres til andre tabeller ved hjælp af fremmednøgler.

Et vigtigt aspekt af relationelle databaser er, at en ændring i et skema skal anvendes på alle poster. Dette kan nogle gange forårsage brud og store hovedpine under migrationer. Ikke-relationelle databaser tackle tingene på en anden måde. De er i sagens natur skemaløse, hvilket betyder, at poster kan gemmes med forskellige skemaer og med en anden, indlejret struktur. Poster kan stadig have primære nøgler, men en ændring i skemaet foretages på en indtastningsbasis.

Du skal udføre en hastighedssammenligningstest baseret på den type funktion, der udføres. Du kan vælge INSERT , UPDATE , DELETE eller en anden funktion. Skemadesign, indekser, antallet af aggregeringer og antallet af poster vil også påvirke denne analyse, så du bliver nødt til at teste grundigt. Du vil lære mere om, hvordan du gør dette senere.

Databaser adskiller sig også i skalerbarhed . En ikke-relationel database kan være mindre hovedpine at distribuere. Det skyldes, at en samling af relaterede poster nemt kan gemmes på en bestemt node. På den anden side kræver relationsdatabaser mere omtanke og gør normalt brug af et master-slave-system.



Et SQLite-eksempel

Nu hvor du har svaret på, hvad relationsdatabaser er, er det tid til at grave i noget Python! SQLite er en praktisk database, som du kan bruge på din lokale maskine. Databasen er en enkelt fil, hvilket gør den ideel til prototyping formål. Importer først det nødvendige Python-bibliotek og opret en ny database:

import sqlite3

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

Du er nu forbundet til en database i hukommelsen og har dit markørobjekt klar til brug.

Dernæst skal du oprette følgende tre tabeller:

  1. Kunde: Denne tabel vil indeholde en primær nøgle samt kundens for- og efternavne.
  2. Elementer: Denne tabel vil indeholde en primær nøgle, varens navn og varens pris.
  3. Købte varer :Denne tabel vil indeholde et ordrenummer, dato og pris. Den vil også oprette forbindelse til de primære nøgler i tabellerne for varer og kunder.

Nu hvor du har en idé om, hvordan dine borde vil se ud, kan du gå videre og oprette dem:

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) )''')

Du har sendt en forespørgsel til cur.execute() for at oprette dine tre tabeller.

Det sidste trin er at udfylde dine tabeller med data:

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 

Nu hvor der er nogle få poster i hver tabel, kan du bruge disse data til at besvare et par flere dataingeniørinterviewspørgsmål.



Spørgsmål 2:SQL-sammenlægningsfunktioner

Aggregationsfunktioner er dem, der udfører en matematisk operation på et resultatsæt. Nogle eksempler inkluderer AVG , COUNT , MIN , MAX og SUM . Ofte skal du bruge GROUP BY og HAVING klausuler til at supplere disse sammenlægninger. En nyttig aggregeringsfunktion er AVG , som du kan bruge til at beregne gennemsnittet af et givet resultatsæt:

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

Her har du hentet gennemsnitsprisen for hver af de købte varer i din database. Du kan se, at varen har et itemid af 1 har en gennemsnitspris på 10,20 USD.

For at gøre ovenstående output nemmere at forstå, kan du vise elementets navn i stedet for 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)]

Nu kan du nemmere se, at varen med en gennemsnitspris på 10,20 USD er USB .

En anden nyttig sammenlægning er SUM . Du kan bruge denne funktion til at vise det samlede beløb, som hver kunde har brugt:

>>>
>>> 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)]

I gennemsnit brugte kunden ved navn Amy omkring 180 USD, mens Rob kun brugte 11,23 USD!

Hvis din interviewer kan lide databaser, vil du måske friske op på indlejrede forespørgsler, jointyper og de trin, en relationsdatabase tager for at udføre din forespørgsel.



Spørgsmål 3:Fremskyndelse af SQL-forespørgsler

Hastigheden afhænger af forskellige faktorer, men er mest påvirket af, hvor mange af hver af følgende, der er til stede:

  • Deltager
  • Aggregationer
  • Gennemgang
  • Optegnelser

Jo større antal joinforbindelser, jo højere kompleksitet og jo større antal gennemløb i tabeller. Multiple joins er ret dyre at udføre på flere tusinde poster, der involverer flere tabeller, fordi databasen også skal cache mellemresultatet! På dette tidspunkt begynder du måske at tænke over, hvordan du kan øge din hukommelsesstørrelse.

Hastigheden er også påvirket af, om der er indekser eller ej findes i databasen. Indeks er ekstremt vigtige og giver dig mulighed for hurtigt at søge gennem en tabel og finde et match for en kolonne, der er angivet i forespørgslen.

Indeks sorterer posterne på bekostning af højere indsættelsestid samt en vis lagring. Flere kolonner kan kombineres for at skabe et enkelt indeks. For eksempel kolonnerne date og price kan kombineres, fordi din forespørgsel afhænger af begge betingelser.



Spørgsmål 4:Fejlretning af SQL-forespørgsler

De fleste databaser indeholder en EXPLAIN QUERY PLAN der beskriver de trin, databasen tager for at udføre forespørgslen. For SQLite kan du aktivere denne funktionalitet ved at tilføje EXPLAIN QUERY PLAN foran en SELECT erklæring:

>>>
>>> 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=?)')]

Denne forespørgsel forsøger at angive fornavn, varetitel, originalpris og købt pris for alle de købte varer.

Sådan ser selve forespørgselsplanen ud:

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=?)

Bemærk, at fetch-sætningen i din Python-kode kun returnerer forklaringen, men ikke resultaterne. Det er fordi EXPLAIN QUERY PLAN er ikke beregnet til at blive brugt i produktionen.




Spørgsmål om ikke-relationelle databaser

I det foregående afsnit opstillede du forskellene mellem relationelle og ikke-relationelle databaser og brugte SQLite med Python. Nu vil du fokusere på NoSQL. Dit mål er at fremhæve dets styrker, forskelle og anvendelsesmuligheder.


Et MongoDB-eksempel

Du vil bruge de samme data som før, men denne gang vil din database være MongoDB. Denne NoSQL-database er dokumentbaseret og skalerer meget godt. Først og fremmest skal du installere det nødvendige Python-bibliotek:

$ pip install pymongo

Du vil måske også installere MongoDB Compass Community. Det inkluderer en lokal IDE, der er perfekt til at visualisere databasen. Med den kan du se de oprettede poster, oprette triggere og fungere som visuel administrator for databasen.

Bemærk: For at køre koden i dette afsnit skal du bruge en kørende databaseserver. For at lære mere om, hvordan du sætter det op, se Introduktion til MongoDB og Python.

Sådan opretter du databasen og indsætter nogle data:

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)

Som du måske har bemærket, gemmer MongoDB dataposter i samlinger , som svarer til en liste over ordbøger i Python. I praksis gemmer MongoDB BSON-dokumenter.



Spørgsmål 5:Forespørgsel til data med MongoDB

Lad os prøve at replikere BoughtItem tabel først, som du gjorde i SQL. For at gøre dette skal du tilføje et nyt felt til en kunde. MongoDBs dokumentation specificerer, at søgeordsoperatoren sæt kan bruges til at opdatere en post uden at skulle skrive alle de eksisterende felter:

# 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
                    }
                ]
            },
        }
    )

Bemærk, hvordan du føjede yderligere felter til customer uden eksplicit at definere skemaet på forhånd. Pænt!

Faktisk kan du opdatere en anden kunde med et lidt ændret skema:

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

I lighed med SQL tillader dokumentbaserede databaser også at udføre forespørgsler og aggregeringer. Funktionaliteten kan dog variere både syntaktisk og i den underliggende udførelse. Faktisk har du måske bemærket, at MongoDB reserverer $ tegn for at angive en kommando eller aggregering på posterne, såsom $group . Du kan lære mere om denne adfærd i de officielle dokumenter.

Du kan udføre forespørgsler ligesom du gjorde i SQL. For at starte kan du oprette et indeks:

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

Dette er valgfrit, men det fremskynder forespørgsler, der kræver navneopslag.

Derefter kan du hente kundenavnene sorteret i stigende rækkefølge:

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

Du kan også gentage og udskrive de købte varer:

>>>
>>> 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}]

Du kan endda hente en liste over unikke navne i databasen:

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

Nu hvor du kender navnene på kunderne i din database, kan du oprette en forespørgsel for at hente oplysninger om dem:

>>>
>>> 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}]}

Her er den tilsvarende SQL-forespørgsel:

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

Bemærk, at selvom syntaksen kun kan afvige en smule, er der en drastisk forskel i den måde, forespørgsler udføres under emhætten. Dette kan forventes på grund af de forskellige forespørgselsstrukturer og use cases mellem SQL- og NoSQL-databaser.



Q6:NoSQL vs SQL

Hvis du har et konstant skiftende skema, såsom finansiel lovgivningsinformation, så kan NoSQL ændre registreringerne og indlejre relaterede oplysninger. Forestil dig antallet af joinforbindelser, du skulle gøre i SQL, hvis du havde otte ordrer af indlejring! Denne situation er dog mere almindelig, end du skulle tro.

Hvad nu, hvis du vil køre rapporter, udtrække information om disse økonomiske data og udlede konklusioner? I dette tilfælde skal du køre komplekse forespørgsler, og SQL har en tendens til at være hurtigere i denne henseende.

Bemærk: SQL-databaser, især PostgreSQL, har også frigivet en funktion, der gør det muligt at indsætte JSON-data, der kan forespørges, som en del af en post. Selvom dette kan kombinere det bedste fra begge verdener, kan hastighed være et problem.

Det er hurtigere at forespørge ustrukturerede data fra en NoSQL-database, end det er at forespørge på JSON-felter fra en JSON-type kolonne i PostgreSQL. Du kan altid lave en hastighedssammenligningstest for at få et endeligt svar.

Ikke desto mindre kan denne funktion muligvis reducere behovet for en ekstra database. Nogle gange bliver syltede eller serialiserede objekter gemt i poster i form af binære typer og derefter afserialiseret ved læsning.

Hastighed er dog ikke den eneste metrik. Du vil også gerne tage højde for ting som transaktioner, atomicitet, holdbarhed og skalerbarhed. Transaktioner er vigtige i finansielle applikationer, og sådanne funktioner har forrang.

Da der er en bred vifte af databaser, hver med sine egne funktioner, er det dataingeniørens opgave at træffe en informeret beslutning om, hvilken database der skal bruges i hver applikation. For mere information, kan du læse om ACID-egenskaber i forbindelse med databasetransaktioner.

Du kan også blive spurgt, hvilke andre databaser du kender til i dit dataingeniørinterview. Der er flere andre relevante databaser, som bruges af mange virksomheder:

  • Elastisk søgning er yderst effektiv i tekstsøgning. Den udnytter sin dokumentbaserede database til at skabe et kraftfuldt søgeværktøj.
  • Newt DB kombinerer ZODB og PostgreSQL JSONB-funktionen for at skabe en Python-venlig NoSQL-database.
  • InfluxDB bruges i tidsserieapplikationer til at gemme begivenheder.

Listen fortsætter, men dette illustrerer, hvordan en lang række tilgængelige databaser alle henvender sig til deres nicheindustri.




Spørgsmål om cachedatabaser

Cachedatabaser opbevare ofte tilgåede data. De lever sammen med de vigtigste SQL- og NoSQL-databaser. Deres mål er at lette belastningen og betjene anmodninger hurtigere.


Et Redis-eksempel

Du har dækket SQL- og NoSQL-databaser til langsigtede lagringsløsninger, men hvad med hurtigere og mere øjeblikkelig lagring? Hvordan kan en dataingeniør ændre, hvor hurtigt data hentes fra en database?

Typiske webapplikationer henter ofte brugte data, såsom en brugers profil eller navn. Hvis alle data er indeholdt i én database, er antallet af hits databaseserveren bliver overdreven og unødvendig. Som sådan er der brug for en hurtigere og mere øjeblikkelig opbevaringsløsning.

Selvom dette reducerer serverbelastningen, skaber det også to hovedpine for dataingeniøren, backend-teamet og DevOps-teamet. For det første skal du nu bruge en database, der har en hurtigere læsetid end din primære SQL- eller NoSQL-database. Dog skal indholdet af begge databaser til sidst matche. (Velkommen til problemet med statskonsistens mellem databaser! God fornøjelse.)

Den anden hovedpine er, at DevOps nu skal bekymre sig om skalerbarhed, redundans og så videre for den nye cachedatabase. I næste afsnit vil du dykke ned i problemer som disse ved hjælp af Redis.



Q7:Sådan bruges cachedatabaser

Du har muligvis fået nok information fra introduktionen til at besvare dette spørgsmål! En cachedatabase er en hurtig lagringsløsning, der bruges til at gemme kortlivede, strukturerede eller ustrukturerede data. Den kan opdeles og skaleres efter dine behov, men den er typisk meget mindre i størrelse end din hoveddatabase. På grund af dette kan din cachedatabase ligge i hukommelsen, så du kan omgå behovet for at læse fra en disk.

Bemærk: Hvis du nogensinde har brugt ordbøger i Python, så følger Redis den samme struktur. Det er et nøgleværdilager, hvor du kan SET og GET data ligesom en Python dict .

Når der kommer en forespørgsel, tjekker du først cachedatabasen og derefter hoveddatabasen. På denne måde kan du forhindre unødvendige og gentagne anmodninger i at nå hoveddatabasens server. Da en cachedatabase har en lavere læsetid, drager du også fordel af en ydelsesforøgelse!

Du kan bruge pip til at installere det nødvendige bibliotek:

$ pip install redis

Overvej nu en anmodning om at få brugerens navn fra deres 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

Denne kode kontrollerer, om navnet er i Redis ved hjælp af id nøgle. Hvis ikke, så er navnet sat med en udløbstid, som du bruger, fordi cachen er kortvarig.

Hvad nu hvis din interviewer spørger dig, hvad der er galt med denne kode? Dit svar bør være, at der ikke er nogen undtagelseshåndtering! Databaser kan have mange problemer, såsom afbrudte forbindelser, så det er altid en god idé at prøve at fange disse undtagelser.




Spørgsmål om designmønstre og ETL-koncepter

I store applikationer vil du ofte bruge mere end én type database. Faktisk er det muligt at bruge PostgreSQL, MongoDB og Redis alle inden for kun én applikation! Et udfordrende problem er at håndtere tilstandsændringer mellem databaser, hvilket udsætter udvikleren for problemer med konsistens. Overvej følgende scenarie:

  1. En værdi i database #1 er opdateret.
  2. Den samme værdi i database #2 holdes den samme (ikke opdateret).
  3. En forespørgsel køres på database #2.

Nu har du fået dig selv et inkonsekvent og forældet resultat! Resultaterne, der returneres fra den anden database, afspejler ikke den opdaterede værdi i den første. Dette kan ske med alle to databaser, men det er især almindeligt, når hoveddatabasen er en NoSQL-database, og information omdannes til SQL til forespørgselsformål.

Databaser kan have baggrundsarbejdere til at tackle sådanne problemer. Disse arbejdere udvinder data fra én database, omdan det på en eller anden måde, og indlæs det ind i måldatabasen. Når du konverterer fra en NoSQL-database til en SQL-database, tager processen Extract, transform, load (ETL) følgende trin:

  1. Udtræk: Der er en MongoDB-udløser, når en post oprettes, opdateres og så videre. En tilbagekaldsfunktion kaldes asynkront på en separat tråd.
  2. Transformer: Dele af posten udtrækkes, normaliseres og sættes i den korrekte datastruktur (eller række) for at blive indsat i SQL.
  3. Indlæs: SQL-databasen opdateres i batches, eller som en enkelt post for store mængder skrivninger.

Denne arbejdsgang er ret almindelig i økonomi-, spil- og rapporteringsapplikationer. I disse tilfælde kræver det konstant skiftende skema en NoSQL-database, men rapportering, analyse og aggregering kræver en SQL-database.


Q8:ETL-udfordringer

Der er flere udfordrende koncepter i ETL, herunder følgende:

  • Big data
  • Statsfulde problemer
  • Asynkrone arbejdere
  • Typematchning

Listen fortsætter! Men da trinene i ETL-processen er veldefinerede og logiske, vil data- og backend-ingeniørerne typisk bekymre sig mere om ydeevne og tilgængelighed frem for implementering.

Hvis din applikation skriver tusindvis af optegnelser i sekundet til MongoDB, så skal din ETL-medarbejder holde trit med at transformere, indlæse og levere dataene til brugeren i den anmodede form. Hastighed og latenstid kan blive et problem, så disse arbejdere er typisk skrevet på hurtige sprog. Du kan bruge kompileret kode til transformationstrinnet for at fremskynde tingene, da denne del normalt er CPU-bundet.

Bemærk: Multibearbejdning og adskillelse af arbejdere er andre løsninger, som du måske vil overveje.

Hvis du har at gøre med en masse CPU-intensive funktioner, så vil du måske tjekke Numba ud. Dette bibliotek kompilerer funktioner for at gøre dem hurtigere ved udførelse. Det bedste af det hele er, at dette nemt implementeres i Python, selvom der er nogle begrænsninger for, hvilke funktioner der kan bruges i disse kompilerede funktioner.



Spørgsmål 9:Designmønstre i Big Data

Forestil dig, at Amazon skal oprette et anbefalingssystem at foreslå passende produkter til brugerne. Datavidenskabsteamet har brug for data og meget af det! De går til dig, dataingeniøren, og beder dig om at oprette et separat staging-databasevarehus. Det er her, de rydder op og transformerer dataene.

Du kan blive chokeret over at modtage en sådan anmodning. Når du har terabyte data, skal du bruge flere maskiner til at håndtere alle disse oplysninger. En databaseaggregeringsfunktion kan være en meget kompleks operation. Hvordan kan du forespørge, samle og gøre brug af relativt store data på en effektiv måde?

Apache havde oprindeligt introduceret MapReduce, som følger map, shuffle, reduce workflow. Ideen er at kortlægge forskellige data på separate maskiner, også kaldet klynger. Derefter kan du udføre arbejde på dataene, grupperet efter en nøgle, og til sidst aggregere dataene i den sidste fase.

Denne arbejdsgang bruges stadig i dag, men den er for nylig blevet falmet til fordel for Spark. Designmønstret danner dog grundlaget for de fleste big data-arbejdsgange og er et yderst spændende koncept. Du kan læse mere om MapReduce hos IBM Analytics.



Q10:Fælles aspekter af ETL-processen og Big Data-arbejdsgange

Du synes måske, at dette er et ret mærkeligt spørgsmål, men det er simpelthen et tjek af din viden om datalogi såvel som din overordnede designviden og erfaring.

Begge arbejdsgange følger Producent-Forbruger mønster. En arbejder (producenten) producerer data af en eller anden art og udsender dem til en pipeline. Denne pipeline kan antage mange former, herunder netværksmeddelelser og triggere. Efter at producenten har udlæst dataene, forbruger og bruger forbrugeren dem. Disse arbejdere arbejder typisk på en asynkron måde og udføres i separate processer.

Du kan sammenligne producenten med ekstrakt- og transformationstrinene i ETL-processen. Tilsvarende i big data er mapper kan ses som Produceren, mens reduceren er reelt forbrugeren. Denne adskillelse af bekymringer er ekstremt vigtig og effektiv i udviklingen og arkitekturdesignet af applikationer.




Konklusion

Tillykke! Du har dækket meget af jorden og besvaret adskillige dataingeniørinterviewspørgsmål. Du forstår nu lidt mere om de mange forskellige hatte en dataingeniør kan bære, samt hvad dit ansvar er med hensyn til databaser, design og arbejdsgange.

Bevæbnet med denne viden kan du nu:

  • Brug Python med SQL-, NoSQL- og cachedatabaser
  • Brug Python i ETL- og forespørgselsapplikationer
  • Planlæg projekter på forhånd, og husk design og arbejdsgange

Mens interviewspørgsmål kan varieres, har du været udsat for flere emner og lært at tænke ud af boksen inden for mange forskellige områder af datalogi. Nu er du klar til at få et fantastisk interview!



  1. Stort databasestyringssystem:Design og arkitekt

  2. Hvordan finder man summen af ​​flere kolonner i en tabel i SQL Server 2005?

  3. Automatiser versionsnummer-hentning fra .Dtsx-filer

  4. Grupperet LIMIT i PostgreSQL:vis de første N rækker for hver gruppe?