公開文書‎ > ‎

Hyper EstraierによるP2P分散検索システムの構築手法

Software Design (ソフトウエア デザイン) 2007年 03月号 [雑誌] 「第2特集 オープンソース検索エンジン-Hyper Estraierを使いこなせ!」の記事です。

HyperEstraierのP2Pシステム


P2Pシステムは,2000年末にNapsterやGnutellaなどのファイル交換システムによって一躍有名になりました.クライアント同士が直接データ交換を行うP2Pによって大規模なシステムが構築できることが実証されました.しかし,P2Pの知名度とは裏腹にその定義は専門家の間でも曖昧です.また,代表的なP2Pアプリケーションの多くがクライアントアプリケーションのため,「P2PはエンドユーザのPC上で動作するシステム」と言う認識が多いです.

HyperEstraierのP2Pシステムは,「粗結合なシステム同士がデータ交換するシステム」と定義できると思います.ここで言うシステムは,サーバサイドで動作することがほとんどです.このため,クライアントのP2Pアプリケーションと違い,不要な機能は削ぎ落とされています.クライアントアプリケーションでは,P2Pのコマンド伝搬の経路は自動化されています.一方,HyperEstraierではサーバ管理者が明示的に指定する必要があります.つまり,HyperEstraierの各ノードは,自分が次にどのノードにコマンドを伝搬するかを指定します.

コマンド伝搬の経路を指定することは煩雑なため,デメリットのように感じるかもしれません.しかし,サーバごとに役割を持たせ,経路(サーバ)ごとに役割に応じた検索結果の重み付けを行なうことができます.また,大規模なシステムでは,コマンド伝搬の経路は管理者が設定したいという要求も多いです.

P2Pによるメリット


HyperEstraierの検索サービスをP2Pシステムを使って構築するメリットは何でしょうか?

一つが検索インデックスが分散されることによる検索速度の向上があります.1000万件の文書インデックスを単一のサーバで検索することと,100万件ずつ10台のサーバで同時並行で検索することを想像してみてください.単純に考えても,10台のサーバで検索する方が10倍速いことになります.

二つ目として,インデックスの配置やコマンド伝搬の経路設定によっては,フォルトトレランスが実現できることです.同じインデックスを複数のサーバに配置することで,どれか一つのサーバで障害が発生しても他のサーバがサービスを提供し続けられます.

HyperEstraierは,検索サーバ間はP2Pで連携して動作しますが,サーバに対してクエリーを発行するのはクライアントです.つまり,クライアントとサーバ間はクライアント・サーバ方式で動作します.P2Pの利点ではありませんが,検索サーバとクライアントを完全に分離できるようになります.クライアント側は,PythonやRuby,Javaなどの言語バインディングが提供されているので,好きな言語で独自のクライアントアプリケーションを実装することができます.また,複数のクライアントが同時に検索サーバに対して検索することもできます.

P2Pの分散システム構築


HyperEstraierではノード単位で検索サービスを提供しています.各ノードは独自の文書インデックスを管理しています.複数のノードを管理する仕組みとしてノードマスターが提供されています.

HyperEstraierでP2Pシステムを構築する場合,次の二つの方法があります.

  1. 同一ノードマスター内の別のノードにコマンド伝搬経路を指定する方法
  2. 別のノードマスターのノードに対してコマンド伝搬経路を指定する方法

同一サーバ上で複数の文書インデックスを管理している場合は,1の方法が良いでしょう.別サーバ上にあるノードに対して検索を行ないたい場合は,必然的に2の方法になります.両者は文書インデックスの配置の仕方やプロセスの管理の方法が違うだけで,実際にシステムの設定を行なうときに両者の違いを意識する必要はありません.

ノード作成


まず,ノードマスターを作成します.ノードマスターを作成するためには,文書インデックスファイルを作成するディレクトリに移動して,図1のコマンドを実行します.ここでは,/tmp/hstest/ディレクトリにnodemaster1と言う名前でノードマスターを作成しています.次に,図2のコマンドを実行して,ノードマスターのプロセスを起動します.


図1 ノードマスターの作成


$ estmaster init nodemaster1


図2 ノードマスターの起動


$ estmaster start nodemaster1

