Merge pull request #18370 from colings86/refactor/query-profiler

Refactor of query profile classes to make way for other profile implementations
This commit is contained in:
Colin Goodheart-Smithe 2016-05-16 16:16:05 +01:00
commit 83df20b83b
16 changed files with 202 additions and 144 deletions

View File

@ -51,7 +51,7 @@ import org.elasticsearch.search.fetch.FetchSearchResultProvider;
import org.elasticsearch.search.internal.InternalSearchHit;
import org.elasticsearch.search.internal.InternalSearchHits;
import org.elasticsearch.search.internal.InternalSearchResponse;
import org.elasticsearch.search.profile.InternalProfileShardResults;
import org.elasticsearch.search.profile.SearchProfileShardResults;
import org.elasticsearch.search.profile.ProfileShardResult;
import org.elasticsearch.search.query.QuerySearchResult;
import org.elasticsearch.search.query.QuerySearchResultProvider;
@ -405,14 +405,14 @@ public class SearchPhaseController extends AbstractComponent {
}
//Collect profile results
InternalProfileShardResults shardResults = null;
SearchProfileShardResults shardResults = null;
if (!queryResults.isEmpty() && firstResult.profileResults() != null) {
Map<String, List<ProfileShardResult>> profileResults = new HashMap<>(queryResults.size());
for (AtomicArray.Entry<? extends QuerySearchResultProvider> entry : queryResults) {
String key = entry.value.queryResult().shardTarget().toString();
profileResults.put(key, entry.value.queryResult().profileResults());
}
shardResults = new InternalProfileShardResults(profileResults);
shardResults = new SearchProfileShardResults(profileResults);
}
if (aggregations != null) {

View File

@ -33,9 +33,10 @@ import org.apache.lucene.search.Weight;
import org.elasticsearch.common.lease.Releasable;
import org.elasticsearch.index.engine.Engine;
import org.elasticsearch.search.dfs.AggregatedDfs;
import org.elasticsearch.search.profile.ProfileBreakdown;
import org.elasticsearch.search.profile.QueryProfileBreakdown;
import org.elasticsearch.search.profile.ProfileWeight;
import org.elasticsearch.search.profile.Profiler;
import org.elasticsearch.search.profile.QueryProfiler;
import org.elasticsearch.search.profile.QueryTimingType;
import java.io.IOException;
@ -54,7 +55,7 @@ public class ContextIndexSearcher extends IndexSearcher implements Releasable {
private final Engine.Searcher engineSearcher;
// TODO revisit moving the profiler to inheritance or wrapping model in the future
private Profiler profiler;
private QueryProfiler profiler;
public ContextIndexSearcher(Engine.Searcher searcher,
QueryCache queryCache, QueryCachingPolicy queryCachingPolicy) {
@ -70,7 +71,7 @@ public class ContextIndexSearcher extends IndexSearcher implements Releasable {
public void close() {
}
public void setProfiler(Profiler profiler) {
public void setProfiler(QueryProfiler profiler) {
this.profiler = profiler;
}
@ -114,8 +115,8 @@ public class ContextIndexSearcher extends IndexSearcher implements Releasable {
// createWeight() is called for each query in the tree, so we tell the queryProfiler
// each invocation so that it can build an internal representation of the query
// tree
ProfileBreakdown profile = profiler.getQueryBreakdown(query);
profile.startTime(ProfileBreakdown.TimingType.CREATE_WEIGHT);
QueryProfileBreakdown profile = profiler.getQueryBreakdown(query);
profile.startTime(QueryTimingType.CREATE_WEIGHT);
final Weight weight;
try {
weight = super.createWeight(query, needsScores);

View File

@ -28,7 +28,7 @@ import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.InternalAggregations;
import org.elasticsearch.search.profile.InternalProfileShardResults;
import org.elasticsearch.search.profile.SearchProfileShardResults;
import org.elasticsearch.search.profile.ProfileShardResult;
import org.elasticsearch.search.suggest.Suggest;
@ -54,7 +54,7 @@ public class InternalSearchResponse implements Streamable, ToXContent {
private Suggest suggest;
private InternalProfileShardResults profileResults;
private SearchProfileShardResults profileResults;
private boolean timedOut;
@ -64,7 +64,7 @@ public class InternalSearchResponse implements Streamable, ToXContent {
}
public InternalSearchResponse(InternalSearchHits hits, InternalAggregations aggregations, Suggest suggest,
InternalProfileShardResults profileResults, boolean timedOut, Boolean terminatedEarly) {
SearchProfileShardResults profileResults, boolean timedOut, Boolean terminatedEarly) {
this.hits = hits;
this.aggregations = aggregations;
this.suggest = suggest;
@ -141,7 +141,7 @@ public class InternalSearchResponse implements Streamable, ToXContent {
terminatedEarly = in.readOptionalBoolean();
if (in.getVersion().onOrAfter(Version.V_2_2_0) && in.readBoolean()) {
profileResults = new InternalProfileShardResults(in);
profileResults = new SearchProfileShardResults(in);
} else {
profileResults = null;
}

View File

@ -21,7 +21,6 @@ package org.elasticsearch.search.profile;
import java.util.Collections;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
/**
@ -29,22 +28,7 @@ import java.util.Map;
* A node's time may be composed of several internal attributes (rewriting, weighting,
* scoring, etc).
*/
public final class ProfileBreakdown {
/** Enumeration of all supported timing types. */
public enum TimingType {
CREATE_WEIGHT,
BUILD_SCORER,
NEXT_DOC,
ADVANCE,
MATCH,
SCORE;
@Override
public String toString() {
return name().toLowerCase(Locale.ROOT);
}
}
public abstract class AbstractProfileBreakdown<T extends Enum<T>> {
/**
* The accumulated timings for this query node
@ -52,23 +36,26 @@ public final class ProfileBreakdown {
private final long[] timings;
/** Scratch to store the current timing type. */
private TimingType currentTimingType;
private T currentTimingType;
/**
* The temporary scratch space for holding start-times
*/
private long scratch;
private T[] timingTypes;
/** Sole constructor. */
public ProfileBreakdown() {
timings = new long[TimingType.values().length];
public AbstractProfileBreakdown(T[] timingTypes) {
this.timingTypes = timingTypes;
timings = new long[timingTypes.length];
}
/**
* Begin timing a query for a specific Timing context
* @param timing The timing context being profiled
*/
public void startTime(TimingType timing) {
public void startTime(T timing) {
assert currentTimingType == null;
assert scratch == 0;
currentTimingType = timing;
@ -91,10 +78,10 @@ public final class ProfileBreakdown {
return time;
}
/** Convert this record to a map from {@link TimingType} to times. */
/** Convert this record to a map from timingType to times. */
public Map<String, Long> toTimingMap() {
Map<String, Long> map = new HashMap<>();
for (TimingType timingType : TimingType.values()) {
for (T timingType : timingTypes) {
map.put(timingType.toString(), timings[timingType.ordinal()]);
}
return Collections.unmodifiableMap(map);
@ -104,7 +91,7 @@ public final class ProfileBreakdown {
* Add <code>other</code>'s timings into this breakdown
* @param other Another Breakdown to merge with this one
*/
public void merge(ProfileBreakdown other) {
public void merge(AbstractProfileBreakdown<T> other) {
assert(timings.length == other.timings.length);
for (int i = 0; i < timings.length; ++i) {
timings[i] += other.timings[i];

View File

@ -30,12 +30,12 @@ import java.util.concurrent.LinkedBlockingDeque;
/**
* This class tracks the dependency tree for queries (scoring and rewriting) and
* generates {@link ProfileBreakdown} for each node in the tree. It also finalizes the tree
* generates {@link QueryProfileBreakdown} for each node in the tree. It also finalizes the tree
* and returns a list of {@link ProfileResult} that can be serialized back to the client
*/
final class InternalProfileTree {
final class InternalQueryProfileTree {
private ArrayList<ProfileBreakdown> timings;
private ArrayList<QueryProfileBreakdown> timings;
/** Maps the Query to it's list of children. This is basically the dependency tree */
private ArrayList<ArrayList<Integer>> tree;
@ -55,7 +55,7 @@ final class InternalProfileTree {
private int currentToken = 0;
public InternalProfileTree() {
public InternalQueryProfileTree() {
timings = new ArrayList<>(10);
stack = new LinkedBlockingDeque<>(10);
tree = new ArrayList<>(10);
@ -64,7 +64,7 @@ final class InternalProfileTree {
}
/**
* Returns a {@link ProfileBreakdown} for a scoring query. Scoring queries (e.g. those
* Returns a {@link QueryProfileBreakdown} for a scoring query. Scoring queries (e.g. those
* that are past the rewrite phase and are now being wrapped by createWeight() ) follow
* a recursive progression. We can track the dependency tree by a simple stack
*
@ -74,7 +74,7 @@ final class InternalProfileTree {
* @param query The scoring query we wish to profile
* @return A ProfileBreakdown for this query
*/
public ProfileBreakdown getQueryBreakdown(Query query) {
public QueryProfileBreakdown getQueryBreakdown(Query query) {
int token = currentToken;
boolean stackEmpty = stack.isEmpty();
@ -131,14 +131,14 @@ final class InternalProfileTree {
* Helper method to add a new node to the dependency tree.
*
* Initializes a new list in the dependency tree, saves the query and
* generates a new {@link ProfileBreakdown} to track the timings
* generates a new {@link QueryProfileBreakdown} to track the timings
* of this query
*
* @param query The query to profile
* @param token The assigned token for this query
* @return A ProfileBreakdown to profile this query
*/
private ProfileBreakdown addDependencyNode(Query query, int token) {
private QueryProfileBreakdown addDependencyNode(Query query, int token) {
// Add a new slot in the dependency tree
tree.add(new ArrayList<>(5));
@ -146,7 +146,7 @@ final class InternalProfileTree {
// Save our query for lookup later
queries.add(query);
ProfileBreakdown queryTimings = new ProfileBreakdown();
QueryProfileBreakdown queryTimings = new QueryProfileBreakdown();
timings.add(token, queryTimings);
return queryTimings;
}
@ -180,7 +180,7 @@ final class InternalProfileTree {
*/
private ProfileResult doGetQueryTree(int token) {
Query query = queries.get(token);
ProfileBreakdown breakdown = timings.get(token);
QueryProfileBreakdown breakdown = timings.get(token);
Map<String, Long> timings = breakdown.toTimingMap();
List<Integer> children = tree.get(token);
List<ProfileResult> childrenProfileResults = Collections.emptyList();

View File

@ -45,22 +45,22 @@ import java.util.Map;
*/
final class ProfileResult implements Writeable, ToXContent {
private static final ParseField QUERY_TYPE = new ParseField("query_type");
private static final ParseField LUCENE_DESCRIPTION = new ParseField("lucene");
private static final ParseField TYPE = new ParseField("type");
private static final ParseField DESCRIPTION = new ParseField("description");
private static final ParseField NODE_TIME = new ParseField("time");
private static final ParseField CHILDREN = new ParseField("children");
private static final ParseField BREAKDOWN = new ParseField("breakdown");
private final String queryType;
private final String luceneDescription;
private final String type;
private final String description;
private final Map<String, Long> timings;
private final long nodeTime;
private final List<ProfileResult> children;
public ProfileResult(String queryType, String luceneDescription, Map<String, Long> timings, List<ProfileResult> children,
public ProfileResult(String type, String description, Map<String, Long> timings, List<ProfileResult> children,
long nodeTime) {
this.queryType = queryType;
this.luceneDescription = luceneDescription;
this.type = type;
this.description = description;
this.timings = timings;
this.children = children;
this.nodeTime = nodeTime;
@ -70,8 +70,8 @@ final class ProfileResult implements Writeable, ToXContent {
* Read from a stream.
*/
public ProfileResult(StreamInput in) throws IOException{
this.queryType = in.readString();
this.luceneDescription = in.readString();
this.type = in.readString();
this.description = in.readString();
this.nodeTime = in.readLong();
int timingsSize = in.readVInt();
@ -90,8 +90,8 @@ final class ProfileResult implements Writeable, ToXContent {
@Override
public void writeTo(StreamOutput out) throws IOException {
out.writeString(queryType);
out.writeString(luceneDescription);
out.writeString(type);
out.writeString(description);
out.writeLong(nodeTime); // not Vlong because can be negative
out.writeVInt(timings.size());
for (Map.Entry<String, Long> entry : timings.entrySet()) {
@ -108,14 +108,14 @@ final class ProfileResult implements Writeable, ToXContent {
* Retrieve the lucene description of this query (e.g. the "explain" text)
*/
public String getLuceneDescription() {
return luceneDescription;
return description;
}
/**
* Retrieve the name of the query (e.g. "TermQuery")
*/
public String getQueryName() {
return queryType;
return type;
}
/**
@ -144,9 +144,9 @@ final class ProfileResult implements Writeable, ToXContent {
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder = builder.startObject()
.field(QUERY_TYPE.getPreferredName(), queryType)
.field(LUCENE_DESCRIPTION.getPreferredName(), luceneDescription)
.field(NODE_TIME.getPreferredName(), String.format(Locale.US, "%.10gms", (double)(getTime() / 1000000.0)))
.field(TYPE.getPreferredName(), type)
.field(DESCRIPTION.getPreferredName(), description)
.field(NODE_TIME.getPreferredName(), String.format(Locale.US, "%.10gms", getTime() / 1000000.0))
.field(BREAKDOWN.getPreferredName(), timings);
if (!children.isEmpty()) {

View File

@ -35,9 +35,9 @@ final class ProfileScorer extends Scorer {
private final Scorer scorer;
private ProfileWeight profileWeight;
private final ProfileBreakdown profile;
private final QueryProfileBreakdown profile;
ProfileScorer(ProfileWeight w, Scorer scorer, ProfileBreakdown profile) throws IOException {
ProfileScorer(ProfileWeight w, Scorer scorer, QueryProfileBreakdown profile) throws IOException {
super(w);
this.scorer = scorer;
this.profileWeight = w;
@ -51,7 +51,7 @@ final class ProfileScorer extends Scorer {
@Override
public float score() throws IOException {
profile.startTime(ProfileBreakdown.TimingType.SCORE);
profile.startTime(QueryTimingType.SCORE);
try {
return scorer.score();
} finally {
@ -78,10 +78,10 @@ final class ProfileScorer extends Scorer {
public DocIdSetIterator iterator() {
final DocIdSetIterator in = scorer.iterator();
return new DocIdSetIterator() {
@Override
public int advance(int target) throws IOException {
profile.startTime(ProfileBreakdown.TimingType.ADVANCE);
profile.startTime(QueryTimingType.ADVANCE);
try {
return in.advance(target);
} finally {
@ -91,7 +91,7 @@ final class ProfileScorer extends Scorer {
@Override
public int nextDoc() throws IOException {
profile.startTime(ProfileBreakdown.TimingType.NEXT_DOC);
profile.startTime(QueryTimingType.NEXT_DOC);
try {
return in.nextDoc();
} finally {
@ -122,7 +122,7 @@ final class ProfileScorer extends Scorer {
@Override
public int advance(int target) throws IOException {
profile.startTime(ProfileBreakdown.TimingType.ADVANCE);
profile.startTime(QueryTimingType.ADVANCE);
try {
return inApproximation.advance(target);
} finally {
@ -132,7 +132,7 @@ final class ProfileScorer extends Scorer {
@Override
public int nextDoc() throws IOException {
profile.startTime(ProfileBreakdown.TimingType.NEXT_DOC);
profile.startTime(QueryTimingType.NEXT_DOC);
try {
return inApproximation.nextDoc();
} finally {
@ -153,7 +153,7 @@ final class ProfileScorer extends Scorer {
return new TwoPhaseIterator(approximation) {
@Override
public boolean matches() throws IOException {
profile.startTime(ProfileBreakdown.TimingType.MATCH);
profile.startTime(QueryTimingType.MATCH);
try {
return in.matches();
} finally {

View File

@ -36,16 +36,16 @@ import java.util.List;
*/
public final class ProfileShardResult implements Writeable, ToXContent {
private final List<ProfileResult> profileResults;
private final List<ProfileResult> queryProfileResults;
private final CollectorResult profileCollector;
private final long rewriteTime;
public ProfileShardResult(List<ProfileResult> profileResults, long rewriteTime,
public ProfileShardResult(List<ProfileResult> queryProfileResults, long rewriteTime,
CollectorResult profileCollector) {
assert(profileCollector != null);
this.profileResults = profileResults;
this.queryProfileResults = queryProfileResults;
this.profileCollector = profileCollector;
this.rewriteTime = rewriteTime;
}
@ -55,9 +55,9 @@ public final class ProfileShardResult implements Writeable, ToXContent {
*/
public ProfileShardResult(StreamInput in) throws IOException {
int profileSize = in.readVInt();
profileResults = new ArrayList<>(profileSize);
queryProfileResults = new ArrayList<>(profileSize);
for (int j = 0; j < profileSize; j++) {
profileResults.add(new ProfileResult(in));
queryProfileResults.add(new ProfileResult(in));
}
profileCollector = new CollectorResult(in);
@ -66,8 +66,8 @@ public final class ProfileShardResult implements Writeable, ToXContent {
@Override
public void writeTo(StreamOutput out) throws IOException {
out.writeVInt(profileResults.size());
for (ProfileResult p : profileResults) {
out.writeVInt(queryProfileResults.size());
for (ProfileResult p : queryProfileResults) {
p.writeTo(out);
}
profileCollector.writeTo(out);
@ -76,7 +76,7 @@ public final class ProfileShardResult implements Writeable, ToXContent {
public List<ProfileResult> getQueryResults() {
return Collections.unmodifiableList(profileResults);
return Collections.unmodifiableList(queryProfileResults);
}
public long getRewriteTime() {
@ -90,7 +90,7 @@ public final class ProfileShardResult implements Writeable, ToXContent {
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.startArray("query");
for (ProfileResult p : profileResults) {
for (ProfileResult p : queryProfileResults) {
p.toXContent(builder, params);
}
builder.endArray();

View File

@ -38,9 +38,9 @@ import java.util.Set;
public final class ProfileWeight extends Weight {
private final Weight subQueryWeight;
private final ProfileBreakdown profile;
private final QueryProfileBreakdown profile;
public ProfileWeight(Query query, Weight subQueryWeight, ProfileBreakdown profile) throws IOException {
public ProfileWeight(Query query, Weight subQueryWeight, QueryProfileBreakdown profile) throws IOException {
super(query);
this.subQueryWeight = subQueryWeight;
this.profile = profile;
@ -48,7 +48,7 @@ public final class ProfileWeight extends Weight {
@Override
public Scorer scorer(LeafReaderContext context) throws IOException {
profile.startTime(ProfileBreakdown.TimingType.BUILD_SCORER);
profile.startTime(QueryTimingType.BUILD_SCORER);
final Scorer subQueryScorer;
try {
subQueryScorer = subQueryWeight.scorer(context);

View File

@ -25,13 +25,13 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/** Wrapper around several {@link Profiler}s that makes management easier. */
/** Wrapper around several {@link QueryProfiler}s that makes management easier. */
public final class Profilers {
private final ContextIndexSearcher searcher;
private final List<Profiler> profilers;
private final List<QueryProfiler> profilers;
/** Sole constructor. This {@link Profilers} instance will initially wrap one {@link Profiler}. */
/** Sole constructor. This {@link Profilers} instance will initially wrap one {@link QueryProfiler}. */
public Profilers(ContextIndexSearcher searcher) {
this.searcher = searcher;
this.profilers = new ArrayList<>();
@ -39,20 +39,20 @@ public final class Profilers {
}
/** Switch to a new profile. */
public Profiler addProfiler() {
Profiler profiler = new Profiler();
public QueryProfiler addProfiler() {
QueryProfiler profiler = new QueryProfiler();
searcher.setProfiler(profiler);
profilers.add(profiler);
return profiler;
}
/** Get the current profiler. */
public Profiler getCurrent() {
public QueryProfiler getCurrent() {
return profilers.get(profilers.size() - 1);
}
/** Return the list of all created {@link Profiler}s so far. */
public List<Profiler> getProfilers() {
/** Return the list of all created {@link QueryProfiler}s so far. */
public List<QueryProfiler> getProfilers() {
return Collections.unmodifiableList(profilers);
}

View File

@ -0,0 +1,33 @@
/*
* 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.search.profile;
/**
* A record of timings for the various operations that may happen during query execution.
* A node's time may be composed of several internal attributes (rewriting, weighting,
* scoring, etc).
*/
public final class QueryProfileBreakdown extends AbstractProfileBreakdown<QueryTimingType> {
/** Sole constructor. */
public QueryProfileBreakdown() {
super(QueryTimingType.values());
}
}

View File

@ -21,7 +21,6 @@ package org.elasticsearch.search.profile;
import org.apache.lucene.search.Query;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
@ -36,16 +35,16 @@ import java.util.Objects;
* request may execute two searches (query + global agg). A Profiler just
* represents one of those
*/
public final class Profiler {
public final class QueryProfiler {
private final InternalProfileTree queryTree = new InternalProfileTree();
private final InternalQueryProfileTree queryTree = new InternalQueryProfileTree();
/**
* The root Collector used in the search
*/
private InternalProfileCollector collector;
public Profiler() {}
public QueryProfiler() {}
/** Set the collector that is associated with this profiler. */
public void setCollector(InternalProfileCollector collector) {
@ -56,11 +55,11 @@ public final class Profiler {
}
/**
* Get the {@link ProfileBreakdown} for the given query, potentially creating it if it did not exist.
* Get the {@link QueryProfileBreakdown} for the given query, potentially creating it if it did not exist.
* This should only be used for queries that will be undergoing scoring. Do not use it to profile the
* rewriting phase
*/
public ProfileBreakdown getQueryBreakdown(Query query) {
public QueryProfileBreakdown getQueryBreakdown(Query query) {
return queryTree.getQueryBreakdown(query);
}
@ -111,22 +110,5 @@ public final class Profiler {
return collector.getCollectorTree();
}
/**
* Helper method to convert Profiler into InternalProfileShardResults, which can be
* serialized to other nodes, emitted as JSON, etc.
*
* @param profilers A list of Profilers to convert into InternalProfileShardResults
* @return A list of corresponding InternalProfileShardResults
*/
public static List<ProfileShardResult> buildShardResults(List<Profiler> profilers) {
List<ProfileShardResult> results = new ArrayList<>(profilers.size());
for (Profiler profiler : profilers) {
ProfileShardResult result = new ProfileShardResult(
profiler.getQueryTree(), profiler.getRewriteTime(), profiler.getCollector());
results.add(result);
}
return results;
}
}

View File

@ -0,0 +1,36 @@
/*
* 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.search.profile;
import java.util.Locale;
public enum QueryTimingType {
CREATE_WEIGHT,
BUILD_SCORER,
NEXT_DOC,
ADVANCE,
MATCH,
SCORE;
@Override
public String toString() {
return name().toLowerCase(Locale.ROOT);
}
}

View File

@ -37,11 +37,11 @@ import java.util.stream.Collectors;
* A container class to hold all the profile results across all shards. Internally
* holds a map of shard ID -&gt; Profiled results
*/
public final class InternalProfileShardResults implements Writeable, ToXContent{
public final class SearchProfileShardResults implements Writeable, ToXContent{
private Map<String, List<ProfileShardResult>> shardResults;
public InternalProfileShardResults(Map<String, List<ProfileShardResult>> shardResults) {
public SearchProfileShardResults(Map<String, List<ProfileShardResult>> shardResults) {
Map<String, List<ProfileShardResult>> transformed =
shardResults.entrySet()
.stream()
@ -52,7 +52,7 @@ public final class InternalProfileShardResults implements Writeable, ToXContent{
this.shardResults = Collections.unmodifiableMap(transformed);
}
public InternalProfileShardResults(StreamInput in) throws IOException {
public SearchProfileShardResults(StreamInput in) throws IOException {
int size = in.readInt();
shardResults = new HashMap<>(size);
@ -105,4 +105,22 @@ public final class InternalProfileShardResults implements Writeable, ToXContent{
builder.endArray().endObject();
return builder;
}
/**
* Helper method to convert Profiler into InternalProfileShardResults, which
* can be serialized to other nodes, emitted as JSON, etc.
*
* @param profilers
* A list of Profilers to convert into
* InternalProfileShardResults
* @return A list of corresponding InternalProfileShardResults
*/
public static List<ProfileShardResult> buildShardResults(List<QueryProfiler> profilers) {
List<ProfileShardResult> results = new ArrayList<>(profilers.size());
for (QueryProfiler profiler : profilers) {
ProfileShardResult result = new ProfileShardResult(profiler.getQueryTree(), profiler.getRewriteTime(), profiler.getCollector());
results.add(result);
}
return results;
}
}

View File

@ -55,7 +55,7 @@ import org.elasticsearch.search.internal.SearchContext;
import org.elasticsearch.search.profile.CollectorResult;
import org.elasticsearch.search.profile.InternalProfileCollector;
import org.elasticsearch.search.profile.ProfileShardResult;
import org.elasticsearch.search.profile.Profiler;
import org.elasticsearch.search.profile.SearchProfileShardResults;
import org.elasticsearch.search.rescore.RescorePhase;
import org.elasticsearch.search.rescore.RescoreSearchContext;
import org.elasticsearch.search.sort.SortAndFormats;
@ -112,7 +112,8 @@ public class QueryPhase implements SearchPhase {
aggregationPhase.execute(searchContext);
if (searchContext.getProfilers() != null) {
List<ProfileShardResult> shardResults = Profiler.buildShardResults(searchContext.getProfilers().getProfilers());
List<ProfileShardResult> shardResults = SearchProfileShardResults
.buildShardResults(searchContext.getProfilers().getProfilers());
searchContext.queryResult().profileResults(shardResults);
}
}
@ -384,7 +385,8 @@ public class QueryPhase implements SearchPhase {
queryResult.topDocs(topDocsCallable.call(), sortValueFormats);
if (searchContext.getProfilers() != null) {
List<ProfileShardResult> shardResults = Profiler.buildShardResults(searchContext.getProfilers().getProfilers());
List<ProfileShardResult> shardResults = SearchProfileShardResults
.buildShardResults(searchContext.getProfilers().getProfilers());
searchContext.queryResult().profileResults(shardResults);
}

View File

@ -35,7 +35,6 @@ import org.apache.lucene.search.TotalHitCountCollector;
import org.apache.lucene.store.Directory;
import org.apache.lucene.util.IOUtils;
import org.apache.lucene.util.TestUtil;
import org.elasticsearch.common.lucene.Lucene;
import org.elasticsearch.index.engine.Engine;
import org.elasticsearch.search.internal.ContextIndexSearcher;
import org.elasticsearch.test.ESTestCase;
@ -84,45 +83,45 @@ public class ProfileTests extends ESTestCase {
}
public void testBasic() throws IOException {
Profiler profiler = new Profiler();
QueryProfiler profiler = new QueryProfiler();
searcher.setProfiler(profiler);
Query query = new TermQuery(new Term("foo", "bar"));
searcher.search(query, 1);
List<ProfileResult> results = profiler.getQueryTree();
assertEquals(1, results.size());
Map<String, Long> breakdown = results.get(0).getTimeBreakdown();
assertThat(breakdown.get(ProfileBreakdown.TimingType.CREATE_WEIGHT.toString()).longValue(), greaterThan(0L));
assertThat(breakdown.get(ProfileBreakdown.TimingType.BUILD_SCORER.toString()).longValue(), greaterThan(0L));
assertThat(breakdown.get(ProfileBreakdown.TimingType.NEXT_DOC.toString()).longValue(), greaterThan(0L));
assertThat(breakdown.get(ProfileBreakdown.TimingType.ADVANCE.toString()).longValue(), equalTo(0L));
assertThat(breakdown.get(ProfileBreakdown.TimingType.SCORE.toString()).longValue(), greaterThan(0L));
assertThat(breakdown.get(ProfileBreakdown.TimingType.MATCH.toString()).longValue(), equalTo(0L));
assertThat(breakdown.get(QueryTimingType.CREATE_WEIGHT.toString()).longValue(), greaterThan(0L));
assertThat(breakdown.get(QueryTimingType.BUILD_SCORER.toString()).longValue(), greaterThan(0L));
assertThat(breakdown.get(QueryTimingType.NEXT_DOC.toString()).longValue(), greaterThan(0L));
assertThat(breakdown.get(QueryTimingType.ADVANCE.toString()).longValue(), equalTo(0L));
assertThat(breakdown.get(QueryTimingType.SCORE.toString()).longValue(), greaterThan(0L));
assertThat(breakdown.get(QueryTimingType.MATCH.toString()).longValue(), equalTo(0L));
long rewriteTime = profiler.getRewriteTime();
assertThat(rewriteTime, greaterThan(0L));
}
public void testNoScoring() throws IOException {
Profiler profiler = new Profiler();
QueryProfiler profiler = new QueryProfiler();
searcher.setProfiler(profiler);
Query query = new TermQuery(new Term("foo", "bar"));
searcher.search(query, 1, Sort.INDEXORDER); // scores are not needed
List<ProfileResult> results = profiler.getQueryTree();
assertEquals(1, results.size());
Map<String, Long> breakdown = results.get(0).getTimeBreakdown();
assertThat(breakdown.get(ProfileBreakdown.TimingType.CREATE_WEIGHT.toString()).longValue(), greaterThan(0L));
assertThat(breakdown.get(ProfileBreakdown.TimingType.BUILD_SCORER.toString()).longValue(), greaterThan(0L));
assertThat(breakdown.get(ProfileBreakdown.TimingType.NEXT_DOC.toString()).longValue(), greaterThan(0L));
assertThat(breakdown.get(ProfileBreakdown.TimingType.ADVANCE.toString()).longValue(), equalTo(0L));
assertThat(breakdown.get(ProfileBreakdown.TimingType.SCORE.toString()).longValue(), equalTo(0L));
assertThat(breakdown.get(ProfileBreakdown.TimingType.MATCH.toString()).longValue(), equalTo(0L));
assertThat(breakdown.get(QueryTimingType.CREATE_WEIGHT.toString()).longValue(), greaterThan(0L));
assertThat(breakdown.get(QueryTimingType.BUILD_SCORER.toString()).longValue(), greaterThan(0L));
assertThat(breakdown.get(QueryTimingType.NEXT_DOC.toString()).longValue(), greaterThan(0L));
assertThat(breakdown.get(QueryTimingType.ADVANCE.toString()).longValue(), equalTo(0L));
assertThat(breakdown.get(QueryTimingType.SCORE.toString()).longValue(), equalTo(0L));
assertThat(breakdown.get(QueryTimingType.MATCH.toString()).longValue(), equalTo(0L));
long rewriteTime = profiler.getRewriteTime();
assertThat(rewriteTime, greaterThan(0L));
}
public void testUseIndexStats() throws IOException {
Profiler profiler = new Profiler();
QueryProfiler profiler = new QueryProfiler();
searcher.setProfiler(profiler);
Query query = new TermQuery(new Term("foo", "bar"));
searcher.count(query); // will use index stats
@ -134,7 +133,7 @@ public class ProfileTests extends ESTestCase {
}
public void testApproximations() throws IOException {
Profiler profiler = new Profiler();
QueryProfiler profiler = new QueryProfiler();
Engine.Searcher engineSearcher = new Engine.Searcher("test", new IndexSearcher(reader));
// disable query caching since we want to test approximations, which won't
// be exposed on a cached entry
@ -145,12 +144,12 @@ public class ProfileTests extends ESTestCase {
List<ProfileResult> results = profiler.getQueryTree();
assertEquals(1, results.size());
Map<String, Long> breakdown = results.get(0).getTimeBreakdown();
assertThat(breakdown.get(ProfileBreakdown.TimingType.CREATE_WEIGHT.toString()).longValue(), greaterThan(0L));
assertThat(breakdown.get(ProfileBreakdown.TimingType.BUILD_SCORER.toString()).longValue(), greaterThan(0L));
assertThat(breakdown.get(ProfileBreakdown.TimingType.NEXT_DOC.toString()).longValue(), greaterThan(0L));
assertThat(breakdown.get(ProfileBreakdown.TimingType.ADVANCE.toString()).longValue(), equalTo(0L));
assertThat(breakdown.get(ProfileBreakdown.TimingType.SCORE.toString()).longValue(), equalTo(0L));
assertThat(breakdown.get(ProfileBreakdown.TimingType.MATCH.toString()).longValue(), greaterThan(0L));
assertThat(breakdown.get(QueryTimingType.CREATE_WEIGHT.toString()).longValue(), greaterThan(0L));
assertThat(breakdown.get(QueryTimingType.BUILD_SCORER.toString()).longValue(), greaterThan(0L));
assertThat(breakdown.get(QueryTimingType.NEXT_DOC.toString()).longValue(), greaterThan(0L));
assertThat(breakdown.get(QueryTimingType.ADVANCE.toString()).longValue(), equalTo(0L));
assertThat(breakdown.get(QueryTimingType.SCORE.toString()).longValue(), equalTo(0L));
assertThat(breakdown.get(QueryTimingType.MATCH.toString()).longValue(), greaterThan(0L));
long rewriteTime = profiler.getRewriteTime();
assertThat(rewriteTime, greaterThan(0L));