休眠搜索Lucene。建议,但几乎像SQL“ LIKE”

时间:2019-03-07 05:18:44

标签: hibernate lucene hibernate-search lexical-analysis

这是我第一次处理优化的搜索功能,而我的部分熟练程度是在android开发的前端,但是我愿意冒险进行休眠搜索。我确实了解SQL“ LIKE”查询的功能,它的功能及其局限性,这就是我直接进入休眠搜索(lucene)的原因,我的目标是根据输入(输入查询)提供自动建议。这就是我到目前为止所得到的

@Indexed
@Table (name = "shop_table")
@Entity
@AnalyzerDef(name = "myanalyzer",
    tokenizer = @TokenizerDef(factory = KeywordTokenizerFactory.class), //
    filters = { //
            @TokenFilterDef(factory = LowerCaseFilterFactory.class),
            @TokenFilterDef(factory = WordDelimiterFilterFactory.class),
            @TokenFilterDef(factory = EdgeNGramFilterFactory.class, params = 
{ @Parameter(name = "maxGramSize", value = "1024") }),})
@Analyzer(definition = "myanalyzer")
public class Shop implements Serializable {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
enter code here

@Field(index = Index.YES, store = Store.YES, analyze = Analyze.YES)
@Column(name = "name")
private String name;

... other methods

我的查询

 Query lucenQuery = qb.keyword().onField("name").matching(searchTerm).createQuery();

这只是一个基本查询,我只专注于分析器配置以获取所需的内容,这确实令人困惑,我应该专注于哪一部分才能实现所需的标记化?过滤?还是查询本身? 无论如何,我已经索引了这两个词组。

"Apache Lychee Department" 
"Apache Strawberry Club Large"

当我处理/查询“ Straw”时,它会给我 Apache Strawberry Club Large 但是当我处理/查询“ Lychee ”或“ Apache Lychee ”时,查询给了我两个?我只期望 Apache Lychee Department

我了解我所有配置的方式是

EdgeNGramFilterFactory (1024)将为我提供一系列1,024个EdgeNGrams索引

LowerCaseFilterFactory 将给我所有小写的索引

WordDelimiterFilterFactory 通过将查询作为一个单词对其进行过滤,并提供匹配的数据。

,每个条目/数据将由 KeywordTokenizerFactory 标记为关键字,并由EdgeNGram索引1,024

我试图查询一个短语,但仍然得到相同的输出

  Query luceneQuery = qb.phrase().onField("name").sentence(searchTerm).createQuery();

我的目标是进行自动建议。或者至少从模仿sql的“ LIKE”开始。

2 个答案:

答案 0 :(得分:0)

您应该考虑两件事:

  • 默认情况下,当查询中有多个术语时,结果将包括与任何个术语匹配的文档,而不是与 all 个术语匹配的文档。
  • 默认情况下,将使用与建立索引时使用的分析器相同的分析器来分析您的查询。

这尤其意味着您的查询“ Lychee”将被分析为“ L Ly Lyc Lych Lyche Lychee”之类的东西(由于使用了边缘ngram过滤器)。之前已对字符串“ Apache Strawberry Club Large”进行了分析,由于使用了边缘ngram过滤器,因此将“ Large”一词扩展为“ L La Lar Larg Large”。因此,查询“ Lychee”将与“ Apache Strawberry Club Large”匹配,仅仅是因为它们都包含一个以L ...开头的单词。

这显然是不受欢迎的行为。

第一步是更改查询分析的方式,以免最终匹配完全不相关的文档。 基本上,您将需要定义另一个几乎相同的分析器,但没有“ edge ngram”过滤器。然后,您需要告诉Hibernate Search使用该分析器来分析您的查询。

有关详细说明,请参见this answer

第二步,如果文档中存在 all 个条款,则需要使查询匹配。为此,最简单的解决方案是使用simple query string query代替关键字查询。

替换此:

Query lucenQuery = qb.keyword().onField("name").matching(searchTerm).createQuery();

与此:

Query lucenQuery = qb.simpleQueryString().onField("name").withAndAsDefaultOperator().matching(searchTerm).createQuery();

键是对.withAndAsDefaultOperator()的呼叫。

此更改将产生其他一些效果,例如在输入字符串中启用特殊语法,因此,我建议您阅读参考文档以了解simpleQueryString的确切含义。

答案 1 :(得分:0)

通过@yrodiere,我做到了这一点

@Indexed
@Table (name = "shop_table")
@Entity
@AnalyzerDef(name = "edgeNgram",
    tokenizer = @TokenizerDef(factory = WhitespaceTokenizerFactory.class),
    filters = {
            @TokenFilterDef(factory = LowerCaseFilterFactory.class),
            @TokenFilterDef(factory = EdgeNGramFilterFactory.class, params = 
                                      { @Parameter(name = "maxGramSize", value = "1024") }),
    })
@AnalyzerDef(name = "search_query_analyzer",
    tokenizer = @TokenizerDef(factory = WhitespaceTokenizerFactory.class),
    filters = {
            @TokenFilterDef(factory = ASCIIFoldingFilterFactory.class),
            @TokenFilterDef(factory = LowerCaseFilterFactory.class)
    })
public class Shop implements Serializable {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;


@Field(store = Store.YES, analyze = Analyze.YES)
@Column(name = "name")
@Analyzer(definition = "edgeNgram")
private String name;

public void setName(String name) {
    this.name = name;
}

public String getName() {
    return this.name;
}
}

和我的查询

  QueryBuilder qb = fullTextEntityManager.getSearchFactory().buildQueryBuilder().forEntity(Shop.class)
            .overridesForField("name", "search_query_analyzer").get();

    Query lucenQuery = qb.simpleQueryString().onField("name").withAndAsDefaultOperator().matching(shopSearchTerm).createQuery();

但是我不确定我是否以正确的方法实施它。.