İçeriğe geç
academia.sh

Ders 15 / 18

Eşle-İndirge Modeli

Dağıtık hesaplamanın en yalın soyutlaması üç işlevle kurulup koşturuluyor ve ölçü karışım geçişinde taşınan kayıt sayısı oluyor: sekiz kaynak parçasına yayılmış kurgu kümede bölge ortalaması önce karıştırıp sonra indirgeyen sırada 3.199, önce yerel indirgeyip sonra karıştıran sırada 40 kayıt taşır ve kazanç 79,97 kattır. Kazanç anahtar sayısına bağlıdır ve abone anahtarında 2,53 kata iner. Aynı soru iki anahtarla iki değer verir: doğu ortalaması satır ağırlıklı 24,674 m³, abone ortalamalarının ortalaması olarak 24,814 m³'tür ve iki geçişin taşıdığı kayıt 40'tan 1.305'e çıkar. İndirge işlevi birleşmeli değilse hesap modele girmez: toplam ve en büyük yedi ayrı parça sayısında da değişmez, parça ortancalarının ortancası yedi ayrı değer verir ve açıklığı 0,2175 m³'tür.

İçindekiler

Önceki ders kümenin tek makineye sığmadığı noktayı bir satır sayısı olarak yazdı: seçilen kararla 23.173.893 satır. O noktadan sonra hesap bölünmek zorundadır, ama “bölünmek” tek başına bir tarif değildir. Bölünen şey nedir, parçalar arasında ne gider ve kaç kayıt gider.

Bu ders dağıtık hesaplamanın en yalın soyutlamasını kurar ve koşturur. Soyutlama üç işlevdir: eşle bir satırı bir anahtar ile bir ara değere çevirir, karışım geçişi ara değerleri anahtara göre indirgeyicilere taşır, indirge aynı anahtarın ara değerlerini tek bir değere kapatır. Dersin ölçüsü orta adımdadır: karışım geçişinde kaç kayıt taşınıyor. Yanında duran ikinci sayı, o kaydı taşımadan önce indirgemenin ne kadarının yapıldığıdır.

  • OA7. Küme K03–K05’ten devralınır ve kurgudur: 3.199 satır, 1.329 abone, üç dönem, beş bölge, tarife basamakları 10/25/40 m³. Tohum 20260218 ve çıktı koşumdan koşuma aynıdır. Modeldir.
  • OA8. Hiçbir dağıtık işleme motoru kurulmaz; kaynak sekiz parçaya yayılmış sayılır ve üç işlev standart kitaplıkla yazılır. Modeldir.
  • OA9. Karışım geçişinde taşınan kayıt, indirgeyicilere gönderilen (anahtar, ara değer) çiftlerinin sayısıdır. Ham milisaniye ölçülmez.
  • OA10. Ara değer bir karardır. Ortalama için ara değer tek bir sayı değil, (toplam, sayı) çiftidir; bu seçim indirge işlevini birleşmeli kılar.
  • OA11. Bir hesabın modele girmesi, indirge işlevinin kısmi sonuçlar üzerinde birleşmeli ve değişmeli olmasına bağlıdır. Sınama koşularak yapılır: aynı hesap yedi ayrı parça sayısıyla koşulur ve kaç ayrı sayı çıktığı sayılır.
  • OA12. Parça sınırı satır sayısına göre çekilir; parçalar kaynağın verdiği sıradadır.

Üç İşlev

# esle_indirge.py — bolgesel olcum aginin KURGU kumesi ve uc islev: esle,
# karisim gecisi, indirge. MODELDIR: hicbir dagitik motor kurulmaz; kaynak
# PARCA tane parcaya yayilmis sayilir ve karisim gecisinde tasinan kayit sayilir.
import math

TOHUM, HAM, M32, PARCA = 20260218, 1400, 0xFFFFFFFF, 8
BOLGE = [("kuzey", 0.28, 21), ("guney", 0.22, 17), ("dogu", 0.18, 26),
         ("bati", 0.14, 14), ("merkez", 0.18, 23)]


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


def ayrik(u, w):
    t = 0.0
    for i, x in enumerate(w):
        t += x
        if u < t:
            return i
    return len(w) - 1


