Fluentd+ElasticSearch+Kibanaでアイドルデータ分析基盤を作ってみたの回で、FluentdとTwitter Streaming APIを使ってS3にツイートデータを保存したので、このデータをHadoopを使って解析してみます。
今回はMeCabを使って形態素解析してワードカウントを取るような教科書的なMapReduceを試してみました。Hadoop Streamingを使ってPythonでMapper、Reducerを書いていきます。
環境
- OS: Mac OS X(El Capitan)
- Python: 2.7.11
- Hadoop: 2.7.1
Hadoopのインストール&設定
以下のURLを参考にインストール&設定すればOK。 Macなら brew install hadoopで一発。 インストールしたら、~/.bashrcか~/.zshrcにこんな感じで設定しておきます。環境変数HADOOP_CLASSPATHに$HADOOP_HOME/libexec/share/hadoop/tools/lib/*を入れないと"ls: No FileSystem for scheme: s3n hadoop"とエラーが発生するので注意。 ```bash export HADOOP_VER=2.7.1 export HADOOP_HOME=/usr/local/Cellar/hadoop/$HADOOP_VER export HADOOP_CLASSPATH=$HADOOP_CLASSPATH:"$HADOOP_HOME/libexec/share/hadoop/tools/lib/*" ``` Macで擬似分散モードを試すときは[システム環境設定]>[共有]でリモートログインを許可しておく。Hadoop StreamingのMapper、Reducer
Mapperは対象のデータを標準入力で受け取り、Key/Valueを標準出力に吐き出すようなコード、ReducerはMapperの標準出力を入力としてKey/Valueを集計するようなコードをそれぞれ書けばOKです。今回はMapperでMeCabを使って形態素解析をするため、MeCabのインストールを行います。MeCabのダウンロードはこちら。 ```bash $ tar xvf mecab-0.996.tar.gz $ cd mecab-0.996 $ ./configure $ make $ sudo make install ``` 辞書もインストール ```bash $ tar xvf mecab-ipadic-2.7.0-20070801.tar.gz $ cd mecab-ipadic-2.7.0-20070801 $ ./configure --with-charset=utf8 $ make $ sudo make install ``` Pythonバインディングのインストール ```bash $ tar xvf mecab-python-0.996.tar.gz $ cd mecab-python-0.996 $ python setup.py build $ sudo python setup.py install ``` ユーザ辞書の元CSVデータ作成 ```text 乃木坂,1288,1288,*,名詞,固有名詞,*,*,*,*,乃木坂,ノギザカ,ノギザカ 欅坂,1288,1288,*,名詞,固有名詞,*,*,*,*,欅坂,ケヤキザカ,ケヤキザカ ... ``` ユーザ辞書を作成 ```bash $ /usr/local/libexec/mecab/mecab-dict-index -d/usr/local/lib/mecab/dic/ipadic \ -u /path/to/file/user.dic -f utf-8 -t utf-8 /path/to/file/user_dic.csv ```MeCabにユーザ辞書を設定(/usr/local/lib/mecab/dic/ipadic/dicrc)
```text userdic = /path/to/file/user.dic ``` Mapperの実装 ```python #!/usr/bin/env python # -*- coding: utf-8 -*- import sys import json import MeCab import re regex = re.compile(r'[ぁ-ん。、!?!-/:-@≠\[-`{-~a-zA-Z\d_]+') mt = MeCab.Tagger("-Ochasen") for line in sys.stdin: obj = json.loads(line) text = obj['text'] # RTを含むツイートは除く if text.find('RT') > -1: continue m = mt.parseToNode(text.encode('utf-8')) while m: # 一文字、空白な品詞は無視。正規表現によるフィルタリング内容は要検討。 if m.surface == '' or len(m.surface) == 1 or regex.match(m.surface): m = m.next continue print("{0}\t1".format(m.surface)) m = m.next ``` Reducerの実装 ```python #!/usr/bin/env python # -*- coding: utf-8 -*- import sys word_map = {} for line in sys.stdin: word, count = line.strip().split('\t') word_map[word] = word_map[word] + int(count) if word in word_map else int(count) for k, v in sorted(word_map.items(), key=lambda x:x[1], reverse=True): print("{0}\t{1}".format(k, v)) ``` Mapperでツイート内容を形態素解析かけるときは、encodeしないと以下のようなエラーが発生するので注意 ```text Traceback (most recent call last): File "/path/to/hadoop_mapper.py", line 12, inS3のデータを利用する設定
core-site.xmlの設定はこんな感じで↓
```xmlHadoopの起動
$ hadoop jar ${HADOOP_HOME}/libexec/share/hadoop/tools/lib/hadoop-streaming-2.7.1.jar \
-input s3n://{BUCKET_NAME}/20160319_*_twitter.gz \
-output /output -mapper ./hadoop_mapper.py -reducer ./hadoop_reducer.py
結果の確認は以下のコマンドで
$ hadoop fs -cat /output/part-00000 | less
3/19のツイート収集結果はこんな感じ
乃木坂:2565
西野七瀬:532
白石麻衣:436
欅坂:426
橋本奈々未:369
生駒里奈:356
希望:327
齋藤飛鳥:302
永島聖羅:286
生田絵梨花:274
高山一実:257
生:251
写真:241
紅白:239
衣装:237
提供:236
松村沙友理:213
人:210
日:187
衛藤美彩:180
中:167
北野日奈子:150
深川麻衣:147
正規表現のフィルタリングをキツ目に設定しているのでメンバーが良い感じに出力できています。卒業コンサートがあった永島聖羅が高め。アンダーでは北野日奈子強いです。