使用简单查询字符串时,空白标记生成器不起作用
Whitespace tokenizer not working when using simple query string
我首先使用如下所示的 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
}
我在这里使用白色 space 分词器工厂,因为默认的标准分析器会忽略特殊字符,这在我的用例中并不理想。我参考的文件是https://lucene.apache.org/solr/guide/6_6/tokenizers.html#Tokenizers-WhiteSpaceTokenizer。在本文档中,它指出简单分词器将文本流拆分为白色 space 和 returns 非白色 space 字符序列作为标记。
简单查询字符串方法
protected Query inputFilterBuilder() {
SimpleQueryStringMatchingContext simpleQueryStringMatchingContext = queryBuilder.simpleQueryString().onField("name");
return simpleQueryStringMatchingContext
.withAndAsDefaultOperator()
.matching(searchRequest.getQuery() + "*").createQuery();
}
searchRequest.getQuery() returns 搜索查询字符串,然后我在最后追加前缀运算符,使其支持前缀查询。
但是,对于以下示例,这并不像预期的那样工作。
假设我有一个名称为 "AT&T Account" 的实体,当使用 "AT&" 搜索时,它不会 return 这个实体。
然后我进行了以下更改以直接使用白色 space 分析器。这次使用 "AT&" 搜索按预期工作。但是现在搜索区分大小写,即搜索 "at&" return 现在什么都没有。
@Field
@Analyzer(impl = WhitespaceAnalyzer.class)
@Column(name = "NAME")
private String name;
我的问题是:
为什么我第一次尝试使用白色space工厂时它不起作用?我假设使用工厂与使用实际分析器实现是不同的?
如果我在第二次尝试中使用@Analyzer 注释,如何使我的搜索不区分大小写?
Why doesn't it work when I use the white space factory in my first attempt? I assume using the factory versus using the actual analyzer implementation is different?
通配符和前缀查询(当您在查询字符串中添加 *
后缀时使用的查询)永远不会应用分析。这意味着您的小写过滤器未应用于您的搜索查询,但它已应用于您的索引文本,这意味着它永远不会匹配:AT&*
不匹配索引的 at&t
.
使用 @Analyzer
注释之所以有效,是因为您在索引时删除了小写字母。使用此分析器,您最终在索引中得到 AT&T
(大写),并且 AT&*
与索引 AT&T
匹配。不过,这只是偶然:如果您索引 At&t
,您最终会在索引中得到 At&t
,并且最终会遇到同样的问题。
How to make my search case-insensitive if I use the @Analyzer annotation as in my second attempt?
正如我上面提到的,@Analyzer
注释不是解决方案,您实际上使搜索变得更糟。
通配符和前缀查询没有内置的解决方案进行分析,主要是因为分析可能会删除模式字符,例如?
或*
,那将不会很好地结束。
您可以恢复您的初始分析器,并自己将查询小写,但这只会让您走到这一步:ascii 折叠和其他分析功能将不起作用。
我通常推荐的解决方案是使用 edge-ngrams 过滤器。这个想法是索引每个单词的每个前缀,所以 "AT&T Account" 会被索引为术语 a, at, at&, at&t, a, ac, acc, acco, accou, accoun, account
并且即使没有通配符,搜索 "at&" 也会 return 正确的结果.
有关更详细的解释,请参阅 。
如果您使用 ELasticsearch 集成,则必须依靠 hack 才能使 "query-only" 分析器正常工作。参见 here。
我首先使用如下所示的 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
}
我在这里使用白色 space 分词器工厂,因为默认的标准分析器会忽略特殊字符,这在我的用例中并不理想。我参考的文件是https://lucene.apache.org/solr/guide/6_6/tokenizers.html#Tokenizers-WhiteSpaceTokenizer。在本文档中,它指出简单分词器将文本流拆分为白色 space 和 returns 非白色 space 字符序列作为标记。
简单查询字符串方法
protected Query inputFilterBuilder() {
SimpleQueryStringMatchingContext simpleQueryStringMatchingContext = queryBuilder.simpleQueryString().onField("name");
return simpleQueryStringMatchingContext
.withAndAsDefaultOperator()
.matching(searchRequest.getQuery() + "*").createQuery();
}
searchRequest.getQuery() returns 搜索查询字符串,然后我在最后追加前缀运算符,使其支持前缀查询。
但是,对于以下示例,这并不像预期的那样工作。 假设我有一个名称为 "AT&T Account" 的实体,当使用 "AT&" 搜索时,它不会 return 这个实体。
然后我进行了以下更改以直接使用白色 space 分析器。这次使用 "AT&" 搜索按预期工作。但是现在搜索区分大小写,即搜索 "at&" return 现在什么都没有。
@Field
@Analyzer(impl = WhitespaceAnalyzer.class)
@Column(name = "NAME")
private String name;
我的问题是:
为什么我第一次尝试使用白色space工厂时它不起作用?我假设使用工厂与使用实际分析器实现是不同的?
如果我在第二次尝试中使用@Analyzer 注释,如何使我的搜索不区分大小写?
Why doesn't it work when I use the white space factory in my first attempt? I assume using the factory versus using the actual analyzer implementation is different?
通配符和前缀查询(当您在查询字符串中添加 *
后缀时使用的查询)永远不会应用分析。这意味着您的小写过滤器未应用于您的搜索查询,但它已应用于您的索引文本,这意味着它永远不会匹配:AT&*
不匹配索引的 at&t
.
使用 @Analyzer
注释之所以有效,是因为您在索引时删除了小写字母。使用此分析器,您最终在索引中得到 AT&T
(大写),并且 AT&*
与索引 AT&T
匹配。不过,这只是偶然:如果您索引 At&t
,您最终会在索引中得到 At&t
,并且最终会遇到同样的问题。
How to make my search case-insensitive if I use the @Analyzer annotation as in my second attempt?
正如我上面提到的,@Analyzer
注释不是解决方案,您实际上使搜索变得更糟。
通配符和前缀查询没有内置的解决方案进行分析,主要是因为分析可能会删除模式字符,例如?
或*
,那将不会很好地结束。
您可以恢复您的初始分析器,并自己将查询小写,但这只会让您走到这一步:ascii 折叠和其他分析功能将不起作用。
我通常推荐的解决方案是使用 edge-ngrams 过滤器。这个想法是索引每个单词的每个前缀,所以 "AT&T Account" 会被索引为术语 a, at, at&, at&t, a, ac, acc, acco, accou, accoun, account
并且即使没有通配符,搜索 "at&" 也会 return 正确的结果.
有关更详细的解释,请参阅
如果您使用 ELasticsearch 集成,则必须依靠 hack 才能使 "query-only" 分析器正常工作。参见 here。