在将应用程序从Hibernate搜索5转换为6的过程中,我阅读了很多文档,特别是关于如何在简单场景中转换查询DSL的单个/#查询-引用,但是如何将谓词嵌套到其他嵌套谓词中,然后在更大的查询中将它们与其他谓词结合起来呢?
在Hibernate搜索5中,我们将使用queryBuilder.bool()创建一个BooleanJunction,然后通过在bool上调用createQuery来在另一个BooleanJunction中添加它,并反复创建嵌套谓词查询。
我所讨论的转换代码类型的示例:
BooleanJunction vendorNameBool = queryBuilder.bool();
BooleanJunction nameBool = queryBuilder.bool();
nameBool.must(
qb.keyword()
.onField(CompanyName)
.matching(nameToken1)
.createQuery()
);
nameBool.must(
qb.keyword()
.onField(CompanyName)
.matching(nameToken2)
.createQuery()
);
vendorNameBool.should(nameBool.createQuery);
// do vendorNameBool.should(...) for as many vendor Names that exist, then createQuery
probableVendorNamesQuery = vendorNameBool.createQuery();
// creating a number of Queries from various bools and then combining them:
Query taxIdOrVendorNameOrPhoneNumberQuery = qb.bool()
.should(probableVendorNamesQuery)
.should(taxIdQuery)
.should(phoneNumberQuery)
.createQuery();
//and add to the final BooleanQuery along with other Query pieces
Query idQuery = getIdQuery();
Query fileIdQuery = getFileIdQuery();
BooleanQuery.Builder theQuery = new BooleanQuery.Builder();
theQuery.add(taxIdOrVendorNameOrPhoneNumberQuery, MUST);
theQuery.add(fileIdQuery, MUST);
theQuery.add(idQuery, MUST_NOT);
BooleanQuery probableQuery = theQuery.build();
// add some projections and execute query
大多数HS6代码示例都以lambda形式出现。有一节这里提供了一个创建非lamba谓词的简单示例,并将它们添加到list中,但是,例如,您将如何将谓词列表添加到外部must子句中,然后将该must子句以及另一个must子句添加到外部“必须”子句,等等。
发布于 2022-03-14 23:38:44
就我个人而言,我只需要使用lambda语法并嵌套第二个lambda。修改迁移指南中的示例:
MySearchParameters searchParameters = ...;
SearchSession session = Search.session( entityManager );
List<Book> hits = searchSession.search( Book.class )
.where( f -> f.bool( b -> {
b.must( f.matchAll() );
if ( searchParameters.getSearchTerms() != null ) {
b.must( f.simpleQueryString().fields( "title", "description" )
.matching( searchParameters.getSearchTerms() )
.defaultOperator( BooleanOperator.AND ) );
}
// ...
// BEGIN NEW CODE
SomeComplexParameter complexParam = searchParameters.getSomeComplexParameter();
if ( complexParam != null ) {
b.must( f.bool( b2 -> {
b2.should( f.match().field( "someField1" )
.matching( complexParam.getSomeField1() ) );
b2.should( f.match().field( "someField2" )
.matching( complexParam.getSomeField2() ) );
} ) );
}
// END NEW CODE
} ) )
.fetchHits( params.getPageIndex() * params.getPageSize(), params.getPageSize() );
如果在编译时知道子句的数量,甚至不需要第二个lambda:
MySearchParameters searchParameters = ...;
SearchSession session = Search.session( entityManager );
List<Book> hits = searchSession.search( Book.class )
.where( f -> f.bool( b -> {
b.must( f.matchAll() );
if ( searchParameters.getSearchTerms() != null ) {
b.must( f.simpleQueryString().fields( "title", "description" )
.matching( searchParameters.getSearchTerms() )
.defaultOperator( BooleanOperator.AND ) );
}
// ...
// BEGIN NEW CODE
SomeComplexParameter complexParam = searchParameters.getSomeComplexParameter();
if ( complexParam != null ) {
b.must( f.bool()
.should( f.match().field( "someField1" )
.matching( complexParam.getSomeField1() ) )
.should( f.match().field( "someField2" )
.matching( complexParam.getSomeField2() ) ) );
}
// END NEW CODE
} ) )
.fetchHits( params.getPageIndex() * params.getPageSize(), params.getPageSize() );
如果您真的不想在顶层使用lambda(为什么?),至少可以将lambda用于嵌套谓词:
MySearchParameters searchParameters = ...;
SearchSession session = Search.session( entityManager );
SearchPredicateFactory pf = session.scope( Book.class ).predicate();
List<SearchPredicate> predicates = new ArrayList<>();
if ( searchParameters.getSearchTerms() != null ) {
predicates.add( pf.simpleQueryString().fields( "title", "description" )
.matching( searchParameters.getSearchTerms() )
.defaultOperator( BooleanOperator.AND )
.toPredicate() );
}
// ...
// BEGIN NEW CODE
SomeComplexParameter complexParam = searchParameters.getSomeComplexParameter();
if ( complexParam != null ) {
predicates.add( pf.bool( b -> {
b.should( pf.match().field( "someField1" )
.matching( complexParam.getSomeField1() ) );
b.should( pf.match().field( "someField2" )
.matching( complexParam.getSomeField2() ) );
} )
.toPredicate() );
}
// END NEW CODE
List<Book> hits = searchSession.search( Book.class )
.where( f -> f.bool( b -> {
b.must( f.matchAll() );
for ( SearchPredicate predicate : predicates ) {
b.must( predicate );
}
} )
在这里,只要事先知道谓词的数量,就不需要lambda:
MySearchParameters searchParameters = ...;
SearchSession session = Search.session( entityManager );
SearchPredicateFactory pf = session.scope( Book.class ).predicate();
List<SearchPredicate> predicates = new ArrayList<>();
if ( searchParameters.getSearchTerms() != null ) {
predicates.add( pf.simpleQueryString().fields( "title", "description" )
.matching( searchParameters.getSearchTerms() )
.defaultOperator( BooleanOperator.AND )
.toPredicate() );
}
// ...
// BEGIN NEW CODE
SomeComplexParameter complexParam = searchParameters.getSomeComplexParameter();
if ( complexParam != null ) {
predicates.add( pf.bool()
.should( pf.match().field( "someField1" )
.matching( complexParam.getSomeField1() ) )
.should( pf.match().field( "someField2" )
.matching( complexParam.getSomeField2() ) )
.toPredicate() );
}
// END NEW CODE
List<Book> hits = searchSession.search( Book.class )
.where( f -> f.bool( b -> {
b.must( f.matchAll() );
for ( SearchPredicate predicate : predicates ) {
b.must( predicate );
}
} )
.fetchHits( params.getPageIndex() * params.getPageSize(), params.getPageSize() );
最后,如果您真的想完全远离lambdas (但同样,为什么?),您可能可以这样做。但是,请注意,BooleanPredicateClausesStep
的泛型类型参数在Hibernate搜索的次要版本中可能会发生变化,因此在升级时,这段代码更有可能中断。
MySearchParameters searchParameters = ...;
SearchSession session = Search.session( entityManager );
SearchPredicateFactory pf = session.scope( Book.class ).predicate();
BooleanPredicateClausesStep<?> boolStep = pf.bool();
boolStep.must( f.matchAll() );
if ( searchParameters.getSearchTerms() != null ) {
boolStep.must( pf.simpleQueryString().fields( "title", "description" )
.matching( searchParameters.getSearchTerms() )
.defaultOperator( BooleanOperator.AND ) );
}
// ...
SomeComplexParameter complexParam = searchParameters.getSomeComplexParameter();
if ( complexParam != null ) {
BooleanPredicateClausesStep<?> boolStep2 = pf.bool();
boolStep2.should( f.match().field( "someField1" )
.matching( complexParam.getSomeField1() ) );
boolStep2.should( f.match().field( "someField2" )
.matching( complexParam.getSomeField2() ) );
boolStep.must( boolStep2 );
}
SearchPredicate boolPredicate = boolStep.toPredicate();
List<Book> hits = searchSession.search( Book.class )
.where( boolPredicate )
.fetchHits( params.getPageIndex() * params.getPageSize(), params.getPageSize() );
如果使用JDK 11进行编译,更健壮的解决方案是使用var
关键字:
MySearchParameters searchParameters = ...;
SearchSession session = Search.session( entityManager );
SearchPredicateFactory pf = session.scope( Book.class ).predicate();
var boolStep = pf.bool();
boolStep.must( f.matchAll() );
if ( searchParameters.getSearchTerms() != null ) {
boolStep.must( pf.simpleQueryString().fields( "title", "description" )
.matching( searchParameters.getSearchTerms() )
.defaultOperator( BooleanOperator.AND ) );
}
// ...
SomeComplexParameter complexParam = searchParameters.getSomeComplexParameter();
if ( complexParam != null ) {
var boolStep2 = pf.bool();
boolStep2.should( f.match().field( "someField1" )
.matching( complexParam.getSomeField1() ) );
boolStep2.should( f.match().field( "someField2" )
.matching( complexParam.getSomeField2() ) );
boolStep.must( boolStep2 );
}
SearchPredicate boolPredicate = boolStep.toPredicate();
List<Book> hits = searchSession.search( Book.class )
.where( boolPredicate )
.fetchHits( params.getPageIndex() * params.getPageSize(), params.getPageSize() );
https://stackoverflow.com/questions/71470810
复制相似问题