我正在尝试将一个使用ElasticSearch的项目迁移到Hibernate Search。目前,我们通过组合由以下不同方法创建的多个QueryBuilder
对象来构建复杂的ElasticSearch查询:
protected QueryBuilder createSetQuery(String key, Set<?> values, boolean contains) {
if (contains && !values.isEmpty()) {
return QueryBuilders.termsQuery(key, values);
} else if (!contains && Objects.nonNull(values)) {
BoolQueryBuilder boolQuery = new BoolQueryBuilder();
return boolQuery.mustNot(QueryBuilders.termsQuery(key, values));
} else {
return QueryBuilders.matchQuery(key, 0);
}
}
然后,返回的QueryBuilder
对象通过BooleanQueryBuilder
对象组合到调用方法中,如下所示:
...
BoolQueryBuilder boolQuery = new BoolQueryBuilder();
boolQuery.must(createSetQuery(...);
...
现在,我尝试将这些方法迁移到类似的Hibernate Search方法中,返回SearchPredicate
s而不是QueryBuilder
s(阅读Hibernate Search文档https://docs.jboss.org/hibernate/stable/search/reference/en-US/html_single我得到的印象是最接近的匹配(:
protected SearchPredicate createSetSearchPredicate(Class<?> clazz, SearchSession searchSession, String fieldName,
Set<?> fieldValues, boolean contains) {
if (contains) {
SearchScope<?> scope = searchSession.scope(clazz);
SearchPredicateFactory factory = scope.predicate();
return factory.terms().field( fieldName ).matchingAny( fieldValues ).toPredicate();
} else {
SearchScope<?> scope = searchSession.scope(clazz);
SearchPredicateFactory factory = scope.predicate();
return factory.bool().mustNot(factory.terms().field( fieldName ).matchingAny( fieldValues )).toPredicate();
}
}
我遇到的问题是创建一个SearchPredicate
似乎总是需要一个给定的类和一个Hibernate SearchSearchSession
。有没有办法在没有这两个对象的情况下创建这样的SearchPredicate
实例?在类似的";阶级不可知论者;就像构建ElasticSearchQueryBuilder
一样?
目前,我必须选择
- 在最外层的调用方法中创建
SearchSession
,并通过所有中间方法将其与Class
对象一起传递,直到我到达SearchPredicate
创建方法或 - 在每个
SearchPredicate
创建方法中创建SearchSession
对象
我的问题:
- 以后在每个方法中创建
SearchSession
对象是个问题吗?我是否必须确保重用现有会话,或者SearchSession
已经是一个单例,我不必担心这一点 - 有没有一种方法可以在没有
Class
和SearchSession
对象的情况下创建SearchPredicate
,类似于我们创建ElasticSearchQueryBuilder
对象的方法 - 有没有更合适的方法来做我正在尝试的事情?其他一些Hibernate Search类比
SearchPredicate
更适合作为可组合的ElasticSearchQueryBuilder
对象的替代品
非常感谢您的帮助!
我建议看一下参考文档的这一部分,了解如何使用Hibernate Search API。
你可以这样做:
protected List<MyEntity> myOuterMostMethod() {
List<MyEntity> hits = searchSession.search( MyEntity.class )
.where( f -> f.bool( b -> {
b.must( createSetSearchPredicate( f, "myField1",
Set.of( "val1", "val2" ), true ) );
b.must( createSetSearchPredicate( f, "myField2",
Set.of( "val3", "val4" ), false ) );
} ) )
.fetchHits( 20 );
}
protected SearchPredicate createSetSearchPredicate(SearchPredicateFactory factory,
String fieldName, Set<?> fieldValues, boolean contains) {
if (contains) {
return factory.terms()
.field( fieldName ).matchingAny( fieldValues )
.toPredicate();
} else {
return factory.bool().mustNot(factory.terms()
.field( fieldName ).matchingAny( fieldValues ))
.toPredicate();
}
}
你也可以这样做,在我看来更清楚:
protected List<MyEntity> myOuterMostMethod() {
List<MyEntity> hits = searchSession.search( MyEntity.class )
.where( f -> f.bool( b -> {
b.must( containAny( f, "myField1", Set.of( "val1", "val2" ) ) );
b.mustNot( containAny( f, "myField2", Set.of( "val3", "val4" ) ) );
} ) )
.fetchHits( 20 );
}
protected SearchPredicate containAny(SearchPredicateFactory factory,
String fieldName, Set<?> fieldValues) {
return factory.terms().field( fieldName ).matchingAny( fieldValues ).toPredicate();
}
关于您的问题:
以后在每个方法中创建SearchSession对象是个问题吗?我是否必须确保重用现有会话,或者SearchSession已经是一个单例,我不必担心这一点?
后台有一定程度的缓存,所以从性能角度来看,应该不会太差。但实际上,没有必要每次都重新创建SearchSession
。只需获取SearchPredicateFactory
,如我的示例所示,并将其传递给您的方法。
有没有一种方法可以在没有Class和SearchSession对象的情况下创建SearchPredicates,类似于我们创建ElasticSearch QueryBuilder对象的方法?
不是。Hibernate Search检查您引用的字段是否确实存在,并使用元数据将您传递的值转换为JSON。它需要上下文来访问元数据,所以它不能仅仅从静态方法调用中创建谓词。
但是,您可以在没有会话的情况下创建搜索谓词。这消除了从Hibernate ORM获得一个打开的EntityManager
/Session
的要求,但您仍然需要访问EntityManagerFactory
/SessionFactory
(其中包含Hibernate Search需要的元数据(,并且您仍然需要告诉Hibernate Search您将针对哪个类。类似这样的东西:
EntityManagerFactory entityManagerFactory = ...;
SearchScope<?> scope = Search.mapping(entityManagerFactory).scope(clazz);
SearchPredicateFactory factory = scope.predicate()
此外,如果您真的想绕过Hibernate Search元数据,可以直接将JSON查询传递给Hibernate Search。
有没有更合适的方法来做我正在尝试的事情?其他一些Hibernate Search类比SearchPredicates更适合作为可组合的ElasticSearch QueryBuilder对象的替代品?
您使用的类是正确的。我认为您只需要接受这样一个事实:Hibernate Search需要一些上下文(SearchPredicateFactory
实例(来创建谓词,并且不提供创建谓词的静态方法。