İçeriğe geç
Muslu Yüksektepe

CemirCol

Rust çekirdekli, Python'dan kullanılan sütun tabanlı veri depolama formatı. Parquet'ten hızlı okur, çok daha küçük dosya üretir.

CemirCol, sayısal verileri sütun sütun saklayan ve Python'dan kullanılan bir veri depolama kütüphanesi. Çekirdeğini Rust ile yazdım ve PyO3 aracılığıyla Python'a bağladım. Kütüphaneyi PyPI üzerinden pip install cemircol komutuyla kurmak mümkün. Projeyi Cem Emir Yüksektepe ile birlikte geliştirdim.

Amaç

Veri analizi yaparken çoğu zaman bir tablonun tamamına değil, yalnızca birkaç sütununa ihtiyaç duyarım. CSV ya da JSON gibi satır tabanlı biçimlerde tek bir sütunu okumak için bile dosyanın tamamını baştan sona taramak gerekiyor. Parquet bu sorunu sütun tabanlı yapısıyla çözüyor, ancak ben daha sade bir dosya biçimi ve daha küçük dosyalar elde edip edemeyeceğimi denemek istedim.

CemirCol'u bu yüzden geliştirdim. Hedefim, büyük sayısal tabloları diskte olabildiğince az yer kaplayacak şekilde saklamak ve istenen sütunu gereksiz kopyalama yapmadan, doğrudan numpy dizisi olarak geri vermekti.

Nasıl çalışır

Yazma sırasında kütüphaneye sütun adlarını ve değer listelerini içeren bir sözlük veririm. Her sütun önce ham bayt dizisine çevriliyor, ardından birbirinden bağımsız olarak zstd ile sıkıştırılıyor. Sıkıştırma için zstd'nin en yüksek düzeyi olan 22. düzeyi kullanırım. Sütunlar rayon kütüphanesi sayesinde paralel olarak, yani aynı anda birden fazla işlemci çekirdeğinde sıkıştırılıyor.

Dosya .cemir uzantısıyla kaydediliyor ve yapısı oldukça basit. Dosya CEM1 imzasıyla başlıyor, ardından sıkıştırılmış sütun blokları sırayla geliyor. Bunların arkasında her sütunun dosyadaki konumunu, sıkıştırılmış ve açılmış boyutunu ve veri tipini tutan JSON biçiminde bir üst veri bölümü yer alıyor. Dosyanın sonunda üst verinin uzunluğu ve yine CEM1 imzası bulunuyor.

Okuma tarafında dosya mmap ile açılıyor. mmap, dosyayı belleğe kopyalamadan işletim sisteminin sanal belleği üzerinden doğrudan okumayı sağlayan bir yöntem. Okuyucu önce dosyanın sonundaki imzayı ve üst veriyi okuyor. Bir sütun istendiğinde yalnızca o sütunun sıkıştırılmış dilimine erişiliyor. Bu dilim, Python'un sahip olduğu bir bayt dizisinin içine doğrudan açılıyor ve numpy.frombuffer ile kopyalanmadan numpy dizisine dönüştürülüyor. Böylece arada Rust tarafında ayrı bir geçici tampon oluşmuyor.

numpy kurulu değilse kütüphane sonucu Python'un yerleşik array modülüyle, o da mümkün değilse sıradan bir Python listesiyle döndürüyor.

Öne çıkan özellikler

  • Her sütun ayrı ayrı ve en yüksek düzeyde zstd ile sıkıştırıldığı için dosyalar çok küçük kalıyor.
  • Okuma işlemi mmap ve sıfır kopya yaklaşımıyla yapıldığından bellek kullanımı düşük tutuluyor.
  • Yazma sırasında tüm sütunlar paralel sıkıştırılıyor ve makinedeki işlemci çekirdeklerinin tamamı kullanılıyor.
  • query() metodu sonucu doğrudan numpy dizisi olarak döndürdüğü için veri hemen bilimsel hesaplamaya hazır oluyor.
  • columns() ve num_rows() metotlarıyla dosyadaki sütun adlarını ve satır sayısını veriyi açmadan öğrenmek mümkün.
  • from_csv ve from_parquet yardımcılarıyla mevcut CSV ve Parquet dosyalarını tek satırda .cemir biçimine çevirebilirim.
  • Kütüphanenin eski sürümlerinde zlib ile sıkıştırılmış dosyalar da otomatik olarak tanınıyor ve okunabiliyor.
  • Sütun uzunlukları tutarsızsa ya da desteklenmeyen bir veri tipi verilirse yazma işlemi açık bir hata mesajıyla duruyor.

Teknik altyapı

Çekirdek Rust ile yazıldı ve Python uzantısı PyO3 ile oluşturuldu. Paketleme ve derleme için maturin kullanırım. Belleğe eşleme için memmap2, sıkıştırma için zstd, eski dosyaları okumak için flate2, paralel işleme için rayon, üst verinin JSON olarak yazılıp okunması için de serde ve serde_json kütüphanelerinden yararlanırım.

Sürüm derlemesinde en yüksek optimizasyon düzeyini, bağlantı zamanı optimizasyonunu (LTO, derleyicinin tüm programı tek parça olarak iyileştirmesi) ve tek kod üretim birimini açtım. Şu anda desteklenen veri tipleri 64 bitlik tam sayı (int64) ve 64 bitlik ondalıklı sayı (float64). CSV ve Parquet dönüştürücüleri isteğe bağlı olarak pandas ve pyarrow paketlerine ihtiyaç duyuyor; bunlar cemircol[froms] ek paketiyle kuruluyor. Kütüphane Python 3.8 ve üzeri sürümlerle çalışıyor ve MIT lisansıyla yayınlanıyor.

Depodaki benchmark.py betiğiyle 10 milyon satırlık, biri tam sayı biri ondalıklı iki sütundan oluşan bir veri kümesi üzerinde karşılaştırma yaptım. Bu ölçümde CemirCol dosyası yaklaşık 5,5 MB yer kaplarken aynı verinin Parquet dosyası yaklaşık 85 MB, CSV dosyası ise yaklaşık 183 MB tuttu. Tek bir sütunu okuma süresi CemirCol'da 0,108 saniye, Parquet'te 0,113 saniye oldu. Bu sonuçlar o veri kümesine ve o makineye ait; farklı verilerde oranlar değişebilir.

Kullanım alanları

  • Sensör ölçümleri, finans verileri veya log istatistikleri gibi büyük sayısal tabloların arşivlenmesinde kullanılabilir.
  • Analiz sırasında yalnızca belirli sütunlara ihtiyaç duyulan veri bilimi çalışmalarında okuma süresini ve bellek kullanımını azaltır.
  • Disk alanının sınırlı olduğu ortamlarda Parquet veya CSV dosyalarına göre çok daha az yer kaplayan bir saklama biçimi sunar.
  • Mevcut CSV ve Parquet dosyalarını dönüştürerek eski veri arşivlerini küçültmek için kullanılabilir.

Durum

Kütüphanenin 1.0.1 sürümü PyPI'da yayında. Aynı Rust çekirdeğini Go dilinden kullanmak için ayrıca cemircol-go projesini hazırladım.

Kategori
Veri ve veritabanı
Yıl
2026

Teknolojiler

  • Rust
  • Python
  • PyO3
  • PyPI
  • Open Source

Bağlantılar

  • GitHub https://github.com/muslu/cemircol
  • PyPI https://pypi.org/project/cemircol/

Tüm projelere dön