---
title: 'Veri Çarpıklığı'
source: 'https://academia.sh/tr/kurslar/dagitik-veri-isleme/veri-carpikligi'
course: 'Dağıtık Veri İşleme'
language: tr
updated: '2026-08-17T18:08:51+00:00'
license: 'CC BY-SA 4.0'
---

# Veri Çarpıklığı

Dengesiz bölüşümün ölçülmesi ve işçi eklemenin neden bir çözüm olmadığının sayılması: aynı 2200 satır abone anahtarıyla bölüştürüldüğünde dört işçinin yükü 539 ile 561 arasında kalıyor ve çarpıklık 1,02 çıkıyor, bolge anahtarıyla bölüştürüldüğünde yük 374, 0, 0 ve 1826 oluyor, çarpıklık 3,32'ye çıkıyor ve iki işçi hiç satır almıyor. Yanlış anahtarla işçi sayısı artırıldığında çarpıklık 1,66'dan 3,32'ye, 6,64'e ve 6,88'e çıkıyor, boş işçi sayısı 0'dan 13'e yükseliyor; tek işçide 2250 olan süre iki işçiyle 3691'e çıkıyor ve tabanın altına ancak on altı işçide iniyor, bu arada toplam iş 2200'den 8635'e taşınıyor. Doğru anahtarla ise hiçbir işçi sayısında satır taşınmıyor, toplam iş 2200'de sabit kalıyor ve süre 215'e kadar iniyor. Üç bölüşüm de bölge toplamlarının birebir aynısını üretiyor.

Bir önceki dersin bütün tablolarında bir sayı sessizce duruyordu: olgu tarafının işçi yükü
`[374, 0, 0, 1826]`. Dört işçinin **ikisi hiç satır almamıştı** ve bütün süre hesapları en yüklü
işçinin 1826 satırı üzerinden yapılmıştı. İki ders boyunca yavaşlığın kaynağı **hareket** olarak
arandı; oysa bu düzende işçilerin yarısı hiç çalışmıyordu ve bu, hareketten bağımsız bir
kayıptır.

Bu ders bölüşümün kendisine bakar. Ölçülen şey satırların işçilere ne kadar dengesiz dağıldığı,
bu dengesizliğin nereden geldiği ve dengesiz bir bölüşümde **işçi eklemenin** ne işe yaradığıdır.
Sonuncusu bu kursun ikinci iddiasının en açık örneğidir.

- **DB19.** Kaynak, tüketim satırları ve küme **kurgudur** ve ders içinde üretilir. Hiçbir
  dağıtık işleme çatısı, kaynak yöneticisi ya da dosya sistemi çağrılmaz. Tohum 20260218.
- **DB20.** **Veri çarpıklığı (data skew)** en yüklü işçinin işçi başına düşen ortalamaya
  oranıdır. 1,00 kusursuz dengedir; büyüdükçe bir işçi ötekilerden fazla iş yapıyor demektir.
- **DB21.** Süre **en yüklü işçinin işidir**, dolayısıyla çarpıklık doğrudan süreye yazılır.
  Süre bu modelin **kendi birimidir**. **Toplam iş** ayrı sayılır.
- **DB22.** Bölüşüm anahtarın karmasıyla yapılır ve **aynı anahtar değeri hep aynı işçiye gider**.
  Bunun iki sonucu vardır: bir anahtar değerinin satırları **bölünemez**, ve iki ayrı değer
  **aynı işçiye çakışabilir**.
- **DB23.** İndirgeme bütün tablolarda `abone` anahtarı üzerinden yapılır; değişen tek şey
  satırların **hangi anahtarla bölüştürüldüğüdür**. `abone` bu yüzden doğru, `bolge` yanlış
  bölüşüm anahtarıdır.
- **DB24.** `AG_BEDELI` = 3 ve `GOREV_SABIT` = 50 birer **seçimdir**. Bu dersin çarpıklık sayıları
  ikisinden de bağımsızdır; süre ve toplam iş sayıları değildir.
- **DB25.** Taban çizgisi **tek işçidir**: karıştırma yok, çarpıklık 1,00, süre **2250**, toplam
  iş **2200**.
- **DB26.** Bütün bölüşümler **birebir aynı sonucu** üretir; ölçülen tek şey bedeldir.
- **DB27.** Kümenin çözünürlüğü: satır 2200, işçi en çok 16. Dört işçide çarpıklığın adımı
  0,0018'dir; bu ölçüde okunan farklar bu adımın çok üstündedir.

