2012-01-13 24 views
0

単純なMySQLのLIKE%クエリよりもインテリジェントな検索を提供できるように、私はZend_Search_Luceneを使って単純なインデックスを作成しました。 '私は以下のコードを使用しました。ここで、 'companyname'は会社名で、 'document_id'は各ドキュメントの一意のIDです(Luceneは内部的にIDを割り当てていることを認識していますが、静的である)。しかしZend検索Luceneが期待した結果を返さない

$index = Zend_Search_Lucene::create('test-index'); 

$document = new Zend_Search_Lucene_Document(); 
$document->addField(Zend_Search_Lucene_Field::UnIndexed('document_id', 1)); 
$document->addField(Zend_Search_Lucene_Field::Text('companyname', 'XYZ Holdings')); 
$index->addDocument($document); 

$document = new Zend_Search_Lucene_Document(); 
$document->addField(Zend_Search_Lucene_Field::UnIndexed('document_id', 2)); 
$document->addField(Zend_Search_Lucene_Field::Text('companyname', 'X.Y.Z. (Holdings) Ltd')); 
$index->addDocument($document); 

$document = new Zend_Search_Lucene_Document(); 
$document->addField(Zend_Search_Lucene_Field::UnIndexed('document_id', 3)); 
$document->addField(Zend_Search_Lucene_Field::Text('companyname', 'X Y Z Ltd')); 
$index->addDocument($document); 

$index->commit(); 

、私は自分の名前に 'XYZ' の亜種で、すべての企業を見つけるために、次のコードを実行すると:

ID: 1 
Score: 1 
Company: XYZ Holdings 

:私は次のように終わる

$index = Zend_Search_Lucene::open('test-index'); 
$hits = $index->find('companyname:XYZ'); 
foreach ($hits as $hit) 
{ 
    print "ID: " . $hit->document_id . "\n"; 
    print "Score: " . $hit->score . "\n"; 
    print "Company: " . $hit->companyname . "\n"; 
} 

私はXYZがすべての文書に一致することを期待していました。この検索の要点は、同じ名前でわずかに異なる句読点を持つ企業を選ぶことです。単純なLIKE句でそれを処理することはできません。 Luceneがすべての文書に一致しない理由はありますか?これを解決するためにできることはありますか?

'companyname: "x.y.z holding"を検索すると、同じ種類の問題が発生します。これは' companyname:x.y.z holdings 'と一致しません。私は、Luceneが、「保有」と「保有」が十分に近いと考えて、マッチとみなすことを期待しています。私は「XYZ」を検索すると、私はすべての文書がインデックス化されているかなり確信している

はので、私は、文書2及び3

編集のためのマッチを取得する:PHPのバージョン(5.3.5-1ubuntu7.4に言及し忘れましたSuhosin-Patch)とZend Frameworkバージョン(1.11.10-0ubuntu1)を使用しています。

答えて

1

インデックスを作成する前にコンテンツを前処理して問題を解決できます。 Luceneはトークンで動作し、個々のユニットとして扱う必要があります。 2.0を検索すると2.0.3も提供しますが、1.2.0は提供しないように、私はバージョン番号と一致するように過去に似たようなことをしました。

ここのtoCanonical()関数は完璧ではありません。あなた自身が作成し、テストスイートを構築して、期待どおりにテキストを変換することをお勧めします。それがすることは頭字語のように見えるものをグループ化することによってより長い文字列を構築することです。また、検索クエリで呼び出すこともできます。

会社名の代わりに会社名_canonicalで検索する必要があります。

Zend Luceneのフィルタとしては、よりクリーンな方法があります。また、複数のフォームなどを処理するためにステマーを使用することもできます。すでに書かれたポッターステマーの実装があります。 「XYZ(ホールディングス)リミテッド」の場合http://codefury.net/2008/06/a-stemming-analyzer-for-zends-php-lucene/

function toCanonical($text) 
{ 
    $out = $text . ' '; 
    $step = $text; 

    $pattern = '/([A-Z])[\s\.-]([A-Z])([^a-z])/'; 
    while (preg_match($pattern, $step)) { 
     $step = preg_replace($pattern, '$1$2$3', $step); 
     $out .= $step . ' '; 
    } 

    return $out; 
} 

function createDocument($id, $companyName) 
{ 
    $canonicalName = toCanonical($companyName); 

    $document = new Zend_Search_Lucene_Document(); 
    $document->addField(Zend_Search_Lucene_Field::UnIndexed('document_id', $id)); 
    $document->addField(Zend_Search_Lucene_Field::Text('companyname', $companyName)); 
    $document->addField(Zend_Search_Lucene_Field::UnStored('companyname_canonical', $canonicalName)); 

} 

$index->addDocument(createDocument(1, 'XYZ Holdings')); 
$index->addDocument(createDocument(1, 'X.Y.Z. (Holding) Company')); 
+0

おかげで、それはのように聞こえるの頭字語ではない他の大文字の単語と干渉する可能性がありますLuceneは私がそれを望むものを提供していません。それ以外の場合は、私はそれを改革しています。私は何かが欠けていることを保証することができます。 – pwaring

+0

ステミングはサードパーティのプラグインとして利用できます。しかし、私はあなたには、とにかく通常の種付けルールに適合するように求めるものはないと思います。 Javaの実装には、より大きなエコシステムが選択できます。 –

0

あなたインデックス「XYZホールディングス」(あなたはstandardAnalyzerを使用していると言う)、その後、2つのトークン「XYZ」と「保有」が存在します

&「x」、「y」、「z」、「z」、「z」、「lt」のいずれかが表示されます。

「XYZ Ltd」の場合、トークンは「x」、「y」、「z」、 ltd "

企業名「XYZ」または会社名「XYZ」を発行すると、ケース2とケース3が一致します。ケース1が略語であるというXYZがあることをルーネンが知る方法はありません。

は、私はあなたが「XYZ」、「XYZ」と「XYZ」のために同じトークンを生成するために、独自のトークナイザを書くべきだと思いますが、これは

+0

"ルーネンは、ケース1も頭字語であることを知ることはできません" 私はそれが問題だと思っています - Luceneは3つ以上の大文字とスペースの後に頭字語PDF、HTMLなどのように)。私は自分自身のトークナイザーを書くのに十分知らない。 – pwaring

+0

StandardAnalyzerを使用することができます(頭字語で。を削除します)。私はzend luceneにそれに相当するものがあるかどうかわかりません – naresh

関連する問題