将嵌套的 Hibernate Search 5 谓词转换为 Hibernate Search 6
Converting nested Hibernate Search 5 predicates to Hibernate Search 6
在将应用程序从 Hibernate Search 5 转换为 6 的过程中。我通读了很多文档,尤其是 https://docs.jboss.org/hibernate/search/6.0/migration/html_single/#queries-reference
关于如何转换查询 DSL,我在一个简单的场景中理解它,但是你如何将谓词嵌套到其他嵌套谓词中,然后将它们与其他谓词组合在更大的查询中?
在 Hibernate Search 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 形式。有一个部分 here 提供了一个创建非 lamba 谓词的简单示例,将它们添加到列表中,但是,例如,您如何将该谓词列表添加到外部 should 子句,然后将 should 子句与另一个 should 子句一起添加到外部“必须”子句等.等等?
就我个人而言,我会使用 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() );
最后,如果您真的想完全远离 lambda(但又是为什么?),您或许可以这样做。请注意,BooleanPredicateClausesStep
的泛型类型参数可能会在 Hibernate Search 的次要版本中更改,因此此代码在升级时更有可能中断。
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() );
在将应用程序从 Hibernate Search 5 转换为 6 的过程中。我通读了很多文档,尤其是 https://docs.jboss.org/hibernate/search/6.0/migration/html_single/#queries-reference
关于如何转换查询 DSL,我在一个简单的场景中理解它,但是你如何将谓词嵌套到其他嵌套谓词中,然后将它们与其他谓词组合在更大的查询中?
在 Hibernate Search 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 形式。有一个部分 here 提供了一个创建非 lamba 谓词的简单示例,将它们添加到列表中,但是,例如,您如何将该谓词列表添加到外部 should 子句,然后将 should 子句与另一个 should 子句一起添加到外部“必须”子句等.等等?
就我个人而言,我会使用 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() );
最后,如果您真的想完全远离 lambda(但又是为什么?),您或许可以这样做。请注意,BooleanPredicateClausesStep
的泛型类型参数可能会在 Hibernate Search 的次要版本中更改,因此此代码在升级时更有可能中断。
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() );