• 検索結果がありません。

リスト 2. 12 URL の適合度を NaiveBayes 分類器で評価する

2.5 Word 、 PDF 、その他のリンクを持たないドキュメントをラ ンク付けする

2.5.2 DocRank の内部動作

この重要度の指標の選択には大きな自由度があるが、使い物になるようにするためには、新

H

行列の要素は以下の

2

つの性質を満たさなくてはならない。

すべて正の数

すべての行において値の和が

1

となる

我々の指標が成功するかどうかは、処理しようとするドキュメントの種類による。リスト

2.15

DocRankMatrixBuilder

クラスは、

Word

ドキュメントにおける

H

行列を生成する。

リスト

2.15 DocRankMatrixBuilder

:テキストドキュメントをコンテンツに基づいてランク付けする public class DocRankMatrixBuilder implements CrawlDataProcessor {

private final int TERMS_TO_KEEP = 3;

private int termsToKeep =0;

private String indexDir ; private PageRankMatrixH matrixH ; public void run () {

try {

IndexReader idxR = IndexReader . open ( FSDirectory . getDirectory ( indexDir ));

matrixH = buildMatrixH ( idxR );

} catch ( Exception e) {

throw new RuntimeException (" Error : ", e );

} }

// Collects doc ids from the index for documents with matching doc type

// ド キ ュ メ ン ト タ イ プ が マ ッ チ す る ド キ ュ メ ン ト のI Dを 収 集 す る

private List < Integer > getProcessedDocs ( IndexReader idxR ) throws IOException { List < Integer > docs = new ArrayList < Integer >();

for ( int i = 0, n = idxR . maxDoc (); i < n; i ++) { if ( idxR . isDeleted (i) == false ) {

Document doc = idxR . document (i );

if ( eligibleForDocRank ( doc . get (" doctype ") ) ) { docs . add (i );

} } }

return docs ; }

// イ ン デ ッ ク ス エ ン ト リ は 適 格 か ?

private boolean eligibleForDocRank ( String doctype ) {

return ProcessedDocument . DOCUMENT_TYPE_MSWORD . equalsIgnoreCase ( doctype );

}

private PageRankMatrixH buildMatrixH ( IndexReader idxR ) throws IOException { // 取 得 、 パ ー ス さ れ た コ ン テ ン ツ のU R Lの み 考 慮 す る

List < Integer > allDocs = getProcessedDocs ( idxR );

PageRankMatrixH docMatrix = new PageRankMatrixH ( allDocs . size () );

for ( int i = 0, n = allDocs . size (); i < n; i ++) { for ( int j = 0, k = allDocs . size (); j < k; j ++) {

double similarity = 0.0 d;

Document docX = idxR . document (i );

String xURL = docX . get (" url ");

if ( i == j ) {

// 自 分 自 身 へ の リ ン ク を 防 ぐ

docMatrix . addLink ( xURL , xURL , similarity );

} else {

TermFreqVector x = idxR . getTermFreqVector (i , " content ");

TermFreqVector y = idxR . getTermFreqVector (j , " content ");

similarity = getImportance (x. getTerms () ,

x. getTermFrequencies () , y. getTerms () , y. getTermFrequencies ());

// add link from docX to docY // d o c Xか らd o c Yへ の リ ン ク を 追 加 す る Document docY = idxR . document (j );

String yURL = docY . get (" url ");

docMatrix . addLink ( xURL , yURL , similarity );

} } }

docMatrix . calculate ();

return docMatrix ; }

// ド キ ュ メ ン トXか ら 見 た ド キ ュ メ ン トYの 重 要 度 を 計 算 す る private double getImportance ( String [] xTerms , int [] xTermFreq ,

String [] yTerms , int [] yTermFreq ){

// xTerms は 、1番 目 の ド キ ュ メ ン ト の 頻 出 語

Map < String , Integer > xFreqMap = buildFreqMap ( xTerms , xTermFreq );

2.5 Word

PDF

、その他のリンクを持たないドキュメントをランク付けする

59

// yTerms は 、2番 目 の ド キ ュ メ ン ト の 頻 出 語

Map < String , Integer > yFreqMap = buildFreqMap ( yTerms , yTermFreq );

// sharedTerms は 、2つ の 集 合 の 積 集 合

Set < String > sharedTerms = new HashSet < String >( xFreqMap . keySet ());

sharedTerms . retainAll ( yFreqMap . keySet ());

double sharedTermsSum = 0.0;

// 対 照 で は な い こ と に 注 意 。XYを 入 れ 替 え れ ば 異 な る 値 に な る 。 同 じ 値 で あ る な ら 別 だ が 。 double xF , yF ;

for ( String term : sharedTerms ) { xF = xFreqMap . get ( term ). doubleValue ();

yF = yFreqMap . get ( term ). doubleValue ();

sharedTermsSum += Math . round ( Math . tanh ( yF / xF ));

}

return sharedTermsSum ; }

private Map < String , Integer > buildFreqMap ( String [] terms , int [] freq ) { int topNTermsToKeep = ( termsToKeep == 0)? TERMS_TO_KEEP : termsToKeep ; Map < String , Integer > freqMap

= TermFreqMapUtils . getTopNTermFreqMap ( terms , freq , topNTermsToKeep );

return freqMap ; }

}

我々の仕組みは

2