ノードマスターを起動した後に,Webブラウザから管理コンソールにアクセスして設定を行ないます.ノードを作成するために,ブラウザでhttp://localhost:1978/にアクセスして,「Administration」をクリックします.ユーザID,パスワードの入力を求められますので,ユーザIDはadmin,パスワードもadminを入力してください.

ログイン後に表示されるメニューから「Manage Node」をクリックしてノード作成画面を表示します.ノードの名前と表示用のラベルを入力します(図3).ノードの名前は,P2Pの経路指定を行なうときにノードマスターの名前と一緒に使用します.ここでは,図4の二つのノードを作成します.


■ 図3  管理コンソールのノード作成画面


■ 図4 ノード作成
 名前  ラベル
 nodea  ノードA
 nodeb  ノードB

インデックスへの登録

ノード作成後,ノードに文書インデックスを作成します.本稿では,Java2 SDK Standard Editionのドキュメントをnodeaのインデックスに登録します.ドキュメント本体は~/java-document/ディレクトリに保存します.文書インデックスの作成は図5のコマンドを実行します.

■ 図5 文書インデックスの登録
$ find  -type f -name '*.html' |
while read file ; do
 estcmd draft -fh -il ja "$file" |
 estcall put -auth admin admin http://localhost:1978/node/nodea
done

ノードへ文書を登録するには,HyperEstraierの文書ドラフト形式に変換する必要があります.estcmd draftコマンドを使ってファイルを文書ドラフト形式に変換しています.文書ドラフト形式に変換したものを,estcall putでインデックスに登録します.

文書インデックスを作成したら図6のコマンドを実行してnodeaに対して検索します.

■ 図6 nodeaに対しての検索要求
$ estcall search http://localhost:1978/node/nodea "Array"

P2Pの経路指定


次に分散検索するために,ノードに経路を指定します.HyperEstraierでは,この作業を「リンクを張る」と呼びます.nodebからnodeaに対してリンクを張るためには,図7のコマンドを実行します.リンク元のURL,リンク先のURL,表示用のラベル,信頼度の順で引数を指定します.

■ 図7 nodebからnodeaに対してリンクを設定


$ estcall setlink -auth admin admin http://localhost:1978/node/nodeb \
  http://localhost:1978/node/nodea NodeA2NodeB 8000

経路指定は,コマンドからだけでなく,管理コンソールから指定することもできます.管理コンソールにアクセスして,「Administration」-「Manage Node」を選択してnodebの「Edit」を選択します(図8).「list of links」のフィールドにリンク先ノードを指定します.ここは,「http://localhost:1978/node/nodea{{!}}b2a{{!}}8000」と指定します.{{!}}b2a{{!}}がラベルの指定,最後の8000が信頼度になります.

■ 図8 管理コンソールのノード編集画面
genkou5.jpgを見てください

信頼度とは,複数のノードからの検索をマージするとき,検索スコアに重み付けするときに使用する数値です.信頼度の高いノードからの検索結果は,一覧するときに上位に来やすくなります.よく利用するノードの信頼度を高めたり,ノードごとに役割を持たせて役割に応じた信頼度を指定することで,検索精度を上げることができます.

複数のノードで分散環境を構築する場合,経路が循環することがあります.HyperEstraierでは経路の循環を自動的に検出して,同じ検索コマンドが経路を循環するようなことはありません.経路(リンク)の方向は単方向になります.双方向にリンクを貼りたい場合は,同様の操作をnodeaからnodebに対しておこなう必要があります.

経路指定ができたので,nodebに対して検索を行ないます(図9).nodebには文書インデックスはありません.この状態では,検索に何もヒットしません.次に図10のコマンドを実行します.今回は引数に-dpt 1を指定しています.これは,複数のノードに対して検索を行なうときのホップ数になります.ここでは,1ホップ先のノードまで検索対象に含めるという意味になります.したがって,この場合ではnodebとnodeaが検索対象になります.図8でArrayにヒットした文書が一覧されているのがわかると思います.

■ 図9 nodeaに対しての検索要求
$ estcall search http://localhost:1978/node/nodeb "Array"
--------[518CD9153EC98E28]--------
VERSION 1.0
NODE    http://localhost:1978/node/nodeb
HIT     0
HINT#1  hash    0
DOCNUM  0
WORDNUM 0
TIME    0.000075
TIME#i  0.000035
TIME#0  0.000039
LINK#0  http://localhost:1978/node/nodeb        nodeb   10000   0       0       9127932 0
LINK#1  http://localhost:1978/node/nodea        b2a     8000    -1      -1      -1      -1
VIEW    SNIPPET


