MapReduce - Wordcount

Užitečné odkazy

Výpočetní úloha

V zadaném úkolu bude MapReduce provádět jednoduchou úlohu. Pro vstupní soubory spočíta četnost výskytu slov. V našem případě budou slova tvořena jedním písmenem.

Ukázkový vstupní soubor může vypadat následovně:

1
a b c a a b c

Sada vstupních souborů se bude nacházet v adresáři data. Zdrojové soubory budou mít příponu .txt.

Architektura MapReduce

V rámci simulované sítě vytvořenou knihovnou distsim bude architektura MapReduce vypadat následovně:

  1. jeden master uzel
  2. několik worker uzlů provádějící map nebo reduce

Parametr R

Určuje počet reduce operací. Parametr R hraje důležitou roli v hashovací funkci zmíněné níže.

Uzel master

Uzel master má několik povinností:

Uzel worker

Uzel worker má v sobě uložené dvě funkce map a reduce. Uzel woker má několik povinností:

Speciální soubor

Jak již bylo řečeno, uzel worker výsledky operace map ukládá do speciálního souboru. Jeho název se skládá ze dvou částí. První část získame pomoci hashovací funkce hash(key) mod R, key je aktuálně zpracovávaný znak ze souboru. Druhá část je tvořena unikátním UUID vytvořeném na začátku výpočtu.

1
2
3
4
5
6
7
8
9
10
11
12
13
import hashlib
import uuid

# number of reducers
R = 4

# char, for example 'a'
s = 'a'

prefix = int(hashlib.sha1(s.encode()).hexdigest(), 16) % R
worker_task_id = str(uuid.uuid1())

filename = f'{prefix}_{worker_task_id}'

Zpracování požadavku map v uzlu worker

Jakmile uzel worker obdrží zprávu map otevře si přijaté soubory a provede funkci map. V našem případě to bude uložení hodnot ve formátu znak: četnost do speciálně vytvořeného souboru.

Příklad speciálního souboru, všimněte si, že se opakuje řádek a 1. To znamená, že vstupní soubor poslaný uzlu worker k mapování obsahoval dvě slova a.

1
2
3
4
a 1
b 1
a 1
c 1

Příklad funkce map:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
def map_emit_fun(r, worker_task_id):
    def emit(key, value):
        prefix = int(hashlib.sha1(s.encode()).hexdigest(), 16) % r

        filename = f'{prefix}_{worker_task_id}'
        append_line(filename, f"{key} {value}")

    return emit

def map_count (file, emit):
    content = file_to_string(file)
    words = content.split(" ")

    for word in words:
        emit(word, 1)

Vytvoření reduce požadavků v uzlu master

Jakmile uzel master obdrží výsledky od všech uzlů worker vykonávajícíh map (všechny vstupní soubory byly mapovány). Použije stejnou hashovací funkci pro rozdělení mapovacích souborů mezi R uzlů typu worker.

Pokud je R = 2 rozdělí uzel master speciální sobory s názem hash_uuid dle prefixu a rozdělené soubory (cesty k nim) zašlě uzlům worker.

Zpracování požadavku reduce v uzlu worker

Jakmile uzel worker obdrží zprávu reduce otevře si přijaté soubory a provede funkci reduce. V našem případě se bude jednat o součet četností informace ve tvaru znak: četnost. Díky použití hashovací funkce bude každý worker provádět součet pro určitou podmnožinu znaků.

Ukázkový vstupní speciální soubor do operace reduce:

1
2
3
4
a 1
b 1
a 1
c 1

Vysledek poté uloží do souboru a zašlě informaci uzlu master.

Příklad výsledku po operaci reduce:

1
2
3
a 2
b 1
c 1

Příklad funkce reduce:

1
2
3
4
5
6
7
8
9
def reduce_emit_fun(reduce_id, worker_task_id):
    def emit(key, value):
        filename = f'{reduce_id}_{worker_task_id}'
        append_line(filename, f"{key} {value}")

    return emit

def reduce_count(key, values, emit):
    emit(key, len(values))

Úkol
Implementujte MapReduce na úkol výpočtu word count pro vstupní data dostupná zde. Správný výsledek naleznete zde.