2014-04-19 56 views
2

我在我的ASP.NET項目搜索中使用Lucene.net標準分析器。但是,該搜索不會返回像C#,.NET等關鍵字的結果。但是,如果我鍵入C或NET(刪除。和#)它的作品。在Stackoverflow(也使用Lucene)時,我注意到當我輸入.NET時,它在搜索時將其更改爲[.NET],我收到了標準分析器無法處理特殊字符搜索的鏈接,並且White Space Analyzer不會爲我們工作,因爲它沒有給出預期的結果。任何人都可以幫助如何管理搜索?哪個Lucene SearchAnalyzer用於特殊字符搜索

回答

2

我將描述什麼,所以還做了一些更緊密的位置:

雖然我不是真的樞密院StackOverflow上的實現細節,你會爲「Java」的或搜索時,請注意相同的行爲「休眠」,即使這些標準分析儀沒有問題。他們將被轉換爲「[java]」和「[hibernate]」。這只是表示一個標籤搜索。這在搜索「lucene」或「junit」時不會發生,因此它可能與標籤的普及有關。我肯定會懷疑標籤標題會以未分析的形式編入索引。

對於一個有趣的例子,試試「j ++」。這個死衚衕的java實現在SO上使用標籤只有8個問題,所以它不會觸發自動標籤搜索。搜索「[j ++]」,你會看到這些8.搜索「j ++」,你會找到與該特定語言相關的任何事情,但你會發現很多參考

起,到修理你的問題:

是,StandardAnalyzer會(講不準確,請參閱UAX-29了精確的規則)擺脫所有的標點。典型的做法是在查詢時使用相同的分析器。如果您使用StandardAnalyzer分析您的查詢以及索引文檔,則您的搜索條件將匹配,上述兩個查詢條件將縮減爲netc,您應該得到結果。

但是現在,您已經碰到StandardAnalyzer問題的典型示例。這意味着c,c++c#將在索引中全部表示完全相同,沒有辦法在沒有匹配其他兩個的情況下搜索一個!

有幾種方法來解決這個問題,在我的腦海:

  1. 把嬰兒和洗澡水一起倒掉:使用WhitespaceAnalyzer或一些這樣的,並失去所有的漂亮,花哨的東西StandardAnalyzer幫助你。

  2. 只是處理那些少數稍勝一籌的情況下:好,所以Lucene的不喜歡標點和你有一些已知條件是有這樣的問題。幸運的是,你有String.Replace。把它們替換成一些更適合lucene的東西,比如「c」,「cplusplus」和「csharp」。再次確保它在查詢和索引時間都完成。 問題在於::由於您在分析儀之外執行此操作,因此轉換也會影響該字段的存儲版本,並迫使您在將結果顯示給用戶之前進行反轉。

  3. 一樣做#2,但只是有點票友:那麼#2可能的工作不錯,但你已經有了這些分析處理由Lucene的消費轉化數據,這隻會影響索引版而不是存儲的字段。爲什麼不使用它們?分析儀有一個呼叫initReader,您可以在分析儀堆棧的前面敲擊CharFilter(參見the Analysis package documentation底部的示例)。在分析器中運行的文本將在StandardTokenizer之前由CharFilter進行轉換(這是擺脫標點符號等等)的方法。例如,MappingCharFilter

你不能繼承StandardAnalyzer,雖然,思維是,你應該執行分析,而不是繼承它的實現(見the discussion here,如果你有興趣在思維過程的更完整的討論那裏)。因此,假設我們要確保我們得到絕對所有StandardAnalyzer的交易功能,只需複製粘貼的源代碼,並添加initReaders方法的重寫:

public class ExtraFancyStandardAnalyzer extends StopwordAnalyzerBase { 

    public static final int DEFAULT_MAX_TOKEN_LENGTH = 255; 

    private int maxTokenLength = DEFAULT_MAX_TOKEN_LENGTH; 

    public static final CharArraySet STOP_WORDS_SET = StopAnalyzer.ENGLISH_STOP_WORDS_SET; 

    public ExtraFancyStandardAnalyzer(Version matchVersion, 
      CharArraySet stopWords) { 
     super(matchVersion, stopWords); 
     buildMap(); 
    } 

    public ExtraFancyStandardAnalyzer(Version matchVersion) { 
     this(matchVersion, STOP_WORDS_SET); 
    } 

    public ExtraFancyStandardAnalyzer(Version matchVersion, Reader stopwords) 
      throws IOException { 
     this(matchVersion, loadStopwordSet(stopwords, matchVersion)); 
    } 

    public void setMaxTokenLength(int length) { 
     maxTokenLength = length; 
    } 

    public int getMaxTokenLength() { 
     return maxTokenLength; 
    } 


    // The following two methods, and a call to buildMap() in the ctor 
    // are the only things changed from StandardAnalyzer 

    private NormalizeCharMap map; 

    public void buildMap() { 
     NormalizeCharMap.Builder builder = new NormalizeCharMap.Builder(); 
     builder.add("c++", "cplusplus"); 
     builder.add("c#", "csharp"); 
     map = builder.build(); 
    } 

    @Override 
    protected Reader initReader(String fieldName, Reader reader) { 
     return new MappingCharFilter(map, reader); 
    } 

    @Override 
    protected TokenStreamComponents createComponents(final String fieldName, 
      final Reader reader) { 
     final StandardTokenizer src = new StandardTokenizer(matchVersion, 
       reader); 
     src.setMaxTokenLength(maxTokenLength); 
     TokenStream tok = new StandardFilter(matchVersion, src); 
     tok = new LowerCaseFilter(matchVersion, tok); 
     tok = new StopFilter(matchVersion, tok, stopwords); 
     return new TokenStreamComponents(src, tok) { 
      @Override 
      protected void setReader(final Reader reader) throws IOException { 
       src.setMaxTokenLength(ExtraFancyStandardAnalyzer.this.maxTokenLength); 
       super.setReader(reader); 
      } 
     }; 
    } 
} 

注:這是用Java編寫和測試,Lucene 4.7版。 C#實現不應該有太大的不同。複製StandardAnalyzer,構建一個MappingCharFilter(實際上它只是在3.0.3版本中處理的一個簡單的頭髮),並將其包裝在覆蓋initReader方法的覆蓋中。

+0

輝煌的答案! – Vivek