/* * 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.Strings; 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.StatusToXContentObject; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.rest.RestStatus; import org.elasticsearch.rest.action.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.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 StatusToXContentObject { 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(); } /** * Returns the number of reduce phases applied to obtain this search response */ public int getNumReducePhases() { return internalResponse.getNumReducePhases(); } /** * 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 an empty map */ @Nullable public Map<String, ProfileShardResult> getProfileResults() { return internalResponse.profile(); } @Override public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { builder.startObject(); innerToXContent(builder, params); builder.endObject(); return builder; } public XContentBuilder innerToXContent(XContentBuilder builder, Params params) throws IOException { if (scrollId != null) { builder.field("_scroll_id", scrollId); } builder.field("took", tookInMillis); builder.field("timed_out", isTimedOut()); if (isTerminatedEarly() != null) { builder.field("terminated_early", isTerminatedEarly()); } if (getNumReducePhases() != 1) { builder.field("num_reduce_phases", getNumReducePhases()); } 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() { return Strings.toString(this); } }