2011-04-01 149 views
15

我剛剛進入了看似簡單卻非常複雜的搜索世界。對於一個應用程序,我需要建立一個搜索機制來搜索用戶的名字。用Apache Solr搜索名字

閱讀大量的帖子和文章,包括後:

How can I use Lucene for personal name (first name, last name) search?
http://dublincore.org/documents/1998/02/03/name-representation/
what's the best way to search a social network by prioritizing a users relationships first?
http://www.gossamer-threads.com/lists/lucene/java-user/120417
Lucene Index and Query Design Question - Searching People
Lucene Fuzzy Search for customer names and partial address

...和其他一些我無法找到-the-時刻。而得到的,至少索引和基本的搜索結果在我的機器上工作,我已經設計了用戶搜索以下方案:

1)具有第一,第二和第三名稱字段和索引的使用Solr
2)使用edismax作爲搜索requestParser多列
3)使用正常化過濾器,如組合:音譯,拉丁到ASCII convesrion等
4)最後用模糊搜索

顯然,是很新的這一點,我我不確定上述是否是最好的方法,並希望聽到有經驗的用戶比我在這個領域有更好的想法。

我需要能夠通過以下方式相匹配的名稱:

1)口音摺疊:喬恩匹配JORN和反之亦然
2)可選拼寫:卡爾匹配卡爾反之亦然
3)縮短交涉(我相信我做這與SynonymFilterFactory):蘇匹配蘇珊等
4)萊文施泰因匹配:JONN匹配約翰等
5)的Soundex匹配:艾琳和艾倫

任何指導意見,批評或合作mments非常受歡迎。請讓我知道,如果這是可能的...或者我只是白日夢。 :)


編輯

我還要補充一點,我也有一個全稱場的情況下,有些人有長的名字,作爲一個例子從職位之一:喬恩·保羅或卡門應也匹配Jon Paul Del Carmen

由於這是一個新項目,因此我可以以任何我認爲合適的方式修改架構和體系結構,因此限制非常有限。

+1

你會試圖在一個時間來解決1個問題得到了最好的結果。 (你可能知道這一點,我只是提醒你;-))...我會嘗試首先解決最簡單的問題。您的列表看起來按照相反的順序排序。我會從#5開始,回到#1。這些問題中的每一個都對S.O.在這裏單獨提出了一個問題最後,我想你會在每個項目主站點的用戶論壇上獲得更好的幫助。幾個月前,我花了幾個小時閱讀apache.org上的lucene論壇,並發現它非常令人鼓舞和啓發。祝你好運! – shellter 2011-04-04 03:44:59

+0

重口音摺疊,據我所知,我並不真正知道瑞典語,但是當你在文本上使用某個語言分析器時,只要在查詢中使用同一個分析器,它就會使索引文件可搜索。儘管關於文本上的語言檢測我並不是很瞭解。 – Joyce 2011-04-04 13:25:41

回答

9

這聽起來像你正在尋找一個搜索的語料庫,你需要非常鬆散地匹配?

如果你這樣做,你會想選擇你的領域,並設置不同的提升排名結果。

所以在Solr的單獨的「複製」字段:

進行精確的全名
  • 一個字段(過濾器)
  • 有過濾器ASCIIFolding,小寫多值字段...
  • 多值字段與SynonymFilterFactory ASCIIFolding,小寫...
  • PhoneticFilterFactory(與CaverphoneDouble-Metaphone

See Also: more non-english Soundex discussion

名稱的同義詞,我不知道是否有公有同義詞db可用。

模糊搜索,我沒有發現它有用,它使用Levenshtein距離。

其他過濾器和索引獲得更優越的「搜索相關」結果。在名稱

Unicode字符可以與ASCIIFoldingFilterFactory

你所描述前面的預期使用情況的解決方案來處理。

如果你想要高質量的結果,打算調優Search Relevance

這種調整將是特別有價值,試圖匹配的同義詞,就像麥當勞和麥當勞(其中有一個更大的Levenshtein距離比卡爾和卡爾)時。

+0

謝謝你的回覆。由於我急於實現此功能,因此我刪除了一些功能並按以下方式實施(大部分與您的建議類似): 1)添加了帶全名的字段(如您所說) 2)創建了分析儀與小寫,ASCIIFolding和n-gram分析器(用於自動建議) 3)添加了同義詞過濾器 我還使用了edismax查詢分析器。由於您的解決方案接近我的嘗試;我會將這個答案標記爲正確的。 :) 再次感謝您的時間! – shachibista 2011-04-16 16:16:04

0

我們創建了一個簡單的'name'字段類型,允許混合'key'(例如SOUNDEX)和上面答案的'pairwise'部分。

這裏的概述:

  1. 在索引時間,自定義類型的字段被索引到一組與相應的值(子)字段用於高召回匹配不同種變體中的

