protected ShardIterator shards(ClusterState state, ExplainRequest request) throws ElasticSearchException { return clusterService .operationRouting() .getShards( clusterService.state(), request.index(), request.getType(), request.getId(), request.getRouting(), request.getPreference()); }
private ParsedQuery parseQuery(ExplainRequest request, IndexService indexService) { try { XContentParser parser = XContentHelper.createParser(request.getSource()); for (XContentParser.Token token = parser.nextToken(); token != XContentParser.Token.END_OBJECT; token = parser.nextToken()) { if (token == XContentParser.Token.FIELD_NAME) { String fieldName = parser.currentName(); if ("query".equals(fieldName)) { return indexService.queryParserService().parse(parser); } else if ("query_binary".equals(fieldName)) { byte[] querySource = parser.binaryValue(); XContentParser qSourceParser = XContentFactory.xContent(querySource).createParser(querySource); return indexService.queryParserService().parse(qSourceParser); } } } } catch (Exception e) { throw new ElasticSearchException("Couldn't parse query from source.", e); } throw new ElasticSearchException("No query specified"); }
@Override public void handleRequest(final RestRequest request, final RestChannel channel) { final ExplainRequest explainRequest = new ExplainRequest(request.param("index"), request.param("type"), request.param("id")); explainRequest.parent(request.param("parent")); explainRequest.routing(request.param("routing")); explainRequest.preference(request.param("preference")); String sourceString = request.param("source"); String queryString = request.param("q"); if (request.hasContent()) { explainRequest.source(request.content(), request.contentUnsafe()); } else if (sourceString != null) { explainRequest.source(new BytesArray(request.param("source")), false); } else if (queryString != null) { QueryStringQueryBuilder queryStringBuilder = QueryBuilders.queryString(queryString); queryStringBuilder.defaultField(request.param("df")); queryStringBuilder.analyzer(request.param("analyzer")); queryStringBuilder.analyzeWildcard(request.paramAsBoolean("analyze_wildcard", false)); queryStringBuilder.lowercaseExpandedTerms( request.paramAsBoolean("lowercase_expanded_terms", true)); queryStringBuilder.lenient(request.paramAsBooleanOptional("lenient", null)); String defaultOperator = request.param("default_operator"); if (defaultOperator != null) { if ("OR".equals(defaultOperator)) { queryStringBuilder.defaultOperator(QueryStringQueryBuilder.Operator.OR); } else if ("AND".equals(defaultOperator)) { queryStringBuilder.defaultOperator(QueryStringQueryBuilder.Operator.AND); } else { throw new ElasticSearchIllegalArgumentException( "Unsupported defaultOperator [" + defaultOperator + "], can either be [OR] or [AND]"); } } ExplainSourceBuilder explainSourceBuilder = new ExplainSourceBuilder(); explainSourceBuilder.query(queryStringBuilder); explainRequest.source(explainSourceBuilder); } client.explain( explainRequest, new ActionListener<ExplainResponse>() { @Override public void onResponse(ExplainResponse response) { try { XContentBuilder builder = restContentBuilder(request); builder.startObject(); builder.field(Fields.OK, response.exists()); builder.field(Fields.MATCHES, response.match()); if (response.hasExplanation()) { builder.startObject(Fields.EXPLANATION); buildExplanation(builder, response.explanation()); builder.endObject(); } builder.endObject(); channel.sendResponse( new XContentRestResponse(request, response.exists() ? OK : NOT_FOUND, builder)); } catch (Exception e) { onFailure(e); } } private void buildExplanation(XContentBuilder builder, Explanation explanation) throws IOException { builder.field(Fields.VALUE, explanation.getValue()); builder.field(Fields.DESCRIPTION, explanation.getDescription()); Explanation[] innerExps = explanation.getDetails(); if (innerExps != null) { builder.startArray(Fields.DETAILS); for (Explanation exp : innerExps) { builder.startObject(); buildExplanation(builder, exp); builder.endObject(); } builder.endArray(); } } @Override public void onFailure(Throwable e) { try { channel.sendResponse(new XContentThrowableRestResponse(request, e)); } catch (IOException e1) { logger.error("Failed to send failure response", e1); } } }); }
protected ExplainResponse shardOperation(ExplainRequest request, int shardId) throws ElasticSearchException { IndexService indexService = indicesService.indexService(request.index()); IndexShard indexShard = indexService.shardSafe(shardId); Term uidTerm = new Term(UidFieldMapper.NAME, Uid.createUidAsBytes(request.getType(), request.getId())); Engine.GetResult result = indexShard.get(new Engine.Get(false, uidTerm)); if (!result.exists()) { return new ExplainResponse(false); } SearchContext context = new SearchContext( 0, new ShardSearchRequest() .types(new String[] {request.getType()}) .filteringAliases(request.getFilteringAlias()), null, result.searcher(), indexService, indexShard, scriptService); SearchContext.setCurrent(context); try { context.parsedQuery(parseQuery(request, indexService)); context.preProcess(); int topLevelDocId = result.docIdAndVersion().docId + result.docIdAndVersion().reader.docBase; Explanation explanation; if (context.rescore() != null) { RescoreSearchContext ctx = context.rescore(); Rescorer rescorer = ctx.rescorer(); explanation = rescorer.explain(topLevelDocId, context, ctx); } else { explanation = context.searcher().explain(context.query(), topLevelDocId); } if (request.getFields() != null) { if (request.getFields().length == 1 && "_source".equals(request.getFields()[0])) { request.setFields(null); // Load the _source field } // Advantage is that we're not opening a second searcher to retrieve the _source. Also // because we are working in the same searcher in engineGetResult we can be sure that a // doc isn't deleted between the initial get and this call. GetResult getResult = indexShard .getService() .get(result, request.getId(), request.getType(), request.getFields()); return new ExplainResponse(true, explanation, getResult); } else { return new ExplainResponse(true, explanation); } } catch (IOException e) { throw new ElasticSearchException("Could not explain", e); } finally { context.release(); SearchContext.removeCurrent(); } }
@Override protected void resolveRequest(ClusterState state, ExplainRequest request) { String concreteIndex = state.metaData().concreteIndex(request.index()); request.setFilteringAlias(state.metaData().filteringAliases(concreteIndex, request.index())); request.index(state.metaData().concreteIndex(request.index())); }
protected ClusterBlockException checkRequestBlock(ClusterState state, ExplainRequest request) { return state.blocks().indexBlockedException(ClusterBlockLevel.READ, request.index()); }
@Override protected void doExecute(ExplainRequest request, ActionListener<ExplainResponse> listener) { request.nowInMillis = System.currentTimeMillis(); super.doExecute(request, listener); }
@Override protected ExplainResponse shardOperation(ExplainRequest request, ShardId shardId) throws ElasticsearchException { IndexService indexService = indicesService.indexServiceSafe(shardId.getIndex()); IndexShard indexShard = indexService.shardSafe(shardId.id()); Term uidTerm = new Term(UidFieldMapper.NAME, Uid.createUidAsBytes(request.type(), request.id())); Engine.GetResult result = indexShard.get(new Engine.Get(false, uidTerm)); if (!result.exists()) { return new ExplainResponse(shardId.getIndex(), request.type(), request.id(), false); } SearchContext context = new DefaultSearchContext( 0, new ShardSearchRequest(request) .types(new String[] {request.type()}) .filteringAliases(request.filteringAlias()) .nowInMillis(request.nowInMillis), null, result.searcher(), indexService, indexShard, scriptService, pageCacheRecycler, bigArrays, threadPool.estimatedTimeInMillisCounter()); SearchContext.setCurrent(context); try { context.parsedQuery(indexService.queryParserService().parseQuery(request.source())); context.preProcess(); int topLevelDocId = result.docIdAndVersion().docId + result.docIdAndVersion().context.docBase; Explanation explanation = context.searcher().explain(context.query(), topLevelDocId); for (RescoreSearchContext ctx : context.rescore()) { Rescorer rescorer = ctx.rescorer(); explanation = rescorer.explain(topLevelDocId, context, ctx, explanation); } if (request.fields() != null || (request.fetchSourceContext() != null && request.fetchSourceContext().fetchSource())) { // Advantage is that we're not opening a second searcher to retrieve the _source. Also // because we are working in the same searcher in engineGetResult we can be sure that a // doc isn't deleted between the initial get and this call. GetResult getResult = indexShard .getService() .get( result, request.id(), request.type(), request.fields(), request.fetchSourceContext(), false); return new ExplainResponse( shardId.getIndex(), request.type(), request.id(), true, explanation, getResult); } else { return new ExplainResponse( shardId.getIndex(), request.type(), request.id(), true, explanation); } } catch (IOException e) { throw new ElasticsearchException("Could not explain", e); } finally { context.close(); SearchContext.removeCurrent(); } }