more_like_this query to throw an error if the like fields is not provided (#40632)
With the removal of the `_all` field the `mlt` query cannot infer a field name to use to analyze the provided (un)like text if the `fields` parameter is not explicitly set in the query and the `index.query.default_field` is not changed in the index settings (by default it is set to `*`). For this reason the like text is ignored and queries are only built from the provided document ids. This change fixes this bug by throwing an error if the fields option is not set and the `index.query.default_field` is equals to `*`. The error is thrown only if like or unlike texts are provided in the query.
This commit is contained in:
parent
1f5cd410b8
commit
068f8ba223
|
@ -1050,6 +1050,13 @@ public class MoreLikeThisQueryBuilder extends AbstractQueryBuilder<MoreLikeThisQ
|
||||||
List<String> moreLikeFields = new ArrayList<>();
|
List<String> moreLikeFields = new ArrayList<>();
|
||||||
if (useDefaultField) {
|
if (useDefaultField) {
|
||||||
moreLikeFields = context.defaultFields();
|
moreLikeFields = context.defaultFields();
|
||||||
|
if (moreLikeFields.size() == 1
|
||||||
|
&& moreLikeFields.get(0).equals("*")
|
||||||
|
&& (likeTexts.length > 0 || unlikeTexts.length > 0)) {
|
||||||
|
throw new IllegalArgumentException("[more_like_this] query cannot infer the field to analyze the free text, " +
|
||||||
|
"you should update the [index.query.default_field] index setting to a field that exists in the mapping or " +
|
||||||
|
"set the [fields] option in the query.");
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
for (String field : fields) {
|
for (String field : fields) {
|
||||||
MappedFieldType fieldType = context.fieldMapper(field);
|
MappedFieldType fieldType = context.fieldMapper(field);
|
||||||
|
|
|
@ -31,10 +31,12 @@ import org.elasticsearch.action.termvectors.MultiTermVectorsRequest;
|
||||||
import org.elasticsearch.action.termvectors.MultiTermVectorsResponse;
|
import org.elasticsearch.action.termvectors.MultiTermVectorsResponse;
|
||||||
import org.elasticsearch.action.termvectors.TermVectorsRequest;
|
import org.elasticsearch.action.termvectors.TermVectorsRequest;
|
||||||
import org.elasticsearch.action.termvectors.TermVectorsResponse;
|
import org.elasticsearch.action.termvectors.TermVectorsResponse;
|
||||||
|
import org.elasticsearch.cluster.metadata.IndexMetaData;
|
||||||
import org.elasticsearch.common.Strings;
|
import org.elasticsearch.common.Strings;
|
||||||
import org.elasticsearch.common.bytes.BytesReference;
|
import org.elasticsearch.common.bytes.BytesReference;
|
||||||
import org.elasticsearch.common.io.stream.BytesStreamOutput;
|
import org.elasticsearch.common.io.stream.BytesStreamOutput;
|
||||||
import org.elasticsearch.common.lucene.search.MoreLikeThisQuery;
|
import org.elasticsearch.common.lucene.search.MoreLikeThisQuery;
|
||||||
|
import org.elasticsearch.common.settings.Settings;
|
||||||
import org.elasticsearch.common.xcontent.ToXContent;
|
import org.elasticsearch.common.xcontent.ToXContent;
|
||||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
import org.elasticsearch.common.xcontent.XContentFactory;
|
import org.elasticsearch.common.xcontent.XContentFactory;
|
||||||
|
@ -160,13 +162,13 @@ public class MoreLikeThisQueryBuilderTests extends AbstractQueryTestCase<MoreLik
|
||||||
} else {
|
} else {
|
||||||
likeItems = randomLikeItems;
|
likeItems = randomLikeItems;
|
||||||
}
|
}
|
||||||
if (randomBoolean()) { // for the default field
|
if (randomBoolean() && likeItems != null && likeItems.length > 0) { // for the default field
|
||||||
queryBuilder = new MoreLikeThisQueryBuilder(likeTexts, likeItems);
|
queryBuilder = new MoreLikeThisQueryBuilder(null, likeItems);
|
||||||
} else {
|
} else {
|
||||||
queryBuilder = new MoreLikeThisQueryBuilder(randomFields, likeTexts, likeItems);
|
queryBuilder = new MoreLikeThisQueryBuilder(randomFields, likeTexts, likeItems);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (randomBoolean()) {
|
if (randomBoolean() && queryBuilder.fields() != null) {
|
||||||
queryBuilder.unlike(generateRandomStringArray(5, 5, false, false));
|
queryBuilder.unlike(generateRandomStringArray(5, 5, false, false));
|
||||||
}
|
}
|
||||||
if (randomBoolean()) {
|
if (randomBoolean()) {
|
||||||
|
@ -305,6 +307,39 @@ public class MoreLikeThisQueryBuilderTests extends AbstractQueryTestCase<MoreLik
|
||||||
assertThat(e.getMessage(), containsString("more_like_this only supports text/keyword fields"));
|
assertThat(e.getMessage(), containsString("more_like_this only supports text/keyword fields"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testDefaultField() throws IOException {
|
||||||
|
QueryShardContext context = createShardContext();
|
||||||
|
|
||||||
|
{
|
||||||
|
MoreLikeThisQueryBuilder builder =
|
||||||
|
new MoreLikeThisQueryBuilder(new String[]{"hello world"}, null);
|
||||||
|
IllegalArgumentException e = expectThrows(IllegalArgumentException.class,
|
||||||
|
() -> builder.toQuery(context));
|
||||||
|
assertThat(e.getMessage(), containsString("[more_like_this] query cannot infer"));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
context.getIndexSettings().updateIndexMetaData(
|
||||||
|
newIndexMeta("index",
|
||||||
|
context.getIndexSettings().getSettings(),
|
||||||
|
Settings.builder().putList("index.query.default_field", STRING_FIELD_NAME).build()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
try {
|
||||||
|
MoreLikeThisQueryBuilder builder = new MoreLikeThisQueryBuilder(new String[]{"hello world"}, null);
|
||||||
|
builder.toQuery(context);
|
||||||
|
} finally {
|
||||||
|
// Reset the default value
|
||||||
|
context.getIndexSettings().updateIndexMetaData(
|
||||||
|
newIndexMeta("index",
|
||||||
|
context.getIndexSettings().getSettings(),
|
||||||
|
Settings.builder().putList("index.query.default_field", "*").build()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void testMoreLikeThisBuilder() throws Exception {
|
public void testMoreLikeThisBuilder() throws Exception {
|
||||||
Query parsedQuery =
|
Query parsedQuery =
|
||||||
parseQuery(moreLikeThisQuery(new String[]{"name.first", "name.last"}, new String[]{"something"}, null)
|
parseQuery(moreLikeThisQuery(new String[]{"name.first", "name.last"}, new String[]{"something"}, null)
|
||||||
|
@ -390,4 +425,11 @@ public class MoreLikeThisQueryBuilderTests extends AbstractQueryTestCase<MoreLik
|
||||||
}
|
}
|
||||||
return query;
|
return query;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static IndexMetaData newIndexMeta(String name, Settings oldIndexSettings, Settings indexSettings) {
|
||||||
|
Settings build = Settings.builder().put(oldIndexSettings)
|
||||||
|
.put(indexSettings)
|
||||||
|
.build();
|
||||||
|
return IndexMetaData.builder(name).settings(build).build();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -343,10 +343,10 @@ public class MoreLikeThisIT extends ESIntegTestCase {
|
||||||
new MoreLikeThisQueryBuilder(new String[] {"string_value", "int_value"}, null,
|
new MoreLikeThisQueryBuilder(new String[] {"string_value", "int_value"}, null,
|
||||||
new Item[] {new Item("test", "1")}).minTermFreq(1).minDocFreq(1)), SearchPhaseExecutionException.class);
|
new Item[] {new Item("test", "1")}).minTermFreq(1).minDocFreq(1)), SearchPhaseExecutionException.class);
|
||||||
|
|
||||||
// mlt query with no field -> No results (because _all is not enabled)
|
// mlt query with no field -> exception because _all is not enabled)
|
||||||
searchResponse = client().prepareSearch().setQuery(moreLikeThisQuery(new String[] {"index"}).minTermFreq(1).minDocFreq(1))
|
assertThrows(client().prepareSearch()
|
||||||
.get();
|
.setQuery(moreLikeThisQuery(new String[] {"index"}).minTermFreq(1).minDocFreq(1)),
|
||||||
assertHitCount(searchResponse, 0L);
|
SearchPhaseExecutionException.class);
|
||||||
|
|
||||||
// mlt query with string fields
|
// mlt query with string fields
|
||||||
searchResponse = client().prepareSearch().setQuery(moreLikeThisQuery(new String[]{"string_value"}, new String[] {"index"}, null)
|
searchResponse = client().prepareSearch().setQuery(moreLikeThisQuery(new String[]{"string_value"}, new String[] {"index"}, null)
|
||||||
|
|
Loading…
Reference in New Issue