リスト 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
、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;
// 対 照 で は な い こ と に 注 意 。XとYを 入 れ 替 え れ ば 異 な る 値 に な る 。 同 じ 値 で あ る な ら 別 だ が 。 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
値 も一度計算するだけでよく、すべてのクエリで同じ値を再利用できる。プレーンなドキュメントの検索を拡張する手段はほかにもいろいろある。巻末に関連する参考 文献を載せておいた。