## Çarpıklık Bölüşümün Ölçüsüdür

Aşağıdaki blok aynı 2200 satırı üç ayrı anahtarla dört işçiye böler, her bölüşümün çarpıklığını
hesaplar ve üçünün ürettiği bölge toplamlarını karşılaştırır.

```python
# KURGUDUR. Olcum aginin sayac okumalari , tuketim satirlari ve kume ders icinde
# uretilir; hicbir dagitik isleme catisi ya da kaynak yoneticisi cagrilmaz. Tohum 20260218.
TOHUM, M32 = 20260218, 0xFFFFFFFF


def uretec(t):
    x = ((t ^ (t >> 16)) * 2246822507) & M32
    x = ((x ^ (x >> 13)) * 3266489909) & M32
    s = [(x ^ (x >> 16)) & M32]

    def sonraki():
        s[0] = (s[0] * 1664525 + 1013904223) & M32
        return s[0] / 4294967296
    return sonraki


BOLGE = ["dogu", "bati", "kuzey", "guney", "merkez"]
TIP = ["mesken", "isyeri"]
DONEM = [f"2026-{a:02d}" for a in range(1, 13)]
ISCI, AG_BEDELI, GOREV_SABIT = 4, 3, 50
ABONE = {}
for i in range(200):
    r = uretec(TOHUM + 37 * i)
    ABONE[f"A{i + 1:03d}"] = {"bolge": BOLGE[int(r() * 5)], "tip": TIP[int(r() * 2)],
                              "baslangic": 10000 + int(r() * 60000)}


def satirlar():
    """Hattan cikan tuketim satirlari. Saglam kaynakta ayikla ve tekille asamalari
    satir dusurmez; tuketim onceki donemin endeksinden cikarilarak bulunur."""
    ham = []
    for i, (ab, a) in enumerate(ABONE.items()):
        e = a["baslangic"]
        for d in DONEM:
            r = uretec(TOHUM + 101 * i + 7 * DONEM.index(d))
            e += 4 + int(r() * 46)
            ham.append({"abone": ab, "donem": d, "bolge": a["bolge"], "tip": a["tip"],
                        "endeks": e, "birim": "m3"})
    tablo, cikti = {(k["abone"], k["donem"]): k for k in ham}, []
    for k in ham:
        i = DONEM.index(k["donem"])
        onceki = tablo.get((k["abone"], DONEM[i - 1])) if i else None
        if onceki is not None:
            cikti.append(dict(k, m3=k["endeks"] - onceki["endeks"]))
    return cikti


def izno(m):
    h = 2166136261
    for c in str(m):
        h = ((h ^ ord(c)) * 16777619) & 0xFFFFFFFF
    return h


def dagit(kayitlar, anahtar, isci=ISCI):
    """Satirlari anahtara gore isciye atar. Ayni anahtar hep ayni isciye gider."""
    kova = {i: [] for i in range(isci)}
    for k in kayitlar:
        kova[izno(k[anahtar]) % isci].append(k)
    return kova


def yuk(kova):
    """Carpiklik: en yuklu iscinin ortalamaya orani."""
    n = [len(v) for v in kova.values()]
    return {"toplam": sum(n), "en_yuklu": max(n), "en_az": min(n),
            "carpiklik": round(max(n) / (sum(n) / len(n)), 4)}


def karistir(kova, yeni_anahtar, isci=ISCI):
    """Yeniden bolustur. Isci degistiren satir agdan gecer."""
    yeni, tasinan = {i: [] for i in range(isci)}, 0
    for eski, kayitlar in kova.items():
        for k in kayitlar:
            hedef = izno(k[yeni_anahtar]) % isci
            if hedef != eski:
                tasinan += 1
            yeni[hedef].append(k)
    return yeni, tasinan


def maliyet(kova, tasinan=0, isci=ISCI):
    """Sure = en yuklu iscinin isi (paralel). Toplam is ayrica sayilir."""
    n = [len(v) for v in kova.values()]
    return {"sure": max(n) + tasinan * AG_BEDELI // isci + GOREV_SABIT,
            "toplam_is": sum(n) + tasinan * AG_BEDELI,
            "tasinan": tasinan}


def bolge_toplam(kova):
    """Her isci once kendi payinin bolge toplamini cikarir , sonra birlestirilir."""
    son = {}
    for kayitlar in kova.values():
        ara = {}
        for k in kayitlar:
            ara[k["bolge"]] = ara.get(k["bolge"], 0) + k["m3"]
        for b, v in ara.items():
            son[b] = son.get(b, 0) + v
    return tuple(sorted(son.items()))


TUM = satirlar()
print(f"hattan cikan satir {len(TUM)} , isci {ISCI} , ag bedeli {AG_BEDELI}")
print("bolge basina satir: "
      + " , ".join(f"{b} {sum(1 for k in TUM if k['bolge'] == b)}" for b in BOLGE))
print("bolge hangi isciye dusuyor: " + " , ".join(f"{b} {izno(b) % ISCI}" for b in BOLGE))
print("\nanahtar  farkli deger   isci yuku                en yuklu  en az  carpiklik")
for a in ("abone", "bolge", "donem"):
    k, y = dagit(TUM, a), yuk(dagit(TUM, a))
    print(f"{a:<8} {len(set(x[a] for x in TUM)):>12}   {str([len(v) for v in k.values()]):<24}"
          f"{y['en_yuklu']:>6} {y['en_az']:>6} {y['carpiklik']:>10}")
SONUC = {a: bolge_toplam(dagit(TUM, a)) for a in ("abone", "bolge", "donem")}
print(f"\nuc bolusumun urettigi sonuc tek mi: {len(set(SONUC.values())) == 1}")
print("bolge toplami: " + " , ".join(f"{b} {v}" for b, v in SONUC["abone"]))
```

