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:
parent
c1452ff9ea
commit
de1e4e0c15
|
@ -61,7 +61,6 @@ import org.elasticsearch.index.mapper.MappedFieldType;
|
||||||
import org.elasticsearch.index.shard.ShardId;
|
import org.elasticsearch.index.shard.ShardId;
|
||||||
import org.elasticsearch.indices.IndicesService;
|
import org.elasticsearch.indices.IndicesService;
|
||||||
import org.elasticsearch.indices.analysis.AnalysisModule;
|
import org.elasticsearch.indices.analysis.AnalysisModule;
|
||||||
import org.elasticsearch.indices.analysis.PreBuiltTokenizers;
|
|
||||||
import org.elasticsearch.threadpool.ThreadPool;
|
import org.elasticsearch.threadpool.ThreadPool;
|
||||||
import org.elasticsearch.transport.TransportService;
|
import org.elasticsearch.transport.TransportService;
|
||||||
|
|
||||||
|
@ -151,8 +150,12 @@ public class TransportAnalyzeAction extends TransportSingleShardAction<AnalyzeRe
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (field == null) {
|
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) {
|
if (indexService != null) {
|
||||||
field = indexService.getIndexSettings().getDefaultField();
|
field = indexService.getIndexSettings().getDefaultFields().get(0);
|
||||||
} else {
|
} else {
|
||||||
field = AllFieldMapper.NAME;
|
field = AllFieldMapper.NAME;
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,6 @@ import org.apache.lucene.index.MergePolicy;
|
||||||
import org.elasticsearch.Version;
|
import org.elasticsearch.Version;
|
||||||
import org.elasticsearch.cluster.metadata.IndexMetaData;
|
import org.elasticsearch.cluster.metadata.IndexMetaData;
|
||||||
import org.elasticsearch.common.logging.Loggers;
|
import org.elasticsearch.common.logging.Loggers;
|
||||||
import org.elasticsearch.common.lucene.all.AllField;
|
|
||||||
import org.elasticsearch.common.settings.IndexScopedSettings;
|
import org.elasticsearch.common.settings.IndexScopedSettings;
|
||||||
import org.elasticsearch.common.settings.Setting;
|
import org.elasticsearch.common.settings.Setting;
|
||||||
import org.elasticsearch.common.settings.Setting.Property;
|
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.ByteSizeValue;
|
||||||
import org.elasticsearch.common.unit.TimeValue;
|
import org.elasticsearch.common.unit.TimeValue;
|
||||||
import org.elasticsearch.index.mapper.AllFieldMapper;
|
import org.elasticsearch.index.mapper.AllFieldMapper;
|
||||||
import org.elasticsearch.index.mapper.MapperService;
|
|
||||||
import org.elasticsearch.index.translog.Translog;
|
import org.elasticsearch.index.translog.Translog;
|
||||||
import org.elasticsearch.node.Node;
|
import org.elasticsearch.node.Node;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
@ -50,9 +50,9 @@ import java.util.function.Function;
|
||||||
*/
|
*/
|
||||||
public final class IndexSettings {
|
public final class IndexSettings {
|
||||||
public static final String DEFAULT_FIELD_SETTING_KEY = "index.query.default_field";
|
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 {
|
static {
|
||||||
Function<Settings, String> defValue = settings -> {
|
Function<Settings, List<String>> defValue = settings -> {
|
||||||
final String defaultField;
|
final String defaultField;
|
||||||
if (settings.getAsVersion(IndexMetaData.SETTING_VERSION_CREATED, null) != null &&
|
if (settings.getAsVersion(IndexMetaData.SETTING_VERSION_CREATED, null) != null &&
|
||||||
Version.indexCreated(settings).before(Version.V_6_0_0_alpha1)) {
|
Version.indexCreated(settings).before(Version.V_6_0_0_alpha1)) {
|
||||||
|
@ -60,9 +60,9 @@ public final class IndexSettings {
|
||||||
} else {
|
} else {
|
||||||
defaultField = "*";
|
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 =
|
public static final Setting<Boolean> QUERY_STRING_LENIENT_SETTING =
|
||||||
Setting.boolSetting("index.query_string.lenient", false, Property.IndexScope);
|
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
|
// volatile fields are updated via #updateIndexMetaData(IndexMetaData) under lock
|
||||||
private volatile Settings settings;
|
private volatile Settings settings;
|
||||||
private volatile IndexMetaData indexMetaData;
|
private volatile IndexMetaData indexMetaData;
|
||||||
private final String defaultField;
|
private volatile List<String> defaultFields;
|
||||||
private final boolean queryStringLenient;
|
private final boolean queryStringLenient;
|
||||||
private final boolean queryStringAnalyzeWildcard;
|
private final boolean queryStringAnalyzeWildcard;
|
||||||
private final boolean queryStringAllowLeadingWildcard;
|
private final boolean queryStringAllowLeadingWildcard;
|
||||||
|
@ -241,10 +241,14 @@ public final class IndexSettings {
|
||||||
private final boolean singleType;
|
private final boolean singleType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the default search field for this index.
|
* Returns the default search fields for this index.
|
||||||
*/
|
*/
|
||||||
public String getDefaultField() {
|
public List<String> getDefaultFields() {
|
||||||
return defaultField;
|
return defaultFields;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setDefaultFields(List<String> defaultFields) {
|
||||||
|
this.defaultFields = defaultFields;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -304,12 +308,12 @@ public final class IndexSettings {
|
||||||
this.indexMetaData = indexMetaData;
|
this.indexMetaData = indexMetaData;
|
||||||
numberOfShards = settings.getAsInt(IndexMetaData.SETTING_NUMBER_OF_SHARDS, null);
|
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.queryStringLenient = QUERY_STRING_LENIENT_SETTING.get(settings);
|
||||||
this.queryStringAnalyzeWildcard = QUERY_STRING_ANALYZE_WILDCARD.get(nodeSettings);
|
this.queryStringAnalyzeWildcard = QUERY_STRING_ANALYZE_WILDCARD.get(nodeSettings);
|
||||||
this.queryStringAllowLeadingWildcard = QUERY_STRING_ALLOW_LEADING_WILDCARD.get(nodeSettings);
|
this.queryStringAllowLeadingWildcard = QUERY_STRING_ALLOW_LEADING_WILDCARD.get(nodeSettings);
|
||||||
this.defaultAllowUnmappedFields = scopedSettings.get(ALLOW_UNMAPPED);
|
this.defaultAllowUnmappedFields = scopedSettings.get(ALLOW_UNMAPPED);
|
||||||
this.durability = scopedSettings.get(INDEX_TRANSLOG_DURABILITY_SETTING);
|
this.durability = scopedSettings.get(INDEX_TRANSLOG_DURABILITY_SETTING);
|
||||||
|
defaultFields = scopedSettings.get(DEFAULT_FIELD_SETTING);
|
||||||
syncInterval = INDEX_TRANSLOG_SYNC_INTERVAL_SETTING.get(settings);
|
syncInterval = INDEX_TRANSLOG_SYNC_INTERVAL_SETTING.get(settings);
|
||||||
refreshInterval = scopedSettings.get(INDEX_REFRESH_INTERVAL_SETTING);
|
refreshInterval = scopedSettings.get(INDEX_REFRESH_INTERVAL_SETTING);
|
||||||
flushThresholdSize = scopedSettings.get(INDEX_TRANSLOG_FLUSH_THRESHOLD_SIZE_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(INDEX_REFRESH_INTERVAL_SETTING, this::setRefreshInterval);
|
||||||
scopedSettings.addSettingsUpdateConsumer(MAX_REFRESH_LISTENERS_PER_SHARD, this::setMaxRefreshListeners);
|
scopedSettings.addSettingsUpdateConsumer(MAX_REFRESH_LISTENERS_PER_SHARD, this::setMaxRefreshListeners);
|
||||||
scopedSettings.addSettingsUpdateConsumer(MAX_SLICES_PER_SCROLL, this::setMaxSlicesPerScroll);
|
scopedSettings.addSettingsUpdateConsumer(MAX_SLICES_PER_SCROLL, this::setMaxSlicesPerScroll);
|
||||||
|
scopedSettings.addSettingsUpdateConsumer(DEFAULT_FIELD_SETTING, this::setDefaultFields);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setTranslogFlushThresholdSize(ByteSizeValue byteSizeValue) {
|
private void setTranslogFlushThresholdSize(ByteSizeValue byteSizeValue) {
|
||||||
|
|
|
@ -59,7 +59,6 @@ import org.elasticsearch.index.mapper.UidFieldMapper;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
@ -1033,7 +1032,7 @@ public class MoreLikeThisQueryBuilder extends AbstractQueryBuilder<MoreLikeThisQ
|
||||||
boolean useDefaultField = (fields == null);
|
boolean useDefaultField = (fields == null);
|
||||||
List<String> moreLikeFields = new ArrayList<>();
|
List<String> moreLikeFields = new ArrayList<>();
|
||||||
if (useDefaultField) {
|
if (useDefaultField) {
|
||||||
moreLikeFields = Collections.singletonList(context.defaultField());
|
moreLikeFields = context.defaultFields();
|
||||||
} else {
|
} else {
|
||||||
for (String field : fields) {
|
for (String field : fields) {
|
||||||
MappedFieldType fieldType = context.fieldMapper(field);
|
MappedFieldType fieldType = context.fieldMapper(field);
|
||||||
|
|
|
@ -40,14 +40,11 @@ import org.elasticsearch.index.IndexSettings;
|
||||||
import org.elasticsearch.index.analysis.IndexAnalyzers;
|
import org.elasticsearch.index.analysis.IndexAnalyzers;
|
||||||
import org.elasticsearch.index.cache.bitset.BitsetFilterCache;
|
import org.elasticsearch.index.cache.bitset.BitsetFilterCache;
|
||||||
import org.elasticsearch.index.fielddata.IndexFieldData;
|
import org.elasticsearch.index.fielddata.IndexFieldData;
|
||||||
import org.elasticsearch.index.fielddata.plain.ConstantIndexFieldData;
|
|
||||||
import org.elasticsearch.index.mapper.ContentPath;
|
import org.elasticsearch.index.mapper.ContentPath;
|
||||||
import org.elasticsearch.index.mapper.DocumentMapper;
|
import org.elasticsearch.index.mapper.DocumentMapper;
|
||||||
import org.elasticsearch.index.mapper.IndexFieldMapper;
|
|
||||||
import org.elasticsearch.index.mapper.MappedFieldType;
|
import org.elasticsearch.index.mapper.MappedFieldType;
|
||||||
import org.elasticsearch.index.mapper.Mapper;
|
import org.elasticsearch.index.mapper.Mapper;
|
||||||
import org.elasticsearch.index.mapper.MapperService;
|
import org.elasticsearch.index.mapper.MapperService;
|
||||||
import org.elasticsearch.index.mapper.MetadataFieldMapper;
|
|
||||||
import org.elasticsearch.index.mapper.ObjectMapper;
|
import org.elasticsearch.index.mapper.ObjectMapper;
|
||||||
import org.elasticsearch.index.mapper.TextFieldMapper;
|
import org.elasticsearch.index.mapper.TextFieldMapper;
|
||||||
import org.elasticsearch.index.query.support.NestedScope;
|
import org.elasticsearch.index.query.support.NestedScope;
|
||||||
|
@ -60,10 +57,10 @@ import java.io.IOException;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.function.BiConsumer;
|
import java.util.function.BiConsumer;
|
||||||
import java.util.function.BiFunction;
|
import java.util.function.BiFunction;
|
||||||
import java.util.function.Function;
|
|
||||||
import java.util.function.LongSupplier;
|
import java.util.function.LongSupplier;
|
||||||
|
|
||||||
import static java.util.Collections.unmodifiableMap;
|
import static java.util.Collections.unmodifiableMap;
|
||||||
|
@ -144,8 +141,8 @@ public class QueryShardContext extends QueryRewriteContext {
|
||||||
return similarityService != null ? similarityService.similarity(mapperService) : null;
|
return similarityService != null ? similarityService.similarity(mapperService) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String defaultField() {
|
public List<String> defaultFields() {
|
||||||
return indexSettings.getDefaultField();
|
return indexSettings.getDefaultFields();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean queryStringLenient() {
|
public boolean queryStringLenient() {
|
||||||
|
|
|
@ -42,7 +42,7 @@ import org.joda.time.DateTimeZone;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
@ -738,31 +738,18 @@ public class QueryStringQueryBuilder extends AbstractQueryBuilder<QueryStringQue
|
||||||
Fuzziness fuzziness = QueryStringQueryBuilder.DEFAULT_FUZZINESS;
|
Fuzziness fuzziness = QueryStringQueryBuilder.DEFAULT_FUZZINESS;
|
||||||
String fuzzyRewrite = null;
|
String fuzzyRewrite = null;
|
||||||
String rewrite = null;
|
String rewrite = null;
|
||||||
Map<String, Float> fieldsAndWeights = new HashMap<>();
|
Map<String, Float> fieldsAndWeights = null;
|
||||||
boolean autoGenerateSynonymsPhraseQuery = true;
|
boolean autoGenerateSynonymsPhraseQuery = true;
|
||||||
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
|
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
|
||||||
if (token == XContentParser.Token.FIELD_NAME) {
|
if (token == XContentParser.Token.FIELD_NAME) {
|
||||||
currentFieldName = parser.currentName();
|
currentFieldName = parser.currentName();
|
||||||
} else if (token == XContentParser.Token.START_ARRAY) {
|
} else if (token == XContentParser.Token.START_ARRAY) {
|
||||||
if (FIELDS_FIELD.match(currentFieldName)) {
|
if (FIELDS_FIELD.match(currentFieldName)) {
|
||||||
while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) {
|
List<String> fields = new ArrayList<>();
|
||||||
String fField = null;
|
while (parser.nextToken() != XContentParser.Token.END_ARRAY) {
|
||||||
float fBoost = AbstractQueryBuilder.DEFAULT_BOOST;
|
fields.add(parser.text());
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
fieldsAndWeights = QueryParserHelper.parseFieldsAndWeights(fields);
|
||||||
} else {
|
} else {
|
||||||
throw new ParsingException(parser.getTokenLocation(), "[" + QueryStringQueryBuilder.NAME +
|
throw new ParsingException(parser.getTokenLocation(), "[" + QueryStringQueryBuilder.NAME +
|
||||||
"] query does not support [" + currentFieldName + "]");
|
"] query does not support [" + currentFieldName + "]");
|
||||||
|
@ -851,7 +838,9 @@ public class QueryStringQueryBuilder extends AbstractQueryBuilder<QueryStringQue
|
||||||
}
|
}
|
||||||
|
|
||||||
QueryStringQueryBuilder queryStringQuery = new QueryStringQueryBuilder(queryString);
|
QueryStringQueryBuilder queryStringQuery = new QueryStringQueryBuilder(queryString);
|
||||||
queryStringQuery.fields(fieldsAndWeights);
|
if (fieldsAndWeights != null) {
|
||||||
|
queryStringQuery.fields(fieldsAndWeights);
|
||||||
|
}
|
||||||
queryStringQuery.defaultField(defaultField);
|
queryStringQuery.defaultField(defaultField);
|
||||||
queryStringQuery.defaultOperator(defaultOperator);
|
queryStringQuery.defaultOperator(defaultOperator);
|
||||||
queryStringQuery.analyzer(analyzer);
|
queryStringQuery.analyzer(analyzer);
|
||||||
|
@ -943,16 +932,19 @@ public class QueryStringQueryBuilder extends AbstractQueryBuilder<QueryStringQue
|
||||||
final Map<String, Float> resolvedFields = QueryParserHelper.resolveMappingFields(context, fieldsAndWeights);
|
final Map<String, Float> resolvedFields = QueryParserHelper.resolveMappingFields(context, fieldsAndWeights);
|
||||||
queryParser = new QueryStringQueryParser(context, resolvedFields, isLenient);
|
queryParser = new QueryStringQueryParser(context, resolvedFields, isLenient);
|
||||||
} else {
|
} else {
|
||||||
String defaultField = context.defaultField();
|
List<String> defaultFields = context.defaultFields();
|
||||||
if (context.getMapperService().allEnabled() == false &&
|
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
|
// 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);
|
queryParser = new QueryStringQueryParser(context, lenient == null ? true : lenient);
|
||||||
} else {
|
} else {
|
||||||
queryParser = new QueryStringQueryParser(context, defaultField, isLenient);
|
final Map<String, Float> resolvedFields = QueryParserHelper.resolveMappingFields(context,
|
||||||
|
QueryParserHelper.parseFieldsAndWeights(defaultFields));
|
||||||
|
queryParser = new QueryStringQueryParser(context, resolvedFields, isLenient);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -37,8 +37,10 @@ import org.elasticsearch.index.search.SimpleQueryStringQueryParser;
|
||||||
import org.elasticsearch.index.search.SimpleQueryStringQueryParser.Settings;
|
import org.elasticsearch.index.search.SimpleQueryStringQueryParser.Settings;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
@ -402,18 +404,18 @@ public class SimpleQueryStringBuilder extends AbstractQueryBuilder<SimpleQuerySt
|
||||||
if (fieldsAndWeights.isEmpty() == false) {
|
if (fieldsAndWeights.isEmpty() == false) {
|
||||||
resolvedFieldsAndWeights = QueryParserHelper.resolveMappingFields(context, fieldsAndWeights);
|
resolvedFieldsAndWeights = QueryParserHelper.resolveMappingFields(context, fieldsAndWeights);
|
||||||
} else {
|
} else {
|
||||||
String defaultField = context.defaultField();
|
List<String> defaultFields = context.defaultFields();
|
||||||
if (context.getMapperService().allEnabled() == false &&
|
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
|
// 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) {
|
if (isAllField) {
|
||||||
newSettings.lenient(lenientSet ? settings.lenient() : true);
|
newSettings.lenient(lenientSet ? settings.lenient() : true);
|
||||||
}
|
}
|
||||||
resolvedFieldsAndWeights = QueryParserHelper.resolveMappingField(context, defaultField, 1.0f,
|
resolvedFieldsAndWeights = QueryParserHelper.resolveMappingFields(context,
|
||||||
false, !isAllField);
|
QueryParserHelper.parseFieldsAndWeights(defaultFields));
|
||||||
}
|
}
|
||||||
|
|
||||||
final SimpleQueryStringQueryParser sqp;
|
final SimpleQueryStringQueryParser sqp;
|
||||||
|
@ -474,7 +476,7 @@ public class SimpleQueryStringBuilder extends AbstractQueryBuilder<SimpleQuerySt
|
||||||
float boost = AbstractQueryBuilder.DEFAULT_BOOST;
|
float boost = AbstractQueryBuilder.DEFAULT_BOOST;
|
||||||
String queryName = null;
|
String queryName = null;
|
||||||
String minimumShouldMatch = null;
|
String minimumShouldMatch = null;
|
||||||
Map<String, Float> fieldsAndWeights = new HashMap<>();
|
Map<String, Float> fieldsAndWeights = null;
|
||||||
Operator defaultOperator = null;
|
Operator defaultOperator = null;
|
||||||
String analyzerName = null;
|
String analyzerName = null;
|
||||||
int flags = SimpleQueryStringFlag.ALL.value();
|
int flags = SimpleQueryStringFlag.ALL.value();
|
||||||
|
@ -489,24 +491,11 @@ public class SimpleQueryStringBuilder extends AbstractQueryBuilder<SimpleQuerySt
|
||||||
currentFieldName = parser.currentName();
|
currentFieldName = parser.currentName();
|
||||||
} else if (token == XContentParser.Token.START_ARRAY) {
|
} else if (token == XContentParser.Token.START_ARRAY) {
|
||||||
if (FIELDS_FIELD.match(currentFieldName)) {
|
if (FIELDS_FIELD.match(currentFieldName)) {
|
||||||
while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) {
|
List<String> fields = new ArrayList<>();
|
||||||
String fField = null;
|
while (parser.nextToken() != XContentParser.Token.END_ARRAY) {
|
||||||
float fBoost = 1;
|
fields.add(parser.text());
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
fieldsAndWeights = QueryParserHelper.parseFieldsAndWeights(fields);
|
||||||
} else {
|
} else {
|
||||||
throw new ParsingException(parser.getTokenLocation(), "[" + SimpleQueryStringBuilder.NAME +
|
throw new ParsingException(parser.getTokenLocation(), "[" + SimpleQueryStringBuilder.NAME +
|
||||||
"] query does not support [" + currentFieldName + "]");
|
"] query does not support [" + currentFieldName + "]");
|
||||||
|
@ -565,7 +554,10 @@ public class SimpleQueryStringBuilder extends AbstractQueryBuilder<SimpleQuerySt
|
||||||
}
|
}
|
||||||
|
|
||||||
SimpleQueryStringBuilder qb = new SimpleQueryStringBuilder(queryBody);
|
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);
|
qb.flags(flags).defaultOperator(defaultOperator);
|
||||||
if (lenient != null) {
|
if (lenient != null) {
|
||||||
qb.lenient(lenient);
|
qb.lenient(lenient);
|
||||||
|
|
|
@ -35,11 +35,12 @@ import org.elasticsearch.index.query.QueryShardContext;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
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 {
|
public final class QueryParserHelper {
|
||||||
// Mapping types the "all-ish" query can be executed against
|
// Mapping types the "all-ish" query can be executed against
|
||||||
|
@ -59,6 +60,29 @@ public final class QueryParserHelper {
|
||||||
|
|
||||||
private 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.
|
* Get a {@link FieldMapper} associated with a field name or null.
|
||||||
* @param mapperService The mapper service where to find the mapping.
|
* @param mapperService The mapper service where to find the mapping.
|
||||||
|
|
|
@ -43,6 +43,7 @@ import org.apache.lucene.search.spans.SpanOrQuery;
|
||||||
import org.apache.lucene.search.spans.SpanQuery;
|
import org.apache.lucene.search.spans.SpanQuery;
|
||||||
import org.apache.lucene.util.BytesRef;
|
import org.apache.lucene.util.BytesRef;
|
||||||
import org.apache.lucene.util.IOUtils;
|
import org.apache.lucene.util.IOUtils;
|
||||||
|
import org.elasticsearch.common.lucene.all.AllField;
|
||||||
import org.elasticsearch.common.lucene.search.Queries;
|
import org.elasticsearch.common.lucene.search.Queries;
|
||||||
import org.elasticsearch.common.regex.Regex;
|
import org.elasticsearch.common.regex.Regex;
|
||||||
import org.elasticsearch.common.unit.Fuzziness;
|
import org.elasticsearch.common.unit.Fuzziness;
|
||||||
|
@ -610,18 +611,15 @@ public class QueryStringQueryParser extends XQueryParser {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Query getWildcardQuery(String field, String termStr) throws ParseException {
|
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.
|
* We rewrite _all:* to a match all query.
|
||||||
* TODO: We can remove this special case when _all is completely removed.
|
* 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();
|
return newMatchAllDocsQuery();
|
||||||
}
|
}
|
||||||
String actualField = field;
|
|
||||||
if (actualField == null) {
|
|
||||||
actualField = this.field;
|
|
||||||
}
|
|
||||||
// effectively, we check if a field exists or not
|
// effectively, we check if a field exists or not
|
||||||
return existsQuery(actualField);
|
return existsQuery(actualField);
|
||||||
}
|
}
|
||||||
|
@ -629,6 +627,8 @@ public class QueryStringQueryParser extends XQueryParser {
|
||||||
Map<String, Float> fields = extractMultiFields(field, false);
|
Map<String, Float> fields = extractMultiFields(field, false);
|
||||||
if (fields.isEmpty()) {
|
if (fields.isEmpty()) {
|
||||||
return newUnmappedFieldQuery(termStr);
|
return newUnmappedFieldQuery(termStr);
|
||||||
|
} else if (fields.containsKey(AllFieldMapper.NAME)) {
|
||||||
|
return newMatchAllDocsQuery();
|
||||||
}
|
}
|
||||||
List<Query> queries = new ArrayList<>();
|
List<Query> queries = new ArrayList<>();
|
||||||
for (Map.Entry<String, Float> entry : fields.entrySet()) {
|
for (Map.Entry<String, Float> entry : fields.entrySet()) {
|
||||||
|
|
|
@ -32,6 +32,7 @@ import org.elasticsearch.test.ESTestCase;
|
||||||
import org.elasticsearch.test.VersionUtils;
|
import org.elasticsearch.test.VersionUtils;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.TimeUnit;
|
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")));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,10 +47,12 @@ import org.apache.lucene.util.BytesRef;
|
||||||
import org.apache.lucene.util.automaton.TooComplexToDeterminizeException;
|
import org.apache.lucene.util.automaton.TooComplexToDeterminizeException;
|
||||||
import org.elasticsearch.Version;
|
import org.elasticsearch.Version;
|
||||||
import org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest;
|
import org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest;
|
||||||
|
import org.elasticsearch.cluster.metadata.IndexMetaData;
|
||||||
import org.elasticsearch.common.ParsingException;
|
import org.elasticsearch.common.ParsingException;
|
||||||
import org.elasticsearch.common.compress.CompressedXContent;
|
import org.elasticsearch.common.compress.CompressedXContent;
|
||||||
import org.elasticsearch.common.lucene.all.AllTermQuery;
|
import org.elasticsearch.common.lucene.all.AllTermQuery;
|
||||||
import org.elasticsearch.common.lucene.search.MultiPhrasePrefixQuery;
|
import org.elasticsearch.common.lucene.search.MultiPhrasePrefixQuery;
|
||||||
|
import org.elasticsearch.common.settings.Settings;
|
||||||
import org.elasticsearch.common.unit.Fuzziness;
|
import org.elasticsearch.common.unit.Fuzziness;
|
||||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
import org.elasticsearch.common.xcontent.json.JsonXContent;
|
import org.elasticsearch.common.xcontent.json.JsonXContent;
|
||||||
|
@ -63,6 +65,7 @@ import org.joda.time.DateTimeZone;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static org.elasticsearch.index.query.AbstractQueryBuilder.parseInnerQueryBuilder;
|
import static org.elasticsearch.index.query.AbstractQueryBuilder.parseInnerQueryBuilder;
|
||||||
|
@ -75,7 +78,6 @@ import static org.hamcrest.Matchers.containsString;
|
||||||
import static org.hamcrest.Matchers.instanceOf;
|
import static org.hamcrest.Matchers.instanceOf;
|
||||||
|
|
||||||
public class QueryStringQueryBuilderTests extends AbstractQueryTestCase<QueryStringQueryBuilder> {
|
public class QueryStringQueryBuilderTests extends AbstractQueryTestCase<QueryStringQueryBuilder> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected QueryStringQueryBuilder doCreateTestQueryBuilder() {
|
protected QueryStringQueryBuilder doCreateTestQueryBuilder() {
|
||||||
int numTerms = randomIntBetween(0, 5);
|
int numTerms = randomIntBetween(0, 5);
|
||||||
|
@ -989,4 +991,34 @@ public class QueryStringQueryBuilderTests extends AbstractQueryTestCase<QueryStr
|
||||||
.toQuery(createShardContext());
|
.toQuery(createShardContext());
|
||||||
assertEquals(new MatchNoDocsQuery(""), query);
|
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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,11 +39,15 @@ import org.apache.lucene.search.spans.SpanQuery;
|
||||||
import org.apache.lucene.search.spans.SpanTermQuery;
|
import org.apache.lucene.search.spans.SpanTermQuery;
|
||||||
import org.apache.lucene.util.TestUtil;
|
import org.apache.lucene.util.TestUtil;
|
||||||
import org.elasticsearch.Version;
|
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.index.search.SimpleQueryStringQueryParser;
|
||||||
import org.elasticsearch.search.internal.SearchContext;
|
import org.elasticsearch.search.internal.SearchContext;
|
||||||
import org.elasticsearch.test.AbstractQueryTestCase;
|
import org.elasticsearch.test.AbstractQueryTestCase;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
@ -264,7 +268,8 @@ public class SimpleQueryStringBuilderTests extends AbstractQueryTestCase<SimpleQ
|
||||||
assertTermOrBoostQuery(query, field.getKey(), queryBuilder.value(), field.getValue());
|
assertTermOrBoostQuery(query, field.getKey(), queryBuilder.value(), field.getValue());
|
||||||
}
|
}
|
||||||
} else if (queryBuilder.fields().size() == 0) {
|
} 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) {
|
if (query instanceof DisjunctionMaxQuery) {
|
||||||
for (Query disjunct : (DisjunctionMaxQuery) query) {
|
for (Query disjunct : (DisjunctionMaxQuery) query) {
|
||||||
assertThat(disjunct, either(instanceOf(TermQuery.class)).or(instanceOf(MatchNoDocsQuery.class)));
|
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"));
|
||||||
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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -116,7 +116,7 @@ documents that contain "baz".
|
||||||
==== Default Field
|
==== Default Field
|
||||||
When not explicitly specifying the field to search on in the query
|
When not explicitly specifying the field to search on in the query
|
||||||
string syntax, the `index.query.default_field` will be used to derive
|
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,
|
attempt to determine the existing fields in the index's mapping that are queryable,
|
||||||
and perform the search on those fields.
|
and perform the search on those fields.
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue