hibernate-search - 使用简单查询字符串时空白标记器不起作用
问题描述
我首先使用 SimpleQueryString 实现了查询搜索,如下所示。
实体定义
@Entity
@Indexed
@AnalyzerDef(name = "whitespace", tokenizer = @TokenizerDef(factory = WhitespaceTokenizerFactory.class),
filters = {
@TokenFilterDef(factory = LowerCaseFilterFactory.class),
@TokenFilterDef(factory = ASCIIFoldingFilterFactory.class)
})
public class AdAccount implements SearchableEntity, Serializable {
@Id
@DocumentId
@Column(name = "ID")
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Field(store = Store.YES, analyzer = @Analyzer(definition = "whitespace"))
@Column(name = "NAME")
private String name;
//other properties and getters/setters
}
我在这里使用空格标记器工厂,因为默认的标准分析器会忽略特殊字符,这在我的用例中并不理想。我提到的文件是https://lucene.apache.org/solr/guide/6_6/tokenizers.html#Tokenizers-WhiteSpaceTokenizer。在本文档中,它指出 Simple tokenizer 将文本流拆分为空格并将非空白字符序列作为标记返回。
SimpleQueryString 方法
protected Query inputFilterBuilder() {
SimpleQueryStringMatchingContext simpleQueryStringMatchingContext = queryBuilder.simpleQueryString().onField("name");
return simpleQueryStringMatchingContext
.withAndAsDefaultOperator()
.matching(searchRequest.getQuery() + "*").createQuery();
}
searchRequest.getQuery() 返回搜索查询字符串,然后我在最后附加前缀运算符,以便它支持前缀查询。
但是,这在以下示例中无法按预期工作。假设我有一个名为“AT&T Account”的实体,当使用“AT&”搜索时,它不会返回该实体。
然后我进行了以下更改以直接使用空白分析器。这次使用“AT&”进行搜索按预期工作。但是现在搜索是区分大小写的,即用“at&”搜索现在什么都不返回。
@Field
@Analyzer(impl = WhitespaceAnalyzer.class)
@Column(name = "NAME")
private String name;
我的问题是:
为什么我第一次尝试使用空白工厂时它不起作用?我假设使用工厂与使用实际的分析器实现不同?
如果我在第二次尝试中使用@Analyzer 注释,如何使我的搜索不区分大小写?
解决方案
为什么我第一次尝试使用空白工厂时它不起作用?我假设使用工厂与使用实际的分析器实现不同?
通配符和前缀查询(您*
在查询字符串中添加后缀时使用的查询)永远不会应用分析。这意味着您的小写过滤器未应用于您的搜索查询,但已应用于您的索引文本,这意味着它永远不会匹配:AT&*
不匹配索引的at&t
.
仅使用@Analyzer
注释有效,因为您在索引时删除了小写字母。使用此分析器,您最终AT&T
在索引中使用 (大写),并且AT&*
与索引的AT&T
. 不过,这只是偶然:如果你 index At&t
,你最终会At&t
在 index 中,你最终会遇到同样的问题。
如果我在第二次尝试中使用@Analyzer 注释,如何使我的搜索不区分大小写?
正如我上面提到的,@Analyzer
注释不是解决方案,您实际上使您的搜索变得更糟。
没有内置的解决方案可以使通配符和前缀查询应用分析,主要是因为分析可以删除诸如?
or之类的模式字符*
,而这不会很好地结束。
您可以恢复您的初始分析器,并自己小写查询,但这只会让您到目前为止:ascii 折叠和其他分析功能将不起作用。
我通常推荐的解决方案是使用 edge-ngrams 过滤器。这个想法是索引每个单词的每个前缀,因此“AT&T Account”将被索引为术语a, at, at&, at&t, a, ac, acc, acco, accou, accoun, account
,即使没有通配符,搜索“at&”也会返回正确的结果。
有关更广泛的解释,请参阅此答案。
如果您使用 ELlasticsearch 集成,您将不得不依靠 hack 来使“仅查询”分析器正常工作。见这里。
推荐阅读
- ruby-on-rails - Rails admin gem co-related 下拉菜单不起作用
- forms - 在 WTForms 中,如果另一个字段为空,我如何制作可选的必填字段?
- yaml - 如何在 YAML 中重用列表条目锚点?
- php - 如何使用 FOSRestBundle 在 Symfony 4 控制器的所有方法中设置自定义标头?
- javascript - 循环依赖 - Eloquent Javascript 书中的练习
- python - pybind11 python 在 Windows 10 上嵌入,致命的 Python 错误:initfsencoding:无法加载文件系统编解码器 #1930
- c# - 将所有数据表值显示到文本框中
- node.js - mongodb链接回存储在目录中的图像
- tensorflow - TensorflowJs conv2d - 张量形状
- google-cloud-dataflow - 需要从 apache 光束(数据流)在 clickhouseIO 中插入行