```
hattan cikan satir 2200 , isci 4 , ag bedeli 3
bolge basina satir: dogu 374 , bati 341 , kuzey 506 , guney 440 , merkez 539
bolge hangi isciye dusuyor: dogu 0 , bati 3 , kuzey 3 , guney 3 , merkez 3

anahtar  farkli deger   isci yuku                en yuklu  en az  carpiklik
abone             200   [539, 550, 561, 550]       561    539       1.02
bolge               5   [374, 0, 0, 1826]         1826      0       3.32
donem              11   [600, 600, 400, 600]       600    400     1.0909

uc bolusumun urettigi sonuc tek mi: True
bolge toplami: bati 9164 , dogu 9695 , guney 11721 , kuzey 13338 , merkez 14536
```

Son iki satır bütün dersin ön koşuludur. Üç bölüşüm de **birebir aynı** bölge toplamlarını
üretir; hangi anahtarla bölüşüldüğünden bağımsız olarak her satır hesaba tam bir kez girer. Bu
kursun üçüncü iddiasıdır ve buradaki biçimi en sert olanıdır: **sonucu denetleyen hiçbir sınama
`bolge` bölüşümündeki dengesizliği göremez.** Çarpıklık bir doğruluk sorunu değil, yalnızca
sayıldığında görünen bir bedeldir.

İlk tablo çarpıklığın nereden geldiğini gösterir. `abone` anahtarında 200 farklı değer vardır,
dört işçiye 539 ile 561 arasında dağılırlar ve çarpıklık **1,02**'dir. `donem` anahtarında 11
farklı değer vardır — hattın ilk dönemi tüketim hesaplanamadığı için düşmüştür — ve 11 değer dört
işçiye 3, 3, 2, 3 olarak bölündüğü için yük 600, 600, 400, 600 ve çarpıklık **1,0909** olur.
`bolge` anahtarında ise yalnız **5** farklı değer vardır ve çarpıklık **3,32**'ye çıkar.

Üçüncü satırın nedeni ikinci satırda yazılıdır. Beş bölgenin **dördü de üçüncü işçiye düşer**:
341 artı 506 artı 440 artı 539 tam olarak 1826 eder. Geriye kalan tek bölge `dogu`, tek başına
sıfırıncı işçidedir ve iki işçi hiç satır almaz. Burada iki ayrı mekanizma üst üste biner.
Birincisi **anahtarın azlığıdır**: beş farklı değer en çok beş işçiyi doldurabilir. İkincisi
**karma çakışmasıdır**: beş değerden dördü aynı kovaya düşmüştür.

Bunun ayırt edilmesi gereken bir sonucu var. Bölgeler kendi içlerinde çok dengesiz değildir; en
küçüğü 341, en büyüğü 539 satır taşır ve aralarındaki oran ikinin altındadır. Yani veri, kendi
başına, çarpık değildir. Çarpıklığı üreten şey **anahtar ile işçi sayısının birlikte
davranışıdır**. "Veri çarpıktı" cümlesi bu yüzden eksiktir; çarpıklık verinin bir özelliği değil,
**bölüşümün** bir özelliğidir ve bölüşüm bir karardır.

## İşçi Eklemek Bir Çözüm Değildir

