Hadoop @ Java CCC 2008 Spring

Preview:

Citation preview

100行ぐらいで書く分散検索エンジン

Hadoop + Lucene

太田一樹

<kzk@il.is.s.u-tokyo.ac.jp>

自己紹介

• 太田一樹

– http://kzk9.net/

– 東京大学情報理工学系研究科コンピューター科学専攻石川研究室

今回のテーマ

• Javaで分散検索エンジンを楽をして作る

– Lucene (検索エンジン)

– Hadoop (MapReduceフレームワーク)

• 個人でも大規模な検索エンジンがさくっと作れる時代ということを示してみる

Agenda

• Luceneの説明

• Hadoopの説明

• Lucene + Hadoopで検索エンジンを構築

• まとめ

(Lucene)とは?

• Javaで書かれた検索エンジン– Yahoo ResearchのDougCutting氏が開発

– Javaのクラスライブラリとして提供され、他のソフトウェアから簡単に使用可能

– 文章サイズにもよるが、数百万件程度なら1台で検索可能

• 検索できるようになるまでの流れ– 文章を登録し、検索用インデックスを作成

– 検索用インデックスを読み込み、クエリーを発行

Luceneインデックス作成サンプル

//インデックスに登録するファイルのあるディレクトリFile directory = new File(args[0]);String[] filepath = directory.list();//インデックスの保存先String index = args[1];//インデクサの生成IndexWriter writer = new IndexWriter(index, new JapaneseAnalyzer(), true);//文書の解析for (int i = 0; i < filepath.length; i++) {

Document doc = new Document();//ファイルの登録doc.add(Field.UnIndexed("url", filepath[i]));Reader reader = new FileReader(filepath[i]);//文書内容の登録doc.add(Field.Text("contents",reader));writer.addDocument(doc);

} //インデクサのクローズwriter.optimize(); writer.close();

Luceneインデックス作成サンプル

//インデックスに登録するファイルのあるディレクトリFile directory = new File(args[0]);String[] filepath = directory.list();//インデックスの保存先String index = args[1];//インデクサの生成IndexWriter writer = new IndexWriter(index, new JapaneseAnalyzer(), true);//文書の解析for (int i = 0; i < filepath.length; i++) {

Document doc = new Document();//ファイルの登録doc.add(Field.UnIndexed("url", filepath[i]));Reader reader = new FileReader(filepath[i]);//文書内容の登録doc.add(Field.Text("contents",reader));writer.addDocument(doc);

} //インデクサのクローズwriter.optimize(); writer.close();

Luceneインデックス作成サンプル

//インデックスに登録するファイルのあるディレクトリFile directory = new File(args[0]);String[] filepath = directory.list();//インデックスの保存先String index = args[1];//インデクサの生成IndexWriter writer = new IndexWriter(index, new JapaneseAnalyzer(), true);//文書の解析for (int i = 0; i < filepath.length; i++) {

Document doc = new Document();//ファイルの登録doc.add(Field.UnIndexed("url", filepath[i]));Reader reader = new FileReader(filepath[i]);//文書内容の登録doc.add(Field.Text("contents",reader));writer.addDocument(doc);

} //インデクサのクローズwriter.optimize(); writer.close();

Luceneインデックス作成サンプル

//インデックスに登録するファイルのあるディレクトリFile directory = new File(args[0]);String[] filepath = directory.list();//インデックスの保存先String index = args[1];//インデクサの生成IndexWriter writer = new IndexWriter(index, new JapaneseAnalyzer(), true);//文書の解析for (int i = 0; i < filepath.length; i++) {

Document doc = new Document();//ファイルの登録doc.add(Field.UnIndexed("url", filepath[i]));Reader reader = new FileReader(filepath[i]);//文書内容の登録doc.add(Field.Text("contents",reader));writer.addDocument(doc);

} //インデクサのクローズwriter.optimize(); writer.close();

Lucene検索サンプル

// インデックス読み込みIndexSearcher is = new IndexSearcher("index");// クエリーパーサーの作成QueryParser qp = new QueryParser("content", new SimpleAnalyzer());// 検索クエリーの準備Query q = qp.parse(“SomeQuery");// 検索を実行Hits hs = is.search(q);// 検索結果を表示System.out.println(hs.length() + " hit(s)");for(int i=0; i<hs.length(); i++) {

