Delta Lake bez JVM i PySpark w projektach Rust i Python
Każdy, kto próbował wdrożyć format Delta Lake w małych usługach lub skryptach, szybko napotyka na surową rzeczywistość. Aby po prostu odczytać kilka gigabajtów plików dziennika transakcji, trzeba zabrać ze sobą Apache Spark, a wraz z nim ciężką infrastrukturę JVM. Na dużych platformach danych jest to uzasadnione, ale dla lokalnej aplikacji, mikrousługi działającej w tle lub bezserwerowej funkcji AWS Lambda, takie rozwiązanie wydaje się zbyt uciążliwe.
Twórcy ze społeczności Delta Lake postanowili zamknąć tę lukę. Stworzyli projekt delta-rs — natywną bibliotekę do pracy z Delta Lake w Rust, wraz z oficjalnymi powiązaniami dla Pythona.
Dlaczego kolejna biblioteka do danych
Format Delta Lake jest świetny, ponieważ rozwiązuje główne problemy otwartego przechowywania plików. Dodaje dziennik transakcji ACID na szczycie plików Parquet, historię zmian z możliwością cofnięcia się do poprzednich wersji (podróż w czasie) oraz ścisłe wymuszanie schematu.
Klasyczny stos wokół Delta Lake był historycznie powiązany ze Scalą i Javą. Jeśli Twój główny stos to Rust lub lekki Python bez ciężkich frameworków takich jak PySpark, przed pojawieniem się delta-rs opcje były ograniczone.
Biblioteka zapewnia niskopoziomowe API dla Rust i wysokopoziomowy interfejs dla Pythona. Teraz możesz pisać dane z gwarancjami ACID do koszyka S3 lub lokalnego dysku w zaledwie kilku liniach kodu bez uruchamiania procesów JVM.
Szybki start w Python i Rust
Interfejs pakietu Pythona deltalake został zaprojektowany tak, aby deweloperzy nie musieli uczyć się wszystkiego od nowa. Łatwo integruje się z znanymi bibliotekami analitycznymi — Pandas, Arrow lub Polars.
Pisanie i odczytywanie tabeli w Pythonie wygląda bardzo znajomo:
import pandas as pd
from deltalake import DeltaTable, write_deltalake
# Создаем тестовый датафрейм и сохраняем его в формате Delta
df = pd.DataFrame({"id": [1, 2], "value": ["foo", "boo"]})
write_deltalake("./data/delta", df)
# Считываем данные обратно
dt = DeltaTable("./data/delta")
df_read = dt.to_pandas()
assert df.equals(df_read)
Interesujący szczegół: możesz natychmiast otworzyć tę samą tabelę z aplikacji Rust. Nie jest wymagane ręczne składanie metadanych. Biblioteka automatycznie przeanalizuje dziennik commitów JSON w katalogu _delta_log.
Przykład odczytu metadanych tabeli w Rust:
use deltalake::{open_table, DeltaTableError};
use url::Url;
#[tokio::main]
async fn main() -> Result<(), DeltaTableError> {
let delta_path = Url::from_directory_path("/abs/data/delta").unwrap();
let table = open_table(delta_path).await?;
let files: Vec<_> = table.get_file_uris()?.collect();
println!("{files:?}");
Ok(())
}
Pod maską i integracje
Wysoka prędkość i niskie zużycie pamięci nie są przypadkowe. Projekt jest zbudowany na silniku Apache Arrow i wektorowym silniku DataFusion. Rust jest używany do bezpiecznego zarządzania pamięcią i równoległego I/O podczas pracy z magazynem w chmurze.
Biblioteka może pracować bezpośrednio z AWS S3, Google Cloud Storage, Azure Blob Storage i lokalnym systemem plików.
Dzięki wspólnemu fundamentowi na Rust i Arrow, delta-rs szybko stało się częścią nowoczesnego ekosystemu przetwarzania danych. Popularne narzędzia współpracują z nim out of the box:
- Polars wykorzystuje delta-rs do bezpośredniego odczytu i zapisu tabel Delta.
- DuckDB może wykonywać analityczne zapytania SQL względem dzienników Delta.
- Da, Dask i Ray używają tego modułu do rozproszonego przetwarzania danych w Pythonie.
- AWS SDK for Pandas wykorzystuje go jako natywny silnik dla formatu Delta.
Praktyczne przypadki użycia
W jakich sytuacjach delta-rs wygrywa z klasycznym podejściem?
Pierwszy przypadek to architektura mikrousług. Na przykład masz usługę w Rust lub Pythonie, która zbiera zdarzenia z kolejki wiadomości i musi dołączać partie do magazynu danych co pięć minut. Uruchomienie klastra Spark jest kosztowne i złożone w utrzymaniu. Z delta-rs usługa po prostu łączy bibliotekę i zapisuje dane bezpośrednio do S3.
Drugi przypadek to lekkie potoki ETL. Jeśli objętości danych mierzone są w dziesiątkach lub setkach gigabajtów, Polars w połączeniu z delta-rs przetworzy je na jednej instancji szybciej niż klaster PySpark zostanie zainicjowany.
Trzeci przypadek to architektura bezserwerowa. W funkcjach AWS Lambda z surowymi limitami rozmiaru obrazu i czasu uruchomienia, dopasowanie środowiska Java jest problematyczne. Skompilowany plik binarny Rust z delta-rs uruchamia się w milisekundach.
Czy projekt ma ograniczenia? Tak, specyfikacja Delta Lake jest dość rozbudowana i jest stale aktualizowana przez Databricks. Niektóre rzadkie lub nowe funkcje formatu są implementowane w delta-rs z lekkim opóźnieniem. Przed użyciem złożonych operacji jak MERGE z określonymi warunkami, powinieneś sprawdzić tabelę obsługiwanych funkcji w dokumentacji projektu.
Podsumowanie
Zespół delta-io wykonał doskonałą pracę. Natywna biblioteka Rust przywróciła lekkość pracy z formatem Delta Lake.
Jeśli potrzebujesz transakcyjności, wersjonowania danych i niezawodnego przechowywania na szczycie Parquet, ale nie chcesz zajmować się infrastrukturą Java, zdecydowanie wypróbuj delta-rs. Możesz zainstalować pakiet w Pythonie za pomocą polecenia pip install deltalake, a dodać go do projektu Rust przez cargo add deltalake.
Powiązane projekty