使用简单查询字符串时,空白标记生成器不起作用

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;

我的问题是:

  1. 为什么我第一次尝试使用白色space工厂时它不起作用?我假设使用工厂与使用实际分析器实现是不同的?

  2. 如果我在第二次尝试中使用@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