Lucene Hibernate Search | ngram分析器,具有minGramSize 1

Lucene Hibernate Search | ngram分析器,具有minGramSize 1,lucene,hibernate-search,n-gram,analyzer,Lucene,Hibernate Search,N Gram,Analyzer,我的Hibernate搜索分析器配置有一些问题。 我的一个索引实体(“医院”)有一个字符串字段(“名称”),可以包含长度为1-40的值。我希望能够通过搜索一个字符来找到实体(因为医院可能只有一个字符名) 如果添加名为“我的测试医院”的医院,Lucene索引如下所示: 1 name al 1 name e 1 name es 1 name est 1 name h 1 name ho 1 name hos 1 name

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

如果添加名为“我的测试医院”的医院,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();  

所以问题是,有人知道更好的analyzer配置或其他构建搜索查询的方法来解决问题吗

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

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


此外,如果您正在实现某种自动完成(
foo*
),而不是在word搜索(
*foo*
)中,您可能希望使用
EdgeNGramFilterFactory
而不是
NGramFilterFactory
:它将只生成作为索引令牌前缀的Ngram。

您可以设置第二个分析器,相同,只是它没有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。

Yoann的回答是正确的,添加了一些建议:不要使用如此大的
maxGramSize
:对于大多数用例,选择3或4。此外,您可能希望使用多个@field注释为同一字段编制索引:为每个字段指定不同的名称和不同的分析器,然后在查询时执行针对这两个字段的布尔查询,每个都有正确的分析器。Yoann的回答是正确的,并添加了一些建议:不要使用如此大的
maxGramSize
:对于大多数用例,选择3或4。此外,您可能希望使用多个@field注释为同一字段编制索引:为每个字段指定不同的名称和不同的分析器,然后在查询该字段时,使用正确的分析器针对这两个字段执行布尔查询。谢谢您的帮助。这几乎解决了问题,但是否有可能覆盖所有字段的分析器?我有许多具有相同问题的嵌入式索引实体。所以我必须重写它们所有(.overridesForField(“careUnits.name”…)也许可以加载一个“my_analyzer”的实例,而不使用“ngrams”通过编程并使用此实例生成搜索查询?@Andre您能提供您正在使用的实际代码吗?我在原始问题中只看到一个字段,因此我看不出问题的确切原因,解决方案可能会根据问题的性质而有所不同。您是否生成一个针对多个字段的查询?多个查询,each针对单个字段?其他?在最初的问题中,我试图分解复杂性。我在实际实现中有更多的索引实体。这就是我目前实现搜索的方式:。它是这样工作的,但在我看来,所有字段的手动覆盖都有点脏。因此,如果你知道一个更好的方法为了解决这个问题,我会很高兴你的解决方案。谢谢你的帮助和你的时间。好的,从你正在做的事情来看,你最好使用
org.apache.lucene.queryparser.simple.simplequalyparser
解析搜索字符串。只需使用
simplequalyparser(Analyzer Analyzer,Map weights)
constructor,并通过执行
fullTextSession.getSearchFactory().getAnalyzer(“搜索”)检索您的分析器
。请注意,我们正在进行中,但在5.8之前,最多几周内将无法提供。@yrodiere我对这个答案很感兴趣,但您能否更详细地解释覆盖的工作原理?也许可以举个例子?谢谢您的帮助。这几乎解决了问题,但是否有可能覆盖所有f的分析器IELD?我有许多具有相同问题的嵌入式索引实体。因此我必须覆盖它们所有(.overridesForField(“careUnits.name”…)也许可以加载“my_analyzer”的实例,而不加载任何内存通过编程并使用此实例生成搜索查询?@Andre您能提供您正在使用的实际代码吗?我在原始问题中只看到一个字段,因此我看不出问题的确切原因,解决方案可能会根据问题的性质而有所不同。您是否生成一个针对多个字段的查询?多个查询,each针对单个字段?其他?在最初的问题中,我试图分解复杂性。我在实际实现中有更多的索引实体。这就是我目前实现搜索的方式:。它是这样工作的,但在我看来,所有字段的手动覆盖都有点脏。因此,如果你知道一个更好的方法为了解决这个问题,我会很高兴你的解决方案。谢谢你的帮助和你的时间。好的,从你正在做的事情来看,你最好使用
org.apache.lucene.queryparser.simple.simplequalyparser
解析搜索字符串。只需使用
simplequalyparser(Analyzer Analyzer,Map weights)
constructor,并通过执行
fullTextSession.getSearchFactory().getAnalyzer(“搜索”)检索您的分析器
。请注意,我们正在进行中,但在5.8之前,最多几周内无法提供该选项。@yrodiere我对这个答案很感兴趣,但您能否更详细地解释覆盖的工作原理?也许可以举个例子?
QueryBuilder hospitalQb = fullTextEntityManager.getSearchFactory().buildQueryBuilder().forEntity(Hospital.class)
    .overridesForField( "name", "my_analyzer_without_ngrams" )
    .get();
// Then it's business as usual