lucene Hibernate搜索多个实体

ego6inou  于 2022-11-07  发布在  Lucene
关注(0)|答案(1)|浏览(159)

是否有可能搜索多个实体的同一关键字,过滤每一个类型与特定的过滤器,并获得他们在一个单一的列表?
例如,具有实体、饲养者和动物,并在它们的数据中搜索术语“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();
sz81bmfz

sz81bmfz1#

假设你不关心饲养者和动物之间的关系,而只想搜索动物OR饲养者:是,你可以的。
但有一些条件:

  • 您将应用“Boston Terrier”术语过滤器的字段必须在Animal类和Breeder类中以 * 完全相同的方式 * 进行配置:相同的分析器。否则,您的搜索结果可能会不一致。字段不必同时存在于两个索引中:在“animalName”和“breederName”字段上进行过滤应该可以正常工作。
  • 你想用来按位置过滤饲养者的位置字段Animal类中不能存在。否则,动物也会按位置过滤。
  • Breeder类中不能存在用于按物种筛选动物的物种字段。否则,饲养者也将按物种筛选。

如果以上三个问题的答案都是“是的,我很好”,那么你可以做下面的事情。
编辑:现在我强烈建议升级到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类和Breeder类传递给createFullTextQuery方法。
查询应返回动物和饲养员。
大概是这样的:

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 );

相关问题