2011-02-08 82 views
2

有許多單詞被連字符或空格分隔,但經常用作一個單詞。例如:籃球或籃球可以寫成籃球。現在Lucene索引/連字符查詢策略

當我指數一句,說:"Hey dude, I played basket ball yesterday". 現在我嘗試查詢"basketball" [沒有雙引號] ..

這種情況下,或者在相反的情況下,(指數basketball和查詢basket ball)我將不會得到任何結果。有什麼辦法可以直接或間接解決這個問題嗎?

Edit:
我舉了個例子來說明問題。在我的實際應用場景中,我將索引和搜索ID。 如果我索引:011 12345,
我應該能夠使用01112345查詢它。

在此先感謝。

+0

您的ID /電話號碼是存儲在一個單獨的字段中,還是隻出現在文本中? – ffriend 2011-02-08 11:22:53

+0

有一個例子說明你的問題沒有意義,這個例子與你的問題沒什麼關係,因爲它意味着任何答案都不一定關注你正在做的事情。今後用真實的場景演示問題。 – Joel 2011-02-09 15:57:08

回答

0

我不是Lucene的用戶,但這裏是我的2美分:在開始索引之前,您必須對數據進行預處理,使其看起來像您想要搜索的方式。如果有人只搜索球,你是否也希望它出現在搜索結果中?如果是,那麼你必須用這個單句(「嘿夥計,我昨天打籃球」&「嘿夥計,我昨天打籃球」)輸入兩個句子作爲輸入,並索引他們兩個。這是你想要的?

3

連字符在這裏不是問題,假設您使用的是類似於連字符等標記的StandardTokenizer,那麼搜索「籃球」的用戶將匹配原始文本「Basket-Ball」(並且反之亦然),所以沒有問題。

問題出現在兩個單詞和一個單詞之間,例如, 「籃球」和「籃球」。你基本上需要處理的同義詞(例如夾克/大衣或在你的情況下籃球/'籃球')。

你可以通過自己創建一個等價單詞列表或者使用像WordNet這樣的字典來解決這個問題,並且可以使用每個術語的同義詞補充索引或搜索。 Solr有一個SynonymFilter,你可以利用(也見here)。

編輯:

下面是一個非常基本的代名詞過濾器,我寫了,而以前的代碼。同義詞不是外化的,但是你可以很容易地添加自己。

public class SynonymFilter extends TokenFilter { 
    private static final Logger log = Logger.getLogger(SynonymFilter.class); 

    private Stack<Token> synStack = new Stack<Token>(); 

    static CharArrayMap<String[]> synLookup = new CharArrayMap<String[]>(5, true); 
    static { 
     synLookup.put("basketball".toCharArray(), new String[]{"basket ball"}); 
     synLookup.put("trainer".toCharArray(), new String[]{"sneaker"}); 
     synLookup.put("burger".toCharArray(), new String[]{"hamburger"}); 
     synLookup.put("bike".toCharArray(), new String[]{"bicycle", "cycle"}); 
    } 

    // TODO reverse map all the syns to each other e.g. sneaker to trainer 

    protected SynonymFilter(TokenStream input) { 
     super(input); 
    } 

    @Override 
    public Token next(Token reusableToken) throws IOException { 
     if (synStack.size() > 0) 
      return synStack.pop(); 

     Token nextToken = input.next(reusableToken); 
     if (nextToken != null) { 
      addSynonyms(nextToken); 
     } 

     return nextToken; 
    } 

    private void addSynonyms(Token nextToken) { 
     char[] word = Arrays.copyOf(nextToken.termBuffer(), nextToken.termLength()); 
     String[] synonyms = synLookup.get(word); 
     if (synonyms != null) { 
      for (String s : synonyms) { 
       if (!equals(word, s)) { 
        char[] chars = s.toCharArray(); 
        Token synToken = new Token(chars, 0, chars.length, nextToken.startOffset(), nextToken.endOffset()); 
        synToken.setPositionIncrement(0); 
        synStack.add(synToken); 
        log.info("Found synonym: " + s + " for: " + new String(nextToken.term())); 
       } 
      } 
     } 
    } 

public static boolean equals(char[] word, String subString) { 
    return equals(word, word.length, subString); 
} 

public static boolean equals(char[] word, int len, String subString) { 

    if (len != subString.length()) 
     return false; 

    for (int i = 0 ; i < subString.length(); i++) { 
     if (word[len - i - 1] != subString.charAt(subString.length() - i - 1)) 
      return false; 
    } 

    return true; 

} 
}