Hibernate 搜索多个实体

Hibernate search multiple entities

是否可以为同一关键字搜索多个实体,使用特定过滤器过滤每种类型并将它们放在一个列表中?

例如,拥有实体、饲养员和动物,并在其数据中搜索术语 "Boston Terrier"。之后,饲养员根据位置和物种过滤动物,并返回包含动物和饲养员的单个列表。

然后可以修剪此列表以在 Web 应用程序的前端启用结果分页:

        // FullTextQuery ftq = .... definiing and filtering the query

        int numResults = ftq.getResultSize();
        ftq.setFirstResult((pageNum-1)*numPerPage);
        ftq.setMaxResults(numPerPage);

        List<Object> results = ftq.getResultList();

假设您不关心饲养者和动物之间的关系,只想搜索动物或饲养者:是的,您可以。

但是有一些条件:

  • 您将应用“波士顿梗犬”术语过滤器的字段必须按照 完全相同的方式Animal class 和 Breeder class: 特别是同一个分析器。否则,您的搜索结果可能会不一致。这些字段不必存在于两个索引中:过滤“animalName”和“breederName”字段应该可以正常工作。
  • 您要用于按位置筛选育种者的位置字段不得存在 Animal class。否则,动物也会按位置过滤。
  • 您要用于按物种筛选动物的物种字段不得存在 Breeder class。否则,饲养者也会被物种过滤。

如果以上三项的答案都是“是的,我很好”,那么您可以执行以下操作。


编辑:现在我强烈建议升级到 Hibernate Search 6.0 或更高版本,这使得在同一查询中搜索多个索引变得更加容易。

事实上,除了列出目标类型之外,您无需执行任何特定操作。

我的原始答案中的片段,转换为 Hibernate Search 6,看起来像这样:

EntityManager em = ...;
List<Object> hits = Search.session(em)
        .search(Arrays.asList(Animal.class, Breeder.class))
        .where(f -> f.bool()
                .must(f.simpleQueryString()
                        .fields("animalName",
                                "breeder.company.legalName",
                                "breeder.firstName",
                                "breeder.lastName")
                        .matching("Boston Terrier")
                        .defaultOperator(BooleanOperator.AND))
                .must(f.bool()
                        .should(f.spatial().within()
                               .field("breederLocation")
                               .circle(42.0, 42.0,
                                        50, DistanceUnit.KILOMETERS))
                        .should(f.match()
                               .field("species")
                               .matching(<some species>)))
        .fetchHits( 20 );

原始解决方案,用于 Hibernate Search 5:

  • Animal 创建一个 QueryBuilder,比如 animalQueryBuilder
  • Breeder 创建另一个 QueryBuilder,比如 breederQueryBuilder
  • 使用 animalQueryBuilder 作为物种过滤器。
  • 使用 breederQueryBuilder 作为位置过滤器
  • 使用一个构建器或另一个构建器(这无关紧要)作为术语过滤器

然后,在创建查询时,将 Animal class 和 Breeder class 传递给 createFullTextQuery 方法。

查询应 return 动物和育种者。

类似的东西:

QueryBuilder animalQueryBuilder = fullTextEntityManager.getSearchFactory().buildQueryBuilder().forEntity( Animal.class ).get();
QueryBuilder breederQueryBuilder = fullTextEntityManager.getSearchFactory().buildQueryBuilder().forEntity( Breeder.class ).get();

Query locationQuery = breederQueryBuilder.spatial()
    .onField( "breederLocation" )
    .within( 10.0, DistanceUnit.KM )
    .ofLatitude( 42.0 ).andLongitude( 42.0 )
    .createQuery();
Query speciesQuery = animalQueryBuilder.keyword()
    .onField( "species" )
    .matching( <some species> );
Query termsQuery = animalQueryBuilder.simpleQueryString()
    .onFields(
        "animalName", "breeder.company.legalName",
        "breeder.firstName", "breeder.lastName"
    )
    .withAndAsDefaultOperator()
    .matching( "Boston Terrier" );

Query booleanQuery = animalQueryBuilder.bool()
    .must( termsQuery )
    .must( animalQueryBuilder.bool()
        .should( locationQuery )
        .should( speciesQuery )
        .createQuery()
    )
    .createQuery();

FullTextQuery fullTextQuery = fullTextEntityManager.createFullTextQuery( booleanQuery, Animal.class, Breeder.class );