lxcficon.jpg Hadoop でのデータマイニング例

元のページに戻る

Hadoop でのデータマイニング例

LXCFでHadoopが使えるようになりました。 人として、良く切れる太刀が手に入れば試し斬りがしたくなります。 鉄砲が手に入れば撃ってみたくなるものです。
そこでHadoopを使って、実際にBig Dataの処理の実例を示しましょう。
今回はFedora 20を使います。

1. Big Data処理の対象

- 文量のある日本語文書を対象とする → 青空文庫の小説を対象にする
- 日本語の形態素解析を行う → MeCabを使う
- Javaではなく、一般的なシェルスクリプトやAWKスクリプトでプログラムする → streaming処理を使う
- 日本語の名詞を抜き出して、ワードカウントを行う

2. 日本語文書

分量のある日本語文書として、小説を一冊対象としましょう。
青空文庫ではありがたいことに、著作権切れの小説を多数公開しています。 この中で有名な夏目漱石の「坊ちゃん」を例題の対象としたいと思います。

青空文庫: 坊っちゃん (新字新仮名、作品ID:752) 
http://www.aozora.gr.jp/cards/000148/card752.html

3. 日本語の形態素解析

日本語は英語と違って、単語が分かち書きされているわけではないので文章の解析をするのが難しいです。
そこで、日本語の文章を名詞や動詞といった品詞に分解してくれる形態素解析を行ってくれるソフトを使います。
いろいろとあるのですが今回はFedora20にもパッケージが含まれるMeCab ( https://code.google.com/p/mecab/ )をインストールして使います。

1) インストール

MeCab本体と、形態素解析に必要な辞書をインストールします。
HOSTにだけインストールするだけでなく、すでにHadoop用にコンテナを作ってある場合にはそれらにもすべてインストールしなければなりません。 そのような場合には、LXCFのupdateコマンドを使います。

# lxcf update yum install -y mecab mecab-ipadic mecab-jumandic

このインストールにはかなり時間(数十分)がかかるかもしれません。 気長にまってください。すべてのコンテナとHOSTの両方にMeCabと辞書がインストールされます。

2) 形態素解析のテスト

MeCabに日本語文を入力してみましょう。

$ echo "これはペンです"  |  mecab
これ	指示詞,名詞形態指示詞,*,*,これ,これ,*
は	助詞,副助詞,*,*,は,は,*
ペン	名詞,普通名詞,*,*,ペン,ぺん,代表表記:ペン
です	判定詞,*,判定詞,デス列基本形,だ,です,*
EOS


日本語の文がいい感じに分解されました。
ビッグデータ処理で大量の日本語の文の中で名詞だけ取り出せば、それらの文章の中で何に興味があるのか知ることができるかもしれません。

4. MapReduce処理

Hadoopの大きな特徴であるMapReduce処理を使います。 もともとのHadoopは、ビッグデータの大量データをMapReduce処理を使い複数の並列サーバで分担してデータ処理することでスケールアウトするシステムでした。 最近のHadoopはMapReduce処理以外にも手を伸ばしているようです。 しかし、やはり大規模なMapReduce処理を簡単に実現できるのがHadoopのもっとも魅力的なところであると私は思います。

mapreduce.jpg

なお、ここでは、説明しきれないのでMapReduce処理自体の説明は行いません。 Web上または書籍上で多くのMapReduce処理の情報がありますのでそれらを参考にしてください。

Hadoopの場合、MapReduce処理を実現するためには、JAVAでプログラムするのが本来は正当派です。
しかし、それでは小回りが効きにくく、また自分の慣れたプログラム言語が使えません。 Python, Ruby, Awk, デカルト言語、Perl, Scala, クロージャ言語など自分の使い慣れたプログラム言語でMapReduce処理を行うためには、HadoopではStreaming処理で実行できるようになります。
今回は日本語処理のためにMeCabを使いますので、BashとAwk言語を使うことにします。

5. Hadoop Streaming 処理

Hadoop Streaming処理のためのjarファイルは以下にあります。

   /usr/share/java/hadoop/hadoop-streaming.jar

