hadoop lab 1: konfiguracja w laboratoriach MIMUW; word count

Będziemy używać hadoopa uruchomianego na komputerach w wydziałowych laboratoriach. Każdy ze was będzie tworzył swój własny klaster hadoopa; w tym celu prościej jest używać hadoopa w wersji 1.x niż 2.x (2.x umożliwia lepsze zarządzanie wieloma użytkownikami i wieloma zadaniami w ramach jednego klastra). Aplikacje hadoopa używają HDFS, rozproszonego systemu plików. Węzłami HDFS będą te same komputery na których przeprowadzać będziemy obliczenia. HDFS przechowuje dane na lokalnych dyskach twardych (/tmp/), które są okresowo czyszczone.

Programy można też testować na pojedynczej maszynie na której stawiamy wiele procesów hadoopa: http://hadoop.apache.org/docs/r1.2.1/cli_minicluster.html

Do programowania będziemy wykorzystywać "stare" (oryginalne) API (pakiet org.apache.hadoop.mapred); nowe API jest w pakiecie org.apache.hadoop.mapreduce. Różnice między API są w prezentacji: http://www.slideshare.net/sh1mmer/upgrading-to-the-new-map-reduce-api

Pliki:

1 Alternatywy

Hadoop można też uruchamiać lokalnie na pojedynczym komputerze jako oddzielny proces (pseudo-distributed); albo na pojedynczym komputerze w tym samym procesie co testowany programem (stand-alone).

