() -> searchTarget.predicate().match().onField( "unknown_field" ) () -> searchTarget.predicate().match().onFields( indexMapping.string1Field.relativeFieldName, "unknown_field" ) () -> searchTarget.predicate().match().onField( indexMapping.string1Field.relativeFieldName ).orField( "unknown_field" ) () -> searchTarget.predicate().match().onField( indexMapping.string1Field.relativeFieldName ).orFields( "unknown_field" )
public SearchPredicate extendedPredicate(String fieldName, String value) { return delegate.match().onField( fieldName ).matching( value ).toPredicate(); } }
/** * Target the given field in the match predicate. * <p> * Multiple fields may be targeted by the same predicate: * the predicate will match if <em>any</em> targeted field matches. * <p> * When targeting multiple fields, those fields must have compatible types. * See <a href="SearchPredicateFactoryContext.html#commonconcepts-parametertype">there</a> for more information. * * @param absoluteFieldPath The absolute path (from the document root) of the targeted field. * @return A {@link MatchPredicateFieldSetContext} allowing to define field-specific settings * (such as the {@link MatchPredicateFieldSetContext#boostedTo(float) boost}), * or simply to continue the definition of the match predicate * ({@link MatchPredicateFieldSetContext#matching(Object) value to match}, ...). */ default MatchPredicateFieldSetContext onField(String absoluteFieldPath) { return onFields( absoluteFieldPath ); }
@Test public void queryWrapper() { StubMappingSearchTarget searchTarget = indexManager.createSearchTarget(); QueryWrapper queryWrapper = searchTarget.query() .asReference( QueryWrapper::new ) .predicate( f -> f.match().onField( "string" ).matching( "platypus" ).toPredicate() ) .build(); assertThat( queryWrapper.query.getQueryString() ).contains( "platypus" ); }
/** * Target the given field in the match predicate. * <p> * Multiple fields may be targeted by the same predicate: * the predicate will match if <em>any</em> targeted field matches. * <p> * When targeting multiple fields, those fields must have compatible types. * See <a href="SearchPredicateFactoryContext.html#commonconcepts-parametertype">there</a> for more information. * * @param absoluteFieldPath The absolute path (from the document root) of the targeted field. * @return A {@link MatchPredicateFieldSetContext} allowing to define field-specific settings * (such as the {@link MatchPredicateFieldSetContext#boostedTo(float) boost}), * or simply to continue the definition of the match predicate * ({@link MatchPredicateFieldSetContext#matching(Object) value to match}, ...). */ default MatchPredicateFieldSetContext onField(String absoluteFieldPath) { return onFields( absoluteFieldPath ); }
@Test public void getQueryString() { StubMappingSearchTarget searchTarget = indexManager.createSearchTarget(); SearchQuery<DocumentReference> query = searchTarget.query() .asReference() .predicate( f -> f.match().onField( "string" ).matching( "platypus" ).toPredicate() ) .build(); assertThat( query.getQueryString() ).contains( "platypus" ); }
.predicate( f -> f.match().onField( indexMapping.string1Field.relativeFieldName ) .orField( indexMapping.string2Field.relativeFieldName ) .matching( indexMapping.string1Field.document1Value.indexedValue ) .predicate( f -> f.match().onField( indexMapping.string1Field.relativeFieldName ) .orField( indexMapping.string2Field.relativeFieldName ) .matching( indexMapping.string2Field.document1Value.indexedValue ) .predicate( f -> f.match().onField( indexMapping.string1Field.relativeFieldName ) .orFields( indexMapping.string2Field.relativeFieldName, indexMapping.string3Field.relativeFieldName ) .matching( indexMapping.string1Field.document1Value.indexedValue ) .predicate( f -> f.match().onField( indexMapping.string1Field.relativeFieldName ) .orFields( indexMapping.string2Field.relativeFieldName, indexMapping.string3Field.relativeFieldName ) .matching( indexMapping.string2Field.document1Value.indexedValue ) .predicate( f -> f.match().onField( indexMapping.string1Field.relativeFieldName ) .orFields( indexMapping.string2Field.relativeFieldName, indexMapping.string3Field.relativeFieldName ) .matching( indexMapping.string3Field.document1Value.indexedValue ) .predicate( f -> f.match().onFields( indexMapping.string1Field.relativeFieldName, indexMapping.string3Field.relativeFieldName ) .matching( indexMapping.string1Field.document1Value.indexedValue ) .toPredicate() .predicate( f -> f.match().onFields( indexMapping.string1Field.relativeFieldName, indexMapping.string2Field.relativeFieldName ) .matching( indexMapping.string2Field.document1Value.indexedValue ) .toPredicate()
@Override public List<Person> search(String terms, int offset, int limit) { if ( terms == null || terms.isEmpty() ) { return Collections.emptyList(); } FullTextSearchTarget<Person> target = entityManager.search( Person.class ); FullTextQuery<Person> query = target.query() .asEntity() .predicate( f -> f.match().onFields( "firstName", "lastName" ).matching( terms ).toPredicate() ) .sort( c -> { c.byField( "lastName_sort" ); c.byField( "firstName_sort" ); } ) .build(); query.setFirstResult( offset ); query.setMaxResults( limit ); return query.getResultList(); }
@Test public void error_invalidType() { StubMappingSearchTarget searchTarget = indexManager.createSearchTarget(); List<ByTypeFieldModel<?>> fieldModels = new ArrayList<>(); fieldModels.addAll( indexMapping.supportedFieldModels ); fieldModels.addAll( indexMapping.supportedFieldWithDslConverterModels ); for ( ByTypeFieldModel<?> fieldModel : fieldModels ) { String absoluteFieldPath = fieldModel.relativeFieldName; Object invalidValueToMatch = new InvalidType(); SubTest.expectException( "match() predicate with invalid parameter type on field " + absoluteFieldPath, () -> searchTarget.predicate().match().onField( absoluteFieldPath ).matching( invalidValueToMatch ) ) .assertThrown() .isInstanceOf( SearchException.class ) .hasMessageContaining( "Unable to convert DSL parameter: " ) .hasMessageContaining( InvalidType.class.getName() ) .hasCauseInstanceOf( ClassCastException.class ) .satisfies( FailureReportUtils.hasContext( EventContexts.fromIndexFieldAbsolutePath( absoluteFieldPath ) ) ); } }
@Override public List<Person> search(String terms, int offset, int limit) { if ( terms == null || terms.isEmpty() ) { return Collections.emptyList(); } FullTextSearchTarget<Person> target = entityManager.search( Person.class ); FullTextQuery<Person> query = target.query() .asEntity() .predicate( target.predicate().match().onFields( "firstName", "lastName" ).matching( terms ).toPredicate() ) .sort( target.sort() .byField( "lastName_sort" ) .then().byField( "firstName_sort" ) .toSort() ) .build(); query.setFirstResult( offset ); query.setMaxResults( limit ); return query.getResultList(); }
@Override public Optional<Book> getByIsbn(String isbnAsString) { if ( isbnAsString == null ) { return Optional.empty(); } // Must use Hibernate ORM types (as opposed to JPA types) to benefit from query.uniqueResult() FullTextSession fullTextSession = entityManager.unwrap( FullTextSession.class ); org.hibernate.search.mapper.orm.hibernate.FullTextQuery<Book> query = fullTextSession.search( Book.class ).query() .asEntity() // TODO allow to bypass the bridge in the DSL .predicate( f -> f.match().onField( "isbn" ).matching( new ISBN( isbnAsString ) ).toPredicate() ) .build(); return Optional.ofNullable( query.uniqueResult() ); }
@Test public void should_mustNot() { StubMappingSearchTarget searchTarget = indexManager.createSearchTarget(); SearchQuery<DocumentReference> query = searchTarget.query() .asReference() .predicate( f -> f.bool() .should( f.match().onField( "field1" ).matching( FIELD1_VALUE1 ) ) .should( f.match().onField( "field1" ).matching( FIELD1_VALUE3 ) ) .mustNot( f.match().onField( "field1" ).matching( FIELD1_VALUE1 ) ) .toPredicate() ) .build(); assertThat( query ) .hasDocRefHitsAnyOrder( INDEX_NAME, DOCUMENT_3 ); }
@Override public Optional<Book> getByIsbn(String isbnAsString) { if ( isbnAsString == null ) { return Optional.empty(); } // Must use Hibernate ORM types (as opposed to JPA types) to benefit from query.uniqueResult() FullTextSession fullTextSession = entityManager.unwrap( FullTextSession.class ); org.hibernate.search.mapper.orm.hibernate.FullTextSearchTarget<Book> target = fullTextSession.search( Book.class ); org.hibernate.search.mapper.orm.hibernate.FullTextQuery<Book> query = target.query() .asEntity() .predicate( // TODO allow to bypass the bridge in the DSL target.predicate().match().onField( "isbn" ).matching( new ISBN( isbnAsString ) ).toPredicate() ) .build(); return Optional.ofNullable( query.uniqueResult() ); }
.asReference() .predicate( f -> f.bool() .mustNot( f.match().onField( "field1" ).matching( FIELD1_VALUE2 ) ) .mustNot( f.match().onField( "field1" ).matching( FIELD1_VALUE3 ) ) .should( f.match().onField( "field2" ).matching( FIELD2_VALUE2 ) ) .should( f.match().onField( "field3" ).matching( FIELD3_VALUE3 ) ) .toPredicate() .asReference() .predicate( f -> f.bool() .mustNot( f.match().onField( "field1" ).matching( FIELD1_VALUE1 ) ) .mustNot( f.match().onField( "field1" ).matching( FIELD1_VALUE3 ) ) .should( f.match().onField( "field2" ).matching( FIELD2_VALUE2 ) ) .should( f.match().onField( "field3" ).matching( FIELD3_VALUE3 ) ) .toPredicate()
@Test public void score() { StubMappingSearchTarget searchTarget = indexManager.createSearchTarget(); SearchQuery<Float> query = searchTarget.query() .asProjection( f -> f.score().toProjection() ) .predicate( f -> f.match().onField( indexMapping.scoreField.relativeFieldName ).matching( "scorepattern" ).toPredicate() ) .sort( c -> c.byScore().desc() ) .build(); SearchResult<Float> result = query.execute(); assertThat( result ).hasHitCount( 2 ); Float score1 = result.getHits().get( 0 ); Float score2 = result.getHits().get( 1 ); Assertions.assertThat( score1 ).isNotNull(); Assertions.assertThat( score2 ).isNotNull(); Assertions.assertThat( score1 ).isGreaterThan( score2 ); }
@Test public void match_lambda_caching_root() { StubMappingSearchTarget searchTarget = indexManager.createSearchTarget(); AtomicReference<SearchPredicate> cache = new AtomicReference<>(); Function<? super SearchPredicateFactoryContext, SearchPredicate> cachingContributor = c -> { if ( cache.get() == null ) { SearchPredicate result = c.match().onField( "string" ).matching( STRING_1 ).toPredicate(); cache.set( result ); return result; } else { return cache.get(); } }; Assertions.assertThat( cache ).hasValue( null ); SearchQuery<DocumentReference> query = searchTarget.query() .asReference() .predicate( cachingContributor ) .build(); assertThat( query ) .hasDocRefHitsAnyOrder( INDEX_NAME, DOCUMENT_1 ); Assertions.assertThat( cache ).doesNotHaveValue( null ); query = searchTarget.query() .asReference() .predicate( cachingContributor ) .build(); assertThat( query ) .hasDocRefHitsAnyOrder( INDEX_NAME, DOCUMENT_1 ); }
private SearchResultAssert<DocumentReference> assertMatchQuery(String valueToMatch) { StubMappingSearchTarget searchTarget = indexManager.createSearchTarget(); SearchQuery<DocumentReference> query = searchTarget.query() .asReference() .predicate( f -> f.match().onField( indexMapping.field.relativeFieldName ).matching( valueToMatch ).toPredicate() ) .build(); return assertThat( query ); }
@Test public void must_should() { StubMappingSearchTarget searchTarget = indexManager.createSearchTarget(); // A boolean predicate with must + should clauses: // documents should match regardless of whether should clauses match. // Non-matching "should" clauses SearchQuery<DocumentReference> query = searchTarget.query() .asReference() .predicate( f -> f.bool() .must( f.match().onField( "field1" ).matching( FIELD1_VALUE1 ) ) .should( f.match().onField( "field2" ).matching( FIELD2_VALUE2 ) ) .should( f.match().onField( "field3" ).matching( FIELD3_VALUE3 ) ) .toPredicate() ) .build(); assertThat( query ) .hasDocRefHitsAnyOrder( INDEX_NAME, DOCUMENT_1 ); // One matching and one non-matching "should" clause query = searchTarget.query() .asReference() .predicate( f -> f.bool() .must( f.match().onField( "field1" ).matching( FIELD1_VALUE2 ) ) .should( f.match().onField( "field2" ).matching( FIELD2_VALUE1 ) ) .should( f.match().onField( "field3" ).matching( FIELD3_VALUE3 ) ) .toPredicate() ) .build(); assertThat( query ) .hasDocRefHitsAnyOrder( INDEX_NAME, DOCUMENT_2 ); }
@Test public void filter_should() { StubMappingSearchTarget searchTarget = indexManager.createSearchTarget(); // A boolean predicate with filter + should clauses: // documents should match regardless of whether should clauses match. // Non-matching "should" clauses SearchQuery<DocumentReference> query = searchTarget.query() .asReference() .predicate( f -> f.bool() .filter( f.match().onField( "field1" ).matching( FIELD1_VALUE1 ) ) .should( f.match().onField( "field2" ).matching( FIELD2_VALUE2 ) ) .should( f.match().onField( "field3" ).matching( FIELD3_VALUE3 ) ) .toPredicate() ) .build(); assertThat( query ) .hasDocRefHitsAnyOrder( INDEX_NAME, DOCUMENT_1 ); // One matching and one non-matching "should" clause query = searchTarget.query() .asReference() .predicate( f -> f.bool() .filter( f.match().onField( "field1" ).matching( FIELD1_VALUE1 ) ) .should( f.match().onField( "field2" ).matching( FIELD2_VALUE1 ) ) .should( f.match().onField( "field3" ).matching( FIELD3_VALUE3 ) ) .toPredicate() ) .build(); assertThat( query ) .hasDocRefHitsAnyOrder( INDEX_NAME, DOCUMENT_1 ); }
@Test public void match_error_null() { StubMappingSearchTarget searchTarget = indexManager.createSearchTarget(); for ( ByTypeFieldModel<?> fieldModel : indexMapping.supportedFieldModels ) { SubTest.expectException( "matching() predicate with null value to match on field " + fieldModel.relativeFieldName, () -> searchTarget.predicate().match().onField( fieldModel.relativeFieldName ).matching( null ) ) .assertThrown() .isInstanceOf( SearchException.class ) .hasMessageContaining( "Invalid value" ) .hasMessageContaining( "value to match" ) .hasMessageContaining( "must be non-null" ) .hasMessageContaining( fieldModel.relativeFieldName ); } }