Skip to content

Commit

Permalink
Validate API: support for verbose explanation of succesfully validate…
Browse files Browse the repository at this point in the history
…d queries

This commit adds a `rewrite` parameter to the validate API in order to shown
how the given query is re-written into primitive queries. For example, an MLT
query is re-written into a disjunction of the selected terms. Other use cases
include `fuzzy`, `common_terms`, or `match` query especially with a
`cutoff_frequency` parameter. Note that the explanation is only given for a
single randomly chosen shard only, so the output may vary from one shard to
another.

Relates #1412
Closes #10147
  • Loading branch information
alexksikes committed Apr 13, 2015
1 parent c13e604 commit c347dfe
Show file tree
Hide file tree
Showing 7 changed files with 221 additions and 29 deletions.
81 changes: 81 additions & 0 deletions docs/reference/search/validate.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -75,3 +75,84 @@ curl -XGET 'http://localhost:9200/twitter/tweet/_validate/query?q=post_date:foo&
} ]
}
--------------------------------------------------

coming[1.6] When the query is valid, the explanation defaults to the string
representation of that query. With `rewrite` set to `true`, the explanation
is more detailed showing the actual Lucene query that will be executed.

For Fuzzy Queries:

[source,js]
--------------------------------------------------
curl -XGET 'http://localhost:9200/imdb/movies/_validate/query?rewrite=true'
{
"query": {
"fuzzy": {
"actors": "kyle"
}
}
}
--------------------------------------------------

Response:

[source,js]
--------------------------------------------------
{
"valid": true,
"_shards": {
"total": 1,
"successful": 1,
"failed": 0
},
"explanations": [
{
"index": "imdb",
"valid": true,
"explanation": "filtered(plot:kyle plot:kylie^0.75 plot:kyne^0.75 plot:lyle^0.75 plot:pyle^0.75)->cache(_type:movies)"
}
]
}
--------------------------------------------------

For More Like This:

[source,js]
--------------------------------------------------
curl -XGET 'http://localhost:9200/imdb/movies/_validate/query?rewrite=true'
{
"query": {
"more_like_this": {
"like": {
"_id": "88247"
},
"boost_terms": 1
}
}
}
--------------------------------------------------

Response:

[source,js]
--------------------------------------------------
{
"valid": true,
"_shards": {
"total": 1,
"successful": 1,
"failed": 0
},
"explanations": [
{
"index": "imdb",
"valid": true,
"explanation": "filtered(((title:terminator^3.71334 plot:future^2.763601 plot:human^2.8415773 plot:sarah^3.4193945 plot:kyle^3.8244398 plot:cyborg^3.9177752 plot:connor^4.040236 plot:reese^4.7133346 ... )~6) -ConstantScore(_uid:movies#88247))->cache(_type:movies)"
}
]
}
--------------------------------------------------

CAUTION: The request is executed on a single shard only, which is randomly
selected. The detailed explanation of the query may depend on which shard is
being hit, and therefore may vary from one request to another.
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ class ShardValidateQueryRequest extends BroadcastShardOperationRequest {
private BytesReference source;
private String[] types = Strings.EMPTY_ARRAY;
private boolean explain;
private boolean rewrite;
private long nowInMillis;

@Nullable
Expand All @@ -51,6 +52,7 @@ class ShardValidateQueryRequest extends BroadcastShardOperationRequest {
this.source = request.source();
this.types = request.types();
this.explain = request.explain();
this.rewrite = request.rewrite();
this.filteringAliases = filteringAliases;
this.nowInMillis = request.nowInMillis;
}
Expand All @@ -67,6 +69,10 @@ public boolean explain() {
return this.explain;
}

public boolean rewrite() {
return this.rewrite;
}

public String[] filteringAliases() {
return filteringAliases;
}
Expand Down Expand Up @@ -96,6 +102,7 @@ public void readFrom(StreamInput in) throws IOException {
}

explain = in.readBoolean();
rewrite = in.readBoolean();
nowInMillis = in.readVLong();
}

Expand All @@ -118,6 +125,7 @@ public void writeTo(StreamOutput out) throws IOException {
}

out.writeBoolean(explain);
out.writeBoolean(rewrite);
out.writeVLong(nowInMillis);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@

package org.elasticsearch.action.admin.indices.validate.query;

import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.action.ShardOperationFailedException;
Expand All @@ -34,11 +36,14 @@
import org.elasticsearch.cluster.routing.GroupShardsIterator;
import org.elasticsearch.cluster.routing.ShardRouting;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.lucene.search.MatchNoDocsFilter;
import org.elasticsearch.common.lucene.search.MatchNoDocsQuery;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.BigArrays;
import org.elasticsearch.index.IndexService;
import org.elasticsearch.index.engine.Engine;
import org.elasticsearch.index.query.IndexQueryParserService;
import org.elasticsearch.index.query.QueryParsingException;
import org.elasticsearch.index.IndexService;
import org.elasticsearch.index.shard.IndexShard;
import org.elasticsearch.indices.IndicesService;
import org.elasticsearch.script.ScriptService;
Expand All @@ -48,6 +53,7 @@
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.transport.TransportService;

