[英]Hibernate search to find partial matches of a phrase
In my project we are using hibernate search 4.5 with lucene-analyzers and solar.在我的项目中,我们使用带有 lucene 分析器和太阳能的休眠搜索 4.5。 I provide a text field to my clients.
我为我的客户提供了一个文本字段。 When they type in a phrase I would like to find all
User
entities whose names include the given phrase.当他们输入一个短语时,我想找到名称包含给定短语的所有
User
实体。
For example consider having list of entries in database with following titles:例如,考虑在数据库中有以下标题的条目列表:
[ Alan Smith, John Cane, Juno Taylor, Tom Caner Junior ]
jun
should return Juno Taylor
and Tom Caner Junior
jun
应该回归Juno Taylor
和小Tom Caner Junior
an
should return Alan Smith
, John Cane
and 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;
}
I have tried with wildcard search but我试过通配符搜索,但
Wildcard queries do not apply the analyzer on the matching terms. 通配符查询不会在匹配项上应用分析器。 Otherwise the risk of * or ?
否则风险 * 或 ? being mangled is too high.
被伤害太高了。
Query luceneQuery = mythQB
.keyword()
.wildcard()
.onFields("fname")
.matching("ju*")
.createQuery();
How can I achieve this?我怎样才能做到这一点?
First, you didn't assign the analyzer to your field, so it isn't used currently.首先,您没有将分析器分配给您的字段,因此当前未使用它。 You should use @Field.analyzer.
你应该使用@Field.analyzer。
Second, to answer your question, this kind of text is best analyzed with an EdgeNGramFilter
.其次,要回答您的问题,最好使用
EdgeNGramFilter
分析此类文本。 You should add this filter to your analyzer definition.您应该将此过滤器添加到您的分析器定义中。
EDIT: Also, to prevent queries such as "sathya" from matching "sanchana" for instance, you should use a different analyzer when querying.编辑:另外,为了防止诸如“sathya”之类的查询匹配“sachana”,您应该在查询时使用不同的分析器。
Below is a full example.下面是一个完整的例子。
@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;
}
And then specifically mention that you want to use this "query" analyzer when building your query:然后特别提到你想在构建查询时使用这个“查询”分析器:
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);
See also: https://stackoverflow.com/a/43047342/6692043另见: https : //stackoverflow.com/a/43047342/6692043
By the way, if your data includes only first and last names, you shouldn't use stemming ( SnowballPorterFilterFactory
): it will only make the search less accurate for no good reason.顺便说一句,如果您的数据仅包含名字和姓氏,则不应使用词干提取 (
SnowballPorterFilterFactory
):它只会无缘无故地降低搜索的准确性。
Why not use a standard TypedQuery
?为什么不使用标准的
TypedQuery
?
(where String term
is your search-term) (其中
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 + "%");
Didn't test this one, but something like this should do the trick.没有测试这个,但是这样的事情应该可以解决问题。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.