Dengesiz bir bölüşümde akla gelen ilk düzeltme daha çok işçidir. Aşağıdaki blok aynı süpürmeyi
iki anahtarla yapar: yanlış olanla (`bolge`) ve doğru olanla (`abone`). İndirgeme her ikisinde de
`abone` üzerindendir.

```python
# Bu blok ilk bloktaki satirlar() , izno() , dagit() , yuk() , karistir() ,
# maliyet() ve TUM tanimlarini surdurur. Indirgeme her iki tabloda da abone
# anahtari uzerinden yapiliyor; degisen tek sey bolusum anahtari.
def supur(bolusum):
    print(f"bolusum anahtari {bolusum} , indirgeme abone")
    print("isci  carpiklik  en yuklu  bos isci  tasinan   sure  toplam is")
    for isci in (1, 2, 4, 8, 16):
        k = dagit(TUM, bolusum, isci)
        _, t = karistir(k, "abone", isci)
        m, y = maliyet(k, t, isci), yuk(k)
        print(f"{isci:>4} {y['carpiklik']:>10} {y['en_yuklu']:>9}"
              f" {sum(1 for v in k.values() if not v):>9}"
              f" {t:>8} {m['sure']:>6} {m['toplam_is']:>10}")


supur("bolge")
print()
supur("abone")
```

```
bolusum anahtari bolge , indirgeme abone
isci  carpiklik  en yuklu  bos isci  tasinan   sure  toplam is
   1        1.0      2200         0        0   2250       2200
   2       1.66      1826         0     1210   3691       5830
   4       3.32      1826         2     1738   3179       7414
   8       6.64      1826         6     1958   2610       8074
  16       6.88       946        13     2145   1398       8635

bolusum anahtari abone , indirgeme abone
isci  carpiklik  en yuklu  bos isci  tasinan   sure  toplam is
   1        1.0      2200         0        0   2250       2200
   2        1.0      1100         0        0   1150       2200
   4       1.02       561         0        0    611       2200
   8       1.04       286         0        0    336       2200
  16        1.2       165         0        0    215       2200
```

İlk tablonun ikinci satırı bu kursun **ikinci iddiasıdır**: tek işçide süre **2250** iken, ikinci
işçi eklendiğinde **3691**'e **çıkar**. İşçi eklemek işi kötüleştirmiştir. Nedeni okunabilir:
tek işçide karıştırma yoktur, çünkü bütün satırlar zaten aynı yerdedir. İkinci işçi ortaya
çıktığı anda indirgeme anahtarı bölüşüm anahtarından ayrışır, 1210 satır ağdan geçer ve toplam iş
2200'den **5830**'a sıçrar. Paralellik bedava değildir ve bu düzende **ilk adımı negatiftir**.

Süre ancak dörtten sonra inmeye başlar, ama tek işçilik tabanın altına ancak **on altı işçide**
iner (1398). Dört işçide 3179, sekiz işçide 2610 — her ikisi de 2250'nin üstündedir. Yani
`bolge` anahtarıyla bölüştürülmüş bir iş, sekiz işçilik bir kümede tek bir işçiden **hâlâ
yavaştır**. Bu tablo yazılmadan "kümeyi büyüttük, hızlandı" cümlesinin doğru olup olmadığı
bilinemez.

En yüklü işçi sütunu bunun mekanizmasını verir ve tablonun en çarpıcı sayısı odur: iki, dört ve
sekiz işçide en yüklü işçinin yükü **1826'da sabittir**. İşçi sayısı dört katına çıkarken o işçi
tek bir satır bile devretmez, çünkü ona düşen dört bölge her üç bölüşümde de aynı kovada kalır.
Süredeki iniş (3691, 3179, 2610) yükün azalmasından değil, yalnızca taşıma payının daha çok
işçiye bölünmesinden gelir. Yük ilk kez on altı işçide kırılır ve **946**'ya iner.

Çarpıklık sütunu işçi eklendikçe **kötüleşir**: 1,66, 3,32, 6,64, 6,88. Boş işçi sayısı 0'dan
2'ye, 6'ya ve **13**'e çıkar. On altı işçilik kümede yalnız üç işçi satır almaktadır. Bunun
sınırı anahtarın kendisinde yazılıdır: `bolge` beş farklı değer taşır, dolayısıyla kaç işçi
eklenirse eklensin en çok **beş** işçi satır alabilir. Bir anahtar değerinin satırları
bölünemediği için en yüklü işçi de en büyük bölgenin altına, yani **539** satırın altına inemez.
Süre bu yüzden kaç işçi eklenirse eklensin görev sabitiyle birlikte **589**'un altına inemez.
İkinci tablonun on altıncı satırı bunu bir karşılaştırmaya çevirir: `abone` anahtarıyla süre
zaten **215**'tir ve o eşiğin çok altındadır. **Bölüşüm anahtarı yanlışsa işçi sayısı bir çözüm
değildir**, çünkü yanlış anahtar kümeye bir tavan koyar.

