2010-09-23 54 views
2

使用Hibernate搜索註釋(大多數只是@Field(index = Index.TOKENIZED))我已經爲一個名爲Compound的持久化類相關的許多字段建立索引。我已經使用MultiFieldQueryParser設置了對所有索引字段的文本搜索,目前爲止它工作正常。Lucene通配符匹配在化學符號(?)上失敗

在索引和搜索的字段是被稱爲compoundName字段,具有采樣值:

  • 3-Hydroxyflavone
  • 6,4'-Dihydroxyflavone

當我在充分的相關化合物搜索這些值之一實例返回。然而,當我使用部分名稱和介紹通配符出現問題:

  • 尋找3-Hydroxyflav*仍然給出了正確的打擊,但
  • 尋找6,4'-Dihydroxyflav*沒有發現任何東西。

現在因爲我很新的Lucene/Hibernate的搜索,我不太清楚在哪裏看在這一點..我認爲它可能有一些做的'存在於第二個查詢,但我不知道如何繼續..我應該看看Tokenizers/Analyzers/QueryParsers還是其他的東西?

或者任何人都可以告訴我如何獲得第二次通配符搜索匹配,最好不打破MultiField搜索行爲?

我正在使用Hibernate-Search 3.1.0.GA & Lucene-core 2.9.3。


一些相關的碼位來說明我目前的做法:

@Entity 
@Indexed 
@Data 
@EqualsAndHashCode(callSuper = false, of = { "inchikey" }) 
public class Compound extends DomainObject { 
    @NaturalId 
    @NotEmpty 
    @Length(max = 30) 
    @Field(index = Index.TOKENIZED) 
    private String     inchikey; 

    @ManyToOne 
    @IndexedEmbedded 
    private ChemicalClass   chemicalClass; 

    @Field(index = Index.TOKENIZED) 
    private String     commonName; 
... 
} 

如何我目前搜索在索引字段:

String[] searchfields = Compound.getSearchfields(); 
MultiFieldQueryParser parser = 
    new MultiFieldQueryParser(Version.LUCENE_29, searchfields, new StandardAnalyzer(Version.LUCENE_29)); 
FullTextSession fullTextSession = Search.getFullTextSession(getSession()); 
FullTextQuery fullTextQuery = 
    fullTextSession.createFullTextQuery(parser.parse("searchterms"), Compound.class); 
List<Compound> hits = fullTextQuery.list(); 

索引複合類的相關部分

回答

2

我認爲你的問題是分析器和查詢語言問題的結合。很難說究竟是什麼導致了這個問題。爲了解決這個問題,我建議你使用Lucene索引工具Luke檢查你的索引。

由於在您的Hibernate Search配置中沒有使用自定義分析器,因此使用默認設置 - StandardAnalyzer - 。這與您在MultiFieldQueryParser的構造函數中使用StandardAnalyzer(始終使用相同的分析器進行索引和搜索!)一致。我不太確定的是「6,4'-二羥基黃酮」是如何通過StandardAnalyzer得到標記的。首先你必須找出答案。例如javadoc中說:

在連字符

拆分的話,除非 有令牌的數字,在 這種情況下,整個令牌 解釋爲產品編號,並 不分裂。

這可能是你需要編寫自己的分析器,它以你需要的方式爲你的用例標記化學名。

接下來是查詢解析器。確保您瞭解查詢語法 - Lucene query syntax。有些字符有特殊含義,例如' - '。這可能是您的查詢以錯誤的方式被解析。

無論採用哪種方法,首先要了解您的化學名稱是如何得到標記的。希望有所幫助。

+0

僅供參考,我趕緊查了StandardAnalyzer如何您的標記化的例子。 「3-Hydroxyflavone」似乎屬於上述產品規則。它成爲一個單一的標誌「3-羥基黃酮」。另一方面,「6,4'-二羥基黃酮」變成兩個「6,4」和「二羥基黃酮」。 – Hardy 2010-09-24 09:03:06

+0

哇,謝謝!我只是試圖在這裏使用盧克來測試相同的..這是否意味着我需要使用備用分析儀? (我嘗試將該字段設置爲UN_TOKENIZED,但甚至打破了第一個搜索示例..) – Tim 2010-09-24 10:27:02

+0

它看起來StandardTokenizer將單詞分隔爲撇號。這至少查明瞭問題,但需要一些時間才能修復這.. ..謝謝你的幫助! – Tim 2010-09-24 13:52:33

4

使用WhitespaceAnalyzer代替StandardAnalyzer。它只會以空格分隔,而不是逗號,連字符等(它不會將它們小寫,所以如果您希望搜索不區分大小寫,您需要構建自己的空白鏈+小寫字母)。如果您需要針對不同領域採取不同的處理方式,則可以使用PerFieldAnalyzer。

您不能將它設置爲un-tokenized,因爲它會將您的整個文本主體解釋爲一個標記。

+0

嗯,這聽起來很有希望,但迄今爲止的初始測試還沒有解決問題..我可能不得不嘗試一連串的過濾器和PerFieldAnalyzer ..一旦我做了,我會報告回來。 – Tim 2010-09-24 15:45:04

1

我寫我自己的分析:

import java.util.Set; 
import java.util.regex.Pattern; 

import org.apache.lucene.index.memory.PatternAnalyzer; 
import org.apache.lucene.util.Version; 

public class ChemicalNameAnalyzer extends PatternAnalyzer { 

    private static Version version = Version.LUCENE_29; 
    private static Pattern pattern = compilePattern(); 
    private static boolean toLowerCase = true; 
    private static Set stopWords = null; 

    public ChemicalNameAnalyzer(){ 
     super(version, pattern, toLowerCase, stopWords); 
    } 

    public static Pattern compilePattern() { 
     StringBuilder sb = new StringBuilder(); 
     sb.append("(-{0,1}\\(-{0,1})");//Matches an optional dash followed by an opening round bracket followed by an optional dash 
     sb.append("|");//"OR" (regex alternation) 
     sb.append("(-{0,1}\\)-{0,1})"); 
     sb.append("|");//"OR" (regex alternation) 
     sb.append("((?<=([a-zA-Z]{2,}))-(?=([^a-zA-Z])))");//Matches a dash ("-") preceded by two or more letters and succeeded by a non-letter 
     return Pattern.compile(sb.toString()); 
    } 
}