BIG01: Juna-alusta
Tämä harjoitus poikkeaa muista harjoituksista siten, että alustan toteutukseen löytyy YouTube-soittolista avuksi. Soittolistan videoissa kasataan lähes identtinen alusta siitä, mitä sinä kasaat. Erona on eri data, mikä vaikuttaa pienissä määrin tiedon lataukseen, tiedon mallintamiseen ja visualisointiin.
- Videot: YouTube Playlist: Data-alustat BIG101 demo
- Esimerkkitoteutuksen data: Jäätelöauto API
- Esimerkkitoteutuksen koodi: data-alustat-demo
Soittolistan videoilla kasataan alusta, joka:
- Tuo feikkidataa jaateloauto-API:sta
- Edustaa Data-alustat/Arkkitehtuuri mukaista yhden koneen ja yhden tietolähteen arkkitehtuuria
- Mallintaa datan Kimballin tähtimallia muotoilevaksi Silver-kerrokseksi
- Mallinta datan one big table -tyyppiseksi aggregaattitauluksi Gold-kerrokselle
- Tarjoaa loppukäyttäjille Evidence BI-työkalun, jolla valittu bisnesongelma visualisoidaan
Sinun tehtäväsi on luoda mahdollisimman automatisoitu putki, joka hyödyntää dbt:tä, DuckDB:tä ja Evidenceä työkaluina, ja DuckDB-tietovarastoon tehdään medaljonkiarkkitehtuuri (bronze, silver, gold).
Muokkaa monorepoksi
Vuoden 2025 toteutuksessa tämä oli kurssin loppupuoliskon käytännön toteutus, ja täten se eli yksin omassa repositoriossaan. Vuodesta 2026 alkaen toteutuksessa on käytetty monorepoa. Älä siis toista laput silmillä opettajan komentoja vanhasta videosta: tee samat asiat nykyisen etunimisukunimi/ repositoriosi sisään, esimerkiksi hakemistoon etunimisukunimi/big01/.
Voi olla kannattavaa avata tuo hakemisto omaan VS Code -ikkunaan. Osa VS Coden ominaisuuksista, erityisesti Python virtuaaliympäristöön liittyvät, toimivat parhaiten kun ne ovat VS Coden näkökulmasta projektin juurihakemistossa.
Videon vaiheet
Soittolistan videoissa näkyy TODO-lista, jota opettaja seuraa. Alla on sama lista tarjottuna sinulle, siltä varalta, että se helpottaa tehtävän tekemistä tai videoiden seuraamista. Jos siitä ei ole apua, hyppää yli.
Demossa valittu bisnesongelma on: Jäätelöautojen viikoittainen kumulatiivinen sekä keskimääräinen (p50 ja p90) pysäkiltä myöhässä lähteminen (eli "departure lateness").
Luento 1: Jaateloauto REST API to staging
Part 1/3: Projektin aloitus
- Valitse bisnesongelma
- Tutustu REST API:n dokumentaatioon ja varmista että valitsemasi ongelmaa vastaava data on olemassa. Jos ei, vaihda bisnesongelma.
- Alusta repositorio
- Asenna uv
- Asenna Python 3.12 (
uv python install 3.12) - Pinnaa versio (
uv python pin 3.12) - Alusta uv-projekti (
uv init --lib --name "ope-data-alusta" .)-
--libselitetään myöhemmin hakemistorakenteessa.
-
- Luo virtuaaliympäristö (
uv sync) - ... ja varmista, että VS Code käyttää sitä Python Interpreterinä.
- Asenna Python 3.12 (
- Päätä projektihakemiston rakenne, esim:
- Data menee aina
./data/- Raakadata louhitaan
./data/lake/*/* - Tietovarasto sijoitetaan
./data/warehouse/jotain.db
- Raakadata louhitaan
- Koodi sijoitetaan
./src/(uv huolehti jo tästä) - Automaatioskriptit sijoitetaan
./scripts/ - Tee tyhjistä hakemistoista pysyviä
.gitkeep-tiedostojen avulla. - Puske GitLabiin (muista
git status -u!!!)
- Data menee aina
HOX! Oikeaa tehtävää tehdessä tässä välissä olisi hyvä pitää dokumentaatio kunnossa. Onhan sinulla README.md-tiedosto vähintään jo otsikkotasolla päivitetty?
Part 2/3: Jaateloauto REST API
HOX! Tähän väliin käytännön vinkki: teille on täysin sallittua sijoittaa repositorioon MEMO.md tai ./notes/*.md tai ylläpitää muistiinpanoja Notionissa tai käyttää fyysistä muistivihkoa. Minä en sitä tee videoilla, mutta opiskellesssa suosittelen tekemään muistiinpanoja. Ethän aja itseäsi tilanteeseen, jossa "Ajoin komennon, jota en muista, ja sit tuli virhe, jota en muista, mutta nyt tämä ei enää toimi." Tätä kannattaa käyttää myös työelämässä.
HOX! Tee muistiinpanoja myös kurssipalautteeseen liittyvistä asioita. Näin osaat antaa parempaa palautetta kurssin lopuksi, kun ongelmakohdat eivät ole muistin varassa. Voit käytännössä copy-pasteta palautteen intran kaavakkeeseen. Kukaan meistä ei ole täydellinen, mutta me kaikki voimme kehittyä. Palaute auttaa tässä.
- Kloonaa Jäätelöauto API
- Lue README.md ja aja palvelu ylös.
- Tutustu Swagger UI:iin (
localhost:8000) - Tutustu Rautatieliikenne API:iin
- Swagger
- (Optional) GraphQL
- Tsekkaa myös Keskusteluryhmä. Näet aitoa bugi-ilmoittelua!
- Tutustu REST:n olemukseen JSONPlaceholder avulla.
- Selain
- HTTPie
- Testaa samat vielä Jäätelöauto API:n datalla
- Tsekkaa vielä HTTP verbit
- Python Notebook Playground
- Asenna IPykernel ja requests (
uv add ipykernel requests) - Tee hakemisto Notebookeille (esim.
./notebooks/) - Luo uusi Notebook,
rest_tutuksi.ipynb - Kokeile
requests-kirjastoa (requests.get('url').json()
- Asenna IPykernel ja requests (
- Bonus: kurkataan huvikseen myös Vanhat junat zip-paketteina -vaihtoehtoa. Tämä voi olla houkutteleva, mikäli jonkun bisnesongelma käsittelee pidemmän ajanjakson ongelmaa useampaan junaan liittyen. Keksitkö tavan automatisoida kaikkien näiden S3:lla olevien zip-tiedostojen lataamisen (esimerkiksi
./data/lake/staging/vr-zip/yyyy-mm-dd.zip) ja purkamisen (./data/lake/staging/vr-data/yyyy/mm/dd/???.zip). - Puske GitLabiin
HOX! Varsinaiset skriptit voit kehittää .ipynb-Notebookissa, jos kaipaat interaktiivisuutta kehittäessä, mutta luo niistä kuitenkin lopulta .py-skriptit, jotta niiden parametrisointi ja automatisointi on helppoa myöhemmin.
HOX! Get-metodin palauttaman objektin metodi .json() on kiva plärätessä, mutta jos haluat Bronzen todella olevan as-raw-as-possible, kirjoita palautuneet bytet sellaisina kuin ne ovat saapuneet ilman turhia enkoodauksia, joita ko. metodi väkisinkin ujuttaa mukaan.
HOX! Huomaa, että sinun tulee aina lukea käyttämäsi API:n käyttöehdot ja -ohjeet. Esimerkiksi Fintrafficilla on oma Tuki > Ohjeita ja lisätietoa rajapintojen käyttöön -ohje, jossa neuvotaan pakolliset headerit (eli 'Digitraffic-User: Junamies/FoobarApp 1.0') sekä kuvaukset rajoituksista, jotka rajoittavat kyselyiden tiehyttä (default: 60 kpl/min).
Part 3/3: Ingestion Tool
- Koodaa dummy ingestion tool.
- Jupyter Notebook (
./notebooks/jaateloauto_ingestion.ipynb) - Hetken miete datan/skeeman tarkistukselle (e.g. Polars schema)
- Hetken miete JSON koskemattomana vai esim. JSON Lines (
ELTvsEtLT) - Hetken miete, saako tässä välissä tiputtaa tarpeettomia kenttiä pois
- Jupyter Notebook (
- (Advanced:) Koodaa helpommin ajettava ingestion tool
- Python (
./src/ingestor/jaateloauto.py) jaargparse - Immutability!
- Python (
- Laita
data/lake/staging/gitignoreen. Data ei kuulu versionhallintaan. - Puske GitLabiin.
📅 Tähän pisteeseen teidän pitäisi päästä ensimmäisellä viikolla! Kirjoittakaa jäätelöautodatan kylkeen skriptit, jotka louhivat kyseisen dummydatan sijasta aitoa raideliikennedataa.
Luento 2: Staging to Bronze using dbt
Part 1/3: dbt ja DuckDB
- Asenna dbt
- Aloita asentamalla DuckDB CLI. (⚠️ Huomaa mahdollinen vaatimus C++ kirjastojen asentamiselle Windowsissa! ⚠️).
- Tämän jälkeen asenna dbt-duckdb (
uv add dbt-duckdb), jonka riippuvuuksina asentuvat myösdbt-corejaduckdb.
- Luo dbt-projekti
- Päätä: voit luoda joko jäätelöautolle ja junadatalle yhteisen tai kummallekin erikseen.
-
uv run dbt init -
cd <projektin_nimi> - Luo lokaali
profiles.yml(katso malli alta)
- Tutustu seuraaviin tiedostoihin:
-
profiles.yml(configuration precedence: Project, User, System) -
dbt_project.yml -
models/**/*.yml -
models/**/*.sql- Ja niissä
{{ jotain }}-syntaksi
- Ja niissä
-
Luo lokaali profiles.yml:
dbt_warehouse:
target: dev
outputs:
dev:
type: duckdb
path: '../data/warehouse/warehouse.duckdb'
schema: main
- Aja ensimmäinen malli
-
uv run dbt run -
uv run dbt test<= 🚧 Noteeraa virhe 🚧 - Tutki tiedostoja, etsi virhe, korjaa se.
-
- Tutustu DuckDB UI:in
- Aja
duckdb -ui polku/sinun/warehouseen.duckdb. Selaimeen aukeaa etäisesti Jupyter Notebookin oloinen SQL-client. - Huomaa, että se luo Notebookit ja muun datan kotikansioosi
~/.duckdb/extension_data/ui/
- Aja
- Tutustu docsiin
-
uv run dbt docs generate -
uv run dbt docs serve
-
- Puske GitLabiin
Part 2/3: dbt ja Fake CSV
- Luo tiedostot
-
data/lake/staging/csvtest/customers.csv(id, name, email) -
.../orders.csv(id, customer_id, product, quantity)
-
- Luo datamalli Bronzelle
- Hakemisto
<projektin_nimi>/models/bronze/csvtest - Tiedostot
csvtest_customers.sqljacsvtest_orders.sql- HOX! Harjoittele SQL:ää DuckDB UI:ssa!
- Tutustu DuckDB:n CSV Importtiin
- Lisää
dbt_project.ymltiedostoon model- materialized: table
- schema: bronze (muokkaa profilesiin
target: dev, jotta DuckDB schemaksi tuleedev_bronze)
- Kirjoita myös
schema.yml(taiwhatever.yml)- (Optional:) Käytä
docs.mdtiedostoa ja tuo se näin:'{{ doc("customers_desc") }}'
- (Optional:) Käytä
- Hakemisto
- Puske GitLabiin
Part 3/3: dbt Jaatelo Bronzelle
- Tarkastele tiedostoja
-
data/lake/staging/jaatelo/<junanro>/<date>.json - Tiedosta, että REST API saa olla nyt alhaalla.
-
- Luo datamalli Bronzelle
- Hakemisto
models/bronze/jaatelo - Tiedosto
jaateloauto_api.sql- Suunnittele, älä hutki!
- Luo primääriavain
sk_jaateloauto(truckId + departureDate + operatorId) - ... käytä myös concat_ws, coalesce tai ifnull ja md5 hash
- ... ja dbt:ssä käytä dbt utils (
packages.ymljauv run dbt deps)
- Lisää
dbt_project.ymltiedostoon modelseihin - Dokumentoi
schema.yml
- Hakemisto
- Puske GitLabiin
Luento 3: Silver and Gold modelling
Part 1/3: Silver Timetable
-
Luo datamalli Silverille
-
Suunnittele ennen kuin teet! Sinun pitää tietää, mikä yksi rivi yhdessä taulussa edustaa!
-
Tästä alkaen työ on mekaanista toistoa yllä olevasta, mutta kaikki tehdään
models/silverjagoldkansioon -
SQL kannattaa taas harjoitella interaktiivisessa DuckDB UI -tilassa ja myöhemmin liittää
.sql-tiedostoon. -
Luotavat 🥈 Silver taulut:
-
jaateloauto_timetable: one row per an event (arrive, departure) that has ever happened. In other words, this is the unnested JSON data from Bronze. Primary key needs to be a surrogate key.-
timetable_row -> '$.station' as method_a(JSON Functions) (json_extract) sopii kaikille paitsi stringeille. -
timetable_row --> '$.stopName' as method_b(json_extract_string) parsii pois hipsukat stringeistä. - Yhdistä castin kanssa:
json_extract(ttr, '$stopId')::INT - Jos kenttä on yhä nestattu:
json_extract(ttr, '$.latenessCauses')::JSON[] - PK/SK:
sk_jaateloauto_timetable: (sk_jaateloauto + stop_id + stop_direction) - Lisää modeliksi ja dokumentoi taulu.
-
-
-
Puske GitLabiin
-
Part 2/3: Silver Fact and Dim
Luotavat 🥈 Silver taulut hakevat kumpikin tiedot yllä tehdystä aputaulusta.
-
f_stop: A fact table representing one row per stop - including arrival and departure. The ice cream trucks stops to sell ice cream. It will include columns for arrives lateness and depature lateness. In short, the data is nearly the same as in the one above, but granularity has been reduced to stop (instead of stop-event). The moment of a truck stopping to sell ice cream has been chosen as a business event that is tracked. Primary key needs to be a surrogate key, since we don't get a unifying UUID from source system of other suitable id.- PK/SK:
sk_stop(sk_jaateloauto + stop_id) using
- PK/SK:
-
d_truck: One row per truck. In real life, we would most likely enrich this data with other information such as route length, amount of stops on the truck's route et cetera. Primary key is truck_id, which is essentially a natural key, since customer's would see this truck id in the time schedule.- PK:
truck_id - Huomaa, että koska jäätelöauton perustiedot pysyvät päivästä toiseen samana, voimme noutaa kaiken tiedon kyseisen trukin uusimmasta rivistä, ja voimme myös pitää esimerkiksi pelkästään departuren.
- PK:
- Puske GitLabiin
Part 3/3: Gold
Luotavat 🥇 Gold taulut:
-
jaateloauto_weekly_lateness: one row perweek + truck_id + operator_namecombo. We will focus on departure times. Aggregated fields field be e.g.total_departure_lateness,p50_departure_lateness(alias median) andp90_departure_lateness. - Tarkista, että dbt docsissa lineage näkyy oikein.
- Puske GitLabiin
Luento 4: Evidence
Info
Jos haluat, voit korvata Evidencen jollakin toisella BI-työkalulla. Vaihtoehtoja ovat esimerkiksi:
- Marimo Notebook + Altair
- Streamlit + Matplotlib/Plotly/Altair/etc.
- Power BI tai Tableau
- JavaScript + D3.js
Evidencen setup on aiheuttanut joillakin Windows-käyttäjillä päänvaivaa, joten sallin myös vaihtoehtoiset ratkaisut. BI-kerros ei ole tämän harjoituksen pääpointti, mutta se pitää kuitenkin olla olemassa, jotta Gold-tason tauluille on jokin merkitys olemassa.
Part 1/2
- Tutustu Evidencen dokumentaatioon
- Ja gh:evidence-dev/docker-devenv esimerkkiin
- Ja minun vastaaviin Docker Compose ja Dockerfile tiedostoihin
- Aja ensin init
-
docker compose -f docker-compose.init.yml up --build -
docker compose -f docker-compose.init.yml down - ... jotta saat
bi/workspacekansion.
-
- Lisää GitLabiin
Tässä välissä, jos haluat, voit tutkia mitä uusi volume sisältää.
# Huomaat, että sinulle on uusi volume evidence_node_modules
docker volume ls
# Luo tilapäinen kontti, johon volume on mountattu
docker run --rm -it \
-v evidence_node_modules:/mnt \
ubuntu bash
# Kontin sisällä voit ajaa seuraavat komennot.
# Ctrl + D sulkee ja tuhoaa kontin (mutta ei volumea)
cd /mnt
ls
- Aja sitten palvelu ylös
- Tarpeen mukaan
docker compose build -
docker compose up --watch - Kokeile muokata index.md:tä. Sivun pitäisi päivittyä.
- Tarpeen mukaan
- Puske GitLabiin
Tässä välissä vaihdan Windowsiin, jotta homma olisi hieman cross OS -testattua:
- Aja ensin
dbt-komennot, jottawarehouse.duckdbon ajan tasalla. - Testaa kummatkin tilanteet:
- on ensin ajettu
rm -r bi/workspaceja sitten ajetaan kummatkindocker-komennot. Kontin pitäisi päivittyä kunindex.md:tä muokataan. - workspace on valmiiksi olemassa, mutta tämän koneen Docker-ympäristöstä puuttuu
evidence_node_modules. Muista tuhota se ensin yllä olevan testin jäljiltä. Muutoin testi on sama kuin yllä.
- on ensin ajettu
Part 2/2
- Kirjoita
update_data.shskripti, joka ajaa tarvittavatdbt-rimpsut, jotta warehouse on ajan tasalla, ja lopulta kopioi senbi/workspaces/sources/warehouse/warehouse.duckdbtiedoston päälle. - Tutustu Evidence Docs: Build Your First App
- Luo source:
- HOX! Koska Compose Watch:n sync on yksisuuntainen
host -> container, et voi luoda tietolähteitä Evidence GUI:ssa. Tee tämä ihan vain luomalla tiedostoja. - Luo
connection.yamljajaateloauto_weekly_lateness.sqlesimerkkinä toimivanneedful_thingskaltaisesti. - Testaa Evidence SQL Consolessa
select * from warehouse.jaateloauto_weekly_lateness
- HOX! Koska Compose Watch:n sync on yksisuuntainen
- Luo itse sivu:
- Muokkaa
index.md-tiedostoa. - Luo perus SQL code block, kuten ohjeissa neuvotaan, jotta saat datan aliakseen.
- Kokeile ihan vain
<DataTable data={code_block_nimi_ylta} /> - Lisää
<BarChart />, jonka pitäisi istua tähän käyttöön varsin hyvin.-
data= -
x=week_monday -
y=p50_departure_lateness -
y2=p90_depatrure_lateness -
xFmt=shortdate -
xAxisTitle=Week -
yAxisTitle=Minutes
-
- Ja toinen, jossa on lisäksi
series=truck_idjatype=groupedtai=stacked
- Muokkaa
- Puske GitLabiin
Videolla esitettävä
Tässä harjoituksessa videon tulee osoittaa alustasi ja datarakenteesi keskeisimmät oivallukset. Koska teit tässä useita vaiheita, tiivistä presentaatio näyttämään prosessin kulku. Videolla näkyy vähimmillään seuraavat vaiheet:
- Aloitus ja tavoite: Kerro valitsemasi junadatan bisnesongelma (esim. joidenkin tiettyjen junien myöhästymiset) ja näytä, mihin REST API -päätepisteeseen olet yhdistänyt.
- Raakadatan nouto: Näytä Python-skriptisi (ingestion tool), joka hakee datan, ja demonstroi, että raakadata tallentuu onnistuneesti
.jsontai.csv-muodossa Datalaken staging-kansioon. - Bronze (dbt & DuckDB): Esittele, miten dbt tekee raakadatasta DuckDB-tietovaraston Bronze-tason taulun (näytä esim. SQL-kyselysi tai DuckDB UI -näkymä).
- Silver & Gold -mallinnus (dbt): Esittele tekemäsi dimensionalinen mallinnus (Silver-tason ratkaisut) sekä lopputuloksena syntyvä Gold-tason aggregaatiotaulu.
- dbt Docs & Lineage: Avaa
dbt docsselaimessa ja näytä projektisi data lineage -graafi varmistaaksesi putken oikeellisuuden. - BI: Esittele lopuksi dashboard, joka hyödyntää DuckDB:n Gold-tasoa ja vastaa alussa asettamaasi bisnesongelmaan. Voit tehdä kerroksen valitsemallasi työkaulla; ei ole pakko käyttää Evidenceä.