import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.Set;
Expand Down Expand Up @@ -147,7 +153,7 @@ protected ValidateQueryResponse newResponse(ValidateQueryRequest request, Atomic
} else {
ShardValidateQueryResponse validateQueryResponse = (ShardValidateQueryResponse) shardResponse;
valid = valid && validateQueryResponse.isValid();
if (request.explain()) {
if (request.explain() || request.rewrite()) {
if (queryExplanations == null) {
queryExplanations = newArrayList();
}
Expand All @@ -173,10 +179,11 @@ protected ShardValidateQueryResponse shardOperation(ShardValidateQueryRequest re
boolean valid;
String explanation = null;
String error = null;
Engine.Searcher searcher = indexShard.acquireSearcher("validate_query");

DefaultSearchContext searchContext = new DefaultSearchContext(0,
new ShardSearchLocalRequest(request.types(), request.nowInMillis(), request.filteringAliases()),
null, indexShard.acquireSearcher("validate_query"), indexService, indexShard,
null, searcher, indexService, indexShard,
scriptService, pageCacheRecycler, bigArrays, threadPool.estimatedTimeInMillisCounter()
);
SearchContext.setCurrent(searchContext);
Expand All @@ -190,17 +197,32 @@ protected ShardValidateQueryResponse shardOperation(ShardValidateQueryRequest re
if (request.explain()) {
explanation = searchContext.query().toString();
}
if (request.rewrite()) {
explanation = getRewrittenQuery(searcher.searcher(), searchContext.query());
}
} catch (QueryParsingException e) {
valid = false;
error = e.getDetailedMessage();
} catch (AssertionError e) {
valid = false;
error = e.getMessage();
} catch (IOException e) {
valid = false;
error = e.getMessage();
} finally {
SearchContext.current().close();
SearchContext.removeCurrent();
}

return new ShardValidateQueryResponse(request.shardId(), valid, explanation, error);
}

private String getRewrittenQuery(IndexSearcher searcher, Query query) throws IOException {
Query queryRewrite = searcher.rewrite(query);
if (queryRewrite instanceof MatchNoDocsQuery || queryRewrite instanceof MatchNoDocsFilter) {
return query.toString();
} else {
return queryRewrite.toString();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ public class ValidateQueryRequest extends BroadcastOperationRequest<ValidateQuer
private BytesReference source;

private boolean explain;
private boolean rewrite;

private String[] types = Strings.EMPTY_ARRAY;

Expand Down Expand Up @@ -163,6 +164,20 @@ public boolean explain() {
return explain;
}

/**
* Indicates whether the query should be rewritten into primitive queries
*/
public void rewrite(boolean rewrite) {
this.rewrite = rewrite;
}

/**
* Indicates whether the query should be rewritten into primitive queries
*/
public boolean rewrite() {
return rewrite;
}

@Override
public void readFrom(StreamInput in) throws IOException {
super.readFrom(in);
Expand All @@ -178,7 +193,7 @@ public void readFrom(StreamInput in) throws IOException {
}

explain = in.readBoolean();

rewrite = in.readBoolean();
}

@Override
Expand All @@ -193,6 +208,7 @@ public void writeTo(StreamOutput out) throws IOException {
}

out.writeBoolean(explain);
out.writeBoolean(rewrite);
}

@Override
Expand All @@ -203,6 +219,7 @@ public String toString() {
} catch (Exception e) {
// ignore
}
return "[" + Arrays.toString(indices) + "]" + Arrays.toString(types) + ", source[" + sSource + "], explain:" + explain;
return "[" + Arrays.toString(indices) + "]" + Arrays.toString(types) + ", source[" + sSource + "], explain:" + explain +
", rewrite:" + rewrite;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,14 @@ public ValidateQueryRequestBuilder setExplain(boolean explain) {
return this;
}

/**
* Indicates whether the query should be rewritten into primitive queries
*/
public ValidateQueryRequestBuilder setRewrite(boolean rewrite) {
request.rewrite(rewrite);
return this;
}

@Override
protected void doExecute(ActionListener<ValidateQueryResponse> listener) {
if (sourceBuilder != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,11 @@ public void handleRequest(final RestRequest request, final RestChannel channel,
} else {
validateQueryRequest.explain(false);
}
if (request.paramAsBoolean("rewrite", false)) {
validateQueryRequest.rewrite(true);
} else {
validateQueryRequest.rewrite(false);
}

client.admin().indices().validateQuery(validateQueryRequest, new RestBuilderListener<ValidateQueryResponse>(channel) {
@Override
Expand Down
Loading

0 comments on commit c347dfe

Please sign in to comment.