Hadoopコマンドの引数にして使うことによって、標準入出力を経由してMapReduce処理を行うことができるようになります。

hadoop jar \  
        /usr/share/java/hadoop/hadoop-streaming.jar \
        -input 入力データ -output 出力データ \
        -file map処理プログラム  \
        -mapper map処理プログラム  \
        -file reduce処理プログラム \
        -reducer reduce処理ファイル

-file 引数は、map処理プログラムやreduce処理プログラムを、並列演算するDataNodeに送って実行させます。

6. map処理プログラム

streamingのmapプログラムは、標準入力(stdin)からデータを受け取り、それを処理して、標準出力(stdout)に(Key value)の組を出力しなければなりません。
標準入力からのデータはHadoopによって各DataNodeのコンテナに分散して配布されます。DataNodeは受けとったデータを分担して処理します。

map_prog.jpg

では、実際のプログラムを見てみましょう。

  1. #!/bin/sh
  2. mecab | awk '{if ($2 ~ /名詞/) printf "%s 1\n", $1}'

このプログラムを"map_step-j.sh"という名前で保存して実行権を付けておきます。
簡単ですね。1行だけです。
こんなに簡単に実現できるのは、MeCabが日本語の単語の切り出しを行ってくれることが大きな理由です。
このプログラムには、Hadoopから入力データが標準入力から入ります。
それを、まずmecabプログラムで品詞に分解します。
次にその結果から、第2引数に"名詞"が含まれている場合、"名詞のワード 1"を標準出力に出します。
この出力がmapプログラムからの(key, value)の値となります。

7. reduce処理プログラム

次はreduce処理プログラムです。

streamingのreduceプログラムは、mapプログラムと同様に標準入力(stdin)からデータを受け取り、それを処理して、標準出力(stdout)に(Key value)の組を出力しなければなりません。
reduceプログラムに入力されるデータは、Hadoopによって、Keyでソートされたデータが順に入力されます。

reduceprog.jpg

では、実際のプログラムを見てみましょう。
今回はawkでプログラムしました。
1行目の"#!/usr/bin/awk -f"がそれを示します。
このプログラムを"reduce_step.awk"という名前で保存して実行権を付けておきます。

#!/usr/bin/awk -f

BEGIN {
        word=""
        count=0
}

{
        if (word == $1) {
                count += $2
        } else {
                if (count > 0) {
                        printf "%s %d\n", word, count
                }
                word = $1
                count = $2
        }
}

END {
        printf "%s %d\n", word, count
}       


このプログラムは、map処理で出力されSortされたKeyのワードを数えて(key, ワードカウント数)の組にして出力します。
簡単にプログラム内容について説明します。
awk言語では、BEGINの処理を実行してから、入力データを処理し、入力データがなくなるとENDの処理を実行します。
まず、BEGIN処理では、変数wordとcountを初期化します。
次の処理では、一つ前のデータと入力されたKeyが一致すれば、加算して合計します。一致しなければ、Keyのカウント数を"word count"として出力します。 HadoopのSort処理によって同じKeyは連続して入力されてくるのでこのような簡単な処理でワードカウント数をまとめて合計することができます。
最後にデータが尽きたら、最後に残ったデータをENDの処理で出力します。

8. Hadoopでの実行