System.out.println(hs.doc(i).toString()); }is.close();

Hadoopとは?

• Googleの基盤ソフトウェアのクローン

– Google File System

– MapReduce

• Yahoo Research の Doug Cutting氏が開発

– 元々はNutch Crawlerのサブプロジェクト

– Dougの子供の持っているぬいぐるみの名前

• Javaで記述

Hadoop参考文献

• Hadoop公式サイト

– http://hadoop.apache.org/core/

– Wiki: http://wiki.apache.org/hadoop/

• インストール方法・チュートリアル・プレゼン資料など

• Hadoop解析資料 (拙著)

• http://preferred.jp/pub/hadoop.html

• Hadoop, hBaseで構築する大規模データ処理システム on CodeZine (拙著)

– http://codezine.jp/a/article/aid/2448.aspx

MapReduceの実行フロー

Data Map

Data Map

Data Map

Reduce

Reduce

Data

Data

Shuffle

Hadoopのスケーラビリティ

• Scaling 4000 nodes at Yahoo!

– http://developer.yahoo.net/blogs/hadoop/2008/09/scaling_hadoop_to_4000_nodes_a.html

• Hadoop wins Terabyte Sort Benchmark

– http://developer.yahoo.net/blogs/hadoop/2008/07/apache_hadoop_wins_terabyte_sort_benchmark.html

• Hadoopで書いとけば、4000ノードぐらいまではスケールするよ!

例: ワードカウント

Data Map

Data Map

Data Map

Reduce

Reduce

Data

Data

Shuffle

foo foo foobar bar buzz

入力文書: doc1

例: ワードカウント

Data Map

Data Map

Data Map

Reduce

Reduce

Data

Data

Shuffle

foo foo foobar bar buz

入力文書: doc1

doc1: foodoc1: foo

doc1: foodoc1: bar

doc1: bardoc1: buz

例: ワードカウント

Data Map

Data Map

Data Map

Reduce

Reduce

Data

Data

Shuffle

foo foo foobar bar buz

入力文書: doc1

doc1: foodoc1: bar

doc1: bardoc1: buz

doc1: foodoc1: foo

例: ワードカウント

Data Map

Data Map

Data Map

Reduce

Reduce

Data

Data

foo foo foobar bar buz

入力文書: doc1

doc1: foodoc1: bar

doc1: bardoc1: buz

doc1: foodoc1: foo

foo: 1foo: 1

bar: 1foo: 1

bar: 1buz: 1

例: ワードカウント

Data Map

Data Map

Data Map

Reduce

Reduce

Data

Data

foo foo foobar bar buz

入力文書: doc1

foo: 1foo: 1

bar: 1foo: 1

bar: 1buz: 1

bar: <1, 1>buz: <1>

foo: <1, 1, 1>

例: ワードカウント

Data Map

Data Map

Data Map

Reduce

Reduce

Data

Data

foo foo foobar bar buz

入力文書: doc1

bar: <1, 1>buz: <1>

foo: <1, 1, 1>

例: ワードカウント

Data Map

Data Map

Data Map

Reduce

Reduce

Data

Data

foo foo foobar bar buz

入力文書: doc1

foo: <1, 1, 1>

bar: <1, 1>buz: <1>

foo: 3

bar: 2buz: 1

例: ワードカウント

Data Map

Data Map

Data Map

Reduce

Reduce

Data

Data

foo foo foobar bar buz

入力文書: doc1

bar: 2buz: 1

foo: 3

作成する検索エンジンの仕組み

url1: <html>…url2: <html>…url3: <html>…url4: <html>…url5: <html>…url6: <html>…url7: <html>…

クロールしてきた文章 Lucene

インデックス1

Lucene

インデックス2

Lucene

インデックス3

Lucene

インデックス4

Lucene

インデックス5

Hadoopによる分散インデックス

作成

分散クエリー発行

検索用ノード

Hadoopによる分散インデックス作成

Data Map

Data Map

Data Map

Reduce

Reduce

Data

Data

Shuffleurl3: <html>…url4: <html>…

url1: <html>…url2: <html>…

url5: <html>…url6: <html>…

Hadoopによる分散インデックス作成

