休眠搜索 |具有 minGramSize 1 的 ngram 分析器
Hibernate Search | ngram analyzer with minGramSize 1
我的 Hibernate Search 分析器配置有一些问题。
我的一个索引实体 ("Hospital") 有一个字符串字段 ("name"),它可以包含长度为 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 = "";
}
如果我添加名称为 "My Test Hospital" 的医院,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 分析器也用于我的搜索查询。因此,当我搜索 "hospital" 时,我会找到名称中包含 "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
所以问题是,是否有人知道更好的分析器配置或其他构建解决问题的搜索查询的方法?
Hibernate Search 6 的更新答案
使用 Hibernate Search 6,您可以定义第二个分析器,与您的“ngram”分析器相同,只是它没有 ngram 过滤器,并将其指定为您的字段的 searchAnalyzer
:
public class Hospital {
// ...
@FullTextField(analyzer = "ngram",
searchAnalyzer = "my_analyzer_without_ngrams")
private String name = "";
// ...
}
然后 Hibernate Search 会在索引时自动使用“ngram”分析器,但在搜索时会使用“my_analyzer_without_ngrams”,这将导致预期的行为。
此外,如果您正在实施某种自动完成 (foo*
),而不是词内搜索 (*foo*
),您可能需要使用 EdgeNGramFilterFactory
NGramFilterFactory
:它只会生成作为索引标记前缀的 ngram。
Hibernate Search 5 的原始答案
您可以设置第二个分析器,与您的“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。
我的 Hibernate Search 分析器配置有一些问题。 我的一个索引实体 ("Hospital") 有一个字符串字段 ("name"),它可以包含长度为 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 = "";
}
如果我添加名称为 "My Test Hospital" 的医院,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 分析器也用于我的搜索查询。因此,当我搜索 "hospital" 时,我会找到名称中包含 "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
所以问题是,是否有人知道更好的分析器配置或其他构建解决问题的搜索查询的方法?
Hibernate Search 6 的更新答案
使用 Hibernate Search 6,您可以定义第二个分析器,与您的“ngram”分析器相同,只是它没有 ngram 过滤器,并将其指定为您的字段的 searchAnalyzer
:
public class Hospital {
// ...
@FullTextField(analyzer = "ngram",
searchAnalyzer = "my_analyzer_without_ngrams")
private String name = "";
// ...
}
然后 Hibernate Search 会在索引时自动使用“ngram”分析器,但在搜索时会使用“my_analyzer_without_ngrams”,这将导致预期的行为。
此外,如果您正在实施某种自动完成 (foo*
),而不是词内搜索 (*foo*
),您可能需要使用 EdgeNGramFilterFactory
NGramFilterFactory
:它只会生成作为索引标记前缀的 ngram。
Hibernate Search 5 的原始答案
您可以设置第二个分析器,与您的“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。