hibernate - Hibernate 搜索多个实体
问题描述
是否可以在多个实体中搜索相同的关键字,使用特定的过滤器过滤每种类型并将它们放在一个列表中?
例如,拥有实体、饲养员和动物,并在他们的数据中搜索术语“波士顿梗犬”。之后,筛选饲养员的位置和物种的动物,并返回一个包含动物和饲养员的列表。
然后可以修剪此列表以在 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();
解决方案
假设您不关心饲养员和动物之间的关系,只想搜索动物或饲养员:是的,您可以。
但是有一些条件:
- 您将应用“波士顿梗犬”术语过滤器的字段必须在班级和班级中以完全相同的方式配置:特别是相同的分析器。否则,您的搜索结果可能会不一致。这些字段不必在两个索引中都存在:对“animalName”和“breederName”字段进行过滤应该可以正常工作。
Animal
Breeder
- 您要用于按位置过滤育种者的位置字段不得存在于
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:
- 创建一个
QueryBuilder
forAnimal
,比如说animalQueryBuilder
- 创造另一个
QueryBuilder
,Breeder
说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 );
推荐阅读
- python - Jupyter:运行模型
- r - 使用 dplyr 排列行时引用循环中的变量
- amazon-s3 - 无法直接导航到托管在 s3 + cloudfront 上的网站
- css - css 可调整大小的 div 位置不同的大小
- jax-rs - 找不到媒体类型 = 应用程序/八位字节流的 MessageBodyWriter
- bash - read -t 没有在 bash 中暂停我的 while 循环
- r - 如何使用 R 语言在 Word Cloud 中将上下文的一部分变成其他颜色?
- android - 在我的计算器应用程序中,我引入了四个按钮,但是当我在输入值之前单击它们时,应用程序崩溃了。如何解决这个问题呢
- c# - System.ArgumentNullException: '值不能为空。参数名称:providerInvariantName'
- php - php strpos()无法在字符串中找到括号