--------[518CD9153EC98E28]--------:END

■ 図10 nodeaに対しての深度を指定して検索要求
$ estcall search -dpt 1 http://localhost:1978/node/nodeb "Array"
--------[39AD0AB72941C881]--------
VERSION 1.0
NODE    http://localhost:1978/node/nodeb
HIT     471
HINT#1  hash    471
DOCNUM  11197
WORDNUM 52141
TIME    0.063979
TIME#i  0.000041
TIME#0  0.000047
TIME#1  0.063844
TIME#2  0.012556
LINK#0  http://localhost:1978/node/nodeb        nodeb   10000   0       0       9127932 0
LINK#1  http://localhost:1978/node/nodea        b2a     8000    11197   52141   50762270        471
VIEW    SNIPPET


--------[39AD0AB72941C881]--------
[以下略]

パフォーマンス


次にパフォーマンスの測定してみます.パフォーマンスの測定にはAMD Athlon64X2 3800+,メモリ2GBを搭載したGentoo Linuxを使用しています.計測には,それぞれ5回計測して平均を取っています.

キャッシュによる効能


HyperEstraierではキャッシュ機能により検索速度が改善されています.最初にキャッシュ機能の性能を計測してみます.ノードの経路を図11のように指定して,キーワードを「hash」で検索します.なお,ここでのノードは,同一マスター上のノードを指定しています.ノードマスターを起動後,最初の検索と2回目の検索の応答速度を比較します.結果は図12のようになります.キャッシュ機能により,応答速度が約5分の1になっています.


■ 図11 キャッシュ機能測定のための経路
+--------+      +-------+
| nodeb  | ---> | nodea |
+--------+      +-------+

■ 図12 キャッシュ機能の応答速度
          1回目     2回目
------------------------------
応答時間  0.303280    0.06357

# 分散したインデックスによる検索速度

次にインデックスを複数のノードマスターのノードに分散して検索を行ないます.ここでは,実験するマシンの都合上,一台のPC上に複数のノードマスターを動作させています.ノードの配置は図13のようにします.インデックスファイルは,Javaのドキュメントを適当に2分割して,nodeaとnodecに登録しています.nodebに対してキーワード「hash」で検索しています.


■ 図13 分散インデックスの経路
+- ノードマスター1 -----------+
|  +--------+      +-------+  |
|  | nodeb  | ---> | nodea |  |
|  |        |      | (インデックス1)
|  +---+----+      +-------+  |
+------|----------------------+
       |
       +--------------+
                      |
+- ノードマスター2 ---|------+
|                     ↓      |
|                  +-------+  |
|                  | nodec |  |
|                  | (インデックス2)
|                  +-------+  |
+-----------------------------+

結果は図14のようになります.今回の結果からは有意な差が得られませんでした.おそらく,検索インデックスのサイズが小さすぎたため効率があがらなかったことなどが考えられます.インデックスのサイズが小さすぎると,検索のスピードより,P2Pでのネゴシエーション,検索結果のマージなどの処理のオーバーヘッドが大きくなることが考えられます.

■図14 分散インデックスによる効果
            単一ノードの場合  複数のノードの場合
-------------------------------------------------------
 応答時間   0.303280            0.315257

次に,手元にあるドキュメントをすべてインデックスに登録して,同様に検証してみた結果が図15です.ドキュメントを単一ノードに集中してインデキシングしたものと,二つのノードに分割してインデクシングしたもので比較しています.インデックスのサイズはJ2SE Standard Editionだけのものと比較して,約5倍の大きさになっています.今回の結果から,複数ノードに分散した場合は単一ノードに比べて約2倍のパフォーマンス改善が見られます.

■図15 インデックスを大きい場合の分散インデックスによる効果
            単一ノードの場合  複数のノードの場合
-------------------------------------------------------
 応答時間   0.619903            0.312685

最後に


今回の結果からインデックスのサイズが大きくなると分散検索のメリットは享受できると思われます.また,フォルトトレランスなど,パフォーマンス以外にもメリットも大きいため,P2Pによる分散検索環境の構築を検討してみてはどうでしょうか?

Comments