Lucene通配符匹配失败的化学符号(?)

时间:2010-09-23 14:26:11

标签: java lucene wildcard matching hibernate-search

使用Hibernate搜索注释(大多数只是@Field(index = Index.TOKENIZED))我已经将一些名为Compound的持久类的相关字段编入索引。我使用MultiFieldQueryParser设置了所有索引字段的文本搜索,到目前为止工作正常。

在索引和可搜索的字段中,有一个名为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();

3 个答案:

答案 0 :(得分:4)

使用WhitespaceAnalyzer而不是StandardAnalyzer。它只会在空格中分割,而不是在逗号,连字符等处分开(虽然它不会小写它们,所以你需要构建自己的空白字符串+小写,假设你希望你的搜索不区分大小写)。如果您需要针对不同的字段执行不同的操作,可以使用PerFieldAnalyzer。

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

答案 1 :(得分:2)

我认为您的问题是分析器和查询语言问题的组合。很难说究竟是什么导致了这个问题。为了解决这个问题,我建议您使用Lucene索引工具Luke检查索引。

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

  

在连字符上拆分单词,除非   在令牌中有一个数字,在   整个令牌是哪种情况   被解释为产品编号而且是   不分裂。

您可能需要编写自己的分析仪,以便根据您的使用情况对您的化学名称进行标记。

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

无论哪种方式,首先要了解您的化学名称如何被标记化。希望有所帮助。

答案 2 :(得分: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());
    }
}