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:
commit
83df20b83b
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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];
|
|
@ -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();
|
|
@ -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()) {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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 -> 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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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));
|
||||
|
|
Loading…
Reference in New Issue