/* * Licensed to Elasticsearch under one or more contributor * license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright * ownership. Elasticsearch licenses this file to you under * the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.elasticsearch.action.search; import org.elasticsearch.action.ActionResponse; import org.elasticsearch.common.Nullable; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.xcontent.StatusToXContent; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentBuilderString; import org.elasticsearch.common.xcontent.XContentFactory; import org.elasticsearch.rest.RestStatus; import org.elasticsearch.rest.action.support.RestActions; import org.elasticsearch.search.SearchHits; import org.elasticsearch.search.aggregations.Aggregations; import org.elasticsearch.search.internal.InternalSearchResponse; import org.elasticsearch.search.profile.ProfileShardResult; import org.elasticsearch.search.suggest.Suggest; import java.io.IOException; import java.util.List; import java.util.Map; import static org.elasticsearch.action.search.ShardSearchFailure.readShardSearchFailure; import static org.elasticsearch.search.internal.InternalSearchResponse.readInternalSearchResponse; /** * A response of a search request. */ public class SearchResponse extends ActionResponse implements StatusToXContent { private InternalSearchResponse internalResponse; private String scrollId; private int totalShards; private int successfulShards; private ShardSearchFailure[] shardFailures; private long tookInMillis; public SearchResponse() { } public SearchResponse(InternalSearchResponse internalResponse, String scrollId, int totalShards, int successfulShards, long tookInMillis, ShardSearchFailure[] shardFailures) { this.internalResponse = internalResponse; this.scrollId = scrollId; this.totalShards = totalShards; this.successfulShards = successfulShards; this.tookInMillis = tookInMillis; this.shardFailures = shardFailures; } @Override public RestStatus status() { return RestStatus.status(successfulShards, totalShards, shardFailures); } /** * The search hits. */ public SearchHits getHits() { return internalResponse.hits(); } public Aggregations getAggregations() { return internalResponse.aggregations(); } public Suggest getSuggest() { return internalResponse.suggest(); } /** * Has the search operation timed out. */ public boolean isTimedOut() { return internalResponse.timedOut(); } /** * Has the search operation terminated early due to reaching * <code>terminateAfter</code> */ public Boolean isTerminatedEarly() { return internalResponse.terminatedEarly(); } /** * How long the search took. */ public TimeValue getTook() { return new TimeValue(tookInMillis); } /** * How long the search took in milliseconds. */ public long getTookInMillis() { return tookInMillis; } /** * The total number of shards the search was executed on. */ public int getTotalShards() { return totalShards; } /** * The successful number of shards the search was executed on. */ public int getSuccessfulShards() { return successfulShards; } /** * The failed number of shards the search was executed on. */ public int getFailedShards() { // we don't return totalShards - successfulShards, we don't count "no shards available" as a failed shard, just don't // count it in the successful counter return shardFailures.length; } /** * The failures that occurred during the search. */ public ShardSearchFailure[] getShardFailures() { return this.shardFailures; } /** * If scrolling was enabled ({@link SearchRequest#scroll(org.elasticsearch.search.Scroll)}, the * scroll id that can be used to continue scrolling. */ public String getScrollId() { return scrollId; } public void scrollId(String scrollId) { this.scrollId = scrollId; } /** * If profiling was enabled, this returns an object containing the profile results from * each shard. If profiling was not enabled, this will return null * * @return The profile results or null */ public @Nullable Map<String, List<ProfileShardResult>> getProfileResults() { return internalResponse.profile(); } static final class Fields { static final XContentBuilderString _SCROLL_ID = new XContentBuilderString("_scroll_id"); static final XContentBuilderString TOOK = new XContentBuilderString("took"); static final XContentBuilderString TIMED_OUT = new XContentBuilderString("timed_out"); static final XContentBuilderString TERMINATED_EARLY = new XContentBuilderString("terminated_early"); } @Override public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { if (scrollId != null) { builder.field(Fields._SCROLL_ID, scrollId); } builder.field(Fields.TOOK, tookInMillis); builder.field(Fields.TIMED_OUT, isTimedOut()); if (isTerminatedEarly() != null) { builder.field(Fields.TERMINATED_EARLY, isTerminatedEarly()); } RestActions.buildBroadcastShardsHeader(builder, params, getTotalShards(), getSuccessfulShards(), getFailedShards(), getShardFailures()); internalResponse.toXContent(builder, params); return builder; } @Override public void readFrom(StreamInput in) throws IOException { super.readFrom(in); internalResponse = readInternalSearchResponse(in); totalShards = in.readVInt(); successfulShards = in.readVInt(); int size = in.readVInt(); if (size == 0) { shardFailures = ShardSearchFailure.EMPTY_ARRAY; } else { shardFailures = new ShardSearchFailure[size]; for (int i = 0; i < shardFailures.length; i++) { shardFailures[i] = readShardSearchFailure(in); } } scrollId = in.readOptionalString(); tookInMillis = in.readVLong(); } @Override public void writeTo(StreamOutput out) throws IOException { super.writeTo(out); internalResponse.writeTo(out); out.writeVInt(totalShards); out.writeVInt(successfulShards); out.writeVInt(shardFailures.length); for (ShardSearchFailure shardSearchFailure : shardFailures) { shardSearchFailure.writeTo(out); } out.writeOptionalString(scrollId); out.writeVLong(tookInMillis); } @Override public String toString() { try { XContentBuilder builder = XContentFactory.jsonBuilder().prettyPrint(); builder.startObject(); toXContent(builder, EMPTY_PARAMS); builder.endObject(); return builder.string(); } catch (IOException e) { return "{ \"error\" : \"" + e.getMessage() + "\"}"; } } }