【问题标题】:Hibernate Search | ngram analyzer with minGramSize 1休眠搜索 |具有 minGramSize 1 的 ngram 分析器
【发布时间】:2017-08-20 00:56:33
【问题描述】:

我的 Hibernate Search 分析器配置存在一些问题。 我的索引实体之一(“医院”)有一个字符串字段(“名称”),它可以包含长度为 1-40 的值。我希望能够通过仅搜索一个字符来找到一个实体(因为医院可能有单个字符名称)。

@Indexed(index = "HospitalIndex")
@AnalyzerDef(name = "ngram",
        tokenizer = @TokenizerDef(factory = StandardTokenizerFactory.class),
        filters = {
                @TokenFilterDef(factory = StandardFilterFactory.class),
                @TokenFilterDef(factory = LowerCaseFilterFactory.class),
                @TokenFilterDef(factory = NGramFilterFactory.class,
                        params = {
                                @Parameter(name = "minGramSize", value = "1"),
                                @Parameter(name = "maxGramSize", value = "40")})
        })
public class Hospital {

        @Field(index = Index.YES, analyze = Analyze.YES, store = Store.NO, analyzer = @Analyzer(definition = "ngram"))
        private String name = "";
}

如果我添加一个名为“我的测试医院”的医院,Lucene 索引如下所示:

1   name    al
1   name    e
1   name    es
1   name    est
1   name    h
1   name    ho
1   name    hos
1   name    hosp
1   name    hospi
1   name    hospit
1   name    hospita
1   name    hospital
1   name    i
1   name    it
1   name    ita
1   name    ital
1   name    l
1   name    m
1   name    my
1   name    o
1   name    os
1   name    osp
1   name    ospi
1   name    ospit
1   name    ospita
1   name    ospital
1   name    p
1   name    pi
1   name    pit
1   name    pita
1   name    pital
1   name    s
1   name    sp
1   name    spi
1   name    spit
1   name    spita
1   name    spital
1   name    st
1   name    t
1   name    ta
1   name    tal
1   name    te
1   name    tes
1   name    test
1   name    y
1   name    a

这就是我构建和执行搜索查询的方式:

QueryBuilder hospitalQb = fullTextEntityManager.getSearchFactory().buildQueryBuilder().forEntity(Hospital.class).get();
Query hospitalQuery = hospitalQb.keyword().onFields("name")().matching(searchString).createQuery();
javax.persistence.Query persistenceQuery = fullTextEntityManager.createFullTextQuery(hospitalQuery, Hospital.class);
List<Hospital> results = persistenceQuery.getResultList();  

问题是我的搜索查询也使用了相同的 ngram 分析器。因此,当我搜索“医院”时,我会找到名称中包含“a”字符的所有医院。 这是搜索查询的样子,当我在其上调用 toString 方法时:

name:h name:ho name:hos name:hosp name:hospi name:hospit name:hospita name:hospital name:o name:os name:osp name:ospi name:ospit name:ospita name:ospital name:s name:sp name:spi name:spit name:spita name:spital name:p name:pi name:pit name:pita name:pital name:i name:it name:ita name:ital name:t name:ta name:tal name:a name:al name:l

所以问题是,是否有人知道更好的分析器配置或其他方式构建解决问题的搜索查询?

【问题讨论】:

  • Yoann 的回答是正确的 添加一些建议:不要使用这么大的maxGramSize:对于大多数用例,请选择 3 或 4。此外,您可能希望使用索引相同的字段多个@Field 注释:给每个注释一个不同的名称和一个不同的分析器,然后当您查询它时,您执行一个针对两个字段的布尔查询,每个字段都有其正确的分析器。

标签: lucene hibernate-search n-gram analyzer


【解决方案1】:

您可以设置第二个分析器,除了没有 ngram 过滤器外,其他相同,然后覆盖用于查询的分析器:

QueryBuilder hospitalQb = fullTextEntityManager.getSearchFactory().buildQueryBuilder().forEntity(Hospital.class)
    .overridesForField( "name", "my_analyzer_without_ngrams" )
    .get();
// Then it's business as usual

此外,如果您正在实现某种自动完成 (foo*),而不是字内搜索 (*foo*),您可能希望使用 EdgeNGramFilterFactory 而不是 NGramFilterFactory:它只会生成作为索引标记前缀的 ngram。

【讨论】:

  • 感谢您的帮助。这几乎解决了问题,但是是否有可能覆盖所有字段的分析器?我有许多具有相同问题的嵌入式索引实体。所以我必须全部覆盖它们( .overridesForField( "careUnits.name" ....) 也许可以以编程方式加载“my_analyzer_without_ngrams”的实例并使用此实例构建搜索查询?
  • @Andre 你能提供你正在使用的实际代码吗?我在您的原始问题中只看到一个字段,所以我看不出问题到底是什么,并且解决方案可能会因问题的性质而异。您是否构建一个针对多个字段的查询?多个查询,每个都针对一个字段?还有什么?
  • 在最初的问题中,我试图分解复杂性。在实际实现中,我有更多一个索引实体。这就是我目前实现搜索的方式:PastBin。它以这种方式工作,但在我看来,所有字段的所有手动覆盖都有点脏。因此,如果您知道解决此问题的更好方法,我会对您的解决方案感到高兴。感谢您的帮助和时间。
  • 好的,从你所做的判断,你最好使用org.apache.lucene.queryparser.simple.SimpleQueryParser 来解析搜索字符串。只需使用SimpleQueryParser(Analyzer analyzer, Map&lt;String, Float&gt; weights) 构造函数,并通过执行fullTextSession.getSearchFactory().getAnalyzer("search") 检索您的分析器。请注意,我们正在处理adding support for such parsing to the QueryBuilder,但在 5.8 之前,最多几周后才能使用。
  • @yrodiere 我对这个答案很感兴趣,但你能更详细地解释一下覆盖的工作原理吗?也许有一个例子?
猜你喜欢
  • 2017-04-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-03-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多