def basamak(v):
    return "0-10" if v <= 10 else "10-25" if v <= 25 else "25-40" if v <= 40 else "40 ustu"


KUME = []
for i in range(HAM):
    r = uretec(TOHUM + i)
    b = BOLGE[ayrik(r(), [x[1] for x in BOLGE])]
    hane = 1 + ayrik(r(), [0.06, 0.24, 0.30, 0.24, 0.11, 0.05])
    memnun = 1 + ayrik(r(), [0.08, 0.14, 0.27, 0.34, 0.17])
    if r() < 0.046:                      # kayda girememis sayac
        continue
    no, q = 10001 + i, uretec(TOHUM + 7000 + 10001 + i)
    for d in range(ayrik(q(), [0.05, 0.12, 0.21, 0.62])):
        v = 0.0 if q() < 0.038 else math.floor(
            b[2] * math.exp((q() + q() + q() - 1.5) * 0.62)
            * (1 - d * 0.05) * 100 + 0.5) / 100
        KUME.append((no, b[0], d + 1, hane, memnun, v, basamak(v)))
        q()


def parcala(kume, p):
    n = len(kume)
    return [kume[i * n // p:(i + 1) * n // p] for i in range(p)]


def esle(satir, anahtar):
    return (anahtar(satir), (satir[5], 1))        # ara deger: (toplam, sayi)


def birlestir(a, b):
    return (a[0] + b[0], a[1] + b[1])


def kos(parcalar, anahtar, birlestirici):
    """Esle -> (varsa yerel indirge) -> karisim gecisi -> indirge.
    Donen ikinci sayi karisim gecisinde tasinan kayit sayisidir."""
    tasinan = []
    for p in parcalar:
        ciftler = [esle(s, anahtar) for s in p]
        if birlestirici:
            yerel = {}
            for k, v in ciftler:
                yerel[k] = birlestir(yerel[k], v) if k in yerel else v
            ciftler = sorted(yerel.items(), key=lambda x: str(x[0]))
        tasinan += ciftler
    kova = {}
    for k, v in tasinan:
        kova[k] = birlestir(kova[k], v) if k in kova else v
    return {k: (v[0] / v[1], v[1]) for k, v in kova.items()}, len(tasinan)


P = parcala(KUME, PARCA)
sonuc, tasinan = kos(P, lambda s: s[1], False)
print(f"tohum {TOHUM}; {len(KUME)} satir, {PARCA} kaynak parcasi "
      f"{[len(x) for x in P]}")
print(f"{'bolge':<10}{'satir':>7}{'ortalama m3':>14}")
for b in sorted(sonuc):
    print(f"{b:<10}{sonuc[b][1]:>7}{sonuc[b][0]:>14.3f}")
print(f"dogu - kuzey = {sonuc['dogu'][0] - sonuc['kuzey'][0]:.3f} m3; "
      f"karisim gecisinde tasinan kayit {tasinan}")
tohum 20260218; 3199 satir, 8 kaynak parcasi [399, 400, 400, 400, 400, 400, 400, 400]
bolge       satir   ortalama m3
bati          476        13.778
dogu          557        24.674
guney         645        16.602
kuzey         921        20.210
merkez        600        22.396
dogu - kuzey = 4.463 m3; karisim gecisinde tasinan kayit 3199

Küme sekiz parçaya yayıldı ve hiçbir yerde bütünüyle bir araya gelmedi, ama kursun çıpası değişmedi: doğu ortalaması 24,674 m³, kuzey 20,210 m³, fark 4,463 m³. Model doğru kurulduğunda bölünme cevabı oynatmaz; oynattığı şey cevabı üretmek için taşınan kayıttır.

Bu ilk koşumda taşınan kayıt 3.199, yani kümenin tamamı. Eşle her satır için bir çift üretti ve çiftlerin hepsi indirgeyicilere gitti. İndirge sonra çalıştı ve beş sayı verdi. Beş sayı için 3.199 kayıt taşındı.

Ara değerin ne olduğu bu noktada görünmez bir karardır. Eşle işlevi okumayı tek başına göndermiyor, yanına 1 sayısını koyup (toplam, sayı) çifti gönderiyor. Tek bir sayı gönderilse indirge işlevi ortalamaların ortalamasını almak zorunda kalırdı ve parça boyutları eşit olmadığı anda sonuç kayardı. Çift göndermek taşınan kaydı iki katına çıkarmaz — kayıt sayısı aynıdır, kaydın içi genişler — ama indirge işlevini birleşmeli kılar. Dersin üçüncü bölümü bu özelliğin olmadığı durumu ölçer.

Karışım Geçişinde Taşınan Kayıt

# tasima.py — ayni toplulastirma iki sirada kosulur: once karistirip sonra
# indirgeyen sira ve once yerel indirgeyip sonra karistiran sira. Olcu,
# karisim gecisinde tasinan kayit sayisidir.
ANAHTAR = (("bolge", lambda s: s[1]), ("bolge + donem", lambda s: (s[1], s[2])),
           ("bolge + basamak", lambda s: (s[1], s[6])),
           ("abone_no", lambda s: s[0]))
print(f"{'gruplama anahtari':<18}{'anahtar':>9}{'once karistir':>15}"
      f"{'once indirge':>14}{'kazanc':>9}{'sonuc ayni':>12}")
for ad, f in ANAHTAR:
    a, ta = kos(P, f, False)
    b, tb = kos(P, f, True)
    esit = all(abs(a[k][0] - b[k][0]) < 1e-9 for k in a)
    print(f"{ad:<18}{len(a):>9}{ta:>15}{tb:>14}{ta / tb:>8.2f}x"
          f"{('evet' if esit else 'hayir'):>12}")
print(f"birlestiricinin gonderdigi kayit, parca basina ayri anahtar sayisidir; "
      f"{PARCA} parca ve 5 bolge {PARCA * 5} kayit eder")
gruplama anahtari   anahtar  once karistir  once indirge   kazanc  sonuc ayni
bolge                     5           3199            40   79.97x        evet
bolge + donem            15           3199           120   26.66x        evet
bolge + basamak          18           3199           137   23.35x        evet
abone_no               1260           3199          1265    2.53x        evet
birlestiricinin gonderdigi kayit, parca basina ayri anahtar sayisidir; 8 parca ve 5 bolge 40 kayit eder

Sıra kararı sonucu oynatmıyor, taşımayı oynatıyor. Dört satırın hepsinde son sütun “evet” diyor: önce karıştırıp sonra indirgemekle önce yerel indirgeyip sonra karıştırmak aynı beş sayıyı veriyor. Değişen şey karışım geçişinden geçen kayıttır ve bölge anahtarında 3.199’dan 40’a iniyor — 79,97 kat.

Kırkın nereden geldiği tek satırlık bir çarpımdır: sekiz parça, her parçada beş bölge. Yerel indirgeme bir parçadaki bütün satırları o parçanın anahtar sayısına indirir; taşınan kayıt artık küme boyundan değil, parça sayısı ile parça içindeki ayrı anahtar sayısından gelir. Küme bin kat büyüse de bölge anahtarında taşınan kayıt kırk kalır.

Son satır sınırı çiziyor. Abone anahtarında 1.260 ayrı anahtar var ve satır sayısı 3.199; bir abonenin satırları en çok üç tane. Yerel indirgeme parça başına ortalama iki buçuk satırı bire indiriyor ve kazanç 2,53 kata düşüyor. Birleştiricinin kazancı anahtar sayısının satır sayısına oranından gelir; anahtar sayısı satır sayısına yaklaştıkça birleştirici taşıyacak bir şey bulamaz.

Ortadaki iki satır bu oranın nasıl işlediğini gösteriyor. Bölgeye dönem eklendiğinde anahtar sayısı beşten on beşe çıkıyor ve taşınan kayıt tam olarak sekiz çarpı on beş, yani 120 oluyor: on beş anahtarın hepsi sekiz parçanın hepsinde var. Basamak eklendiğinde anahtar sayısı on sekiz, ama taşınan kayıt 144 değil 137. Aradaki yedi kayıt eksikliği bir kazanç değil bir seyrekliktir: bölge ile basamağın on sekiz bileşiminden ikisi kümenin tamamında yalnız birkaç satır tutuyor ve sekiz parçanın yedisinde hiç görünmüyor. Taşınan kayıt, anahtar sayısının değil parça başına gerçekten görülen anahtar sayısının toplamıdır ve bu sayı ancak koşularak bilinir.

İki Geçiş ve Modele Girmeyen Hesap

# gecis.py — bazi hesap tek karisim gecisine sigmaz, bazisi hic sigmaz.
# Once iki gecisli hesap, sonra indirge islevinin birlesmeli olup olmadigi
# sinanir: ayni hesap yedi ayri parca sayisiyla kosulur.
import statistics

abone, t1 = kos(P, lambda s: s[0], True)                  # 1. gecis: anahtar abone
BOLGESI = {s[0]: s[1] for s in KUME}
ikinci = [(BOLGESI[k], (v[0], 1)) for k, v in abone.items()]
P2 = parcala(ikinci, PARCA)                               # 2. gecis: anahtar bolge
t2 = sum(len({k for k, _ in p}) for p in P2)
ort2 = {}
for p in P2:
    for k, v in p:
        ort2[k] = birlestir(ort2[k], v) if k in ort2 else v
tek, tt = kos(P, lambda s: s[1], True)
print(f"{'bolge':<10}{'tek gecis: satir agirlikli':>28}"
      f"{'iki gecis: abone ortalamasi':>29}{'fark':>8}")
for b in sorted(tek):
    a2 = ort2[b][0] / ort2[b][1]
    print(f"{b:<10}{tek[b][0]:>28.3f}{a2:>29.3f}{a2 - tek[b][0]:>8.3f}")
print(f"tek gecis {tt} kayit tasir; iki gecis {t1} + {t2} = {t1 + t2} kayit tasir")

ortancalar = []
print(f"{'parca':<8}{'toplam m3':>12}{'en buyuk':>10}"
      f"{'parca ortancalarinin ortancasi':>32}")
for p in (2, 3, 4, 5, 8, 16, 32):
    par = parcala(KUME, p)
    o = statistics.median([statistics.median([x[5] for x in y]) for y in par])
    ortancalar.append(o)
    print(f"{p:<8}{sum(sum(x[5] for x in y) for y in par):>12.2f}"
          f"{max(max(x[5] for x in y) for y in par):>10}{o:>32.4f}")
kova = sum(len({x[5] for x in p}) for p in P)
print(f"gercek ortanca {statistics.median([s[5] for s in KUME])} m3; yedi parca "
      f"sayisi {len(set(ortancalar))} ayri deger verir, acikligi "
      f"{max(ortancalar) - min(ortancalar):.4f} m3")
print(f"okumalar iki ondalikli: {len({s[5] for s in KUME})} ayri deger; sayim "
      f"birlestiricisi {kova} kayit tasir, kazanc {len(KUME) / kova:.2f}x")
bolge       tek gecis: satir agirlikli  iki gecis: abone ortalamasi    fark
bati                            13.778                       13.935   0.158
dogu                            24.674                       24.814   0.140
guney                           16.602                       16.728   0.127
kuzey                           20.210                       20.351   0.141
merkez                          22.396                       22.483   0.087
tek gecis 40 kayit tasir; iki gecis 1265 + 40 = 1305 kayit tasir
parca      toplam m3  en buyuk  parca ortancalarinin ortancasi
2           63060.63     52.47                         18.9900
3           63060.63     52.47                         18.9700
4           63060.63     52.47                         18.9250
5           63060.63     52.47                         18.8400
8           63060.63     52.47                         18.9725
16          63060.63     52.47                         18.8900
32          63060.63     52.47                         19.0575
gercek ortanca 18.98 m3; yedi parca sayisi 7 ayri deger verir, acikligi 0.2175 m3
okumalar iki ondalikli: 1788 ayri deger; sayim birlestiricisi 2839 kayit tasir, kazanc 1.13x

İlk tablo bu dersin gizlenen kararıdır. “Bölge ortalaması” tek bir soru gibi durur, oysa iki ayrı hesaptır. Tek geçişte anahtar bölgedir ve her satır eşit ağırlık taşır: doğu 24,674 m³. İki geçişte önce abone anahtarıyla indirgenir, sonra abone sonuçları bölge anahtarıyla indirgenir ve her abone eşit ağırlık taşır: doğu 24,814 m³. Fark 0,140 m³ ve beş bölgenin hepsinde aynı yönde. İkisi de savunulabilir; hangisinin seçildiği yazılmadığında rapordaki sayı bir bulgu değil bir seçimdir.

Bedel de tabloda. Tek geçiş 40 kayıt taşır, iki geçiş 1.265 artı 40, toplam 1.305 kayıt — otuz iki kat. Geçiş sayısı arttıkça taşınan kayıt katlanır, çünkü ara geçişin çıktısı bir sonraki geçişin girdisi olur ve o çıktı anahtar sayısı kadar büyüktür.

İkinci tablo modele girmenin sınırını çiziyor. Toplam ve en büyük yedi ayrı parça sayısında da kılını kıpırdatmıyor: 63.060,63 m³ ve 52,47 m³. İndirge işlevleri kısmi sonuçlar üzerinde birleşmeli ve değişmelidir, dolayısıyla parçalama görünmez kalır. Ortanca ise yedi parça sayısında yedi ayrı değer veriyor; açıklık 0,2175 m³ ve hiçbiri gerçek ortancaya, 18,98 m³’e eşit değil. Parça ortancalarının ortancası bir yaklaşıklık bile değildir; parça sayısına bağlı bir sayıdır.

Son satır çıkış yolunun bedelini veriyor. Ortanca ara değeri ortanca yerine bir sayım olduğunda modele girer, ama bu kümede kurtarmaz: okumalar iki ondalıkla yazıldığı için 1.788 ayrı değer var ve sayım birleştiricisi 2.839 kayıt taşıyor, yani kazanç 1,13 kat. Ondalık sayısı bir gösterim kararıdır ve burada karışım geçişinin boyunu belirliyor: bir ondalıkla yazılan aynı okumalar birleştiriciyi çalışır kılardı.

Özet

  • Üç işlev koştu ve küme sekiz parçaya yayıldığı halde çıpa değişmedi: doğu 24,674 m³, kuzey 20,210 m³, fark 4,463 m³.
  • Sıra kararı sonucu değil taşımayı oynatır: bölge anahtarında önce karıştırmak 3.199, önce yerel indirgemek 40 kayıt taşır ve kazanç 79,97 kattır.
  • Birleştiricinin taşıdığı kayıt parça sayısı ile parça içindeki ayrı anahtar sayısının çarpımıdır; abone anahtarında 1.260 anahtar kazancı 2,53 kata indirir.
  • Aynı soru iki anahtarla iki değer verir: doğu ortalaması satır ağırlıklı 24,674 m³, abone ortalamalarının ortalaması olarak 24,814 m³’tür ve iki geçiş 40 yerine 1.305 kayıt taşır.
  • Bir hesap indirge işlevi birleşmeli değilse modele girmez: toplam ve en büyük yedi parça sayısında da aynı çıkar, parça ortancalarının ortancası yedi ayrı değer verir ve açıklığı 0,2175 m³’tür.
  • Ortanca ara değeri sayıma çevrildiğinde modele girer ama iki ondalıklı okumalarda 1.788 ayrı değer bulunur ve kazanç 1,13 kata düşer.

Sonraki Adım

Bu ders taşınan kaydı saydı ve taşımanın sıraya bağlı olduğunu gösterdi, ama üç işlevi kimin koşturduğunu hiç sormadı. Gerçek bir işte parçalar bir yerde tanımlanır, görevler dağıtılır, başarısız görev yeniden denenir ve sonuçlar toplanır; bunların hiçbiri satır işlemez ve hepsi iş başına eklenir. Sonraki ders küme üzerinde veri çerçevesi işlemenin eşgüdüm kalemini sayar: bir işlem zinciri kaç aşamaya bölünüyor, aşama başına kaç kalem ekleniyor, yeniden deneme bu sayıyı kaça çıkarıyor ve hangi iş boyutunda kalem sayısı işlenen satır sayısını geçiyor.

İlerlemeni kaydetmek ve not almak için Giriş yap

Notlarım

Not almak için giriş yapmalısın.

Aramak için yazmaya başlayın.

↑↓ Esc gezin · aç · kapat