首页 > 解决方案 > 使用休眠搜索以单词开头或以单词结尾

问题描述

我正在使用带有 spring-boot 的 Hibernate Search。我要求用户必须让搜索运算符对机构名称执行以下操作:

  1. 以一句话开头

.Ali --> 表示该短语应严格以 Ali 开头,这意味着 AlAli 不应在结果中返回

query = queryBuilder.keyword().wildcard().onField("establishmentNameEn")
                        .matching(term + "*").createQuery();

它返回的混合结果包含中间、开始或结尾的术语,不符合上述要求

  1. 以一句话结尾

卡姆兰。--> 表示应该严格结束Kamran,意思是结果中不应该返回Kamranullah

query = queryBuilder.keyword().wildcard().onField("establishmentNameEn")
                        .matching("*"+term).createQuery();

根据文档,将“*”放在开头并不是一个好主意。我的问题是:我怎样才能达到预期的结果

我的域类和分析器:

 @AnalyzerDef(name = "english", tokenizer = @TokenizerDef(factory = StandardTokenizerFactory.class), filters = {
        @TokenFilterDef(factory = StandardFilterFactory.class),
        @TokenFilterDef(factory = LowerCaseFilterFactory.class), })
@Indexed
@Entity
@Table(name = "DIRECTORY")
public class DirectoryEntity {
@Analyzer(definition = "english")
@Field(store = Store.YES)
@Column(name = "ESTABLISHMENT_NAME_EN")
private String establishmentNameEn;

getter and setter
}

标签: lucenehibernate-search

解决方案


这里有两个问题:

标记化

您正在使用分词器,这意味着您的搜索将使用单词,而不是您索引的完整字符串。这说明您在句子中间的术语上得到匹配。

这可以通过为这些特殊的开始/结束查询创建一个单独的字段来解决,并使用带有 的分析器KeywordTokenizer(这是一个无操作)。

例如:

 @AnalyzerDef(name = "english", tokenizer = @TokenizerDef(factory = StandardTokenizerFactory.class), filters = {
        @TokenFilterDef(factory = StandardFilterFactory.class),
        @TokenFilterDef(factory = LowerCaseFilterFactory.class), })
 @AnalyzerDef(name = "english_beginEnd", tokenizer = @TokenizerDef(factory = KeywordTokenizerFactory.class), filters = {
        @TokenFilterDef(factory = StandardFilterFactory.class),
        @TokenFilterDef(factory = LowerCaseFilterFactory.class), })
@Indexed
@Entity
@Table(name = "DIRECTORY")
public class DirectoryEntity {
@Analyzer(definition = "english")
@Field(store = Store.YES)
@Field(name = "establishmentNameEn_beginEnd", store = Store.YES, analyzer = @Analyzer(definition = "english_beginEnd"))
@Column(name = "ESTABLISHMENT_NAME_EN")
private String establishmentNameEn;

getter and setter
}

查询分析和性能

通配符查询不会触发对输入文本的分析。这将导致意外行为。例如,如果您索引“Ali”,然后搜索“ali”,您可能会得到结果,但如果您搜索“Ali”,则不会:文本被分析并索引为“ali”,这不会t 完全匹配“阿里”。

此外,如您所知,前导通配符在性能方面非常非常糟糕。

如果您的字段长度合理(例如,少于 30 个字符),我建议改用“edge-ngram”分析器;你会在这里找到解释:Hibernate Search:如何正确使用通配符?

请注意,您仍然需要使用KeywordTokenizer(与我链接的示例不同)。

这将处理“匹配文本的开头”查询,而不是“匹配文本的结尾”查询。

为了解决第二个查询,我将创建一个单独的字段和一个单独的分析器,类似于用于第一个查询的分析器,唯一的区别是您ReverseStringFilterFactoryEdgeNGramFilterFactory. 这将在索引 ngram 之前反转文本,这将导致所需的行为。不要忘记对该字段使用单独的查询分析器,它可以反转字符串。


推荐阅读