Handle leniency for cross_fields type in multi_match query (#27045)
This commit is contained in:
parent
8a05e5b92c
commit
9a3a1cd1b7
|
@ -43,6 +43,8 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import static org.elasticsearch.common.lucene.search.Queries.newLenientFieldQuery;
|
||||
|
||||
public class MultiMatchQuery extends MatchQuery {
|
||||
|
||||
private Float groupTieBreaker = null;
|
||||
|
@ -204,7 +206,7 @@ public class MultiMatchQuery extends MatchQuery {
|
|||
for (int i = 0; i < terms.length; i++) {
|
||||
values[i] = terms[i].bytes();
|
||||
}
|
||||
return MultiMatchQuery.blendTerms(context, values, commonTermsCutoff, tieBreaker, blendedFields);
|
||||
return MultiMatchQuery.blendTerms(context, values, commonTermsCutoff, tieBreaker, lenient, blendedFields);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -212,7 +214,7 @@ public class MultiMatchQuery extends MatchQuery {
|
|||
if (blendedFields == null) {
|
||||
return super.blendTerm(term, fieldType);
|
||||
}
|
||||
return MultiMatchQuery.blendTerm(context, term.bytes(), commonTermsCutoff, tieBreaker, blendedFields);
|
||||
return MultiMatchQuery.blendTerm(context, term.bytes(), commonTermsCutoff, tieBreaker, lenient, blendedFields);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -227,12 +229,12 @@ public class MultiMatchQuery extends MatchQuery {
|
|||
}
|
||||
|
||||
static Query blendTerm(QueryShardContext context, BytesRef value, Float commonTermsCutoff, float tieBreaker,
|
||||
FieldAndFieldType... blendedFields) {
|
||||
return blendTerms(context, new BytesRef[] {value}, commonTermsCutoff, tieBreaker, blendedFields);
|
||||
boolean lenient, FieldAndFieldType... blendedFields) {
|
||||
return blendTerms(context, new BytesRef[] {value}, commonTermsCutoff, tieBreaker, lenient, blendedFields);
|
||||
}
|
||||
|
||||
static Query blendTerms(QueryShardContext context, BytesRef[] values, Float commonTermsCutoff, float tieBreaker,
|
||||
FieldAndFieldType... blendedFields) {
|
||||
boolean lenient, FieldAndFieldType... blendedFields) {
|
||||
List<Query> queries = new ArrayList<>();
|
||||
Term[] terms = new Term[blendedFields.length * values.length];
|
||||
float[] blendedBoost = new float[blendedFields.length * values.length];
|
||||
|
@ -242,19 +244,12 @@ public class MultiMatchQuery extends MatchQuery {
|
|||
Query query;
|
||||
try {
|
||||
query = ft.fieldType.termQuery(term, context);
|
||||
} catch (IllegalArgumentException e) {
|
||||
// the query expects a certain class of values such as numbers
|
||||
// of ip addresses and the value can't be parsed, so ignore this
|
||||
// field
|
||||
continue;
|
||||
} catch (ElasticsearchParseException parseException) {
|
||||
// date fields throw an ElasticsearchParseException with the
|
||||
// underlying IAE as the cause, ignore this field if that is
|
||||
// the case
|
||||
if (parseException.getCause() instanceof IllegalArgumentException) {
|
||||
continue;
|
||||
} catch (RuntimeException e) {
|
||||
if (lenient) {
|
||||
query = newLenientFieldQuery(ft.fieldType.name(), e);
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
throw parseException;
|
||||
}
|
||||
float boost = ft.boost;
|
||||
while (query instanceof BoostQuery) {
|
||||
|
|
|
@ -30,6 +30,7 @@ import org.apache.lucene.search.SynonymQuery;
|
|||
import org.apache.lucene.search.TermQuery;
|
||||
import org.apache.lucene.util.BytesRef;
|
||||
import org.elasticsearch.common.compress.CompressedXContent;
|
||||
import org.elasticsearch.common.lucene.search.Queries;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.index.IndexService;
|
||||
import org.elasticsearch.index.engine.Engine;
|
||||
|
@ -110,7 +111,7 @@ public class MultiMatchQueryTests extends ESSingleNodeTestCase {
|
|||
Query expected = BlendedTermQuery.dismaxBlendedQuery(terms, boosts, 1.0f);
|
||||
Query actual = MultiMatchQuery.blendTerm(
|
||||
indexService.newQueryShardContext(randomInt(20), null, () -> { throw new UnsupportedOperationException(); }, null),
|
||||
new BytesRef("baz"), null, 1f, new FieldAndFieldType(ft1, 2), new FieldAndFieldType(ft2, 3));
|
||||
new BytesRef("baz"), null, 1f, false, new FieldAndFieldType(ft1, 2), new FieldAndFieldType(ft2, 3));
|
||||
assertEquals(expected, actual);
|
||||
}
|
||||
|
||||
|
@ -126,11 +127,11 @@ public class MultiMatchQueryTests extends ESSingleNodeTestCase {
|
|||
Query expected = BlendedTermQuery.dismaxBlendedQuery(terms, boosts, 1.0f);
|
||||
Query actual = MultiMatchQuery.blendTerm(
|
||||
indexService.newQueryShardContext(randomInt(20), null, () -> { throw new UnsupportedOperationException(); }, null),
|
||||
new BytesRef("baz"), null, 1f, new FieldAndFieldType(ft1, 2), new FieldAndFieldType(ft2, 3));
|
||||
new BytesRef("baz"), null, 1f, false, new FieldAndFieldType(ft1, 2), new FieldAndFieldType(ft2, 3));
|
||||
assertEquals(expected, actual);
|
||||
}
|
||||
|
||||
public void testBlendTermsUnsupportedValue() {
|
||||
public void testBlendTermsUnsupportedValueWithLenient() {
|
||||
FakeFieldType ft1 = new FakeFieldType();
|
||||
ft1.setName("foo");
|
||||
FakeFieldType ft2 = new FakeFieldType() {
|
||||
|
@ -142,13 +143,29 @@ public class MultiMatchQueryTests extends ESSingleNodeTestCase {
|
|||
ft2.setName("bar");
|
||||
Term[] terms = new Term[] { new Term("foo", "baz") };
|
||||
float[] boosts = new float[] {2};
|
||||
Query expected = BlendedTermQuery.dismaxBlendedQuery(terms, boosts, 1.0f);
|
||||
Query expected = new DisjunctionMaxQuery(Arrays.asList(
|
||||
Queries.newMatchNoDocsQuery("failed [" + ft2.name() + "] query, caused by illegal_argument_exception:[null]"),
|
||||
BlendedTermQuery.dismaxBlendedQuery(terms, boosts, 1.0f)
|
||||
), 1f);
|
||||
Query actual = MultiMatchQuery.blendTerm(
|
||||
indexService.newQueryShardContext(randomInt(20), null, () -> { throw new UnsupportedOperationException(); }, null),
|
||||
new BytesRef("baz"), null, 1f, new FieldAndFieldType(ft1, 2), new FieldAndFieldType(ft2, 3));
|
||||
new BytesRef("baz"), null, 1f, true, new FieldAndFieldType(ft1, 2), new FieldAndFieldType(ft2, 3));
|
||||
assertEquals(expected, actual);
|
||||
}
|
||||
|
||||
public void testBlendTermsUnsupportedValueWithoutLenient() {
|
||||
FakeFieldType ft = new FakeFieldType() {
|
||||
@Override
|
||||
public Query termQuery(Object value, QueryShardContext context) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
};
|
||||
ft.setName("bar");
|
||||
expectThrows(IllegalArgumentException.class, () -> MultiMatchQuery.blendTerm(
|
||||
indexService.newQueryShardContext(randomInt(20), null, () -> { throw new UnsupportedOperationException(); }, null),
|
||||
new BytesRef("baz"), null, 1f, false, new FieldAndFieldType(ft, 1)));
|
||||
}
|
||||
|
||||
public void testBlendNoTermQuery() {
|
||||
FakeFieldType ft1 = new FakeFieldType();
|
||||
ft1.setName("foo");
|
||||
|
@ -170,7 +187,7 @@ public class MultiMatchQueryTests extends ESSingleNodeTestCase {
|
|||
), 1.0f);
|
||||
Query actual = MultiMatchQuery.blendTerm(
|
||||
indexService.newQueryShardContext(randomInt(20), null, () -> { throw new UnsupportedOperationException(); }, null),
|
||||
new BytesRef("baz"), null, 1f, new FieldAndFieldType(ft1, 2), new FieldAndFieldType(ft2, 3));
|
||||
new BytesRef("baz"), null, 1f, false, new FieldAndFieldType(ft1, 2), new FieldAndFieldType(ft2, 3));
|
||||
assertEquals(expected, actual);
|
||||
}
|
||||
|
||||
|
|
|
@ -472,6 +472,7 @@ public class MultiMatchQueryIT extends ESIntegTestCase {
|
|||
.setQuery(randomizeType(multiMatchQuery("captain america 15", "full_name", "first_name", "last_name", "category", "skill")
|
||||
.type(MultiMatchQueryBuilder.Type.CROSS_FIELDS)
|
||||
.analyzer("category")
|
||||
.lenient(true)
|
||||
.operator(Operator.AND))).get();
|
||||
assertHitCount(searchResponse, 1L);
|
||||
assertFirstHit(searchResponse, hasId("theone"));
|
||||
|
@ -480,6 +481,7 @@ public class MultiMatchQueryIT extends ESIntegTestCase {
|
|||
.setQuery(randomizeType(multiMatchQuery("captain america 15", "full_name", "first_name", "last_name", "category", "skill", "int-field")
|
||||
.type(MultiMatchQueryBuilder.Type.CROSS_FIELDS)
|
||||
.analyzer("category")
|
||||
.lenient(true)
|
||||
.operator(Operator.AND))).get();
|
||||
assertHitCount(searchResponse, 1L);
|
||||
assertFirstHit(searchResponse, hasId("theone"));
|
||||
|
@ -488,6 +490,7 @@ public class MultiMatchQueryIT extends ESIntegTestCase {
|
|||
.setQuery(randomizeType(multiMatchQuery("captain america 15", "skill", "full_name", "first_name", "last_name", "category", "int-field")
|
||||
.type(MultiMatchQueryBuilder.Type.CROSS_FIELDS)
|
||||
.analyzer("category")
|
||||
.lenient(true)
|
||||
.operator(Operator.AND))).get();
|
||||
assertHitCount(searchResponse, 1L);
|
||||
assertFirstHit(searchResponse, hasId("theone"));
|
||||
|
@ -496,6 +499,7 @@ public class MultiMatchQueryIT extends ESIntegTestCase {
|
|||
searchResponse = client().prepareSearch("test")
|
||||
.setQuery(randomizeType(multiMatchQuery("captain america 15", "first_name", "last_name", "skill")
|
||||
.type(MultiMatchQueryBuilder.Type.CROSS_FIELDS)
|
||||
.lenient(true)
|
||||
.analyzer("category"))).get();
|
||||
assertFirstHit(searchResponse, hasId("theone"));
|
||||
|
||||
|
|
Loading…
Reference in New Issue