使用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();
答案 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());
}
}