在我的项目中,我们正在使用带有lucene-analyzers和solar的hibernate search 4.5。
我向客户提供了一个文本字段。当他们输入短语时,我想找到名称中包含给定短语的所有User
个实体。
例如,考虑在数据库中包含以下标题的条目列表:
[ Alan Smith, John Cane, Juno Taylor, Tom Caner Junior ]
jun
应该返回Juno Taylor
和Tom Caner Junior
an
应该返回Alan Smith
,John Cane
和Tom Caner Junior
@AnalyzerDef(name = "customanalyzer", tokenizer = @TokenizerDef(factory = WhitespaceTokenizerFactory.class), filters = {
@TokenFilterDef(factory = LowerCaseFilterFactory.class),
@TokenFilterDef(factory = SnowballPorterFilterFactory.class, params = { @Parameter(name = "language", value = "English") })
})
@Analyzer(definition = "customanalyzer")
public class Student implements Serializable {
@Column(name = "Fname")
@Field(index = Index.YES, store = Store.YES, analyze = Analyze.YES)
private String fname;
@Column(name = "Lname")
@Field(index = Index.YES, store = Store.YES, analyze = Analyze.YES)
private String lname;
}
我尝试使用通配符搜索,但
Query luceneQuery = mythQB
.keyword()
.wildcard()
.onFields("fname")
.matching("ju*")
.createQuery();
我怎样才能做到这一点?
答案 0 :(得分:2)
首先,您没有将分析仪分配到您的字段,因此当前未使用它。你应该使用@ Field.analyzer。
其次,要回答您的问题,最好使用EdgeNGramFilter
分析此类文本。您应该将此过滤器添加到分析仪定义中。
编辑另外,为避免“sathya”等查询与“sanchana”匹配,您应该在查询时使用其他分析器。
以下是一个完整的例子。
@AnalyzerDef(name = "customanalyzer", tokenizer = @TokenizerDef(factory = WhitespaceTokenizerFactory.class), filters = {
@TokenFilterDef(factory = LowerCaseFilterFactory.class),
@TokenFilterDef(factory = SnowballPorterFilterFactory.class, params = { @Parameter(name = "language", value = "English") })
@TokenFilterDef(factory = EdgeNGramFilterFactory.class, params = { @Parameter(name = "maxGramSize", value = "15") })
})
@AnalyzerDef(name = "customanalyzer_query", tokenizer = @TokenizerDef(factory = WhitespaceTokenizerFactory.class), filters = {
@TokenFilterDef(factory = LowerCaseFilterFactory.class),
@TokenFilterDef(factory = SnowballPorterFilterFactory.class, params = { @Parameter(name = "language", value = "English") })
})
public class Student implements Serializable {
@Column(name = "Fname")
@Field(index = Index.YES, store = Store.YES, analyze = Analyze.YES, analyzer = @Analyzer(definition = "customanalyzer"))
private String fname;
@Column(name = "Lname")
@Field(index = Index.YES, store = Store.YES, analyze = Analyze.YES, analyzer = @Analyzer(definition = "customanalyzer")))
private String lname;
}
然后特别提到您在构建查询时要使用此“查询”分析器:
QueryBuilder queryBuilder = fullTextEntityManager.getSearchFactory().buildQueryBuilder().forEntity(Student.class)
// Here come the assignments of "query" analyzers
.overridesForField( "fname", "customanalyzer_query" )
.overridesForField( "lname", "customanalyzer_query" )
.get();
// Then it's business as usual
Query luceneQuery = queryBuilder.keyword().onFields("fname", "lname").matching("sathya").createQuery();
FullTextQuery query = fullTextEntityManager.createFullTextQuery(luceneQuery, Student.class);
另请参阅:https://stackoverflow.com/a/43047342/6692043
顺便说一句,如果您的数据只包含名字和姓氏,则不应使用词干(SnowballPorterFilterFactory
):它只会使搜索不准确,无理由。
答案 1 :(得分:0)
为什么不使用标准TypedQuery
?
(String term
是您的搜索词)
TypedQuery<Student> q = em.createQuery(
"SELECT s " +
"FROM Student s " +
"WHERE s.fname like :search " +
"OR s.lname like :search";
q.setParameter("search", "%" + term + "%");
没有测试过这个,但是这样的事情应该可以解决问题。