使用 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();