コンパイル
ソースのコンパイルですが,
$ javac -cp $HADOOP_HOME/hadoop-0.20.2-core.jar:$HADOOP_HOME/myproj/lib/cmecab-1.7.jar J2ch.java
jarファイルの作成は以下のように行います。
$ jar cvf J2ch.jar J2ch*.class
実行
hadoopコマンドにJ2ch.
hadoop jar プログラムのjar メイン関数を含んだクラス 第一引数 第二引数
という構文になります。
$ hadoop jar J2ch.jar J2ch 2ch_4.txt 2ch_4_result
ここでは,
$ hadoop dfs -rmr 2ch_4_result
というふうにディレクトリを削除しましょう。
出力データ例
「カイジ 人生逆転ゲーム」
- ※1287144000が21:00を表します。1287151200が23:00を表します
(放送開始から放送終了まで)。
ざっと眺めてみると,
1287144000 1287144000,53,カイジ
1287144000 1287144000,37,俺
1287144000 1287144000,35,女
1287144000 1287144000,34,カット
1287144000 1287144000,26,出
1287144600 1287144600,118,利根川
1287144600 1287144600,114,これ
1287144600 1287144600,110,www
1287144600 1287144600,108,ざわ
1287144600 1287144600,108,船井
1287145200 1287145200,161,カット
1287145200 1287145200,156,原作
1287145200 1287145200,154,映画
1287145200 1287145200,151,カイジ
1287145200 1287145200,126,展開
1287145800 1287145800,225,カット
1287145800 1287145800,201,ビール
1287145800 1287145800,182,カイジ
1287145800 1287145800,169,ペ
1287145800 1287145800,164,映画
1287146400 1287146400,96,映画
1287146400 1287146400,87,カット
1287146400 1287146400,66,落
1287146400 1287146400,65,これ
1287146400 1287146400,60,原作
1287147000 1287147000,126,落
1287147000 1287147000,101,カイジ
1287147000 1287147000,95,原作
1287147000 1287147000,90,これ
1287147000 1287147000,84,佐原
1287147600 1287147600,135,ざわざわ
1287147600 1287147600,115,ざわ
1287147600 1287147600,69,カード
1287147600 1287147600,54,耳
1287147600 1287147600,53,これ
1287148200 1287148200,105,カイジ
1287148200 1287148200,91,CM
1287148200 1287148200,85,利根川
1287148200 1287148200,81,ざわざわ
1287148200 1287148200,76,顔
1287148800 1287148800,88,遠藤
1287148800 1287148800,82,カイジ
1287148800 1287148800,65,映画
1287148800 1287148800,60,原作
1287148800 1287148800,51,何
1287149400 1287149400,198,キタ
1287149400 1287149400,91,利根川
1287149400 1287149400,85,カイジ
1287149400 1287149400,84,血
1287149400 1287149400,76,ざわ
1287150000 1287150000,91,土下座
1287150000 1287150000,88,焼
1287150000 1287150000,31,カイジ
1287150000 1287150000,29,利根川
1287150000 1287150000,22,演技
1287150600 1287150600,118,カイジ
1287150600 1287150600,116,映画
1287150600 1287150600,93,カット
1287150600 1287150600,84,原作
1287150600 1287150600,62,遠藤
1287151200 1287151200,52,映画
1287151200 1287151200,47,カイジ
1287151200 1287151200,35,原作
1287151200 1287151200,33,思
1287151200 1287151200,32,人
全プログラムリスト
最後に全リストを載せておきます。アスキーアートの除外や意味のない単語の削除など上の例では省いていた関数を載せいてます。
J2ch.java
import java.io.IOException;
import java.util.Hashtable;
import java.text.BreakIterator;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.*;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.OutputFormat;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import java.util.regex.*;
import net.moraleboost.mecab.Node;
import net.moraleboost.mecab.Tagger;
import net.moraleboost.mecab.impl.StandardTagger;
import net.moraleboost.mecab.MeCabException;
public class J2ch
{
static final int TIMESEC = 600; // 丸める秒数
static class J2chMapper extends Mapper <LongWritable, Text, IntWritable, Text>
{
private Boolean isAA( String s)
{
Pattern p = Pattern.compile(".*[/ ̄_\ ]{2}+.*");
Matcher m = p.matcher(s);
return m.matches();
}
private String noGomi( String s )
{
Pattern p = Pattern.compile("(h?ttp://|h?ttps://|sssp://){1}[\\w\\.\\-/:\\#\\?\\=\\&\\;\\%\\~\\+]+|>?>[0-9- ]+");
Matcher m = p.matcher(s);
String t = m.replaceAll("");
return t;
}
private Boolean isGomi( String s )
{
Pattern p = Pattern.compile("^[!()━・゚?/:;0-9a-zA-Z∀Д\\`=│*1234567890.\"'#~{}&,:;+<>%$_$%”!#&、;:?|{}@`*+_?><|∴▼△▲▽-]$");
Matcher m = p.matcher(s);
return m.matches();
}
public void map(LongWritable key, Text value, Context context)
throws IOException, InterruptedException
{
// 入力データ
// 1288400498\t94\t主侍 </b>◆HIPPER/a9g <b>\t+rXxBAvc\t\t\t 友近とアジアンかって
String line = value.toString();
String[] arr = line.split("\t");
int _time = Integer.parseInt(arr[0]);
int time = (int)Math.floor(_time/TIMESEC)*TIMESEC; // TIMESECで丸める。
if ( arr.length != 7 ) return;
String b = arr[6]; // ボディーテキストを取得
if ( isAA(b) ) return; // AAを含むモノは削除
String body = noGomi(b); // ゴミを削除(URL,>>123など)
Tagger tagger = new StandardTagger("UTF-8", "");
Node node = tagger.parse(body);
// 名詞,副詞可能,*,*,*,*,本日,ホンジツ,ホンジツ
while (node.hasNext())
{
String surface = node.next();
String feature = node.feature();
String featureArr[] = feature.split(",");
if ( featureArr[0].equals("名詞" ))
{
context.write(new IntWritable(time), new Text(surface));
}
}
}
}
static class J2chReducer extends Reducer <IntWritable, Text, IntWritable, Text>
{
public void reduce(IntWritable key, Iterable<Text> values, Context context)
throws IOException, InterruptedException
{
Hashtable<String, Integer> kvs = new Hashtable<String, Integer>();
for( Text value : values )
{
String k = value.toString();
if ( kvs.containsKey( k ))
{
Integer n = kvs.get(k) + 1;
kvs.put(k, n);
}
else
{
kvs.put(k, 1);
}
}
ArrayList entries = new ArrayList(kvs.entrySet());
Collections.sort(entries, new Comparator(){
public int compare(Object obj1, Object obj2){
Map.Entry ent1 =(Map.Entry)obj1;
Map.Entry ent2 =(Map.Entry)obj2;
int val1 = Integer.parseInt(ent1.getValue().toString());
int val2 = Integer.parseInt(ent2.getValue().toString());
return (val2 - val1);
}
});
for( int i = 0; i < entries.size() && i < 5; i++ )
{
String word = (String)((Map.Entry)entries.get(i)).getKey();
int cnt = Integer.parseInt(((Map.Entry)entries.get(i)).getValue().toString());
context.write(key, new Text( key + "," + cnt + "," + word));
}
}
}
public static void main(String[] args ) throws Exception
{
if ( args.length != 2 )
{
System.err.println("Usage: hogehoge");
System.exit(-1);
}
Job job = new Job();
job.setJarByClass(J2ch.class);
FileInputFormat.addInputPath(job, new Path(args[0]));
FileOutputFormat.setOutputPath(job, new Path(args[1]));
job.setMapperClass(J2chMapper.class);
job.setReducerClass(J2chReducer.class);
job.setOutputKeyClass(IntWritable.class);
job.setOutputValueClass(Text.class);
System.exit(job.waitForCompletion(true) ? 0 : 1 );
}
}
次回はJavaを使わないMapReduceの書き方をご紹介します!