2

使用 Hibernate Search Annotations(大部分只是@Field(index = Index.TOKENIZED))我已经索引了一些与我的一个名为 Compound 的持久类相关的字段。我已经使用 对所有索引字段设置了文本搜索,MultiFieldQueryParser到目前为止效果很好。

在索引和可搜索的字段中,有一个名为 CompoundName 的字段,其中包含示例值:

  • 3-Hydroxyflavone
  • 6,4'-Dihydroxyflavone

当我完全搜索这些值中的任何一个时,都会返回相关的 Compound 实例。但是,当我使用部分名称并引入通配符时会出现问题:

  • 搜索3-Hydroxyflav*仍然给出正确的命中,但是
  • 搜索6,4'-Dihydroxyflav*未能找到任何东西。

现在由于我对 Lucene / Hibernate-search 很陌生,我不太确定在哪里看这一点。我认为这可能与'第二个查询中的当前有关,但我不知道如何继续.. 我应该完全研究 Tokenizers / Analyzers / QueryParsers 还是其他东西?

或者谁能​​告诉我如何让第二个通配符搜索匹配,最好不要破坏多字段搜索行为?

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


一些相关的代码位来说明我目前的方法:

索引 Compound 类的相关部分:

@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();
4

3 回答 3

4

使用 WhitespaceAnalyzer 而不是 StandardAnalyzer。它只会在空格处拆分,而不是在逗号、连字符等处拆分。(但它不会将它们小写,因此您需要构建自己的空格+小写链,假设您希望搜索不区分大小写)。如果您需要为不同的字段做不同的事情,您可以使用 PerFieldAnalyzer。

您不能只将其设置为未标记化,因为这会将您的整个文本正文解释为一个标记。

于 2010-09-24T13:20:15.970 回答
2

我认为您的问题是分析器和查询语言问题的结合。很难说到底是什么导致了这个问题。要找出这一点,我建议您使用 Lucene 索引工具Luke检查您的索引。

由于在您的 Hibernate Search 配置中您没有使用自定义分析器,因此使用了默认值 - StandardAnalyzer这与您在MultiFieldQueryParser的构造函数中使用StandardAnalyzer的事实一致(始终使用相同的分析器进行索引和搜索!)。我不太确定的是“6,4'-二羟基黄酮”如何被StandardAnalyzer标记化。这是你必须找出的第一件事。例如 javadoc 说:

在连字符处拆分单词,除非标记中有数字,在这种情况下,整个标记被解释为产品编号并且不被分割。

您可能需要编写自己的分析器,以按照您的用例需要的方式标记化学名称。

接下来是查询解析器。确保您了解查询语法 - Lucene 查询语法。某些字符具有特殊含义,例如“-”。可能是您的查询以错误的方式解析。

无论哪种方式,第一步都是找出你的化学名称是如何被标记的。希望有帮助。

于 2010-09-24T08:46:37.677 回答
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());
    }
}
于 2011-03-24T12:11:54.533 回答