下面是其實現的核心...

List<IndexableField> createFields(SchemaField field, String name) { 
     Collection<FieldSpec> nameFields = deriveFieldsForName(name); 
     List<IndexableField> docFields = new ArrayList<>(); 
     for (FieldSpec fs : nameFields) { 
      docFields.add(new Field(fs.getName(), fs.getStringValue(), 
         fs.getLuceneField())); 
     } 
     docFields.add(createDocValues(field.getName(), new Name(name))); 
     return docFields; 
} 

的這個心臟是deriveFieldsForName(名稱),您可以在其中包括「鍵」 F ROM PhoneticFilters,LowerCaseFolding等

  • 在查詢時,第一自定義Lucene的查詢產生已調整爲召回和使用相同的字段索引時間
  • 這是它的實現的核心...

    public Query getFieldQuery(QParser parser, SchemaField field, String val) { 
         Name name = parseNameString(externalVal, parser.getParams()); 
         QuerySpec querySpec = buildQuery(name); 
         return querySpec.accept(new SolrQueryVisitor(field.getName())); 
    } 
    

    這樣做的心臟是應該產生一個查詢,高於所以對於一個給定的查詢名稱它會找到很好的候選人的名字瞭解deriveFieldsForName(名稱)BuildQuery對於(name)方法。

  • 然後第二個,Solr的重新排名功能用於應用高精度重新評分算法重新排序的結果
  • 以下是這看起來就像在你的查詢。 ..

    &rq={!myRerank reRankQuery=$rrq} &rrq={!func}myMatch(fieldName, "John Doe") 
    

    myMatch的內容可以有成對的Levenstein或Jaro-Winkler實現。

    N.B.我們自己的完整實現使用deriveFieldsForName,buildQuery和myMatch的專有代碼(請參閱http://www.basistech.com/text-analytics/rosette/name-indexer/)來處理上面提到的各種變體(例如缺少空格,跨語言)。

    +0

    這篇文章不值得(除了廣告您的商業產品),沒有解釋deriveFieldsForName()函數。下圖提供了一些提示:http://www.basistech.com/wp-content/uploads/2013/12/name-matching-capabilities.png – 2015-10-21 08:59:10

    +0

    瞭解。我擴展了答案,試圖清楚如何應用它而不需要商業產品。 – dmurga 2015-10-22 09:56:15

    1

    在另一篇文章的答案是相當不錯的: Training solr to recognize nicknames or name variants

    <fieldType name="name_en" class="solr.TextField" positionIncrementGap="100" autoGeneratePhraseQueries="true"> 
        <analyzer type="index"> 
        <tokenizer class="solr.WhitespaceTokenizerFactory"/> 
        <filter class="solr.WordDelimiterFilterFactory" generateWordParts="1" generateNumberParts="1" catenateWords="1" catenateNumbers="1" catenateAll="0" splitOnCaseChange="1"/> 
        <filter class="solr.LowerCaseFilterFactory"/> 
        <filter class="solr.ASCIIFoldingFilterFactory"/> 
        </analyzer> 
        <analyzer type="query"> 
        <tokenizer class="solr.WhitespaceTokenizerFactory"/> 
        <filter class="solr.WordDelimiterFilterFactory" generateWordParts="1" generateNumberParts="1" catenateWords="0" catenateNumbers="0" catenateAll="0" splitOnCaseChange="1"/> 
        <filter class="solr.LowerCaseFilterFactory"/> 
        <filter class="solr.ASCIIFoldingFilterFactory"/> 
        <filter class="solr.SynonymFilterFactory" synonyms="english_names.txt" ignoreCase="true" expand="true"/> 
        </analyzer> 
    </fieldType> 
    
    0

    對於拼音名稱搜索,你也可以嘗試,如果你有來自不同國家的名字的一種混合物,它工作得很好的Beider-Morse Filter

    如果你想用預輸入功能,使用它,用EdgeNGramFilter結合起來:

    <fieldType name="phoneticNames" class="solr.TextField" positionIncrementGap="100" autoGeneratePhraseQueries="true"> 
        <analyzer type="index"> 
        <tokenizer class="solr.WhitespaceTokenizerFactory"/> 
        <filter class="solr.BeiderMorseFilterFactory" nameType="GENERIC" ruleType="APPROX" concat="true" languageSet="auto"/> 
        <filter class="solr.EdgeNGramFilterFactory" minGramSize="3" maxGramSize="15"/> 
        </analyzer> 
        <analyzer type="query"> 
        <tokenizer class="solr.WhitespaceTokenizerFactory"/> 
        <filter class="solr.BeiderMorseFilterFactory" nameType="GENERIC" ruleType="APPROX" concat="true" languageSet="auto"/> 
        </analyzer> 
    </fieldType>