1.1 Uruchamianie programu w jednym procesie razem z hadoopem (w eclipse; stand-alone)

  1. stwórz projekt w eclipse
  2. dodaj do project properties->java build path->libraries wszystkie jary z hadoop/lib i hadoop-core z hadoop
  3. Stwórz klasę MyWordCount i wklej zawartość z naszych materiałów ( http://mimuw.edu.pl/~krzadca/hadoop-programy.tgz ).
  4. Stwórz katalog z danymi wejściowymi 'input' jako podkatalog katalogu głównego projektu; dodaj tam kilka plików tekstowych.
  5. Stwórz nową konfigurację uruchomieniową: project properties -> run/debug settings -> new configuration; ustaw katalog wejściowy (input) i wyjściowy (output) w zakładce program arguments
  6. Przed każdym uruchomieniem usuń katalog wyjściowy (output).

1.2 Uruchamianie hadoopa w oddzielnym procesie (pseudo-distributed)

W tej wersji uruchamiamy hadoopa jako oddzielny proces (serwera) na jednym węźle. Programy obliczeniowe będą komunikowały się z tym serwerem tak, jakby hadoop uruchomiony był

http://hadoop.apache.org/docs/r1.2.1/single_node_setup.html

2 Przygotowania

Upewnij się, że możesz zalogować się przez ssh bez podawania hasła na wybrane komputery (w tym tutorialu: violet02, violet05 i violet06). Zwykle pierwszy raz musisz zalogować się podając hasło. Zaloguj się na pierwszy z komputerów z tej listy.

3 Instalacja klastra w laboratoriach mimuw

Instalacja klastra polega na instalacji i uruchomieniu systemu plików HDFS (składa się z namenode, czyli węzła tłumaczącego nazwy plików na ich lokalizacje; oraz datanodes, czyli węzłów przechowujących dane); oraz na uruchomieniu systemu obliczeń map-reduce (składa się z jobtracker, czyli węzła zlecającego zadania i kontrolującego ich postęp; oraz tasktrackers, czyli węzłów wykonujących zlecone zadania).

W naszej instrukcji procesy namenode i jobtracker będą działać na tym samym komputerze, zwanym poniżej kontrolerem.

Jeśli coś nie działa:

  • problemem może być usiłowanie korzystania przez hadoop z zajętego portu. Zmodyfikuj wartość first_port w skrypcie mimuw-config.py.
  • inny problem to niezgodność ID w systemie plików HDFS (błędy w logach datanodes); w takim przypadku najprościej jest usunąć katalogi /tmp/hadoop-XX123456 ze wszystkich węzłów, a następnie przeformatować system plików.
  • do zabijania hadoopa i czyszczenia danych HDFS z innych hostów możesz użyć skryptu mimuw-cleanup.py.

Instrukcje:

  1. Ściągnij naszą dystrybucję hadoopa: http://mimuw.edu.pl/~krzadca/mimuw-hadoop-1.2.1.tgz

Dystrybucja ma ustawioną zmienną JAVA_HOME w conf/hadoop-env.sh; oraz dodany skrypt ustawiający najważniejsze pliki konfiguracyjne.

  1. Rozpakuj dystrybucję w swoim katalogu domowym; powstanie katalog ~/hadoop.
  2. Przejdź do katalogu ~/hadoop.
  3. Do pliku hosts wpisz nazwy hostów na których postawisz klaster (jedna nazwa w linii); pierwszy host z tej listy będzie kontrolerem (master node) systemu plików i obliczeń. Jako pierwszy host wpisz nazwę komputera przy którym siedzisz.
  4. Uruchom skrypt
$ python mimuw-config.py

Skrypt ten wygeneruje pliki konfiguracyjne hadoopa: conf/slaves (węzły używane do obliczeń) i wpisze koordynatora do conf/core-site.xml, conf/mapred-site.xml i conf/hdfs-site.xml. Uwaga: zapisz adresy które ten skrypt generuje: np: jobtracker: http://violet02:37770 i namenode: http://violet02:37780

  1. Sformatuj system plików HDFS:
$ bin/hadoop namenode -format

Uwaga: jeśli formatujesz drugi raz, hadoop prosi o potwierdzenie; upewnij się, że wciskasz duże 'Y'.

Szukaj informacji o sukcesie formatowania:

14/04/25 15:13:27 INFO common.Storage: Storage directory /tmp/hadoop-krzadca/dfs/name has been successfully formatted.
  1. Uruchom hadoop:
$ bin/start-all.sh

Na konsoli powinny zostać wypisane logi podobne do (zwróć uwagę, że uruchamiane są wszystkie 3 węzły):

starting namenode, logging to /home/staff/iinf/krzadca/hadoop/libexec/../logs/hadoop-krzadca-namenode-violet02.out
Picked up _JAVA_OPTIONS: -Xmx384M
Picked up _JAVA_OPTIONS: -Xmx384M
violet05: starting datanode, logging to /home/staff/iinf/krzadca/hadoop/libexec/../logs/hadoop-krzadca-datanode-violet05.out
violet06: starting datanode, logging to /home/staff/iinf/krzadca/hadoop/libexec/../logs/hadoop-krzadca-datanode-violet06.out
violet02: starting datanode, logging to /home/staff/iinf/krzadca/hadoop/libexec/../logs/hadoop-krzadca-datanode-violet02.out
localhost: starting secondarynamenode, logging to /home/staff/iinf/krzadca/hadoop/libexec/../logs/hadoop-krzadca-secondarynamenode-violet02.out
starting jobtracker, logging to /home/staff/iinf/krzadca/hadoop/libexec/../logs/hadoop-krzadca-jobtracker-violet02.out
Picked up _JAVA_OPTIONS: -Xmx384M
Picked up _JAVA_OPTIONS: -Xmx384M
violet05: starting tasktracker, logging to /home/staff/iinf/krzadca/hadoop/libexec/../logs/hadoop-krzadca-tasktracker-violet05.out
violet02: starting tasktracker, logging to /home/staff/iinf/krzadca/hadoop/libexec/../logs/hadoop-krzadca-tasktracker-violet02.out
violet06: starting tasktracker, logging to /home/staff/iinf/krzadca/hadoop/libexec/../logs/hadoop-krzadca-tasktracker-violet06.out
  1. Sprawdź czy hadoop działa poprawnie. Logi są w katalogu logs; informacje diagnostyczne są dostępne pod adresem namenode zapisanym w poprzednim punkcie (upewnij się, że strona jobtrackera podaje 3 aktywne węzły, live nodes; oraz że strona namenode podaje 3 aktywne węzły).

W następnych krokach będziemy testować poprawność działania systemu używając aplikacji grep z dystrybucji hadoopa.

  1. Przekopiuj dane wejściowe z lokalnego katalogu hadoop/data-txt (gdzie, z okazji Roku Szekspirowskiego, znajdziesz kilka jego sztuk) do katalogu HDFS input-data-txt:
$ bin/hadoop fs -put data-txt input-data-txt
  1. Sprawdź zawartość katalogu HDFS input-data-txt używając: bin/hadoop fs -ls input-data-txt lub interfejsu http namenode (którego adres wyprodukował skrypt pythona) (powinny być te same pliki co w lokalnym katalogu hadoop/data-txt).
$ bin/hadoop fs -ls input-data-txt
Found 6 items
-rw-r--r--   1 krzadca supergroup     125759 2016-05-23 15:26 /user/krzadca/input-data-txt/burza.txt
-rw-r--r--   1 krzadca supergroup      95146 2016-05-23 15:26 /user/krzadca/input-data-txt/komedia-omylek.txt
-rw-r--r--   1 krzadca supergroup     121195 2016-05-23 15:26 /user/krzadca/input-data-txt/makbet.txt
-rw-r--r--   1 krzadca supergroup     150132 2016-05-23 15:26 /user/krzadca/input-data-txt/poskromienie-zlosnicy.txt
-rw-r--r--   1 krzadca supergroup     161943 2016-05-23 15:26 /user/krzadca/input-data-txt/romeo-i-julia.txt
-rw-r--r--   1 krzadca supergroup     117135 2016-05-23 15:26 /user/krzadca/input-data-txt/sen-nocy-letniej.txt
  1. Uruchom grep, aplikacje hadoopa:
$ bin/hadoop jar hadoop-examples-*.jar grep input-data-txt output '\bse\w+'

W czasie gdy aplikacja działa, możesz oglądać jej postęp przez interfejs http (adres: jobtracker)

  1. Obejrzy logi (logs/): w logu jobtracker powinny pojawić się informacje o uruchamianiu tasków na każdym z węzłów (szukaj linii: Adding task (MAP) ... to tip ... for tracker ...)
  2. Obejrzyj rezultat wykonania grep który został zapisany w katalogu output HDFS (lub przez http, adres: namenode).
$ bin/hadoop fs -ls output
Found 3 items
-rw-r--r--   1 krzadca supergroup          0 2016-05-25 15:16 /user/krzadca/output/_SUCCESS
drwxr-xr-x   - krzadca supergroup          0 2016-05-25 15:16 /user/krzadca/output/_logs
-rw-r--r--   1 krzadca supergroup         52 2016-05-25 15:16 /user/krzadca/output/part-00000

Plik z wynikami:

$ bin/hadoop fs -cat output/part-00000
69  serce
68  serca
33  sen
20  sercu
5   sekutnica
...

Pliki można też skopiować z HDFS do systemu plików przez:

bin/hadoop fs -get output output-local
cat output-local/*
  1. Zamknij hadoop
$ bin/stop-all.sh

4 Kontrola zadań

Lista zadań wykonujących się na klastrze:

$ bin/hadoop job -list

Uwaga: ctrl-c nie przerywa wykonania zadania!

Przerywanie zadania

$ bin/hadoop job -kill JobId

5 Proste map-reduce w hadoopie

5.1 Map

public static class MapClass extends MapReduceBase
implements Mapper<LongWritable, Text, Text, IntWritable> {

  private final static IntWritable one = new IntWritable(1);
  private Text word = new Text();

  public void map(LongWritable key, Text value, 
      OutputCollector<Text, IntWritable> output,
      Reporter reporter) throws IOException {
    String line = value.toString();
    StringTokenizer itr = new StringTokenizer(line);
    while (itr.hasMoreTokens()) {
      word.set(itr.nextToken());
      output.collect(word, one);
    }
  }
}

5.2 Reduce

public static class Reduce extends MapReduceBase
implements Reducer<Text, IntWritable, Text, IntWritable> {

  public void reduce(Text key, Iterator<IntWritable> values,
      OutputCollector<Text, IntWritable> output,
      Reporter reporter) throws IOException {
    int sum = 0;    
    while (values.hasNext()) {
      sum += values.next().get();
    }
    output.collect(key, new IntWritable(sum));
  }
}

5.3 Główny program

public static void main(String[] args) throws Exception {
  Configuration conf = new Configuration();

  JobConf job = new JobConf(conf, MyWordCount.class);

  job.setOutputKeyClass(Text.class);
  job.setOutputValueClass(IntWritable.class);
  job.setOutputFormat(TextOutputFormat.class);

  job.setInputFormat(TextInputFormat.class);

  job.setMapperClass(MapClass.class);
  job.setReducerClass(Reduce.class);
  job.setCombinerClass(Reduce.class);

  FileInputFormat.setInputPaths( job, new Path( args[0] ) );
  FileOutputFormat.setOutputPath( job, new Path( args[1] ) );

  job.setJobName( "MyWordCount" );

  // Run the job
  JobClient.runJob(job);

5.4 kompilowanie i uruchamianie

cd programy
ant
cd ..
bin/hadoop jar programy/dist/mimuw-lab1.jar MyWordCount input-data-txt output

6 liczenie znaków (zadanie zaliczeniowe, 0.5 pkt)

Napisz program, który zliczy wystąpienia każdego znaku w plikach wejściowych, tzn. dla wejścia: "ala ma kota" wyjściem powinno być (przy czym kolejność linii na wyjściu nie ma znaczenia):

a 4
l 1
  2
m 1
j 1
k 1
o 1

Zacznij od szablonu z CharacterCount.java.

7 liczenie bigramów (zadanie zaliczeniowe, 0.5 pkt)

Bigram to para słów. We fragmencie "Wesoły jestem, wesoły" Wyspiańskiego (za http://literat.ug.edu.pl/~literat/wyswier/040.htm ):

Wesoły jestem, wesoły
i śmieję się do łez

bigramy to:

(wesoły jestem) (jestem wesoły) (wesoły i) (i śmieję) (śmieję się) (się do) (do łez)

Napisz program, który dla każdego słowa liczy sumę jego wystąpień w tekście oraz wypisuje względne częstości słow występujących po tym słowie. Do wyłuskiwania słów z polskimi znakami możesz użyć wyrażenia regularnego \p{L}+.

Przykład:

(wesoły *) 2
(wesoły jestem) 0.5
(wesoły i) 0.5

(jestem *) 1
(jestem wesoły) 1

(i *) 1
(i śmieję) 1

(śmieję *) 1
(śmieję się) 1

(się *) 1
(się do) 1

(do *) 1
(do łez) 1

8 Materiały dodatkowe

Data: $Date: 2016-05-25 09:59:48 +0200 (Wed, 25 May 2016) $

Autor: Krzysztof Rządca

Created: 2016-05-30 Mon 14:30

Validate