Hibernate Search:如何在单独的列中搜索全名
Hibernate Search: how to search a full name over separate columns
我有一个名为 'Patient' 的实体,其中包含名为 'firstName'、'lastName' 和 'secondLastName' 的字符串字段(在西班牙语中,我们同时使用父亲和母亲的姓氏)
我有一个带有文本框的视图,可以按姓名搜索患者,用户可以在其中键入任何内容:firstName、lastName、secondLastName 或这些的组合,以任何给定顺序。
例如,我的名字:
名字:毛里西奥,
姓氏:乌比拉,
secondLastName:Carvajal,
如果我搜索 "Mauricio Ubilla Carvajal" 甚至 "Mauricio Ubilla",我希望出现在结果列表的顶部。
问题是:
1- 我应该如何定义这 3 个字段的索引?我做了以下事情:
@Indexed
class Patient {
...
@Field(index=Index.YES, analyze=Analyze.YES, store=Store.NO)
protected String firstName = new String();
@Field(index=Index.YES, analyze=Analyze.YES, store=Store.NO)
protected String lastName = new String();
@Field(index=Index.YES, analyze=Analyze.YES, store=Store.NO)
protected String secondLastName = new String();
...
}
2- 我应该如何构建查询?我这样做了:
QueryBuilder qb = fullTextSession.getSearchFactory().buildQueryBuilder().forEntity(Patient.class).get();
Query luceneQuery = qb.keyword().onFields("firstName", "lastName", "secondLastName").matching(name).createQuery();
但是,这对我不起作用。它没有抛出任何异常,只是它没有 returning 任何东西。
即使我只是搜索 "Mauricio" 它也没有 return 任何东西。
但是,如果我只更改查询以匹配我的名字:
QueryBuilder qb = fullTextSession.getSearchFactory().buildQueryBuilder().forEntity(Patient.class).get();
Query luceneQuery = qb.keyword().onFields("firstName").matching(name).createQuery();
如果我搜索 "Mauricio" 它有效。
我做错了什么?有没有办法为 3 列定义一个复合索引?我应该以不同的方式构建查询吗?
请帮帮我 :(
顺便说一句,我在 Hibernate 4.3 和 Java 1.7
上使用 Hibernate Search 4.5.1
您使用的是非常旧的 Hibernate Search 版本,因此您很可能 运行 遇到了已在较新版本中解决的错误。您真的应该考虑至少升级到 Hibernate Search 5.6 / Hibernate ORM 5.1,或者甚至升级到 Search 5.8 / ORM 5.2(需要 Java 8)。
如果你不能...另一个常见的解决方案是索引一个瞬态 属性 其内容是连接的名称:
@Indexed
class Patient {
...
@Field
protected String firstName = "";
@Field
protected String lastName = "";
@Field
protected String secondLastName = "";
...
@javax.persistence.Transient
@Field
public String getFullName() {
// TODO null safety
return firstName + " " + lastName + " " + secondLastName;
}
...
}
然后查询这个fullName
:
QueryBuilder qb = fullTextSession.getSearchFactory().buildQueryBuilder().forEntity(Patient.class).get();
Query luceneQuery = qb.keyword().onFields("fullName").matching(name).createQuery();
请注意,与您最初的解决方案相反,这会对性能产生负面影响,因为索引 @Transient
字段会禁用某些优化。但至少它应该有效。
回答你的第二个问题。您可以使用短语作为句子而不是关键字进行搜索。
Hibernate Search 还支持使用各种策略组合查询:
-SHOULD:查询应该包含子查询的匹配元素
-MUST:查询必须包含子查询的匹配元素
-MUST NOT:查询不能包含子查询的匹配元素
聚合类似于布尔值 AND、OR 和 NOT。
Query combinedQuery = queryBuilder
.bool()
.must(queryBuilder.phrase()
.onField("productName).sentence("samsung galaxy s8")
.createQuery())
.must(queryBuilder.keyword()
.onField("productCategory").matching("smartphone")
.createQuery())
.createQuery();
// wrap Lucene query in an Hibernate Query object
org.hibernate.search.jpa.FullTextQuery jpaQuery =
fullTextEntityManager.createFullTextQuery(combinedQuery, Product.class);
// execute search and return results (sorted by relevance as default)
@SuppressWarnings("unchecked")
List<Product> results = jpaQuery.getResultList();
我有一个名为 'Patient' 的实体,其中包含名为 'firstName'、'lastName' 和 'secondLastName' 的字符串字段(在西班牙语中,我们同时使用父亲和母亲的姓氏)
我有一个带有文本框的视图,可以按姓名搜索患者,用户可以在其中键入任何内容:firstName、lastName、secondLastName 或这些的组合,以任何给定顺序。 例如,我的名字:
名字:毛里西奥, 姓氏:乌比拉, secondLastName:Carvajal,
如果我搜索 "Mauricio Ubilla Carvajal" 甚至 "Mauricio Ubilla",我希望出现在结果列表的顶部。 问题是:
1- 我应该如何定义这 3 个字段的索引?我做了以下事情:
@Indexed
class Patient {
...
@Field(index=Index.YES, analyze=Analyze.YES, store=Store.NO)
protected String firstName = new String();
@Field(index=Index.YES, analyze=Analyze.YES, store=Store.NO)
protected String lastName = new String();
@Field(index=Index.YES, analyze=Analyze.YES, store=Store.NO)
protected String secondLastName = new String();
...
}
2- 我应该如何构建查询?我这样做了:
QueryBuilder qb = fullTextSession.getSearchFactory().buildQueryBuilder().forEntity(Patient.class).get();
Query luceneQuery = qb.keyword().onFields("firstName", "lastName", "secondLastName").matching(name).createQuery();
但是,这对我不起作用。它没有抛出任何异常,只是它没有 returning 任何东西。 即使我只是搜索 "Mauricio" 它也没有 return 任何东西。
但是,如果我只更改查询以匹配我的名字:
QueryBuilder qb = fullTextSession.getSearchFactory().buildQueryBuilder().forEntity(Patient.class).get();
Query luceneQuery = qb.keyword().onFields("firstName").matching(name).createQuery();
如果我搜索 "Mauricio" 它有效。
我做错了什么?有没有办法为 3 列定义一个复合索引?我应该以不同的方式构建查询吗? 请帮帮我 :( 顺便说一句,我在 Hibernate 4.3 和 Java 1.7
上使用 Hibernate Search 4.5.1您使用的是非常旧的 Hibernate Search 版本,因此您很可能 运行 遇到了已在较新版本中解决的错误。您真的应该考虑至少升级到 Hibernate Search 5.6 / Hibernate ORM 5.1,或者甚至升级到 Search 5.8 / ORM 5.2(需要 Java 8)。
如果你不能...另一个常见的解决方案是索引一个瞬态 属性 其内容是连接的名称:
@Indexed
class Patient {
...
@Field
protected String firstName = "";
@Field
protected String lastName = "";
@Field
protected String secondLastName = "";
...
@javax.persistence.Transient
@Field
public String getFullName() {
// TODO null safety
return firstName + " " + lastName + " " + secondLastName;
}
...
}
然后查询这个fullName
:
QueryBuilder qb = fullTextSession.getSearchFactory().buildQueryBuilder().forEntity(Patient.class).get();
Query luceneQuery = qb.keyword().onFields("fullName").matching(name).createQuery();
请注意,与您最初的解决方案相反,这会对性能产生负面影响,因为索引 @Transient
字段会禁用某些优化。但至少它应该有效。
回答你的第二个问题。您可以使用短语作为句子而不是关键字进行搜索。
Hibernate Search 还支持使用各种策略组合查询:
-SHOULD:查询应该包含子查询的匹配元素
-MUST:查询必须包含子查询的匹配元素
-MUST NOT:查询不能包含子查询的匹配元素
聚合类似于布尔值 AND、OR 和 NOT。
Query combinedQuery = queryBuilder
.bool()
.must(queryBuilder.phrase()
.onField("productName).sentence("samsung galaxy s8")
.createQuery())
.must(queryBuilder.keyword()
.onField("productCategory").matching("smartphone")
.createQuery())
.createQuery();
// wrap Lucene query in an Hibernate Query object
org.hibernate.search.jpa.FullTextQuery jpaQuery =
fullTextEntityManager.createFullTextQuery(combinedQuery, Product.class);
// execute search and return results (sorted by relevance as default)
@SuppressWarnings("unchecked")
List<Product> results = jpaQuery.getResultList();