Skip to content

Commit

Permalink
HSEARCH-4173 Test behavior of most (non-nested) predicates when a fie…
Browse files Browse the repository at this point in the history
…ld exists in only one index

Signed-off-by: Yoann Rodière <yoann@hibernate.org>
  • Loading branch information
yrodiere committed Mar 2, 2021
1 parent f1aa63c commit 02b7974
Show file tree
Hide file tree
Showing 12 changed files with 230 additions and 42 deletions.
Expand Up @@ -31,6 +31,7 @@
import org.hibernate.search.util.impl.integrationtest.mapper.stub.BulkIndexer;
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;

Expand All @@ -39,17 +40,20 @@ public abstract class AbstractPredicateTypeCheckingAndConversionIT<V extends Abs
private final SimpleMappedIndex<IndexBinding> index;
private final SimpleMappedIndex<CompatibleIndexBinding> compatibleIndex;
private final SimpleMappedIndex<RawFieldCompatibleIndexBinding> rawFieldCompatibleIndex;
private final SimpleMappedIndex<MissingFieldIndexBinding> missingFieldIndex;
private final SimpleMappedIndex<IncompatibleIndexBinding> incompatibleIndex;
protected final DataSet<?, V> dataSet;

protected AbstractPredicateTypeCheckingAndConversionIT(SimpleMappedIndex<IndexBinding> index,
SimpleMappedIndex<CompatibleIndexBinding> compatibleIndex,
SimpleMappedIndex<RawFieldCompatibleIndexBinding> rawFieldCompatibleIndex,
SimpleMappedIndex<MissingFieldIndexBinding> missingFieldIndex,
SimpleMappedIndex<IncompatibleIndexBinding> incompatibleIndex,
DataSet<?, V> dataSet) {
this.index = index;
this.compatibleIndex = compatibleIndex;
this.rawFieldCompatibleIndex = rawFieldCompatibleIndex;
this.missingFieldIndex = missingFieldIndex;
this.incompatibleIndex = incompatibleIndex;
this.dataSet = dataSet;
}
Expand Down Expand Up @@ -263,6 +267,68 @@ public void multiIndex_withRawFieldCompatibleIndex_valueConvertNo() {
} );
}

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

// The predicate should not match anything in missingFieldIndex
assertThatQuery( scope.query()
.where( f -> predicate( f, defaultDslConverterField0Path(), unwrappedMatchingParam( 0 ),
ValueConvert.YES ) )
.routing( dataSet.routingKey ) )
.hasDocRefHitsAnyOrder( b -> {
b.doc( index.typeName(), dataSet.docId( 0 ) );
} );

// ... but it should not prevent the query from executing either:
// if the predicate is optional, it should be ignored for missingFieldIndex.
assertThatQuery( scope.query()
.where( f -> f.bool()
.should( predicate( f, defaultDslConverterField0Path(), unwrappedMatchingParam( 0 ),
ValueConvert.YES ) )
.should( f.id().matching( dataSet.docId( DataSet.MISSING_FIELD_INDEX_DOC_ORDINAL ) ) ) ) )
.hasDocRefHitsAnyOrder( c -> c
.doc( index.typeName(), dataSet.docId( 0 ) )
.doc( missingFieldIndex.typeName(), dataSet.docId( DataSet.MISSING_FIELD_INDEX_DOC_ORDINAL ) ) )
.hasTotalHitCount( 2 );
}

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

// The predicate should not match anything in missingFieldIndex
assertThatQuery( scope.query()
.where( f -> predicate( f, defaultDslConverterField0Path(), unwrappedMatchingParam( 0 ),
ValueConvert.NO ) )
.routing( dataSet.routingKey ) )
.hasDocRefHitsAnyOrder( b -> {
b.doc( index.typeName(), dataSet.docId( 0 ) );
} );

