Accept an array of field names and boosts in the index.query.default_field setting (#26320)

* Accept an array of field names and boosts in the index.query.default_field setting

This commit allows to define an array of field names and boosts for the index setting `index.query.default_field`.
The format is equivalent to the `fields` options of the full text search queries (e.g. field_name^boost).
This commit also makes this setting dynamically updatable.

Fixes #25946
This commit is contained in:
Jim Ferenczi 2017-08-23 15:39:54 +02:00 committed by GitHub
parent c1452ff9ea
commit de1e4e0c15
12 changed files with 171 additions and 81 deletions

View File

@ -61,7 +61,6 @@ import org.elasticsearch.index.mapper.MappedFieldType;
import org.elasticsearch.index.shard.ShardId;
import org.elasticsearch.indices.IndicesService;
import org.elasticsearch.indices.analysis.AnalysisModule;
import org.elasticsearch.indices.analysis.PreBuiltTokenizers;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.transport.TransportService;
@ -151,8 +150,12 @@ public class TransportAnalyzeAction extends TransportSingleShardAction<AnalyzeRe
}
}
if (field == null) {
/**
* TODO: _all is disabled by default and index.query.default_field can define multiple fields or pattterns so we should
* probably makes the field name mandatory in analyze query.
**/
if (indexService != null) {
field = indexService.getIndexSettings().getDefaultField();
field = indexService.getIndexSettings().getDefaultFields().get(0);
} else {
field = AllFieldMapper.NAME;
}

View File

@ -23,7 +23,6 @@ import org.apache.lucene.index.MergePolicy;
import org.elasticsearch.Version;
import org.elasticsearch.cluster.metadata.IndexMetaData;
import org.elasticsearch.common.logging.Loggers;
import org.elasticsearch.common.lucene.all.AllField;
import org.elasticsearch.common.settings.IndexScopedSettings;
import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.settings.Setting.Property;
@ -32,10 +31,11 @@ import org.elasticsearch.common.unit.ByteSizeUnit;
import org.elasticsearch.common.unit.ByteSizeValue;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.index.mapper.AllFieldMapper;
import org.elasticsearch.index.mapper.MapperService;
import org.elasticsearch.index.translog.Translog;
import org.elasticsearch.node.Node;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
@ -50,9 +50,9 @@ import java.util.function.Function;
*/
public final class IndexSettings {
public static final String DEFAULT_FIELD_SETTING_KEY = "index.query.default_field";
public static final Setting<String> DEFAULT_FIELD_SETTING;
public static final Setting<List<String>> DEFAULT_FIELD_SETTING;
static {
Function<Settings, String> defValue = settings -> {
Function<Settings, List<String>> defValue = settings -> {
final String defaultField;
if (settings.getAsVersion(IndexMetaData.SETTING_VERSION_CREATED, null) != null &&
Version.indexCreated(settings).before(Version.V_6_0_0_alpha1)) {
@ -60,9 +60,9 @@ public final class IndexSettings {
} else {
defaultField = "*";
}
return defaultField;
return Collections.singletonList(defaultField);
};
DEFAULT_FIELD_SETTING = new Setting<>(DEFAULT_FIELD_SETTING_KEY, defValue, Function.identity(), Property.IndexScope, Property.Dynamic);
DEFAULT_FIELD_SETTING = Setting.listSetting(DEFAULT_FIELD_SETTING_KEY, defValue, Function.identity(), Property.IndexScope, Property.Dynamic);
}
public static final Setting<Boolean> QUERY_STRING_LENIENT_SETTING =
Setting.boolSetting("index.query_string.lenient", false, Property.IndexScope);
@ -205,7 +205,7 @@ public final class IndexSettings {
// volatile fields are updated via #updateIndexMetaData(IndexMetaData) under lock
private volatile Settings settings;
private volatile IndexMetaData indexMetaData;
private final String defaultField;
private volatile List<String> defaultFields;
private final boolean queryStringLenient;
private final boolean queryStringAnalyzeWildcard;
private final boolean queryStringAllowLeadingWildcard;
@ -241,10 +241,14 @@ public final class IndexSettings {
private final boolean singleType;
/**
* Returns the default search field for this index.
* Returns the default search fields for this index.
*/
public String getDefaultField() {
return defaultField;
public List<String> getDefaultFields() {
return defaultFields;
}
private void setDefaultFields(List<String> defaultFields) {
this.defaultFields = defaultFields;
}
/**
@ -304,12 +308,12 @@ public final class IndexSettings {
this.indexMetaData = indexMetaData;
numberOfShards = settings.getAsInt(IndexMetaData.SETTING_NUMBER_OF_SHARDS, null);
this.defaultField = DEFAULT_FIELD_SETTING.get(settings);
this.queryStringLenient = QUERY_STRING_LENIENT_SETTING.get(settings);
this.queryStringAnalyzeWildcard = QUERY_STRING_ANALYZE_WILDCARD.get(nodeSettings);
this.queryStringAllowLeadingWildcard = QUERY_STRING_ALLOW_LEADING_WILDCARD.get(nodeSettings);
this.defaultAllowUnmappedFields = scopedSettings.get(ALLOW_UNMAPPED);
this.durability = scopedSettings.get(INDEX_TRANSLOG_DURABILITY_SETTING);
defaultFields = scopedSettings.get(DEFAULT_FIELD_SETTING);
syncInterval = INDEX_TRANSLOG_SYNC_INTERVAL_SETTING.get(settings);
refreshInterval = scopedSettings.get(INDEX_REFRESH_INTERVAL_SETTING);
flushThresholdSize = scopedSettings.get(INDEX_TRANSLOG_FLUSH_THRESHOLD_SIZE_SETTING);
@ -361,6 +365,7 @@ public final class IndexSettings {
scopedSettings.addSettingsUpdateConsumer(INDEX_REFRESH_INTERVAL_SETTING, this::setRefreshInterval);
scopedSettings.addSettingsUpdateConsumer(MAX_REFRESH_LISTENERS_PER_SHARD, this::setMaxRefreshListeners);
scopedSettings.addSettingsUpdateConsumer(MAX_SLICES_PER_SCROLL, this::setMaxSlicesPerScroll);
scopedSettings.addSettingsUpdateConsumer(DEFAULT_FIELD_SETTING, this::setDefaultFields);
}
private void setTranslogFlushThresholdSize(ByteSizeValue byteSizeValue) {

View File

@ -59,7 +59,6 @@ import org.elasticsearch.index.mapper.UidFieldMapper;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
@ -1033,7 +1032,7 @@ public class MoreLikeThisQueryBuilder extends AbstractQueryBuilder<MoreLikeThisQ
boolean useDefaultField = (fields == null);
List<String> moreLikeFields = new ArrayList<>();
if (useDefaultField) {
moreLikeFields = Collections.singletonList(context.defaultField());
moreLikeFields = context.defaultFields();
} else {
for (String field : fields) {
MappedFieldType fieldType = context.fieldMapper(field);

View File

@ -40,14 +40,11 @@ import org.elasticsearch.index.IndexSettings;
import org.elasticsearch.index.analysis.IndexAnalyzers;
import org.elasticsearch.index.cache.bitset.BitsetFilterCache;
import org.elasticsearch.index.fielddata.IndexFieldData;
import org.elasticsearch.index.fielddata.plain.ConstantIndexFieldData;
import org.elasticsearch.index.mapper.ContentPath;
import org.elasticsearch.index.mapper.DocumentMapper;
import org.elasticsearch.index.mapper.IndexFieldMapper;
import org.elasticsearch.index.mapper.MappedFieldType;
import org.elasticsearch.index.mapper.Mapper;
import org.elasticsearch.index.mapper.MapperService;
import org.elasticsearch.index.mapper.MetadataFieldMapper;
import org.elasticsearch.index.mapper.ObjectMapper;
import org.elasticsearch.index.mapper.TextFieldMapper;
import org.elasticsearch.index.query.support.NestedScope;
@ -60,10 +57,10 @@ import java.io.IOException;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.LongSupplier;
import static java.util.Collections.unmodifiableMap;
@ -144,8 +141,8 @@ public class QueryShardContext extends QueryRewriteContext {
return similarityService != null ? similarityService.similarity(mapperService) : null;
}
public String defaultField() {
return indexSettings.getDefaultField();
public List<String> defaultFields() {
return indexSettings.getDefaultFields();
}
public boolean queryStringLenient() {

View File

@ -42,7 +42,7 @@ import org.joda.time.DateTimeZone;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Map;
@ -738,31 +738,18 @@ public class QueryStringQueryBuilder extends AbstractQueryBuilder<QueryStringQue
Fuzziness fuzziness = QueryStringQueryBuilder.DEFAULT_FUZZINESS;
String fuzzyRewrite = null;
String rewrite = null;
Map<String, Float> fieldsAndWeights = new HashMap<>();
Map<String, Float> fieldsAndWeights = null;
boolean autoGenerateSynonymsPhraseQuery = true;
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
if (token == XContentParser.Token.FIELD_NAME) {
currentFieldName = parser.currentName();
} else if (token == XContentParser.Token.START_ARRAY) {
if (FIELDS_FIELD.match(currentFieldName)) {
while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) {
String fField = null;
float fBoost = AbstractQueryBuilder.DEFAULT_BOOST;
char[] text = parser.textCharacters();
int end = parser.textOffset() + parser.textLength();
for (int i = parser.textOffset(); i < end; i++) {
if (text[i] == '^') {
int relativeLocation = i - parser.textOffset();
fField = new String(text, parser.textOffset(), relativeLocation);
fBoost = Float.parseFloat(new String(text, i + 1, parser.textLength() - relativeLocation - 1));
break;
}
}
if (fField == null) {
fField = parser.text();
}
fieldsAndWeights.put(fField, fBoost);
List<String> fields = new ArrayList<>();
while (parser.nextToken() != XContentParser.Token.END_ARRAY) {
fields.add(parser.text());
}
fieldsAndWeights = QueryParserHelper.parseFieldsAndWeights(fields);
} else {
throw new ParsingException(parser.getTokenLocation(), "[" + QueryStringQueryBuilder.NAME +
"] query does not support [" + currentFieldName + "]");
@ -851,7 +838,9 @@ public class QueryStringQueryBuilder extends AbstractQueryBuilder<QueryStringQue
}
QueryStringQueryBuilder queryStringQuery = new QueryStringQueryBuilder(queryString);
queryStringQuery.fields(fieldsAndWeights);
if (fieldsAndWeights != null) {
queryStringQuery.fields(fieldsAndWeights);
}
queryStringQuery.defaultField(defaultField);
queryStringQuery.defaultOperator(defaultOperator);
queryStringQuery.analyzer(analyzer);
@ -943,16 +932,19 @@ public class QueryStringQueryBuilder extends AbstractQueryBuilder<QueryStringQue
final Map<String, Float> resolvedFields = QueryParserHelper.resolveMappingFields(context, fieldsAndWeights);
queryParser = new QueryStringQueryParser(context, resolvedFields, isLenient);
} else {
String defaultField = context.defaultField();
List<String> defaultFields = context.defaultFields();
if (context.getMapperService().allEnabled() == false &&
AllFieldMapper.NAME.equals(defaultField)) {
defaultFields.size() == 1 && AllFieldMapper.NAME.equals(defaultFields.get(0))) {
// For indices created before 6.0 with _all disabled
defaultField = "*";
defaultFields = Collections.singletonList("*");
}
if (Regex.isMatchAllPattern(defaultField)) {
boolean isAllField = defaultFields.size() == 1 && Regex.isMatchAllPattern(defaultFields.get(0));
if (isAllField) {
queryParser = new QueryStringQueryParser(context, lenient == null ? true : lenient);
} else {
queryParser = new QueryStringQueryParser(context, defaultField, isLenient);
final Map<String, Float> resolvedFields = QueryParserHelper.resolveMappingFields(context,
QueryParserHelper.parseFieldsAndWeights(defaultFields));
queryParser = new QueryStringQueryParser(context, resolvedFields, isLenient);
}
}

View File

@ -37,8 +37,10 @@ import org.elasticsearch.index.search.SimpleQueryStringQueryParser;
import org.elasticsearch.index.search.SimpleQueryStringQueryParser.Settings;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
@ -402,18 +404,18 @@ public class SimpleQueryStringBuilder extends AbstractQueryBuilder<SimpleQuerySt
if (fieldsAndWeights.isEmpty() == false) {
resolvedFieldsAndWeights = QueryParserHelper.resolveMappingFields(context, fieldsAndWeights);
} else {
String defaultField = context.defaultField();
List<String> defaultFields = context.defaultFields();
if (context.getMapperService().allEnabled() == false &&
AllFieldMapper.NAME.equals(defaultField)) {
defaultFields.size() == 1 && AllFieldMapper.NAME.equals(defaultFields.get(0))) {
// For indices created before 6.0 with _all disabled
defaultField = "*";
defaultFields = Collections.singletonList("*");
}
boolean isAllField = Regex.isMatchAllPattern(defaultField);
boolean isAllField = defaultFields.size() == 1 && Regex.isMatchAllPattern(defaultFields.get(0));
if (isAllField) {
newSettings.lenient(lenientSet ? settings.lenient() : true);
}
resolvedFieldsAndWeights = QueryParserHelper.resolveMappingField(context, defaultField, 1.0f,
false, !isAllField);
resolvedFieldsAndWeights = QueryParserHelper.resolveMappingFields(context,
QueryParserHelper.parseFieldsAndWeights(defaultFields));
}
final SimpleQueryStringQueryParser sqp;
@ -474,7 +476,7 @@ public class SimpleQueryStringBuilder extends AbstractQueryBuilder<SimpleQuerySt
float boost = AbstractQueryBuilder.DEFAULT_BOOST;
String queryName = null;
String minimumShouldMatch = null;
Map<String, Float> fieldsAndWeights = new HashMap<>();
Map<String, Float> fieldsAndWeights = null;
Operator defaultOperator = null;
String analyzerName = null;
int flags = SimpleQueryStringFlag.ALL.value();
@ -489,24 +491,11 @@ public class SimpleQueryStringBuilder extends AbstractQueryBuilder<SimpleQuerySt
currentFieldName = parser.currentName();
} else if (token == XContentParser.Token.START_ARRAY) {
if (FIELDS_FIELD.match(currentFieldName)) {
while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) {
String fField = null;
float fBoost = 1;
char[] text = parser.textCharacters();
int end = parser.textOffset() + parser.textLength();
for (int i = parser.textOffset(); i < end; i++) {
if (text[i] == '^') {
int relativeLocation = i - parser.textOffset();
fField = new String(text, parser.textOffset(), relativeLocation);
fBoost = Float.parseFloat(new String(text, i + 1, parser.textLength() - relativeLocation - 1));
break;
}
}
if (fField == null) {
fField = parser.text();
}
fieldsAndWeights.put(fField, fBoost);
List<String> fields = new ArrayList<>();
while (parser.nextToken() != XContentParser.Token.END_ARRAY) {
fields.add(parser.text());
}
fieldsAndWeights = QueryParserHelper.parseFieldsAndWeights(fields);
} else {
throw new ParsingException(parser.getTokenLocation(), "[" + SimpleQueryStringBuilder.NAME +
"] query does not support [" + currentFieldName + "]");
@ -565,7 +554,10 @@ public class SimpleQueryStringBuilder extends AbstractQueryBuilder<SimpleQuerySt
}
SimpleQueryStringBuilder qb = new SimpleQueryStringBuilder(queryBody);
qb.boost(boost).fields(fieldsAndWeights).analyzer(analyzerName).queryName(queryName).minimumShouldMatch(minimumShouldMatch);
if (fieldsAndWeights != null) {
qb.fields(fieldsAndWeights);
}
qb.boost(boost).analyzer(analyzerName).queryName(queryName).minimumShouldMatch(minimumShouldMatch);
qb.flags(flags).defaultOperator(defaultOperator);
if (lenient != null) {
qb.lenient(lenient);

View File

@ -35,11 +35,12 @@ import org.elasticsearch.index.query.QueryShardContext;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* Helpers to extract and expand field names from a mapping
* Helpers to extract and expand field names and boosts
*/
public final class QueryParserHelper {
// Mapping types the "all-ish" query can be executed against
@ -59,6 +60,29 @@ public final class QueryParserHelper {
private QueryParserHelper() {}
/**
* Convert a list of field names encoded with optional boosts to a map that associates
* the field name and its boost.
* @param fields The list of fields encoded with optional boosts (e.g. ^0.35).
* @return The converted map with field names and associated boosts.
*/
public static Map<String, Float> parseFieldsAndWeights(List<String> fields) {
final Map<String, Float> fieldsAndWeights = new HashMap<>();
for (String field : fields) {
int boostIndex = field.indexOf('^');
String fieldName;
float boost = 1.0f;
if (boostIndex != -1) {
fieldName = field.substring(0, boostIndex);
boost = Float.parseFloat(field.substring(boostIndex+1, field.length()));
} else {
fieldName = field;
}
fieldsAndWeights.put(fieldName, boost);
}
return fieldsAndWeights;
}
/**
* Get a {@link FieldMapper} associated with a field name or null.
* @param mapperService The mapper service where to find the mapping.

View File

@ -43,6 +43,7 @@ import org.apache.lucene.search.spans.SpanOrQuery;
import org.apache.lucene.search.spans.SpanQuery;
import org.apache.lucene.util.BytesRef;
import org.apache.lucene.util.IOUtils;
import org.elasticsearch.common.lucene.all.AllField;
import org.elasticsearch.common.lucene.search.Queries;
import org.elasticsearch.common.regex.Regex;
import org.elasticsearch.common.unit.Fuzziness;
@ -610,18 +611,15 @@ public class QueryStringQueryParser extends XQueryParser {
@Override
protected Query getWildcardQuery(String field, String termStr) throws ParseException {
if (termStr.equals("*") && field != null) {
String actualField = field != null ? field : this.field;
if (termStr.equals("*") && actualField != null) {
/**
* We rewrite _all:* to a match all query.
* TODO: We can remove this special case when _all is completely removed.
*/
if (Regex.isMatchAllPattern(field) || AllFieldMapper.NAME.equals(field)) {
if (Regex.isMatchAllPattern(actualField) || AllFieldMapper.NAME.equals(actualField)) {
return newMatchAllDocsQuery();
}
String actualField = field;
if (actualField == null) {
actualField = this.field;
}
// effectively, we check if a field exists or not
return existsQuery(actualField);
}
@ -629,6 +627,8 @@ public class QueryStringQueryParser extends XQueryParser {
Map<String, Float> fields = extractMultiFields(field, false);
if (fields.isEmpty()) {
return newUnmappedFieldQuery(termStr);
} else if (fields.containsKey(AllFieldMapper.NAME)) {
return newMatchAllDocsQuery();
}
List<Query> queries = new ArrayList<>();
for (Map.Entry<String, Float> entry : fields.entrySet()) {

View File

@ -32,6 +32,7 @@ import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.test.VersionUtils;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.TimeUnit;
@ -479,4 +480,19 @@ public class IndexSettingsTests extends ESTestCase {
}
}
}
public void testQueryDefaultField() {
IndexSettings index = newIndexSettings(
newIndexMeta("index", Settings.EMPTY), Settings.EMPTY
);
assertThat(index.getDefaultFields(), equalTo(Collections.singletonList("*")));
index = newIndexSettings(
newIndexMeta("index", Settings.EMPTY), Settings.builder().put("index.query.default_field", "body").build()
);
assertThat(index.getDefaultFields(), equalTo(Collections.singletonList("body")));
index.updateIndexMetaData(
newIndexMeta("index", Settings.builder().putArray("index.query.default_field", "body", "title").build())
);
assertThat(index.getDefaultFields(), equalTo(Arrays.asList("body", "title")));
}
}

View File

@ -47,10 +47,12 @@ import org.apache.lucene.util.BytesRef;
import org.apache.lucene.util.automaton.TooComplexToDeterminizeException;
import org.elasticsearch.Version;
import org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest;
import org.elasticsearch.cluster.metadata.IndexMetaData;
import org.elasticsearch.common.ParsingException;
import org.elasticsearch.common.compress.CompressedXContent;
import org.elasticsearch.common.lucene.all.AllTermQuery;
import org.elasticsearch.common.lucene.search.MultiPhrasePrefixQuery;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.Fuzziness;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.json.JsonXContent;
@ -63,6 +65,7 @@ import org.joda.time.DateTimeZone;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import static org.elasticsearch.index.query.AbstractQueryBuilder.parseInnerQueryBuilder;
@ -75,7 +78,6 @@ import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.instanceOf;
public class QueryStringQueryBuilderTests extends AbstractQueryTestCase<QueryStringQueryBuilder> {
@Override
protected QueryStringQueryBuilder doCreateTestQueryBuilder() {
int numTerms = randomIntBetween(0, 5);
@ -989,4 +991,34 @@ public class QueryStringQueryBuilderTests extends AbstractQueryTestCase<QueryStr
.toQuery(createShardContext());
assertEquals(new MatchNoDocsQuery(""), query);
}
public void testDefaultField() throws Exception {
assumeTrue("test runs only when at least a type is registered", getCurrentTypes().length > 0);
QueryShardContext context = createShardContext();
context.getIndexSettings().updateIndexMetaData(
newIndexMeta("index", context.getIndexSettings().getSettings(), Settings.builder().putArray("index.query.default_field",
STRING_FIELD_NAME, STRING_FIELD_NAME_2 + "^5").build())
);
Query query = new QueryStringQueryBuilder("hello")
.toQuery(context);
Query expected = new DisjunctionMaxQuery(
Arrays.asList(
new TermQuery(new Term(STRING_FIELD_NAME, "hello")),
new BoostQuery(new TermQuery(new Term(STRING_FIELD_NAME_2, "hello")), 5.0f)
), 0.0f
);
assertEquals(expected, query);
// Reset the default value
context.getIndexSettings().updateIndexMetaData(
newIndexMeta("index",
context.getIndexSettings().getSettings(), Settings.builder().putArray("index.query.default_field", "*").build())
);
}
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();
}
}

View File

@ -39,11 +39,15 @@ import org.apache.lucene.search.spans.SpanQuery;
import org.apache.lucene.search.spans.SpanTermQuery;
import org.apache.lucene.util.TestUtil;
import org.elasticsearch.Version;
import org.elasticsearch.cluster.metadata.IndexMetaData;
import org.elasticsearch.common.lucene.all.AllTermQuery;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.index.search.SimpleQueryStringQueryParser;
import org.elasticsearch.search.internal.SearchContext;
import org.elasticsearch.test.AbstractQueryTestCase;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
@ -264,7 +268,8 @@ public class SimpleQueryStringBuilderTests extends AbstractQueryTestCase<SimpleQ
assertTermOrBoostQuery(query, field.getKey(), queryBuilder.value(), field.getValue());
}
} else if (queryBuilder.fields().size() == 0) {
assertThat(query, either(instanceOf(DisjunctionMaxQuery.class)).or(instanceOf(MatchNoDocsQuery.class)));
assertThat(query, either(instanceOf(DisjunctionMaxQuery.class))
.or(instanceOf(MatchNoDocsQuery.class)).or(instanceOf(TermQuery.class)).or(instanceOf(AllTermQuery.class)));
if (query instanceof DisjunctionMaxQuery) {
for (Query disjunct : (DisjunctionMaxQuery) query) {
assertThat(disjunct, either(instanceOf(TermQuery.class)).or(instanceOf(MatchNoDocsQuery.class)));
@ -539,4 +544,29 @@ public class SimpleQueryStringBuilderTests extends AbstractQueryTestCase<SimpleQ
assertEquals(new TermQuery(new Term(STRING_FIELD_NAME, "bar")), parser.parse("bar"));
assertEquals(new TermQuery(new Term(STRING_FIELD_NAME, "bar")), parser.parse("\"bar\""));
}
public void testDefaultField() throws Exception {
assumeTrue("test runs only when at least a type is registered", getCurrentTypes().length > 0);
QueryShardContext context = createShardContext();
context.getIndexSettings().updateIndexMetaData(
newIndexMeta("index", context.getIndexSettings().getSettings(), Settings.builder().putArray("index.query.default_field",
STRING_FIELD_NAME, STRING_FIELD_NAME_2 + "^5").build())
);
Query query = new SimpleQueryStringBuilder("hello")
.toQuery(context);
Query expected = new DisjunctionMaxQuery(
Arrays.asList(
new TermQuery(new Term(STRING_FIELD_NAME, "hello")),
new BoostQuery(new TermQuery(new Term(STRING_FIELD_NAME_2, "hello")), 5.0f)
), 1.0f
);
assertEquals(expected, 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();
}
}

View File

@ -116,7 +116,7 @@ documents that contain "baz".
==== Default Field
When not explicitly specifying the field to search on in the query
string syntax, the `index.query.default_field` will be used to derive
which field to search on. It defaults to `*` and the query will automatically
which fields to search on. It defaults to `*` and the query will automatically
attempt to determine the existing fields in the index's mapping that are queryable,
and perform the search on those fields.