2016-03-22

Hadoop Streamingでアイドルツイート分析

Fluentd+ElasticSearch+Kibanaでアイドルデータ分析基盤を作ってみたの回で、FluentdとTwitter Streaming APIを使ってS3にツイートデータを保存したので、このデータをHadoopを使って解析してみます。

今回はMeCabを使って形態素解析してワードカウントを取るような教科書的なMapReduceを試してみました。Hadoop Streamingを使ってPythonでMapper、Reducerを書いていきます。

環境

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"とエラーが発生するので注意。

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のダウンロードはこちら
$ tar xvf mecab-0.996.tar.gz
$ cd mecab-0.996
$ ./configure
$ make
$ sudo make install

辞書もインストール

$ 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バインディングのインストール

$ tar xvf mecab-python-0.996.tar.gz
$ cd mecab-python-0.996
$ python setup.py build
$ sudo python setup.py install

ユーザ辞書の元CSVデータ作成

乃木坂,1288,1288,*,名詞,固有名詞,*,*,*,*,乃木坂,ノギザカ,ノギザカ
欅坂,1288,1288,*,名詞,固有名詞,*,*,*,*,欅坂,ケヤキザカ,ケヤキザカ
...

ユーザ辞書を作成

$ /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)

userdic = /path/to/file/user.dic

Mapperの実装

#!/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の実装

#!/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しないと以下のようなエラーが発生するので注意

Traceback (most recent call last):
  File "/path/to/hadoop_mapper.py", line 12, in <module>
    m = mt.parseToNode(obj['text'])
  File "/usr/local/lib/python2.7/site-packages/MeCab.py", line 282, in parseToNode
    def parseToNode(self, *args): return _MeCab.Tagger_parseToNode(self, *args)
TypeError: in method 'Tagger_parseToNode', argument 2 of type 'char const *'

S3のデータを利用する設定

core-site.xmlの設定はこんな感じで↓

<configuration>
  <property>
    <name>fs.defaultFS</name>
    <value>hdfs://localhost:9000</value>
  </property>
  <property>
    <name>fs.s3n.awsAccessKeyId</name>
    <value>{AWS_ACCESS_KEY_ID}</value>
  </property>
  <property>
    <name>fs.s3n.awsSecretAccessKey</name>
    <value>{AWS_SECRET_ACCESS_KEY}</value>
  </property>
</configuration>

以下のコマンドを実行して問題なくS3にアクセスできることを確認します。

$ hadoop fs -ls s3n://{BUCKET_NAME}

Hadoopの起動

$ 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

正規表現のフィルタリングをキツ目に設定しているのでメンバーが良い感じに出力できています。卒業コンサートがあった永島聖羅が高め。アンダーでは北野日奈子強いです。

参考URL

このエントリーをはてなブックマークに追加