// ... but it should not prevent the query from executing either:
// if the predicate is optional, it should be ignored for missingFieldIndex.
assertThatQuery( scope.query()
.where( f -> f.bool()
.should( predicate( f, defaultDslConverterField0Path(), unwrappedMatchingParam( 0 ),
ValueConvert.NO ) )
.should( f.id().matching( dataSet.docId( DataSet.MISSING_FIELD_INDEX_DOC_ORDINAL ) ) ) ) )
.hasDocRefHitsAnyOrder( c -> c
.doc( index.typeName(), dataSet.docId( 0 ) )
.doc( missingFieldIndex.typeName(), dataSet.docId( DataSet.MISSING_FIELD_INDEX_DOC_ORDINAL ) ) )
.hasTotalHitCount( 2 );
}

@Test
public void multiIndex_withIncompatibleIndex_valueConvertYes() {
StubMappingScope scope = index.createScope( incompatibleIndex );
Expand Down Expand Up @@ -401,15 +467,23 @@ public IncompatibleIndexBinding(IndexSchemaElement root, Collection<? extends Fi
}
}

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

public static final class DataSet<F, V extends AbstractPredicateTestValues<F>>
extends AbstractPerFieldTypePredicateDataSet<F, V> {
public static final int MISSING_FIELD_INDEX_DOC_ORDINAL = 100;

public DataSet(V values) {
super( values );
}

public void contribute(SimpleMappedIndex<IndexBinding> mainIndex, BulkIndexer mainIndexer,
SimpleMappedIndex<CompatibleIndexBinding> compatibleIndex, BulkIndexer compatibleIndexer,
SimpleMappedIndex<RawFieldCompatibleIndexBinding> rawFieldCompatibleIndex, BulkIndexer rawFieldCompatibleIndexer) {
SimpleMappedIndex<RawFieldCompatibleIndexBinding> rawFieldCompatibleIndex, BulkIndexer rawFieldCompatibleIndexer,
SimpleMappedIndex<MissingFieldIndexBinding> missingFieldIndex, BulkIndexer missingFieldIndexer) {
mainIndexer.add( docId( 0 ), routingKey,
document -> initDocument( mainIndex, document, values.fieldValue( 0 ) ) );
mainIndexer.add( docId( 1 ), routingKey,
Expand All @@ -422,6 +496,7 @@ public void contribute(SimpleMappedIndex<IndexBinding> mainIndex, BulkIndexer ma
document -> initRawFieldCompatibleDocument( rawFieldCompatibleIndex, document, values.fieldValue( 0 ) ) );
rawFieldCompatibleIndexer.add( docId( 1 ), routingKey,
document -> initRawFieldCompatibleDocument( rawFieldCompatibleIndex, document, values.fieldValue( 1 ) ) );
missingFieldIndexer.add( docId( MISSING_FIELD_INDEX_DOC_ORDINAL ), routingKey, document -> { } );
}

private void initDocument(SimpleMappedIndex<IndexBinding> index, DocumentElement document,
Expand Down
Expand Up @@ -31,6 +31,7 @@
import org.hibernate.search.util.impl.integrationtest.mapper.stub.BulkIndexer;
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;

Expand All @@ -39,17 +40,20 @@ public abstract class AbstractPredicateTypeCheckingNoConversionIT<V extends Abst
private final SimpleMappedIndex<IndexBinding> index;
private final SimpleMappedIndex<CompatibleIndexBinding> compatibleIndex;
private final SimpleMappedIndex<RawFieldCompatibleIndexBinding> rawFieldCompatibleIndex;
private final SimpleMappedIndex<MissingFieldIndexBinding> missingFieldIndex;
private final SimpleMappedIndex<IncompatibleIndexBinding> incompatibleIndex;
protected final DataSet<?, V> dataSet;

protected AbstractPredicateTypeCheckingNoConversionIT(SimpleMappedIndex<IndexBinding> index,
SimpleMappedIndex<CompatibleIndexBinding> compatibleIndex,
SimpleMappedIndex<RawFieldCompatibleIndexBinding> rawFieldCompatibleIndex,
SimpleMappedIndex<MissingFieldIndexBinding> missingFieldIndex,
SimpleMappedIndex<IncompatibleIndexBinding> incompatibleIndex,
DataSet<?, V> dataSet) {
this.index = index;
this.compatibleIndex = compatibleIndex;
this.rawFieldCompatibleIndex = rawFieldCompatibleIndex;
this.missingFieldIndex = missingFieldIndex;
this.incompatibleIndex = incompatibleIndex;
this.dataSet = dataSet;
}
Expand Down Expand Up @@ -106,6 +110,35 @@ public void multiIndex_withRawFieldCompatibleIndex() {
} );
}

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

// The predicate should not match anything in missingFieldIndex
assertThatQuery( scope.query()
.where( f -> predicate( f, defaultDslConverterField0Path(), 0 ) )
.routing( dataSet.routingKey ) )
.hasDocRefHitsAnyOrder( b -> {
b.doc( index.typeName(), dataSet.docId( 0 ) );
} );

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

// Fields with a different type *are* a problem, though.
@Test
public void multiIndex_withIncompatibleIndex() {
Expand Down Expand Up @@ -216,6 +249,11 @@ public RawFieldCompatibleIndexBinding(IndexSchemaElement root, Collection<? exte
}
}

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

public static final class IncompatibleIndexBinding {
public IncompatibleIndexBinding(IndexSchemaElement root, Collection<? extends FieldTypeDescriptor<?>> fieldTypes) {
fieldTypes.forEach( fieldType ->
Expand All @@ -235,19 +273,23 @@ public IncompatibleIndexBinding(IndexSchemaElement root, Collection<? extends Fi

public static final class DataSet<F, V extends AbstractPredicateTestValues<F>>
extends AbstractPerFieldTypePredicateDataSet<F, V> {
public static final int MISSING_FIELD_INDEX_DOC_ORDINAL = 100;

public DataSet(V values) {
super( values );
}

public void contribute(SimpleMappedIndex<IndexBinding> mainIndex, BulkIndexer mainIndexer,
SimpleMappedIndex<CompatibleIndexBinding> compatibleIndex, BulkIndexer compatibleIndexer,
SimpleMappedIndex<RawFieldCompatibleIndexBinding> rawFieldCompatibleIndex, BulkIndexer rawFieldCompatibleIndexer) {
SimpleMappedIndex<RawFieldCompatibleIndexBinding> rawFieldCompatibleIndex, BulkIndexer rawFieldCompatibleIndexer,
SimpleMappedIndex<MissingFieldIndexBinding> missingFieldIndex, BulkIndexer missingFieldIndexer) {
mainIndexer.add( docId( 0 ), routingKey,
document -> initDocument( mainIndex, document, values.fieldValue( 0 ) ) );
compatibleIndexer.add( docId( 0 ), routingKey,
document -> initCompatibleDocument( compatibleIndex, document, values.fieldValue( 0 ) ) );
rawFieldCompatibleIndexer.add( docId( 0 ), routingKey,
document -> initRawFieldCompatibleDocument( rawFieldCompatibleIndex, document, values.fieldValue( 0 ) ) );
missingFieldIndexer.add( docId( MISSING_FIELD_INDEX_DOC_ORDINAL ), routingKey, document -> { } );

if ( values.size() > 1 ) {
mainIndexer.add( docId( 1 ), routingKey,
Expand Down
Expand Up @@ -44,7 +44,8 @@ public static void setup() {
InvalidFieldIT.index,
SearchableIT.searchableYesIndex, SearchableIT.searchableNoIndex,
TypeCheckingNoConversionIT.index, TypeCheckingNoConversionIT.compatibleIndex,
TypeCheckingNoConversionIT.rawFieldCompatibleIndex, TypeCheckingNoConversionIT.incompatibleIndex,
TypeCheckingNoConversionIT.rawFieldCompatibleIndex, TypeCheckingNoConversionIT.missingFieldIndex,
TypeCheckingNoConversionIT.incompatibleIndex,
ScaleCheckingIT.index, ScaleCheckingIT.compatibleIndex, ScaleCheckingIT.incompatibleIndex
)
.setup();
Expand All @@ -61,9 +62,11 @@ public static void setup() {
final BulkIndexer typeCheckingMainIndexer = TypeCheckingNoConversionIT.index.bulkIndexer();
final BulkIndexer typeCheckingCompatibleIndexer = TypeCheckingNoConversionIT.compatibleIndex.bulkIndexer();
final BulkIndexer typeCheckingRawFieldCompatibleIndexer = TypeCheckingNoConversionIT.rawFieldCompatibleIndex.bulkIndexer();
final BulkIndexer typeCheckingMissingFieldIndexer = TypeCheckingNoConversionIT.missingFieldIndex.bulkIndexer();
TypeCheckingNoConversionIT.dataSets.forEach( d -> d.contribute( TypeCheckingNoConversionIT.index, typeCheckingMainIndexer,
TypeCheckingNoConversionIT.compatibleIndex, typeCheckingCompatibleIndexer,
TypeCheckingNoConversionIT.rawFieldCompatibleIndex, typeCheckingRawFieldCompatibleIndexer ) );
TypeCheckingNoConversionIT.rawFieldCompatibleIndex, typeCheckingRawFieldCompatibleIndexer,
TypeCheckingNoConversionIT.missingFieldIndex, typeCheckingMissingFieldIndexer ) );

final BulkIndexer scaleCheckingMainIndexer = ScaleCheckingIT.index.bulkIndexer();
final BulkIndexer scaleCheckingCompatibleIndexer = ScaleCheckingIT.compatibleIndex.bulkIndexer();
Expand All @@ -72,7 +75,8 @@ public static void setup() {

singleFieldIndexer.join(
nestingIndexer, scoreIndexer,
typeCheckingMainIndexer, typeCheckingCompatibleIndexer, typeCheckingRawFieldCompatibleIndexer,
typeCheckingMainIndexer, typeCheckingCompatibleIndexer,
typeCheckingRawFieldCompatibleIndexer, typeCheckingMissingFieldIndexer,
scaleCheckingMainIndexer, scaleCheckingCompatibleIndexer
);
}
Expand Down Expand Up @@ -349,12 +353,15 @@ protected void addIrrelevantOptions(FieldTypeDescriptor<?> fieldType,
private static final SimpleMappedIndex<RawFieldCompatibleIndexBinding> rawFieldCompatibleIndex =
SimpleMappedIndex.of( root -> new RawFieldCompatibleIndexBinding( root, supportedFieldTypes ) )
.name( "typeChecking_rawFieldCompatible" );
private static final SimpleMappedIndex<MissingFieldIndexBinding> missingFieldIndex =
SimpleMappedIndex.of( root -> new MissingFieldIndexBinding( root, supportedFieldTypes ) )
.name( "typeChecking_missingField" );
private static final SimpleMappedIndex<IncompatibleIndexBinding> incompatibleIndex =
SimpleMappedIndex.of( root -> new IncompatibleIndexBinding( root, supportedFieldTypes ) )
.name( "typeChecking_incompatible" );

public TypeCheckingNoConversionIT(DataSet<F, ExistsPredicateTestValues<F>> dataSet) {
super( index, compatibleIndex, rawFieldCompatibleIndex, incompatibleIndex, dataSet );
super( index, compatibleIndex, rawFieldCompatibleIndex, missingFieldIndex, incompatibleIndex, dataSet );
}

@Override
Expand Down
Expand Up @@ -57,7 +57,8 @@ public static void setup() {
SearchableIT.searchableYesIndex, SearchableIT.searchableNoIndex,
ArgumentCheckingIT.index,
TypeCheckingAndConversionIT.index, TypeCheckingAndConversionIT.compatibleIndex,
TypeCheckingAndConversionIT.rawFieldCompatibleIndex, TypeCheckingAndConversionIT.incompatibleIndex,
TypeCheckingAndConversionIT.rawFieldCompatibleIndex, TypeCheckingAndConversionIT.missingFieldIndex,
TypeCheckingAndConversionIT.incompatibleIndex,
ScaleCheckingIT.index, ScaleCheckingIT.compatibleIndex, ScaleCheckingIT.incompatibleIndex
)
.setup();
Expand All @@ -84,9 +85,11 @@ public static void setup() {
final BulkIndexer typeCheckingMainIndexer = TypeCheckingAndConversionIT.index.bulkIndexer();
final BulkIndexer typeCheckingCompatibleIndexer = TypeCheckingAndConversionIT.compatibleIndex.bulkIndexer();
final BulkIndexer typeCheckingRawFieldCompatibleIndexer = TypeCheckingAndConversionIT.rawFieldCompatibleIndex.bulkIndexer();
final BulkIndexer typeCheckingMissingFieldIndexer = TypeCheckingAndConversionIT.missingFieldIndex.bulkIndexer();
TypeCheckingAndConversionIT.dataSets.forEach( d -> d.contribute( TypeCheckingAndConversionIT.index, typeCheckingMainIndexer,
TypeCheckingAndConversionIT.compatibleIndex, typeCheckingCompatibleIndexer,
TypeCheckingAndConversionIT.rawFieldCompatibleIndex, typeCheckingRawFieldCompatibleIndexer ) );
TypeCheckingAndConversionIT.rawFieldCompatibleIndex, typeCheckingRawFieldCompatibleIndexer,
TypeCheckingAndConversionIT.missingFieldIndex, typeCheckingMissingFieldIndexer ) );

final BulkIndexer scaleCheckingMainIndexer = ScaleCheckingIT.index.bulkIndexer();
final BulkIndexer scaleCheckingCompatibleIndexer = ScaleCheckingIT.compatibleIndex.bulkIndexer();
Expand All @@ -97,7 +100,8 @@ public static void setup() {
multiFieldIndexer, nestingIndexer,
analysisMainIndexIndexer, analysisCompatibleIndexIndexer, analysisIncompatibleIndexIndexer,
scoreIndexer,
typeCheckingMainIndexer, typeCheckingCompatibleIndexer, typeCheckingRawFieldCompatibleIndexer,
typeCheckingMainIndexer, typeCheckingCompatibleIndexer,
typeCheckingRawFieldCompatibleIndexer, typeCheckingMissingFieldIndexer,
scaleCheckingMainIndexer, scaleCheckingCompatibleIndexer
);
}
Expand Down Expand Up @@ -462,6 +466,9 @@ public static class TypeCheckingAndConversionIT<F>
private static final SimpleMappedIndex<RawFieldCompatibleIndexBinding> rawFieldCompatibleIndex =
SimpleMappedIndex.of( root -> new RawFieldCompatibleIndexBinding( root, supportedFieldTypes ) )
.name( "typeChecking_rawFieldCompatible" );
private static final SimpleMappedIndex<MissingFieldIndexBinding> missingFieldIndex =
SimpleMappedIndex.of( root -> new MissingFieldIndexBinding( root, supportedFieldTypes ) )
.name( "typeChecking_missingField" );
private static final SimpleMappedIndex<IncompatibleIndexBinding> incompatibleIndex =
SimpleMappedIndex.of( root -> new IncompatibleIndexBinding( root, supportedFieldTypes ) )
.name( "typeChecking_incompatible" );
Expand All @@ -472,7 +479,7 @@ public static List<Object[]> parameters() {
}

public TypeCheckingAndConversionIT(DataSet<F, MatchPredicateTestValues<F>> dataSet) {
super( index, compatibleIndex, rawFieldCompatibleIndex, incompatibleIndex, dataSet );
super( index, compatibleIndex, rawFieldCompatibleIndex, missingFieldIndex, incompatibleIndex, dataSet );
}

@Override
Expand Down

0 comments on commit 02b7974

Please sign in to comment.