2012-01-13 119 views
0

我已經創建了一個簡單的索引,使用Zend_Search_Lucene搜索公司名稱列表,因爲我希望能夠提供比簡單的MySQL'LIKE%查詢% 」。我使用了下面的代碼,其中'companyname'是公司名稱,'document_id'是每個文檔的唯一ID(我知道Lucene在內部分配一個ID,但我知道可以更改,而我的文檔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' 的變種:

$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"; 
} 

我結束了以下內容:

ID: 1 
Score: 1 
Company: XYZ Holdings 

我希望XYZ能夠匹配所有的文檔,因爲要進行這種搜索的目的是爲了找到具有相同名稱但標點符號略有不同的公司,這些公司在簡單的LIKE子句中不能滿足要求。是否有一個原因,爲什麼Lucene不匹配所有的文件,有什麼我可以做的,以解決這個問題?

如果我搜索'companyname:'x.y.z持有'' - 這與'companyname:'x.y.z持有''不匹配,我會得到同樣的問題。我期望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()函數並不完美。我建議你自己編寫一個測試套件,以確保它能夠按照您的預期轉換文本。它所做的是通過將看起來像縮寫詞的東西分組來構建更長的字符串。您也可以在搜索查詢中調用它。

您需要搜索companyname_canonical而不是公司名稱。

在Zend Lucene中,可能有一種更簡潔的方式來做它的過濾器。你可能也想用一個詞幹來處理複數形式等等。已經編寫了一個porter stemmer的實現。 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 2012-01-17 09:21:48

+0

該詞幹可作爲第三方插件使用。但是,我不認爲你所要求的適合正常的干擾規則。 Java實現有一個更大的生態系統可供選擇。 – 2012-01-17 12:56:10

0

當指數「XYZ控股」(說你正在使用standardAnalyzer),然後會有兩個記號「某某」和「增持」

在「XYZ(集團)有限公司」案如果「XYZ有限公司」的標記爲「x」,「y」,「z」和「z」,則「x」,「y」,「z」,「holdings」和「 ltd「

當您發出公司名稱:」XYZ「或公司名稱:」XYZ「時,情況2和情況3都匹配。 lucene沒有辦法知道情況1中的XYZ也是首字母縮寫詞。

我想你應該寫自己的標記生成器生成的「XYZ」,「某某」和「XYZ」相同的標記,但是這可能與不是縮略詞

+0

「沒有辦法lucene可以知道情況1中的XYZ也是首字母縮寫詞」 我認爲這是問題 - 我希望Lucene知道三個或更多個大寫字母后跟一個空格可能是首字母縮寫詞(如PDF,HTML等)。我真的不知道寫我自己的記號器。 – pwaring 2012-01-21 21:31:49

+0

您可以使用StandardAnalyzer(因爲它刪除了首字母縮寫詞)。我不知道在zend lucene中是否有與此相同的東西 – naresh 2012-01-22 07:29:20