Data Map

Data Map

Data Map

Reduce

Reduce

Data

Data

Shuffleurl3: <html>…url4: <html>…

url1: <html>…url2: <html>…

url5: <html>…url6: <html>…

Hadoopによる分散インデックス作成

Data Map

Data Map

Data Map

Reduce

Reduce

Data

Data

Shuffleurl3: <html>…url4: <html>…

url1: <html>…url2: <html>…

url5: <html>…url6: <html>…

url1: <html>…url4: <html>…url5: <html>…

url2: <html>…url3: <html>…url6: <html>…

Hadoopによる分散インデックス作成

Data Map

Data Map

Data Map

Reduce

Reduce

Data

Data

Shuffle

url1: <html>…url4: <html>…url5: <html>…

url2: <html>…url3: <html>…url6: <html>…

Lucene

インデックス

Lucene

インデックス

Hadoopによる分散インデックス作成

Data Map

Data Map

Data Map

Reduce

Reduce

Data

Data

Shuffle

Lucene

インデックス

Lucene

インデックス

Hadoopによる分散インデックス作成

Data Map

Data Map

Data Map

Reduce

Reduce

Data

Data

Shuffle

Lucene

インデックス

Lucene

インデックス

Hadoopによる分散インデックス作成

Data Map

Data Map

Data Map

Reduce

Reduce

Data

Data

Shuffle

Lucene

インデックス

Lucene

インデックス

分散インデックス作成(Mapフェーズ)

// 何もしないpublic void map(Text key, Text value,

OutputCollector<Text, Text> output,Reporter reporter) throws IOException {

Text url = key;Text str = value;output.collect(url, str);

}

分散インデックス作成(Reduceフェーズ)

public void reduce(Text key, Iterator<Text> values,OutputCollector<Text, Writable> output,Reporter reporter) throws IOException {

// URLText url = key;// 本文Text str = values.next();// ドキュメントを追加Document doc = new Document();doc.add(new Field("url", url.toString(), Field.Store.YES, Field.Index.NO));doc.add(new Field("content", str.toString(), Field.Store.YES, Field.Index.TOKENIZED));output.collect(url, new LuceneDocumentWrapper(doc));

}

分散インデックス作成(Reduce終了フェーズ)

public void close(final Reporter reporter) throws IOException {// 分散ファイルシステムに保存するための何かfinal Path perm = new Path(job.getOutputPath(), name);final Path temp = job.getLocalPath(

“index/_” + Integer.toString(new Random().nextInt()));// インデックス作成final IndexWriter writer = new IndexWriter(

fs.startLocalOutput(perm, temp).toString(),new JapaneseAnalyzer(), true);

try {writer.optimize();writer.close();fs.completeLocalOutput(perm, temp); // copy to dfs

} finally {closed = true;

} }

以上のコードを実行

• Hadoopのインストール

– 今回は24 (dual core)台のクラスタを使用

• ビルド

• 実行

– bin/hadoop jar indexer.ja net.kzk9.indexer in out

• 分散ファイルシステムのoutというディレクトリにLuceneインデックスが作成されている

– 30Gのドキュメントで約2-3時間?

作成する検索エンジンの仕組み

url1: <html>…url2: <html>…url3: <html>…url4: <html>…url5: <html>…url6: <html>…url7: <html>…

クロールしてきた文章 Lucene

インデックス1

Lucene

インデックス2

Lucene

インデックス3

Lucene

インデックス4

Lucene

インデックス5

Hadoopによる分散インデックス

作成

分散クエリー発行

検索用ノード

ここを作った

落ち穂拾い

• 時間的にここまで

• 残りのタスク

– クエリー受け付け用のサーバーを用意

– 作成されたインデックスをそいつらに転送

– クライアントから各サーバーにクエリーを発行

とはいえ

• 商用検索エンジンにするには絶対的に欠けている要素– ランキング

– クローラー

• OSSの分散検索エンジン– Nutch

• OSSの検索エンジン

• あんまり出来が良くない

– Senna• 分散バージョンマダー?

まとめ

• Luceneの使い方を説明

• Hadoopの使い方を説明

• 組み合わせて分散でインデックスを作成する方法を紹介

おわり

% wc -l indexer.java145 indexer.java

Recommended