Modül 3 · Atölye: Veri Alımı · ⏱ 7 dk

dlt ile ilk ingestion: 5 dakikada API'den tabloya

dlt first ingestion

Bu derste neler öğreneceksin

  • dlt init dlthub:open_library duckdb çalıştırır
  • Open Library API den veri çeker
  • Normalize edilmiş tabloyu inceler

Modern Ingestion Stack

Veri alımı (ingestion) veri mühendisliğinin ilk ve en kritik katmanı. Geleneksel yaklaşım: saatlerce requests + manuel JSON parse + INSERT SQL’leri yaz. Modern yaklaşım: declarative (bildirimsel) — ne istediğini söyle, araç gerisini halletsin.

dlt (data load tool) bu felsefenin Python implementasyonu. Bir dlt pipeline:

  1. Bir kaynak (API, dosya, veritabanı) tanımla.
  2. dlt şemayı otomatik çıkarsın.
  3. Veriyi normalize edip destination’a yaz (DuckDB, BigQuery, Snowflake, Postgres).
  4. State (nerede kaldın) ve schema evolution (yeni sütunlar) otomatik yönetilir.

Bugün bu akışı uçtan uca göreceğiz. Source: Open Library REST API. Destination: DuckDB. Tüm süreç: ~50 satır Python.

Kurulum

pip install "dlt[duckdb]"

dlt[duckdb] ekstra etiketi, DuckDB destination’ı için gerekli driver’ı kurar. Diğer backend’ler (BigQuery, Snowflake, Postgres) kendi ekstralarıyla gelir.

Open Library Source’unu İncele

Open Library ücretsiz, açık bir kitap metadata API’si. URL:

https://openlibrary.org/search.json?q=harry+potter&page=1

JSON yanıtı iç içe (nested) ve heterojen (her kitap farklı alanlar içerebilir). Bu, gerçek dünya API’lerinin tipik özelliği — temiz CSV gibi gelenler nadirdir.

Elle yazsan: response’u parse et, normalize et, INSERT yaz, pagination hallet, rate limit’e dikkat et, … 200-300 satır kod.

dlt ile: 20 satır.

İlk Pipeline

ingest_open_library.py:

import dlt
from dlt.sources.helpers.rest_client import RESTClient
from dlt.sources.helpers.rest_client.paginators import PageNumberPaginator

# Kaynak: REST API client
client = RESTClient(
    base_url="https://openlibrary.org",
    # İstersen auth, headers, retry buraya eklenir
)

@dlt.resource(
    table_name="books",
    name="harry_potter_books",
    write_disposition="replace",  # her çalıştırmada tabloyu yenile
)
def harry_potter_books():
    """Open Library'den Harry Potter kitaplarını paginate et."""
    for page in client.paginate(
        "/search.json",
        params={"q": "harry potter", "limit": 100},
        paginator=PageNumberPaginator(base_page=1, total_path=None),
    ):
        # API her sayfada {docs: [...], num_found: N} döner
        # dlt otomatik docs içindeki her kaydı bir satır yapar
        yield page.get("docs", [])

# Destination'a yaz
pipeline = dlt.pipeline(
    pipeline_name="open_library",
    destination="duckdb",
    dataset_name="raw_books",
    progress="log",  # ilerleme log'u
)

load_info = pipeline.run(harry_potter_books())
print(load_info)

Çalıştır: python ingest_open_library.py. Çıktıda:

  • Kaç sayfa çekildi
  • Kaç kayıt normalize edildi
  • Hangi tablolar oluştu
  • Yükleme süresi

Schema Inference ve Normalization

dlt’in en güçlü özelliği. Response’u oku, alanları incele, otomatik:

  • Primary table (books) ana alanları içerir.
  • Nested arrays (author_name, isbn, subject) ayrı child tablolara ayrılır, FK ile bağlanır.
  • Type coercion: yıl int, başlık text, liste array veya relation table.
  • Missing fields eksik olarak işaretlenir, hata vermez.

Sonuç: dlt’in kendi öğrendiği bir şema, hem tip güvenli hem sorgulanabilir.

İncelemek için:

dlt pipeline open_library show

Açılan browser’da:

  • Tablolar listesi (sütun sayısı, satır sayısı)
  • Her tablonun şeması (veri tipi dahil)
  • Örnek satırlar
  • Load info: son yüklemenin özeti (hata varsa kırmızı, başarı yeşil)

Bu UI, production’da hata ayıklamanın en hızlı yolu.

Production’a Taşıma: Neden Önemli?

Bir startup hayal et. İlk gün DuckDB’de deniyorsun (tek dosya, sıfır infra). 6 ay sonra milyonlarca kitap, yüzlerce GB — DuckDB yetmiyor. destination=“duckdb” satırını destination=“bigquery” ile değiştir, GCP service account JSON’u env’e koy, bitti. Hiçbir pipeline kodu değişmedi.

Bu portability (taşınabilirlik) dlt’in en güçlü satış noktası. Vendor lock-in’den kaçınırsın.

Incrementals: Aynı Komutu Tekrar Çalıştır

write_disposition="replace" her seferinde siler-yazar. Production’da istemezsin — sadece yeni gelenleri eklemek istersin:

@dlt.resource(
    table_name="books",
    write_disposition="merge",  # upsert: varsa güncelle, yoksa ekle
    primary_key="key",  # Open Library unique ID
)
def harry_potter_books():
    ...

merge mode, Open Library’nin son güncellemelerini yakalar. Incremental loading olarak bilinir — veri miktarı büyüdükçe hayati.

Hands-on

  1. q="harry potter" yerine kendi ilgi alanını koy (örn. q="machine learning").
  2. Çalıştır, kaç kitap geldiğini not al.
  3. dlt pipeline ... show ile tabloları incele.
  4. write_disposition="replace" -> "merge" değiştir, tekrar çalıştır, satır sayısı değişmedi mi kontrol et.

Sıradaki

Ingestion çalışıyor. Ama veri kalitesini nasıl garanti ederiz? →