目前,我已经成功配置了一个基本的Hibernate Search索引,以便能够在我的JPA实体的各个字段中搜索完整的单词:
@Entity
@Indexed
class Talk {
@Field String title
@Field String summary
}
我的查询看起来像这样:
List<Talk> search(String text) {
FullTextEntityManager fullTextEntityManager = Search.getFullTextEntityManager(entityManager)
QueryBuilder queryBuilder = fullTextEntityManager.getSearchFactory().buildQueryBuilder().forEntity(Talk).get()
Query query = queryBuilder
.keyword()
.onFields("title", "summary")
.matching(text)
.createQuery()
FullTextQuery jpaQuery = fullTextEntityManager.createFullTextQuery(query, Talk)
return jpaQuery.getResultList()
}
现在我想微调这个设置,以便在我搜索&#34; test&#34;它仍然会找到标题或摘要包含&#34; test&#34;甚至作为另一个单词的前缀。所以题为'#34;单元测试&#34;或其摘要包含&#34;睾丸&#34;应该仍然出现在搜索结果中,而不仅仅是那些标题或摘要包含&#34; test&#34;作为一个完整的词。
我试图查看文档,但我无法弄清楚我是否应该改变我的实体被编入索引的方式,或者它是否与查询有关。请注意,我想做类似以下的事情,但是在几个字段上搜索很难:
Query query = queryBuilder
.keyword().wildcard()
.onField("title")
.matching(text + "*")
.createQuery()
编辑: 根据哈代的回答,我按照这样的方式配置了我的实体:
@Indexed
@Entity
@AnalyzerDefs([
@AnalyzerDef(name = "ngram",
tokenizer = @TokenizerDef(factory = StandardTokenizerFactory.class),
filters = [
@TokenFilterDef(factory = LowerCaseFilterFactory.class),
@TokenFilterDef(factory = NGramFilterFactory.class,
params = [
@Parameter(name = "minGramSize",value = "3"),
@Parameter(name = "maxGramSize",value = "3")
])
])
])
class Talk {
@Field(analyzer=@Analyzer(definition="ngram")) String title
@Field(analyzer=@Analyzer(definition="ngram")) String summary
}
感谢这种配置,当我搜索“艺术”时,我会谈到标题或摘要中包含“艺术”的词语。是(艺术家,手工艺品等)的一个子词。不幸的是,在那些之后我也会得到会谈,其中标题或摘要包含包含我的搜索词(艺术,放屁等)的子词的单词。可能有一些微调可以消除这些,但至少我现在得到的结果很快,而且它们处于合理的顺序。
答案 0 :(得分:3)
你可以在这里做很多事情。在索引时间内通过适当的分析可以做很多事情。
例如,您想要应用适合您语言的词干分析器。对于英语,这通常是Snowball词干分析器。这个想法是,在索引编制过程中,所有单词都缩减为词干,例如测试和测试到_test。这会让你有所作为。
您可以研究的另一件事是ngramm索引。根据您的描述,您也希望在无关词中找到匹配。这里的想法是索引每个单词的“子词”,以便以后可以找到它们。
关于分析器,您需要查看Hibernate Search文档的named analyzers部分。这里的关键是@AnalyzerDef
注释。
在查询方面,您还可以应用一些“技巧”。实际上,您可以使用通配符查询,但是,如果您使用的是Hibernate Search查询DSL,则不能使用keyword
查询,但需要使用wildcard
查询。再次,查看Hibernate Search文档。
答案 1 :(得分:1)
您应该使用Ngram
或EdgeNGram
过滤索引,因为您在答案中已正确记录。但是您应该按照lucene文档中的建议使用不同的分析器进行查询(请参阅search_analyzer
):
https://www.elastic.co/guide/en/elasticsearch/guide/current/_index_time_search_as_you_type.html
这样,您的搜索查询就不会被标记为ngrams,而您的结果将更像SQL中的%text%
或text%
。
不幸的是,由于未知原因,Hibernate Search目前不支持search_analyzer
字段规范。您只能使用特定的分析器进行索引,这也可用于搜索查询分析。
我计划自己实现此功能。
修改强>
您可以指定搜索时间分析器(search_analyzer
),如下所示:
List<Talk> search(String text) {
FullTextEntityManager fullTextEntityManager = Search.getFullTextEntityManager(entityManager)
EntityContext entityContext = fullTextEntityManager.getSearchFactory().buildQueryBuilder().forEntity(Talk);
entityContext.overridesForField("myField", "myNamedAnalyzerDef");
QueryBuilder queryBuilder = ec.get()
Query query = queryBuilder
.keyword()
.onFields("title", "summary")
.matching(text)
.createQuery()
FullTextQuery jpaQuery = fullTextEntityManager.createFullTextQuery(query, Talk)
return jpaQuery.getResultList()
}
我已经使用这种技术来有效地模拟Lucene search_analyzer
属性。
答案 2 :(得分:0)
在Lucene 4.9版中,我使用了EnglishAnalyzer
。我认为这是SnowballAnalyzer的英文版实现,但不是100%肯定。我用它来创建和搜索索引。使用它没有什么特别需要。
Analyzer analyzer = new EnglishAnalyzer(Version.LUCENE_4_9);
IndexWriterConfig iwc = new IndexWriterConfig(Version.LUCENE_4_9, analyzer);
和
analyzer = new EnglishAnalyzer(Version.LUCENE_4_9);
parser = new StandardQueryParser(analyzer);
您可以在Guided Code Search看到它的实际效果。这完全在Lucene附近运行。
Lucene可以集成到Hibernate搜索中,但我还没有尝试过这样做。我似乎很强大,但我不知道:见Apache Lucene™ Integration。
我还读过lucene可以修补到SQL引擎中,但我也没有尝试过。示例:Indexing Databases with Lucene。