使用 Hibernate Search 对 JPA 查询结果执行全文搜索
Performing Full Text Search on Results of JPA Query Using Hibernate Search
我有 3 个实体:
public class Parent{
@Id
@Column(name = "id", nullable = false)
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
@Field(name ="name")
private String name;
@OneToMany(targetEntity = Child.class)
private Set<Child> children;
}
public class Child{
@Id
@Column(name = "id", nullable = false)
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
@ManyToOne(targetEntity = Parent.class)
private Parent parent;
@ManyToOne(targetEntity = GrandChild.class)
private GrandChild grandchild;
}
public class GrandChild{
@Id
@Column(name = "id", nullable = false)
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
}
我目前使用休眠搜索对父级中的“名称”执行全文搜索。我想允许用户提供 GrandChild.id,使用普通的 JPA 查询来获取所有与 Grandchild 相关联的 Parents,然后使用 Hibernate Search 对名称执行全文搜索。
这可能吗?
除非您有非常具体的要求,否则我不建议混合使用 JPA 查询和全文搜索查询;这会使事情变得复杂,并可能导致性能瓶颈。
事实是,仅使用 Hibernate Search 执行整个查询是完全可能的,方法是向全文查询添加两个谓词:一个关于姓名,一个关于孙子 ID。
第 1 步:确保使用 @IndexedEmbeded
:
在 Parent
中包含孙子(及其 ID)
@Indexed // THIS IS NEW
public class Parent{
@Id
@Column(name = "id", nullable = false)
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
@Field(name ="name") // Removed "nullable" here, this attribute doesn't exist
private String name;
// Don't forget to add the missing "mappedBy" here
@OneToMany(targetEntity = Child.class, mappedBy = "parent")
@IndexedEmbedded // THIS IS NEW
private Set<Child> children;
}
public class Child{
@Id
@Column(name = "id", nullable = false)
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
@ManyToOne(targetEntity = Parent.class)
@ContainedIn // THIS IS NEW
private Parent parent;
@IndexedEmbedded(includePaths = "id") // THIS IS NEW
@ManyToOne(targetEntity = GrandChild.class)
private GrandChild grandchild;
}
public class GrandChild{
@Id
@Field // THIS IS NEW
@Column(name = "id", nullable = false)
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
// THIS IS NEW
@OneToMany(targetEntity = Child.class, mappedBy = "grandchild")
@ContainedIn
private Set<Child> parents = new HashSet<>();
}
第 2 步:检查更新实体的代码。您必须确保无论何时在一侧创建或更新关联(例如 Child.grandchild
),您也会更新另一侧(例如 GrandChild.parents
)。
第 3 步:reindex
FullTextSession fullTextSession = Search.getFullTextSession( session );
fullTextSession.createIndexer().startAndWait();
第四步:查询
// Input
int grandChildId = ...;
String terms = ...;
FullTextSession fullTextSession = Search.getFullTextSession( session );
QueryBuilder qb = fullTextSession.getSearchFactory()
.buildQueryBuilder().forEntity( Parent.class ).get();
Query luceneQuery = qb.bool()
.must( qb.keyword().onField( "name" ).matching( terms ) )
.must( qb.keyword().onField( "children.grandchild.id" )
.matching( grandChildId ) )
.createQuery();
org.hibernate.Query query =
fullTextSession.createFullTextQuery( luceneQuery, Parent.class );
List<Parent> result = query.list();
我有 3 个实体:
public class Parent{
@Id
@Column(name = "id", nullable = false)
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
@Field(name ="name")
private String name;
@OneToMany(targetEntity = Child.class)
private Set<Child> children;
}
public class Child{
@Id
@Column(name = "id", nullable = false)
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
@ManyToOne(targetEntity = Parent.class)
private Parent parent;
@ManyToOne(targetEntity = GrandChild.class)
private GrandChild grandchild;
}
public class GrandChild{
@Id
@Column(name = "id", nullable = false)
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
}
我目前使用休眠搜索对父级中的“名称”执行全文搜索。我想允许用户提供 GrandChild.id,使用普通的 JPA 查询来获取所有与 Grandchild 相关联的 Parents,然后使用 Hibernate Search 对名称执行全文搜索。
这可能吗?
除非您有非常具体的要求,否则我不建议混合使用 JPA 查询和全文搜索查询;这会使事情变得复杂,并可能导致性能瓶颈。
事实是,仅使用 Hibernate Search 执行整个查询是完全可能的,方法是向全文查询添加两个谓词:一个关于姓名,一个关于孙子 ID。
第 1 步:确保使用 @IndexedEmbeded
:
Parent
中包含孙子(及其 ID)
@Indexed // THIS IS NEW
public class Parent{
@Id
@Column(name = "id", nullable = false)
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
@Field(name ="name") // Removed "nullable" here, this attribute doesn't exist
private String name;
// Don't forget to add the missing "mappedBy" here
@OneToMany(targetEntity = Child.class, mappedBy = "parent")
@IndexedEmbedded // THIS IS NEW
private Set<Child> children;
}
public class Child{
@Id
@Column(name = "id", nullable = false)
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
@ManyToOne(targetEntity = Parent.class)
@ContainedIn // THIS IS NEW
private Parent parent;
@IndexedEmbedded(includePaths = "id") // THIS IS NEW
@ManyToOne(targetEntity = GrandChild.class)
private GrandChild grandchild;
}
public class GrandChild{
@Id
@Field // THIS IS NEW
@Column(name = "id", nullable = false)
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
// THIS IS NEW
@OneToMany(targetEntity = Child.class, mappedBy = "grandchild")
@ContainedIn
private Set<Child> parents = new HashSet<>();
}
第 2 步:检查更新实体的代码。您必须确保无论何时在一侧创建或更新关联(例如 Child.grandchild
),您也会更新另一侧(例如 GrandChild.parents
)。
第 3 步:reindex
FullTextSession fullTextSession = Search.getFullTextSession( session );
fullTextSession.createIndexer().startAndWait();
第四步:查询
// Input
int grandChildId = ...;
String terms = ...;
FullTextSession fullTextSession = Search.getFullTextSession( session );
QueryBuilder qb = fullTextSession.getSearchFactory()
.buildQueryBuilder().forEntity( Parent.class ).get();
Query luceneQuery = qb.bool()
.must( qb.keyword().onField( "name" ).matching( terms ) )
.must( qb.keyword().onField( "children.grandchild.id" )
.matching( grandChildId ) )
.createQuery();
org.hibernate.Query query =
fullTextSession.createFullTextQuery( luceneQuery, Parent.class );
List<Parent> result = query.list();