Çarpıklığın artarken sürenin azalması ilk bakışta çelişkili görünür ve ayrı ayrı okunması
gerekir. Çarpıklık bir **orandır**: işçi sayısı arttıkça ortalama küçülür, en yüklü işçinin yükü
ise aynı hızda küçülmez, dolayısıyla oran büyür. Süre bir **mutlak sayıdır** ve taşıma payı
işçilere dağıldığı için düşer. İkisi aynı şeyi söylemez: süre **işin ne zaman
bittiğini**, çarpıklık **kaç işçinin boşa ayrıldığını** ölçer. On altı işçide 1398 süre, on üç
işçinin boş beklemesi ve **8635** birimlik toplam iş karşılığında alınmıştır.

İki tablo yan yana konduğunda kursun kuralı görünür. `bolge` tablosunda süre 3691'den 1398'e
inerken toplam iş 5830'dan **8635**'e çıkar; iki ölçü ters yönlere gider ve "dört kat hızlandı"
gibi bir cümle hangisinin ölçüldüğü yazılmadan **eksiktir**. `abone` tablosunda ise toplam iş
beş satırda da **2200**'de durur, çünkü taşınan satır her işçi sayısında sıfırdır. Doğru
anahtarın kazandırdığı şey yalnız süre değildir: kümeye eklenen her işçinin **karşılığında bir
şey ürettiği** tek düzen budur.

## Özet

- Veri çarpıklığı en yüklü işçinin ortalamaya oranıdır: `abone` bölüşümünde **1,02**, `donem`
  bölüşümünde **1,0909**, `bolge` bölüşümünde **3,32**. Son düzende dört işçinin **ikisi boştur**
  ve yük `[374, 0, 0, 1826]`'dır.
- Çarpıklık verinin değil bölüşümün özelliğidir. Bölgeler 341 ile 539 satır arasındadır, yani
  veri kendi başına dengelidir; çarpıklığı üreten şey anahtarın yalnız **5** farklı değer taşıması
  ve bu beş değerden **dördünün aynı işçiye çakışmasıdır** (341 + 506 + 440 + 539 = 1826).
- İşçi eklemek işi kötüleştirebilir: tek işçide süre **2250**, iki işçide **3691**'dir, çünkü
  ikinci işçiyle birlikte 1210 satır ağdan geçer ve toplam iş 2200'den 5830'a çıkar. Süre tek
  işçilik tabanın altına ancak on altı işçide iner.
- Yanlış anahtarla işçi eklendikçe çarpıklık 1,66'dan **6,88**'e, boş işçi 0'dan **13**'e çıkar.
  Beş farklı değerli bir anahtar en çok beş işçi doldurabilir ve en büyük bölge 539 satır olduğu
  için süre **589**'un altına hiçbir işçi sayısında inemez; `abone` anahtarıyla süre on altı
  işçide zaten **215**'tir.
- Üç bölüşüm de bölge toplamlarının birebir aynısını üretir. Doğruluğu denetleyen hiçbir sınama
  bu farkı göstermez; `bolge` tablosunda süre 3691'den 1398'e inerken toplam iş 5830'dan
  **8635**'e çıkar, `abone` tablosunda toplam iş beş satırda da 2200'de durur.

## Sonraki Adım

Üç derste yavaşlığın kaynağı iki başlıkta toplandı: satırların **hareketi** ve işçilerin
**dengesizliği**. Her iki ölçüde de tek bir hesabın tek bir kez yapıldığı varsayıldı; aynı ara
sonuca iki ayrı sorunun ihtiyaç duyması ya da bir işçinin iş bitmeden düşmesi hiç konuşulmadı.
Oysa dağıtık bir işte aynı hesabın iki kez yapılması sık rastlanan bir kalemdir ve bir işçinin
düşmesi, o ana kadar yapılmış işin ne kadarının geri isteneceği sorusunu doğurur. Sonraki ders
ara sonucun saklanmasını ölçer: aynı veriyi iki kez hesaplamakla bir kez hesaplayıp tutmak
arasındaki farkı sayar ve tutmanın kendi bedelini yazar.
