Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,6 @@ public boolean disableCoord() {
protected void doXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject(NAME);
builder.startObject(fieldName);

builder.field("query", text);
builder.field("disable_coord", disableCoord);
builder.field("high_freq_operator", highFreqOperator.toString());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,15 @@
import org.apache.lucene.search.Query;
import org.apache.lucene.util.CloseableThreadLocal;
import org.elasticsearch.Version;
import org.elasticsearch.action.support.IndicesOptions;
import org.elasticsearch.cluster.ClusterService;
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.ParseFieldMatcher;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.lucene.search.Queries;
import org.elasticsearch.common.regex.Regex;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentHelper;
Expand Down Expand Up @@ -72,6 +76,10 @@ protected QueryShardContext initialValue() {

final IndexFieldDataService fieldDataService;

final ClusterService clusterService;

final IndexNameExpressionResolver indexNameExpressionResolver;

final BitsetFilterCache bitsetFilterCache;

private final IndicesQueriesRegistry indicesQueriesRegistry;
Expand All @@ -87,7 +95,8 @@ public IndexQueryParserService(Index index, @IndexSettings Settings indexSetting
ScriptService scriptService, AnalysisService analysisService,
MapperService mapperService, IndexCache indexCache, IndexFieldDataService fieldDataService,
BitsetFilterCache bitsetFilterCache,
@Nullable SimilarityService similarityService) {
@Nullable SimilarityService similarityService, ClusterService clusterService,
IndexNameExpressionResolver indexNameExpressionResolver) {
super(index, indexSettings);
this.scriptService = scriptService;
this.analysisService = analysisService;
Expand All @@ -96,6 +105,8 @@ public IndexQueryParserService(Index index, @IndexSettings Settings indexSetting
this.indexCache = indexCache;
this.fieldDataService = fieldDataService;
this.bitsetFilterCache = bitsetFilterCache;
this.clusterService = clusterService;
this.indexNameExpressionResolver = indexNameExpressionResolver;

this.defaultField = indexSettings.get(DEFAULT_FIELD, AllFieldMapper.NAME);
this.queryStringLenient = indexSettings.getAsBoolean(QUERY_STRING_LENIENT, false);
Expand Down Expand Up @@ -318,4 +329,14 @@ private static ParsedQuery innerParse(QueryShardContext context, QueryBuilder qu
public ParseFieldMatcher parseFieldMatcher() {
return parseFieldMatcher;
}

public boolean matchesIndices(String... indices) {
final String[] concreteIndices = indexNameExpressionResolver.concreteIndices(clusterService.state(), IndicesOptions.lenientExpandOpen(), indices);
for (String index : concreteIndices) {
if (Regex.simpleMatch(index, this.index.name())) {
return true;
}
}
return false;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,14 @@

package org.elasticsearch.index.query;

import org.apache.lucene.search.Query;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.xcontent.XContentBuilder;

import java.io.IOException;
import java.util.Arrays;
import java.util.Objects;

/**
* A query that will execute the wrapped query only for the specified indices, and "match_all" when
Expand All @@ -31,48 +36,64 @@ public class IndicesQueryBuilder extends AbstractQueryBuilder<IndicesQueryBuilde

public static final String NAME = "indices";

private final QueryBuilder queryBuilder;
private final QueryBuilder innerQuery;

private final String[] indices;

private String sNoMatchQuery;
private QueryBuilder noMatchQuery;
private QueryBuilder noMatchQuery = defaultNoMatchQuery();

static final IndicesQueryBuilder PROTOTYPE = new IndicesQueryBuilder(null);
static final IndicesQueryBuilder PROTOTYPE = new IndicesQueryBuilder();

public IndicesQueryBuilder(QueryBuilder queryBuilder, String... indices) {
this.queryBuilder = queryBuilder;
private IndicesQueryBuilder() {
this.innerQuery = null;
this.indices = null;
}

public IndicesQueryBuilder(QueryBuilder innerQuery, String... indices) {
this.innerQuery = Objects.requireNonNull(innerQuery);
this.indices = indices;
}

public QueryBuilder innerQuery() {
return this.innerQuery;
}

public String[] indices() {
return this.indices;
}

/**
* Sets the no match query, can either be <tt>all</tt> or <tt>none</tt>.
* Sets the query to use when it executes on an index that does not match the indices provided.
*/
public IndicesQueryBuilder noMatchQuery(String type) {
this.sNoMatchQuery = type;
public IndicesQueryBuilder noMatchQuery(QueryBuilder noMatchQuery) {
this.noMatchQuery = (noMatchQuery != null) ? noMatchQuery : defaultNoMatchQuery();
return this;
}

/**
* Sets the query to use when it executes on an index that does not match the indices provided.
* Sets the no match query, can either be <tt>all</tt> or <tt>none</tt>.
*/
public IndicesQueryBuilder noMatchQuery(QueryBuilder noMatchQuery) {
this.noMatchQuery = noMatchQuery;
public IndicesQueryBuilder noMatchQuery(String type) {
this.noMatchQuery = IndicesQueryParser.parseNoMatchQuery(type);
return this;
}

public QueryBuilder noMatchQuery() {
return this.noMatchQuery;
}

static QueryBuilder defaultNoMatchQuery() {
return QueryBuilders.matchAllQuery();
}

@Override
protected void doXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject(NAME);
builder.field("indices", indices);
builder.field("query");
queryBuilder.toXContent(builder, params);
if (noMatchQuery != null) {
builder.field("no_match_query");
noMatchQuery.toXContent(builder, params);
} else if (sNoMatchQuery != null) {
builder.field("no_match_query", sNoMatchQuery);
}
innerQuery.toXContent(builder, params);
builder.field("no_match_query");
noMatchQuery.toXContent(builder, params);
printBoostAndQueryName(builder);
builder.endObject();
}
Expand All @@ -81,4 +102,52 @@ protected void doXContent(XContentBuilder builder, Params params) throws IOExcep
public String getWriteableName() {
return NAME;
}

@Override
protected Query doToQuery(QueryShardContext context) throws IOException {
if (context.matchesIndices(indices)) {
return innerQuery.toQuery(context);
}
return noMatchQuery.toQuery(context);
}

@Override
public QueryValidationException validate() {
QueryValidationException validationException = null;
if (this.innerQuery == null) {
validationException = addValidationError("inner query cannot be null", validationException);
}
if (this.indices == null || this.indices.length == 0) {
validationException = addValidationError("list of indices cannot be null or empty", validationException);
}
validationException = validateInnerQuery(innerQuery, validationException);
validationException = validateInnerQuery(noMatchQuery, validationException);
return validationException;
}

@Override
protected IndicesQueryBuilder doReadFrom(StreamInput in) throws IOException {
IndicesQueryBuilder indicesQueryBuilder = new IndicesQueryBuilder(in.readQuery(), in.readStringArray());
indicesQueryBuilder.noMatchQuery = in.readQuery();
return indicesQueryBuilder;
}

@Override
protected void doWriteTo(StreamOutput out) throws IOException {
out.writeQuery(innerQuery);
out.writeStringArray(indices);
out.writeQuery(noMatchQuery);
}

@Override
public int doHashCode() {
return Objects.hash(innerQuery, noMatchQuery, Arrays.hashCode(indices));
}

@Override
protected boolean doEquals(IndicesQueryBuilder other) {
return Objects.equals(innerQuery, other.innerQuery) &&
Arrays.equals(indices, other.indices) && // otherwise we are comparing pointers
Objects.equals(noMatchQuery, other.noMatchQuery);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,37 +19,24 @@

package org.elasticsearch.index.query;

import org.apache.lucene.search.Query;
import org.elasticsearch.action.support.IndicesOptions;
import org.elasticsearch.cluster.ClusterService;
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.ParseField;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.lucene.search.Queries;
import org.elasticsearch.common.regex.Regex;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.index.query.support.XContentStructure;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;

/**
* Parser for {@link IndicesQueryBuilder}.
*/
public class IndicesQueryParser extends BaseQueryParserTemp {
public class IndicesQueryParser extends BaseQueryParser {

private static final ParseField QUERY_FIELD = new ParseField("query", "filter");
private static final ParseField NO_MATCH_QUERY = new ParseField("no_match_query", "no_match_filter");

@Nullable
private final ClusterService clusterService;
private final IndexNameExpressionResolver indexNameExpressionResolver;

@Inject
public IndicesQueryParser(@Nullable ClusterService clusterService, IndexNameExpressionResolver indexNameExpressionResolver) {
this.clusterService = clusterService;
this.indexNameExpressionResolver = indexNameExpressionResolver;
public IndicesQueryParser() {
}

@Override
Expand All @@ -58,65 +45,52 @@ public String[] names() {
}

@Override
public Query parse(QueryShardContext context) throws IOException, QueryParsingException {
QueryParseContext parseContext = context.parseContext();
public QueryBuilder fromXContent(QueryParseContext parseContext) throws IOException, QueryParsingException {
XContentParser parser = parseContext.parser();

Query noMatchQuery = null;
boolean queryFound = false;
boolean indicesFound = false;
boolean currentIndexMatchesIndices = false;
QueryBuilder innerQuery = null;
Collection<String> indices = new ArrayList<>();
QueryBuilder noMatchQuery = IndicesQueryBuilder.defaultNoMatchQuery();

String queryName = null;
float boost = AbstractQueryBuilder.DEFAULT_BOOST;

String currentFieldName = null;
XContentParser.Token token;
XContentStructure.InnerQuery innerQuery = null;
XContentStructure.InnerQuery innerNoMatchQuery = null;
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
if (token == XContentParser.Token.FIELD_NAME) {
currentFieldName = parser.currentName();
} else if (token == XContentParser.Token.START_OBJECT) {
if (parseContext.parseFieldMatcher().match(currentFieldName, QUERY_FIELD)) {
innerQuery = new XContentStructure.InnerQuery(parseContext, null);
queryFound = true;
innerQuery = parseContext.parseInnerQueryBuilder();
} else if (parseContext.parseFieldMatcher().match(currentFieldName, NO_MATCH_QUERY)) {
innerNoMatchQuery = new XContentStructure.InnerQuery(parseContext, null);
noMatchQuery = parseContext.parseInnerQueryBuilder();
} else {
throw new QueryParsingException(parseContext, "[indices] query does not support [" + currentFieldName + "]");
}
} else if (token == XContentParser.Token.START_ARRAY) {
if ("indices".equals(currentFieldName)) {
if (indicesFound) {
if (indices.isEmpty() == false) {
throw new QueryParsingException(parseContext, "[indices] indices or index already specified");
}
indicesFound = true;
Collection<String> indices = new ArrayList<>();
while (parser.nextToken() != XContentParser.Token.END_ARRAY) {
String value = parser.textOrNull();
if (value == null) {
throw new QueryParsingException(parseContext, "[indices] no value specified for 'indices' entry");
}
indices.add(value);
}
currentIndexMatchesIndices = matchesIndices(parseContext.index().name(), indices.toArray(new String[indices.size()]));
} else {
throw new QueryParsingException(parseContext, "[indices] query does not support [" + currentFieldName + "]");
}
} else if (token.isValue()) {
if ("index".equals(currentFieldName)) {
if (indicesFound) {
if (indices.isEmpty() == false) {
throw new QueryParsingException(parseContext, "[indices] indices or index already specified");
}
indicesFound = true;
currentIndexMatchesIndices = matchesIndices(parseContext.index().name(), parser.text());
indices.add(parser.text());
} else if (parseContext.parseFieldMatcher().match(currentFieldName, NO_MATCH_QUERY)) {
String type = parser.text();
if ("all".equals(type)) {
noMatchQuery = Queries.newMatchAllQuery();
} else if ("none".equals(type)) {
noMatchQuery = Queries.newMatchNoDocsQuery();
}
noMatchQuery = parseNoMatchQuery(parser.text());
} else if ("_name".equals(currentFieldName)) {
queryName = parser.text();
} else if ("boost".equals(currentFieldName)) {
Expand All @@ -126,44 +100,26 @@ public Query parse(QueryShardContext context) throws IOException, QueryParsingEx
}
}
}
if (!queryFound) {

if (innerQuery == null) {
throw new QueryParsingException(parseContext, "[indices] requires 'query' element");
}
if (!indicesFound) {
if (indices.isEmpty()) {
throw new QueryParsingException(parseContext, "[indices] requires 'indices' or 'index' element");
}

Query chosenQuery;
if (currentIndexMatchesIndices) {
chosenQuery = innerQuery.asQuery();
} else {
// If noMatchQuery is set, it means "no_match_query" was "all" or "none"
if (noMatchQuery != null) {
chosenQuery = noMatchQuery;
} else {
// There might be no "no_match_query" set, so default to the match_all if not set
if (innerNoMatchQuery == null) {
chosenQuery = Queries.newMatchAllQuery();
} else {
chosenQuery = innerNoMatchQuery.asQuery();
}
}
}
if (queryName != null) {
context.addNamedQuery(queryName, chosenQuery);
}
chosenQuery.setBoost(boost);
return chosenQuery;
return new IndicesQueryBuilder(innerQuery, indices.toArray(new String[indices.size()]))
.noMatchQuery(noMatchQuery)
.boost(boost)
.queryName(queryName);
}

protected boolean matchesIndices(String currentIndex, String... indices) {
final String[] concreteIndices = indexNameExpressionResolver.concreteIndices(clusterService.state(), IndicesOptions.lenientExpandOpen(), indices);
for (String index : concreteIndices) {
if (Regex.simpleMatch(index, currentIndex)) {
return true;
}
static QueryBuilder parseNoMatchQuery(String type) {
if ("all".equals(type)) {
return QueryBuilders.matchAllQuery();
} else if ("none".equals(type)) {
return new MatchNoneQueryBuilder();
}
return false;
throw new IllegalArgumentException("query type can only be [all] or [none] but not " + "[" + type + "]");
}

@Override
Expand Down
Loading