Skip to content

Commit

Permalink
HSEARCH-4173 Test implicit nested predicates on missing fields
Browse files Browse the repository at this point in the history
Signed-off-by: Yoann Rodière <yoann@hibernate.org>
  • Loading branch information
yrodiere authored and fax4ever committed Mar 10, 2021
1 parent b75a846 commit 66c09c3
Show file tree
Hide file tree
Showing 15 changed files with 258 additions and 111 deletions.
Expand Up @@ -16,8 +16,9 @@ public abstract class AbstractPredicateFieldNestingIT<V extends AbstractPredicat

protected final DataSet<?, V> dataSet;

public AbstractPredicateFieldNestingIT(SimpleMappedIndex<IndexBinding> index, DataSet<?, V> dataSet) {
super( index, dataSet );
public AbstractPredicateFieldNestingIT(SimpleMappedIndex<IndexBinding> mainIndex,
SimpleMappedIndex<MissingFieldIndexBinding> missingFieldIndex, DataSet<?, V> dataSet) {
super( mainIndex, missingFieldIndex, dataSet );
this.dataSet = dataSet;
}

Expand All @@ -35,12 +36,16 @@ public DataSet(V values) {
super( values );
}

public void contribute(SimpleMappedIndex<IndexBinding> index, BulkIndexer indexer) {
public void contribute(SimpleMappedIndex<IndexBinding> mainIndex, BulkIndexer mainIndexer,
SimpleMappedIndex<MissingFieldIndexBinding> missingFieldIndex, BulkIndexer missingFieldIndexer) {
F fieldValue = values.fieldValue( 0 );
indexer.add( docId( 0 ), routingKey,
document -> index.binding().initDocument( document, fieldType, fieldValue ) );
mainIndexer.add( docId( 0 ), routingKey,
document -> mainIndex.binding().initDocument( document, fieldType, fieldValue ) );
// Also add an empty document that shouldn't match
indexer.add( docId( 1 ), routingKey, document -> { } );
mainIndexer.add( docId( 1 ), routingKey, document -> { } );

missingFieldIndexer.add( docId( MISSING_FIELD_INDEX_DOC_ORDINAL ), routingKey,
document -> missingFieldIndex.binding().initDocument() );
}
}
}
Expand Up @@ -20,74 +20,110 @@
import org.hibernate.search.integrationtest.backend.tck.testsupport.types.FieldTypeDescriptor;
import org.hibernate.search.integrationtest.backend.tck.testsupport.util.SimpleFieldModelsByType;
import org.hibernate.search.util.impl.integrationtest.mapper.stub.SimpleMappedIndex;
import org.hibernate.search.util.impl.integrationtest.mapper.stub.StubMappingScope;
import org.hibernate.search.util.impl.test.annotation.TestForIssue;

import org.junit.Test;