つの重要な要素からなっている。まず、タームと頻度のペアからなる

Lucene

のタームベクトル(

term vectors

)を用いていること。ここで

Lucene

によるドキュメントのイ ンデックス化について復習しておこう。初めにドキュメントのテキストをパースして、次に解

析(

analyze

)して、最後にインデックス化する。解析フェーズでテキストはトークン(ターム)

に分解されるが、テキストがどのようにトークン化されるかは利用するアナライザに依存する。

Lucene

の素晴らしいところは、その情報を後で取り出して使うことができるという点にある。

テキストのタームに加えて、それぞれのタームがドキュメントに現れた数も取得できる。我々の 場合でいえば、各ドキュメントに含まれているタームとその頻度が取得できさえすれば十分だ。

もうひとつの要素は、それぞれのドキュメントへの重要度の割り当て方の選択にある。リスト

2.15

getImportance

メソッドは、各ドキュメント

X

について、次の順序でドキュメント

Y

の重要度を計算する。(

1

)ドキュメント

X

とドキュメント

Y

の中で最も使われているターム群 の積集合(

intersection

)を求める。(

2

)共通するターム(積集合)それぞれについて、そのター ムがドキュメント

Y

に現れる回数(

Y

出現頻度)とドキュメント

X

に現れる頻度(

X

出現回数)

の比を求める。ドキュメント

X

のコンテキストにおけるドキュメント

Y

の重要度は、これらの 比をすべて足し合わせて

tanh

Math.tanh

)をとり、

Math.round

で丸めたものである。これら の計算の最終結果は、

H

行列中の行

X

、列

Y

の要素となる。

ここで

tanh

を用いたのは、

2

つのドキュメント間において、ある特定のタームが重要度を決定 するのによい指標であるかどうかを測りたいがためである。実際の値がいくつになるかには関心 がない。手ごろな上限下限をもって重要度の値を維持できればそれでよい。

tanh

0

から

1

bsh % oracle.search("nvidia", 5, dr);

Search results using Lucene index scores:

Query: nvidia

Document Title: NVIDIA shares plummet into cheap medicine for you!

Document URL: file:/c:/iWeb2/data/ch02/spam-biz-02.doc --> Relevance Score: 0.4582 ___________________________________________________________

Document Title: Nvidia shares up on PortalPlayer buy

Document URL: file:/c:/iWeb2/data/ch02/biz-05.doc --> Relevance Score: 0.3240 ___________________________________________________________

Document Title: NVidia Now a Supplier for MP3 Players

Document URL: file:/c:/iWeb2/data/ch02/biz-04.doc --> Relevance Score: 01944 ___________________________________________________________

Document Title: Chips Snap: Nvidia, Alter a Shares Jump

Document URL: file:/c:/iWeb2/data/ch02/biz-06.doc --> Relevance Score: 01852 ___________________________________________________________

Search results using combined Lucene scores and page rank scores:

Query: nvidia

Document URL: file:/c:/iWeb2/data/ch02/biz-05.doc --> Relevance Score: 0.03858 Document URL: file:/c:/iWeb2/data/ch02/spam-biz-02.doc --> Relevance Score: 0.03515 Document URL: file:/c:/iWeb2/data/ch02/biz-04.doc --> Relevance Score: 0.02925 Document URL: file:/c:/iWeb2/data/ch02/biz-06.doc --> Relevance Score: 0.02233 ___________________________________________________________

2.11

インデックスとランキングを用いて、

Word

ドキュメントを

“nvidia”

で検索する

間の値を出力するため、最後の丸め操作によって、タームが無視されるか重要度

1

単位として採 用されるかが決まる。これらの関数を用いた理由はここにある。

2.11

を見ると

“nvidia”

を検索したときに

biz-05.doc

ファイルが最も高くランクされている ことがわかる。これは正規の(スパムではない)ファイルで、確かに

nvidia

に関係したものだ。

ドキュメント数が少ないためスパムファイルも生き残っているが、効果はあった。

Lucene

イン デックスが持つ情報はこれまでと同じで、しかも偽ドキュメントによってレレバンスがゆがめら れている。

DocRank

biz-05.doc

のレレバンスを上げるのに役立った。より実用的な場面では、

最も適切なドキュメント群を探し出すことができるだろう。

PageRank

値と同様に、

DocRank

値 も一度計算するだけでよく、すべてのクエリで同じ値を再利用できる。

プレーンなドキュメントの検索を拡張する手段はほかにもいろいろある。巻末に関連する参考 文献を載せておいた。

DocRank

のアルゴリズムはリレーショナルデータベースに適用するとよ り力を発揮する。例えば、ここにテーブル

A

とテーブル

B

が存在するとしよう。これらはテー ブル

C

を通じて関連を持っている。よくある場面だ。具体的にいうと、ユーザテーブル、グルー プテーブルがあって、もうひとつユーザとグループのそれぞれの

ID

を保持することによって両 者をつなげるテーブルがあるようなものだ。結果として、グループごとのユーザを表現するグラ フや、ユーザが属するグループを表現するグラフができあがる。エンティティをリンクでつない でいる場面を目にしたら、それは

DocRank

アルゴリズムやその類型を試す機会だと常に考えよ う。実験をためらってはいけない。この種の問題に唯一無二の正解なんてない。ときにその結果

関連したドキュメント