map処理とreduce処理のプログラムがそろいました。実際にHadoopで実行してみましょう。
手で1行ずつ実行していくのは面倒なので次のようなshスクリプトを作りました。
Data_mining-j.shという名前で保存して実行権を付けてください。

  1. #!/bin/sh
  2. if [ $# -lt 1 ]; then
  3. echo "usage: Data_mining-j.sh input_text"
  4. exit 1
  5. fi
  6. rm -rf out
  7. mkdir -p in
  8. cp $1 in/.
  9. hdfs dfs -rm -r out
  10. hdfs dfs -rm -r in
  11. hdfs dfs -copyFromLocal in in
  12. hadoop jar \
  13. /usr/share/java/hadoop/hadoop-streaming.jar \
  14. -input in -output out \
  15. -file map_step-j.sh \
  16. -mapper map_step-j.sh \
  17. -file reduce_step.awk \
  18. -reducer reduce_step.awk
  19. hdfs dfs -copyToLocal out out
  20. if [ -d out ]; then
  21. sort -g -r -k 2 out/* > outputs
  22. fi

このshスクリプトでは最初にデータの入出力のディレクトリを作成し、Hadoopで処理実行して、最後にワードカウント数でソートしなおしています。

実行は、次のように入力データを引数に指定して実行します。
入力データは、UTF-8コードの文書にしてください。

./Data_mining-j.sh  入力データ

1) 夏目漱石 「坊ちゃん」をデータマイニング

「2. 日本語文書」でダウンロードしておいた「坊ちゃん」をデータマイニングします。(ワードカウントするだけですが)
青空文庫よりもってきた坊ちゃんのデータファイルは、SJISコードでした。まずUTF-8に変換しておきましょう。

$ iconv -f SJIS -t UTF-8 bocchan.txt > bocchan-utf8.txt

Hadoopクラスタを立ち上げて、実行します!

# ./Data_mining-j.sh  bocchan-utf8.txt

結果はoutputsファイルに出力されます。

出力結果 : outputs


上位100カウント以上のデータを見てみましょう。

おれ 471
の 374
事 291
もの 218
ん 216
人 213
君 184
赤 178
一 176
よう 173
シャツ 170
山嵐 155
何 145
お 145
二 120
方 115
時 107
それ 102

ダントツで「おれ」が1番多いです。主人公の1人称で話が進められているためです。
次にワードとして目立つのは「シャツ」です。これは何でしょうか?
元の小説の中でシャツを検索してみると、これは「赤シャツ」のことだとわかります。ワード上位には「シャツ」とともに「赤」もあります。これらが別のワードとして計上されてしまったのでしょう。赤シャツというのは教頭先生のことでした。
また、「山嵐」も同様に目立ちます。この人は確か同僚です。
これらより、作者の夏目漱石は、坊ちゃんでは上司と同僚との職場での話を中心に書きたかったのだろうと推測できます。
生徒の名前などは見当たりません。「学校」は91で、「生徒」は77です。
主人公が教師であるので教育や学校生活が大きなテーマのように感じられるのですが、それらは実際は主題ではないと言えるでしょう。
有名な「マドンナ」は29カウントでした。(だからきっと恋愛物語でもありませんね)
実際に「坊ちゃん」を読み込んだ人にはかないませんが、単純なワードカウントからでも出力されたデータを解釈することによりいろいろと見えてくることもあります。

2) フランツ・カフカ 「変身」をデータマイニング

「ある朝、グレゴール・ザムザが気がかりな夢から目ざめたとき、自分がベッドの上で一匹の巨大な毒虫に変ってしまっているのに気づいた。」の出だしで有名な話です。 やはり、これも青空文庫からダウンロードさせてもらい、LXCF上に構築したHadoopクラスタでデータマイニングしてみましょう。
SJISテキストからUTF-8に変換しておきます。

$ iconv -f SJIS -t UTF-8 henshin.txt > henshin-utf8.txt

Hadoopクラスタを立ち上げて、実行します。

# ./Data_mining-j.sh  henshin-utf8.txt

結果はoutputsファイルに出力されます。

出力結果 : outputs


上位のデータを見てみましょう。

の 402
こと 397
ゴール 219
彼 206
よう 186
妹 165
自分 145
人 118
父親 116
部屋 108
ドア 106
母親 103
身体 100

上位に「妹」、「父親」、「母親」が出ていることから、家族の話だろうと推測できます。
「ゴール」が出ていますが、これは何かと本文で検索してみると、主人公グレーゴールからゴールだけが切り離されて出力されているようなのでとりあえず無視します。 また、「彼」は本文で検索するとやはり主人公を指しています。
「部屋」、「ドア」とあるのは、自分の部屋とそのドアのことを示していました。
毒虫に変身するというショッキングな話ですが、主題としては主人公の部屋の中での家族と主人公との関わり合いを描いているのだろうと解りました。

元のページに戻る