public abstract class AbstractPredicateNestingIT {

private final SimpleMappedIndex<IndexBinding> index;
static final int MISSING_FIELD_INDEX_DOC_ORDINAL = 42;

private final SimpleMappedIndex<IndexBinding> mainIndex;
private final SimpleMappedIndex<MissingFieldIndexBinding> missingFieldIndex;
private final IndexBinding binding;
private final AbstractPredicateDataSet dataSet;

public AbstractPredicateNestingIT(SimpleMappedIndex<IndexBinding> index, AbstractPredicateDataSet dataSet) {
this.index = index;
this.binding = index.binding();
public AbstractPredicateNestingIT(SimpleMappedIndex<IndexBinding> mainIndex,
SimpleMappedIndex<MissingFieldIndexBinding> missingFieldIndex,
AbstractPredicateDataSet dataSet) {
this.mainIndex = mainIndex;
this.missingFieldIndex = missingFieldIndex;
this.binding = mainIndex.binding();
this.dataSet = dataSet;
}

@Test
public void nestedX2_explicit() {
assertThatQuery( index.query()
assertThatQuery( mainIndex.query()
.where( f -> f.nested().objectField( binding.nested.absolutePath )
.nest( f.nested().objectField( binding.nested.nested.absolutePath )
.nest( predicate( f, binding.nested.nested, 0 ) )
) )
.routing( dataSet.routingKey ) )
.hasDocRefHitsAnyOrder( index.typeName(), dataSet.docId( 0 ) );
.hasDocRefHitsAnyOrder( mainIndex.typeName(), dataSet.docId( 0 ) );
}

@Test
public void nestedX2_implicit() {
assertThatQuery( index.query()
assertThatQuery( mainIndex.query()
.where( f -> predicate( f, binding.nested.nested, 0 ) )
.routing( dataSet.routingKey ) )
.hasDocRefHitsAnyOrder( index.typeName(), dataSet.docId( 0 ) );
.hasDocRefHitsAnyOrder( mainIndex.typeName(), dataSet.docId( 0 ) );
}

@Test
public void nestedX2_explicit_implicit() {
assertThatQuery( index.query()
assertThatQuery( mainIndex.query()
.where( f -> f.nested().objectField( binding.nested.absolutePath )
.nest( predicate( f, binding.nested.nested, 0 ) ) )
.routing( dataSet.routingKey ) )
.hasDocRefHitsAnyOrder( index.typeName(), dataSet.docId( 0 ) );
.hasDocRefHitsAnyOrder( mainIndex.typeName(), dataSet.docId( 0 ) );
}

@Test
public void nestedX3_explicitX2_implicit() {
assertThatQuery( index.query()
assertThatQuery( mainIndex.query()
.where( f -> f.nested().objectField( binding.nested.absolutePath )
.nest( f.nested().objectField( binding.nested.nested.absolutePath )
.nest( predicate( f, binding.nested.nested.nested, 0 ) ) ) )
.routing( dataSet.routingKey ) )
.hasDocRefHitsAnyOrder( index.typeName(), dataSet.docId( 0 ) );
.hasDocRefHitsAnyOrder( mainIndex.typeName(), dataSet.docId( 0 ) );
}

@Test
public void nestedX3_explicit_implicitX2() {
assertThatQuery( index.query()
assertThatQuery( mainIndex.query()
.where( f -> f.nested().objectField( binding.nested.absolutePath )
.nest( predicate( f, binding.nested.nested.nested, 0 ) ) )
.routing( dataSet.routingKey ) )
.hasDocRefHitsAnyOrder( index.typeName(), dataSet.docId( 0 ) );
.hasDocRefHitsAnyOrder( mainIndex.typeName(), dataSet.docId( 0 ) );
}

@Test
public void nestedFlattenedNested_implicit() {
assertThatQuery( index.query()
.where( f -> predicate( f, index.binding().nested.flattened.nested, 0 ) )
assertThatQuery( mainIndex.query()
.where( f -> predicate( f, mainIndex.binding().nested.flattened.nested, 0 ) )
.routing( dataSet.routingKey ) )
.hasDocRefHitsAnyOrder( mainIndex.typeName(), dataSet.docId( 0 ) );
}

/**
* Test that no failure occurs when an implicit nested predicate targets a nested field
* that only exists in one of the targeted indexes.
*/
@Test
@TestForIssue(jiraKey = "HSEARCH-4173")
public void multiIndex_missingNestedField_implicit() {
StubMappingScope scope = mainIndex.createScope( missingFieldIndex );

// The "nested" predicate should not match anything in missingFieldIndex
assertThatQuery( scope.query()
.where( f -> predicate( f, binding.nested.nested, 0 ) )
.routing( dataSet.routingKey ) )
.hasDocRefHitsAnyOrder( index.typeName(), dataSet.docId( 0 ) );
.hasDocRefHitsAnyOrder( mainIndex.typeName(), dataSet.docId( 0 ) );

// ... but it should not prevent the query from executing either:
// if the "nested" predicate is optional, it should be ignored for missingFieldIndex.
assertThatQuery( scope.query()
.where( f -> f.bool()
.should( predicate( f, binding.nested.nested, 0 ) )
.should( f.id().matching( dataSet.docId( MISSING_FIELD_INDEX_DOC_ORDINAL ) ) ) )
.routing( dataSet.routingKey ) )
.hasDocRefHitsAnyOrder( c -> c
.doc( mainIndex.typeName(), dataSet.docId( 0 ) )
.doc( missingFieldIndex.typeName(), dataSet.docId( MISSING_FIELD_INDEX_DOC_ORDINAL ) ) )
.hasTotalHitCount( 2 );
}

protected abstract PredicateFinalStep predicate(SearchPredicateFactory f, ObjectFieldBinding objectFieldBinding,
Expand Down Expand Up @@ -162,6 +198,15 @@ protected <F> void addValue(DocumentElement object, AbstractObjectBinding bindin
}
}

static class MissingFieldIndexBinding {

MissingFieldIndexBinding(IndexSchemaElement root, Collection<? extends FieldTypeDescriptor<?>> fieldTypes) {
}

protected void initDocument() {
}
}

static class ObjectFieldBinding extends AbstractObjectBinding {
private static final int MAX_DEPTH = 4;

Expand Down
Expand Up @@ -39,7 +39,8 @@ public class ExistsPredicateBaseIT {
public static void setup() {
setupHelper.start()
.withIndexes(
NestingIT.index, SingleFieldIT.index,
SingleFieldIT.index,
NestingIT.mainIndex, NestingIT.missingFieldIndex,
ScoreIT.index,
InvalidFieldIT.index,
SearchableIT.searchableYesIndex, SearchableIT.searchableNoIndex,
Expand All @@ -53,8 +54,10 @@ public static void setup() {
final BulkIndexer singleFieldIndexer = SingleFieldIT.index.bulkIndexer();
SingleFieldIT.dataSets.forEach( d -> d.contribute( SingleFieldIT.index, singleFieldIndexer ) );

final BulkIndexer nestingIndexer = NestingIT.index.bulkIndexer();
NestingIT.dataSets.forEach( d -> d.contribute( NestingIT.index, nestingIndexer ) );
final BulkIndexer nestingMainIndexer = NestingIT.mainIndex.bulkIndexer();
final BulkIndexer nestingMissingFieldIndexer = NestingIT.missingFieldIndex.bulkIndexer();
NestingIT.dataSets.forEach( d -> d.contribute( NestingIT.mainIndex, nestingMainIndexer,
NestingIT.missingFieldIndex, nestingMissingFieldIndexer ) );

final BulkIndexer scoreIndexer = ScoreIT.index.bulkIndexer();
ScoreIT.dataSets.forEach( d -> d.contribute( scoreIndexer ) );
Expand All @@ -74,7 +77,7 @@ public static void setup() {
ScaleCheckingIT.compatibleIndex, scaleCheckingCompatibleIndexer );

singleFieldIndexer.join(
nestingIndexer, scoreIndexer,
nestingMainIndexer, nestingMissingFieldIndexer, scoreIndexer,
typeCheckingMainIndexer, typeCheckingCompatibleIndexer,
typeCheckingRawFieldCompatibleIndexer, typeCheckingMissingFieldIndexer,
scaleCheckingMainIndexer, scaleCheckingCompatibleIndexer
Expand Down Expand Up @@ -226,17 +229,21 @@ public static class NestingIT<F> extends AbstractPredicateFieldNestingIT<ExistsP
}
}

private static final SimpleMappedIndex<IndexBinding> index =
private static final SimpleMappedIndex<IndexBinding> mainIndex =
SimpleMappedIndex.of( root -> new IndexBinding( root, supportedFieldTypes ) )
.name( "nesting" );

private static final SimpleMappedIndex<MissingFieldIndexBinding> missingFieldIndex =
SimpleMappedIndex.of( root -> new MissingFieldIndexBinding( root, supportedFieldTypes ) )
.name( "nesting_missingField" );

@Parameterized.Parameters(name = "{0}")
public static List<Object[]> parameters() {
return parameters;
}

public NestingIT(DataSet<F, ExistsPredicateTestValues<F>> dataSet) {
super( index, dataSet );
super( mainIndex, missingFieldIndex, dataSet );
}

@Override
Expand Down
Expand Up @@ -47,17 +47,19 @@ public class ExistsPredicateObjectsBaseIT {
public static void setup() {
setupHelper.start()
.withIndexes(
NestingIT.index, ScoreIT.index
NestingIT.mainIndex, NestingIT.missingFieldIndex,
ScoreIT.index
)
.setup();

final BulkIndexer nestingIndexer = NestingIT.index.bulkIndexer();
NestingIT.dataSets.forEach( d -> d.contribute( nestingIndexer ) );
final BulkIndexer nestingMainIndexer = NestingIT.mainIndex.bulkIndexer();
final BulkIndexer nestingMissingFieldIndexer = NestingIT.missingFieldIndex.bulkIndexer();
NestingIT.dataSets.forEach( d -> d.contribute( nestingMainIndexer, nestingMissingFieldIndexer ) );

final BulkIndexer scoreIndexer = ScoreIT.index.bulkIndexer();
ScoreIT.dataSets.forEach( d -> d.contribute( scoreIndexer ) );

nestingIndexer.join( scoreIndexer );
nestingMainIndexer.join( nestingMissingFieldIndexer, scoreIndexer );
}

@Test
Expand All @@ -77,10 +79,14 @@ public static class NestingIT extends AbstractPredicateNestingIT {
}
}

private static final SimpleMappedIndex<IndexBinding> index =
private static final SimpleMappedIndex<IndexBinding> mainIndex =
SimpleMappedIndex.of( root -> new IndexBinding( root, Collections.singletonList( innerFieldType ) ) )
.name( "nesting" );

private static final SimpleMappedIndex<MissingFieldIndexBinding> missingFieldIndex =
SimpleMappedIndex.of( root -> new MissingFieldIndexBinding( root, Collections.singletonList( innerFieldType ) ) )
.name( "nesting_missingField" );

@Parameterized.Parameters(name = "{0}")
public static List<Object[]> parameters() {
return parameters;
Expand All @@ -89,7 +95,7 @@ public static List<Object[]> parameters() {
private final DataSet dataSet;

public NestingIT(DataSet dataSet) {
super( index, dataSet );
super( mainIndex, missingFieldIndex, dataSet );
this.dataSet = dataSet;
}

Expand Down Expand Up @@ -121,10 +127,12 @@ protected DataSet(ObjectStructure structure) {
this.structure = structure;
}

public void contribute(BulkIndexer scoreIndexer) {
scoreIndexer.add( docId( 0 ), routingKey, document -> index.binding()
public void contribute(BulkIndexer mainIndexer, BulkIndexer missingFieldIndexer) {
mainIndexer.add( docId( 0 ), routingKey, document -> mainIndex.binding()
.initDocument( document, innerFieldType, "irrelevant" ) );
scoreIndexer.add( docId( 1 ), routingKey, document -> { } );
mainIndexer.add( docId( 1 ), routingKey, document -> { } );
missingFieldIndexer.add( docId( MISSING_FIELD_INDEX_DOC_ORDINAL ), routingKey,
document -> missingFieldIndex.binding().initDocument() );
}
}
}
Expand Down
Expand Up @@ -35,17 +35,19 @@ public class MatchAllPredicateBaseIT {
public static void setup() {
setupHelper.start()
.withIndexes(
NestingIT.index, ScoreIT.index
NestingIT.mainIndex, NestingIT.missingFieldIndex,
ScoreIT.index
)
.setup();

final BulkIndexer nestingIndexer = NestingIT.index.bulkIndexer();
NestingIT.dataSet.contribute( nestingIndexer );
final BulkIndexer nestingMainIndexer = NestingIT.mainIndex.bulkIndexer();
final BulkIndexer nestingMissingFieldIndexer = NestingIT.missingFieldIndex.bulkIndexer();
NestingIT.dataSet.contribute( nestingMainIndexer, nestingMissingFieldIndexer );

final BulkIndexer scoreIndexer = ScoreIT.index.bulkIndexer();
ScoreIT.dataSet.contribute( scoreIndexer );

nestingIndexer.join( scoreIndexer );
nestingMainIndexer.join( nestingMissingFieldIndexer, scoreIndexer );
}

@Test
Expand All @@ -56,12 +58,16 @@ public void takariCpSuiteWorkaround() {
public static class NestingIT extends AbstractPredicateNestingIT {
private static final DataSet dataSet = new DataSet();

private static final SimpleMappedIndex<IndexBinding> index =
private static final SimpleMappedIndex<IndexBinding> mainIndex =
SimpleMappedIndex.of( root -> new IndexBinding( root, FieldTypeDescriptor.getAll() ) )
.name( "nesting" );

private static final SimpleMappedIndex<MissingFieldIndexBinding> missingFieldIndex =
SimpleMappedIndex.of( root -> new MissingFieldIndexBinding( root, FieldTypeDescriptor.getAll() ) )
.name( "nesting_missingField" );

public NestingIT() {
super( index, dataSet );
super( mainIndex, missingFieldIndex, dataSet );
}

@Override
Expand All @@ -75,15 +81,20 @@ protected DataSet() {
super( "singleRoutingKey" );
}

public void contribute(BulkIndexer scoreIndexer) {
scoreIndexer.add( docId( 0 ), routingKey, document -> index.binding()
public void contribute(BulkIndexer mainIndexer, BulkIndexer missingFieldIndexer) {
mainIndexer.add( docId( 0 ), routingKey, document -> mainIndex.binding()
.initDocument( document, AnalyzedStringFieldTypeDescriptor.INSTANCE, "irrelevant" ) );
scoreIndexer.add( docId( 1 ), routingKey, document -> index.binding()
mainIndexer.add( docId( 1 ), routingKey, document -> mainIndex.binding()
.initDocument( document, AnalyzedStringFieldTypeDescriptor.INSTANCE, "irrelevant" ) );
missingFieldIndexer.add( docId( MISSING_FIELD_INDEX_DOC_ORDINAL ), routingKey,
document -> missingFieldIndex.binding().initDocument() );
}

public List<String> docIdsExcept(int docOrdinal) {
return IntStream.range( 0, 3 ).filter( i -> i != docOrdinal )
return IntStream.concat(
IntStream.range( 0, 3 ).filter( i -> i != docOrdinal ),
IntStream.of( MISSING_FIELD_INDEX_DOC_ORDINAL )
)
.mapToObj( this::docId ).collect( Collectors.toList() );
}
}
Expand Down

0 comments on commit 66c09c3

Please sign in to comment.