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

View File

@ -33,9 +33,10 @@ import org.apache.lucene.search.Weight;
import org.elasticsearch.common.lease.Releasable; import org.elasticsearch.common.lease.Releasable;
import org.elasticsearch.index.engine.Engine; import org.elasticsearch.index.engine.Engine;
import org.elasticsearch.search.dfs.AggregatedDfs; 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.ProfileWeight;
import org.elasticsearch.search.profile.Profiler; import org.elasticsearch.search.profile.QueryProfiler;
import org.elasticsearch.search.profile.QueryTimingType;
import java.io.IOException; import java.io.IOException;
@ -54,7 +55,7 @@ public class ContextIndexSearcher extends IndexSearcher implements Releasable {
private final Engine.Searcher engineSearcher; private final Engine.Searcher engineSearcher;
// TODO revisit moving the profiler to inheritance or wrapping model in the future // TODO revisit moving the profiler to inheritance or wrapping model in the future
private Profiler profiler; private QueryProfiler profiler;
public ContextIndexSearcher(Engine.Searcher searcher, public ContextIndexSearcher(Engine.Searcher searcher,
QueryCache queryCache, QueryCachingPolicy queryCachingPolicy) { QueryCache queryCache, QueryCachingPolicy queryCachingPolicy) {
@ -70,7 +71,7 @@ public class ContextIndexSearcher extends IndexSearcher implements Releasable {
public void close() { public void close() {
} }
public void setProfiler(Profiler profiler) { public void setProfiler(QueryProfiler profiler) {
this.profiler = 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 // 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 // each invocation so that it can build an internal representation of the query
// tree // tree
ProfileBreakdown profile = profiler.getQueryBreakdown(query); QueryProfileBreakdown profile = profiler.getQueryBreakdown(query);
profile.startTime(ProfileBreakdown.TimingType.CREATE_WEIGHT); profile.startTime(QueryTimingType.CREATE_WEIGHT);
final Weight weight; final Weight weight;
try { try {
weight = super.createWeight(query, needsScores); 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.SearchHits;
import org.elasticsearch.search.aggregations.Aggregations; import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.InternalAggregations; 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.profile.ProfileShardResult;
import org.elasticsearch.search.suggest.Suggest; import org.elasticsearch.search.suggest.Suggest;
@ -54,7 +54,7 @@ public class InternalSearchResponse implements Streamable, ToXContent {
private Suggest suggest; private Suggest suggest;
private InternalProfileShardResults profileResults; private SearchProfileShardResults profileResults;
private boolean timedOut; private boolean timedOut;
@ -64,7 +64,7 @@ public class InternalSearchResponse implements Streamable, ToXContent {
} }
public InternalSearchResponse(InternalSearchHits hits, InternalAggregations aggregations, Suggest suggest, public InternalSearchResponse(InternalSearchHits hits, InternalAggregations aggregations, Suggest suggest,
InternalProfileShardResults profileResults, boolean timedOut, Boolean terminatedEarly) { SearchProfileShardResults profileResults, boolean timedOut, Boolean terminatedEarly) {
this.hits = hits; this.hits = hits;
this.aggregations = aggregations; this.aggregations = aggregations;
this.suggest = suggest; this.suggest = suggest;
@ -141,7 +141,7 @@ public class InternalSearchResponse implements Streamable, ToXContent {
terminatedEarly = in.readOptionalBoolean(); terminatedEarly = in.readOptionalBoolean();
if (in.getVersion().onOrAfter(Version.V_2_2_0) && in.readBoolean()) { if (in.getVersion().onOrAfter(Version.V_2_2_0) && in.readBoolean()) {
profileResults = new InternalProfileShardResults(in); profileResults = new SearchProfileShardResults(in);
} else { } else {
profileResults = null; profileResults = null;
} }

View File

@ -21,7 +21,6 @@ package org.elasticsearch.search.profile;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.Locale;
import java.util.Map; 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, * A node's time may be composed of several internal attributes (rewriting, weighting,
* scoring, etc). * scoring, etc).
*/ */
public final class ProfileBreakdown { public abstract class AbstractProfileBreakdown<T extends Enum<T>> {
/** 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);
}
}
/** /**
* The accumulated timings for this query node * The accumulated timings for this query node
@ -52,23 +36,26 @@ public final class ProfileBreakdown {
private final long[] timings; private final long[] timings;
/** Scratch to store the current timing type. */ /** Scratch to store the current timing type. */
private TimingType currentTimingType; private T currentTimingType;
/** /**
* The temporary scratch space for holding start-times * The temporary scratch space for holding start-times
*/ */
private long scratch; private long scratch;
private T[] timingTypes;
/** Sole constructor. */ /** Sole constructor. */
public ProfileBreakdown() { public AbstractProfileBreakdown(T[] timingTypes) {
timings = new long[TimingType.values().length]; this.timingTypes = timingTypes;
timings = new long[timingTypes.length];
} }
/** /**
* Begin timing a query for a specific Timing context * Begin timing a query for a specific Timing context
* @param timing The timing context being profiled * @param timing The timing context being profiled
*/ */
public void startTime(TimingType timing) { public void startTime(T timing) {
assert currentTimingType == null; assert currentTimingType == null;
assert scratch == 0; assert scratch == 0;
currentTimingType = timing; currentTimingType = timing;
@ -91,10 +78,10 @@ public final class ProfileBreakdown {
return time; 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() { public Map<String, Long> toTimingMap() {
Map<String, Long> map = new HashMap<>(); Map<String, Long> map = new HashMap<>();
for (TimingType timingType : TimingType.values()) { for (T timingType : timingTypes) {
map.put(timingType.toString(), timings[timingType.ordinal()]); map.put(timingType.toString(), timings[timingType.ordinal()]);
} }
return Collections.unmodifiableMap(map); return Collections.unmodifiableMap(map);
@ -104,7 +91,7 @@ public final class ProfileBreakdown {
* Add <code>other</code>'s timings into this breakdown * Add <code>other</code>'s timings into this breakdown
* @param other Another Breakdown to merge with this one * @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); assert(timings.length == other.timings.length);
for (int i = 0; i < timings.length; ++i) { for (int i = 0; i < timings.length; ++i) {
timings[i] += other.timings[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 * 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 * 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 */ /** Maps the Query to it's list of children. This is basically the dependency tree */
private ArrayList<ArrayList<Integer>> tree; private ArrayList<ArrayList<Integer>> tree;
@ -55,7 +55,7 @@ final class InternalProfileTree {
private int currentToken = 0; private int currentToken = 0;
public InternalProfileTree() { public InternalQueryProfileTree() {
timings = new ArrayList<>(10); timings = new ArrayList<>(10);
stack = new LinkedBlockingDeque<>(10); stack = new LinkedBlockingDeque<>(10);
tree = new ArrayList<>(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 * 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 * 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 * @param query The scoring query we wish to profile
* @return A ProfileBreakdown for this query * @return A ProfileBreakdown for this query
*/ */
public ProfileBreakdown getQueryBreakdown(Query query) { public QueryProfileBreakdown getQueryBreakdown(Query query) {
int token = currentToken; int token = currentToken;
boolean stackEmpty = stack.isEmpty(); boolean stackEmpty = stack.isEmpty();
@ -131,14 +131,14 @@ final class InternalProfileTree {
* Helper method to add a new node to the dependency tree. * Helper method to add a new node to the dependency tree.
* *
* Initializes a new list in the dependency tree, saves the query and * 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 * of this query
* *
* @param query The query to profile * @param query The query to profile
* @param token The assigned token for this query * @param token The assigned token for this query
* @return A ProfileBreakdown to profile 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 // Add a new slot in the dependency tree
tree.add(new ArrayList<>(5)); tree.add(new ArrayList<>(5));
@ -146,7 +146,7 @@ final class InternalProfileTree {
// Save our query for lookup later // Save our query for lookup later
queries.add(query); queries.add(query);
ProfileBreakdown queryTimings = new ProfileBreakdown(); QueryProfileBreakdown queryTimings = new QueryProfileBreakdown();
timings.add(token, queryTimings); timings.add(token, queryTimings);
return queryTimings; return queryTimings;
} }
@ -180,7 +180,7 @@ final class InternalProfileTree {
*/ */
private ProfileResult doGetQueryTree(int token) { private ProfileResult doGetQueryTree(int token) {
Query query = queries.get(token); Query query = queries.get(token);
ProfileBreakdown breakdown = timings.get(token); QueryProfileBreakdown breakdown = timings.get(token);
Map<String, Long> timings = breakdown.toTimingMap(); Map<String, Long> timings = breakdown.toTimingMap();
List<Integer> children = tree.get(token); List<Integer> children = tree.get(token);
List<ProfileResult> childrenProfileResults = Collections.emptyList(); List<ProfileResult> childrenProfileResults = Collections.emptyList();

View File

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

View File

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

View File

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

View File

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

View File

@ -25,13 +25,13 @@ import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; 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 { public final class Profilers {
private final ContextIndexSearcher searcher; 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) { public Profilers(ContextIndexSearcher searcher) {
this.searcher = searcher; this.searcher = searcher;
this.profilers = new ArrayList<>(); this.profilers = new ArrayList<>();
@ -39,20 +39,20 @@ public final class Profilers {
} }
/** Switch to a new profile. */ /** Switch to a new profile. */
public Profiler addProfiler() { public QueryProfiler addProfiler() {
Profiler profiler = new Profiler(); QueryProfiler profiler = new QueryProfiler();
searcher.setProfiler(profiler); searcher.setProfiler(profiler);
profilers.add(profiler); profilers.add(profiler);
return profiler; return profiler;
} }
/** Get the current profiler. */ /** Get the current profiler. */
public Profiler getCurrent() { public QueryProfiler getCurrent() {
return profilers.get(profilers.size() - 1); return profilers.get(profilers.size() - 1);
} }
/** Return the list of all created {@link Profiler}s so far. */ /** Return the list of all created {@link QueryProfiler}s so far. */
public List<Profiler> getProfilers() { public List<QueryProfiler> getProfilers() {
return Collections.unmodifiableList(profilers); 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 org.apache.lucene.search.Query;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
@ -36,16 +35,16 @@ import java.util.Objects;
* request may execute two searches (query + global agg). A Profiler just * request may execute two searches (query + global agg). A Profiler just
* represents one of those * 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 * The root Collector used in the search
*/ */
private InternalProfileCollector collector; private InternalProfileCollector collector;
public Profiler() {} public QueryProfiler() {}
/** Set the collector that is associated with this profiler. */ /** Set the collector that is associated with this profiler. */
public void setCollector(InternalProfileCollector collector) { 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 * This should only be used for queries that will be undergoing scoring. Do not use it to profile the
* rewriting phase * rewriting phase
*/ */
public ProfileBreakdown getQueryBreakdown(Query query) { public QueryProfileBreakdown getQueryBreakdown(Query query) {
return queryTree.getQueryBreakdown(query); return queryTree.getQueryBreakdown(query);
} }
@ -111,22 +110,5 @@ public final class Profiler {
return collector.getCollectorTree(); 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 * A container class to hold all the profile results across all shards. Internally
* holds a map of shard ID -&gt; Profiled results * 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; 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 = Map<String, List<ProfileShardResult>> transformed =
shardResults.entrySet() shardResults.entrySet()
.stream() .stream()
@ -52,7 +52,7 @@ public final class InternalProfileShardResults implements Writeable, ToXContent{
this.shardResults = Collections.unmodifiableMap(transformed); this.shardResults = Collections.unmodifiableMap(transformed);
} }
public InternalProfileShardResults(StreamInput in) throws IOException { public SearchProfileShardResults(StreamInput in) throws IOException {
int size = in.readInt(); int size = in.readInt();
shardResults = new HashMap<>(size); shardResults = new HashMap<>(size);
@ -105,4 +105,22 @@ public final class InternalProfileShardResults implements Writeable, ToXContent{
builder.endArray().endObject(); builder.endArray().endObject();
return builder; 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.CollectorResult;
import org.elasticsearch.search.profile.InternalProfileCollector; import org.elasticsearch.search.profile.InternalProfileCollector;
import org.elasticsearch.search.profile.ProfileShardResult; 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.RescorePhase;
import org.elasticsearch.search.rescore.RescoreSearchContext; import org.elasticsearch.search.rescore.RescoreSearchContext;
import org.elasticsearch.search.sort.SortAndFormats; import org.elasticsearch.search.sort.SortAndFormats;
@ -112,7 +112,8 @@ public class QueryPhase implements SearchPhase {
aggregationPhase.execute(searchContext); aggregationPhase.execute(searchContext);
if (searchContext.getProfilers() != null) { if (searchContext.getProfilers() != null) {
List<ProfileShardResult> shardResults = Profiler.buildShardResults(searchContext.getProfilers().getProfilers()); List<ProfileShardResult> shardResults = SearchProfileShardResults
.buildShardResults(searchContext.getProfilers().getProfilers());
searchContext.queryResult().profileResults(shardResults); searchContext.queryResult().profileResults(shardResults);
} }
} }
@ -384,7 +385,8 @@ public class QueryPhase implements SearchPhase {
queryResult.topDocs(topDocsCallable.call(), sortValueFormats); queryResult.topDocs(topDocsCallable.call(), sortValueFormats);
if (searchContext.getProfilers() != null) { if (searchContext.getProfilers() != null) {
List<ProfileShardResult> shardResults = Profiler.buildShardResults(searchContext.getProfilers().getProfilers()); List<ProfileShardResult> shardResults = SearchProfileShardResults
.buildShardResults(searchContext.getProfilers().getProfilers());
searchContext.queryResult().profileResults(shardResults); 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.store.Directory;
import org.apache.lucene.util.IOUtils; import org.apache.lucene.util.IOUtils;
import org.apache.lucene.util.TestUtil; import org.apache.lucene.util.TestUtil;
import org.elasticsearch.common.lucene.Lucene;
import org.elasticsearch.index.engine.Engine; import org.elasticsearch.index.engine.Engine;
import org.elasticsearch.search.internal.ContextIndexSearcher; import org.elasticsearch.search.internal.ContextIndexSearcher;
import org.elasticsearch.test.ESTestCase; import org.elasticsearch.test.ESTestCase;
@ -84,45 +83,45 @@ public class ProfileTests extends ESTestCase {
} }
public void testBasic() throws IOException { public void testBasic() throws IOException {
Profiler profiler = new Profiler(); QueryProfiler profiler = new QueryProfiler();
searcher.setProfiler(profiler); searcher.setProfiler(profiler);
Query query = new TermQuery(new Term("foo", "bar")); Query query = new TermQuery(new Term("foo", "bar"));
searcher.search(query, 1); searcher.search(query, 1);
List<ProfileResult> results = profiler.getQueryTree(); List<ProfileResult> results = profiler.getQueryTree();
assertEquals(1, results.size()); assertEquals(1, results.size());
Map<String, Long> breakdown = results.get(0).getTimeBreakdown(); Map<String, Long> breakdown = results.get(0).getTimeBreakdown();
assertThat(breakdown.get(ProfileBreakdown.TimingType.CREATE_WEIGHT.toString()).longValue(), greaterThan(0L)); assertThat(breakdown.get(QueryTimingType.CREATE_WEIGHT.toString()).longValue(), greaterThan(0L));
assertThat(breakdown.get(ProfileBreakdown.TimingType.BUILD_SCORER.toString()).longValue(), greaterThan(0L)); assertThat(breakdown.get(QueryTimingType.BUILD_SCORER.toString()).longValue(), greaterThan(0L));
assertThat(breakdown.get(ProfileBreakdown.TimingType.NEXT_DOC.toString()).longValue(), greaterThan(0L)); assertThat(breakdown.get(QueryTimingType.NEXT_DOC.toString()).longValue(), greaterThan(0L));
assertThat(breakdown.get(ProfileBreakdown.TimingType.ADVANCE.toString()).longValue(), equalTo(0L)); assertThat(breakdown.get(QueryTimingType.ADVANCE.toString()).longValue(), equalTo(0L));
assertThat(breakdown.get(ProfileBreakdown.TimingType.SCORE.toString()).longValue(), greaterThan(0L)); assertThat(breakdown.get(QueryTimingType.SCORE.toString()).longValue(), greaterThan(0L));
assertThat(breakdown.get(ProfileBreakdown.TimingType.MATCH.toString()).longValue(), equalTo(0L)); assertThat(breakdown.get(QueryTimingType.MATCH.toString()).longValue(), equalTo(0L));
long rewriteTime = profiler.getRewriteTime(); long rewriteTime = profiler.getRewriteTime();
assertThat(rewriteTime, greaterThan(0L)); assertThat(rewriteTime, greaterThan(0L));
} }
public void testNoScoring() throws IOException { public void testNoScoring() throws IOException {
Profiler profiler = new Profiler(); QueryProfiler profiler = new QueryProfiler();
searcher.setProfiler(profiler); searcher.setProfiler(profiler);
Query query = new TermQuery(new Term("foo", "bar")); Query query = new TermQuery(new Term("foo", "bar"));
searcher.search(query, 1, Sort.INDEXORDER); // scores are not needed searcher.search(query, 1, Sort.INDEXORDER); // scores are not needed
List<ProfileResult> results = profiler.getQueryTree(); List<ProfileResult> results = profiler.getQueryTree();
assertEquals(1, results.size()); assertEquals(1, results.size());
Map<String, Long> breakdown = results.get(0).getTimeBreakdown(); Map<String, Long> breakdown = results.get(0).getTimeBreakdown();
assertThat(breakdown.get(ProfileBreakdown.TimingType.CREATE_WEIGHT.toString()).longValue(), greaterThan(0L)); assertThat(breakdown.get(QueryTimingType.CREATE_WEIGHT.toString()).longValue(), greaterThan(0L));
assertThat(breakdown.get(ProfileBreakdown.TimingType.BUILD_SCORER.toString()).longValue(), greaterThan(0L)); assertThat(breakdown.get(QueryTimingType.BUILD_SCORER.toString()).longValue(), greaterThan(0L));
assertThat(breakdown.get(ProfileBreakdown.TimingType.NEXT_DOC.toString()).longValue(), greaterThan(0L)); assertThat(breakdown.get(QueryTimingType.NEXT_DOC.toString()).longValue(), greaterThan(0L));
assertThat(breakdown.get(ProfileBreakdown.TimingType.ADVANCE.toString()).longValue(), equalTo(0L)); assertThat(breakdown.get(QueryTimingType.ADVANCE.toString()).longValue(), equalTo(0L));
assertThat(breakdown.get(ProfileBreakdown.TimingType.SCORE.toString()).longValue(), equalTo(0L)); assertThat(breakdown.get(QueryTimingType.SCORE.toString()).longValue(), equalTo(0L));
assertThat(breakdown.get(ProfileBreakdown.TimingType.MATCH.toString()).longValue(), equalTo(0L)); assertThat(breakdown.get(QueryTimingType.MATCH.toString()).longValue(), equalTo(0L));
long rewriteTime = profiler.getRewriteTime(); long rewriteTime = profiler.getRewriteTime();
assertThat(rewriteTime, greaterThan(0L)); assertThat(rewriteTime, greaterThan(0L));
} }
public void testUseIndexStats() throws IOException { public void testUseIndexStats() throws IOException {
Profiler profiler = new Profiler(); QueryProfiler profiler = new QueryProfiler();
searcher.setProfiler(profiler); searcher.setProfiler(profiler);
Query query = new TermQuery(new Term("foo", "bar")); Query query = new TermQuery(new Term("foo", "bar"));
searcher.count(query); // will use index stats searcher.count(query); // will use index stats
@ -134,7 +133,7 @@ public class ProfileTests extends ESTestCase {
} }
public void testApproximations() throws IOException { public void testApproximations() throws IOException {
Profiler profiler = new Profiler(); QueryProfiler profiler = new QueryProfiler();
Engine.Searcher engineSearcher = new Engine.Searcher("test", new IndexSearcher(reader)); Engine.Searcher engineSearcher = new Engine.Searcher("test", new IndexSearcher(reader));
// disable query caching since we want to test approximations, which won't // disable query caching since we want to test approximations, which won't
// be exposed on a cached entry // be exposed on a cached entry
@ -145,12 +144,12 @@ public class ProfileTests extends ESTestCase {
List<ProfileResult> results = profiler.getQueryTree(); List<ProfileResult> results = profiler.getQueryTree();
assertEquals(1, results.size()); assertEquals(1, results.size());
Map<String, Long> breakdown = results.get(0).getTimeBreakdown(); Map<String, Long> breakdown = results.get(0).getTimeBreakdown();
assertThat(breakdown.get(ProfileBreakdown.TimingType.CREATE_WEIGHT.toString()).longValue(), greaterThan(0L)); assertThat(breakdown.get(QueryTimingType.CREATE_WEIGHT.toString()).longValue(), greaterThan(0L));
assertThat(breakdown.get(ProfileBreakdown.TimingType.BUILD_SCORER.toString()).longValue(), greaterThan(0L)); assertThat(breakdown.get(QueryTimingType.BUILD_SCORER.toString()).longValue(), greaterThan(0L));
assertThat(breakdown.get(ProfileBreakdown.TimingType.NEXT_DOC.toString()).longValue(), greaterThan(0L)); assertThat(breakdown.get(QueryTimingType.NEXT_DOC.toString()).longValue(), greaterThan(0L));
assertThat(breakdown.get(ProfileBreakdown.TimingType.ADVANCE.toString()).longValue(), equalTo(0L)); assertThat(breakdown.get(QueryTimingType.ADVANCE.toString()).longValue(), equalTo(0L));
assertThat(breakdown.get(ProfileBreakdown.TimingType.SCORE.toString()).longValue(), equalTo(0L)); assertThat(breakdown.get(QueryTimingType.SCORE.toString()).longValue(), equalTo(0L));
assertThat(breakdown.get(ProfileBreakdown.TimingType.MATCH.toString()).longValue(), greaterThan(0L)); assertThat(breakdown.get(QueryTimingType.MATCH.toString()).longValue(), greaterThan(0L));
long rewriteTime = profiler.getRewriteTime(); long rewriteTime = profiler.getRewriteTime();
assertThat(rewriteTime, greaterThan(0L)); assertThat(rewriteTime, greaterThan(0L));