Skip to content

Commit 5a5d98b

Browse files
committed
[Docs] Add profile section to the Search API documentation (#25880)
1 parent ffc919f commit 5a5d98b

File tree

2 files changed

+167
-5
lines changed

2 files changed

+167
-5
lines changed

client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/SearchDocumentationIT.java

Lines changed: 80 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import org.elasticsearch.action.bulk.BulkRequest;
2424
import org.elasticsearch.action.bulk.BulkResponse;
2525
import org.elasticsearch.action.index.IndexRequest;
26+
import org.elasticsearch.action.index.IndexResponse;
2627
import org.elasticsearch.action.search.ClearScrollRequest;
2728
import org.elasticsearch.action.search.ClearScrollResponse;
2829
import org.elasticsearch.action.search.SearchRequest;
@@ -52,6 +53,11 @@
5253
import org.elasticsearch.search.builder.SearchSourceBuilder;
5354
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
5455
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
56+
import org.elasticsearch.search.profile.ProfileResult;
57+
import org.elasticsearch.search.profile.ProfileShardResult;
58+
import org.elasticsearch.search.profile.aggregation.AggregationProfileShardResult;
59+
import org.elasticsearch.search.profile.query.CollectorResult;
60+
import org.elasticsearch.search.profile.query.QueryProfileShardResult;
5561
import org.elasticsearch.search.sort.FieldSortBuilder;
5662
import org.elasticsearch.search.sort.ScoreSortBuilder;
5763
import org.elasticsearch.search.sort.SortOrder;
@@ -70,6 +76,7 @@
7076

7177
import static org.elasticsearch.index.query.QueryBuilders.matchQuery;
7278
import static org.hamcrest.Matchers.containsString;
79+
import static org.hamcrest.Matchers.equalTo;
7380
import static org.hamcrest.Matchers.greaterThan;
7481

7582
/**
@@ -105,7 +112,7 @@ public void testSearch() throws IOException {
105112
Arrays.asList("kimchy", "tanguy"), "innerObject", Collections.singletonMap("key", "value")));
106113
request.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE);
107114
BulkResponse bulkResponse = client.bulk(request);
108-
assertSame(bulkResponse.status(), RestStatus.OK);
115+
assertSame(RestStatus.OK, bulkResponse.status());
109116
assertFalse(bulkResponse.hasFailures());
110117
}
111118
{
@@ -244,7 +251,7 @@ public void testSearchRequestAggregations() throws IOException {
244251
.source(XContentType.JSON, "company", "Elastic", "age", 40));
245252
request.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE);
246253
BulkResponse bulkResponse = client.bulk(request);
247-
assertSame(bulkResponse.status(), RestStatus.OK);
254+
assertSame(RestStatus.OK, bulkResponse.status());
248255
assertFalse(bulkResponse.hasFailures());
249256
}
250257
{
@@ -317,7 +324,7 @@ public void testSearchRequestSuggestions() throws IOException {
317324
request.add(new IndexRequest("posts", "doc", "4").source(XContentType.JSON, "user", "cbuescher"));
318325
request.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE);
319326
BulkResponse bulkResponse = client.bulk(request);
320-
assertSame(bulkResponse.status(), RestStatus.OK);
327+
assertSame(RestStatus.OK, bulkResponse.status());
321328
assertFalse(bulkResponse.hasFailures());
322329
}
323330
{
@@ -364,7 +371,7 @@ public void testSearchRequestHighlighting() throws IOException {
364371
Arrays.asList("kimchy", "tanguy"), "innerObject", Collections.singletonMap("key", "value")));
365372
request.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE);
366373
BulkResponse bulkResponse = client.bulk(request);
367-
assertSame(bulkResponse.status(), RestStatus.OK);
374+
assertSame(RestStatus.OK, bulkResponse.status());
368375
assertFalse(bulkResponse.hasFailures());
369376
}
370377
{
@@ -412,6 +419,74 @@ public void testSearchRequestHighlighting() throws IOException {
412419
}
413420
}
414421

422+
public void testSearchRequestProfiling() throws IOException {
423+
RestHighLevelClient client = highLevelClient();
424+
{
425+
IndexRequest request = new IndexRequest("posts", "doc", "1")
426+
.source(XContentType.JSON, "tags", "elasticsearch", "comments", 123);
427+
request.setRefreshPolicy(WriteRequest.RefreshPolicy.WAIT_UNTIL);
428+
IndexResponse indexResponse = client.index(request);
429+
assertSame(RestStatus.CREATED, indexResponse.status());
430+
}
431+
{
432+
SearchRequest searchRequest = new SearchRequest();
433+
// tag::search-request-profiling
434+
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
435+
searchSourceBuilder.profile(true);
436+
// end::search-request-profiling
437+
searchSourceBuilder.query(QueryBuilders.termQuery("tags", "elasticsearch"));
438+
searchSourceBuilder.aggregation(AggregationBuilders.histogram("by_comments").field("comments").interval(100));
439+
searchRequest.source(searchSourceBuilder);
440+
441+
SearchResponse searchResponse = client.search(searchRequest);
442+
// tag::search-request-profiling-get
443+
Map<String, ProfileShardResult> profilingResults = searchResponse.getProfileResults(); // <1>
444+
for (Map.Entry<String, ProfileShardResult> profilingResult : profilingResults.entrySet()) { // <2>
445+
String key = profilingResult.getKey(); // <3>
446+
ProfileShardResult profileShardResult = profilingResult.getValue(); // <4>
447+
}
448+
// end::search-request-profiling-get
449+
450+
ProfileShardResult profileShardResult = profilingResults.values().iterator().next();
451+
assertNotNull(profileShardResult);
452+
453+
// tag::search-request-profiling-queries
454+
List<QueryProfileShardResult> queryProfileShardResults = profileShardResult.getQueryProfileResults(); // <1>
455+
for (QueryProfileShardResult queryProfileResult : queryProfileShardResults) { // <2>
456+
457+
}
458+
// end::search-request-profiling-queries
459+
assertThat(queryProfileShardResults.size(), equalTo(1));
460+
461+
for (QueryProfileShardResult queryProfileResult : queryProfileShardResults) {
462+
// tag::search-request-profiling-queries-results
463+
for (ProfileResult profileResult : queryProfileResult.getQueryResults()) { // <1>
464+
String queryName = profileResult.getQueryName(); // <2>
465+
long queryTimeInMillis = profileResult.getTime(); // <3>
466+
List<ProfileResult> profiledChildren = profileResult.getProfiledChildren(); // <4>
467+
}
468+
// end::search-request-profiling-queries-results
469+
470+
// tag::search-request-profiling-queries-collectors
471+
CollectorResult collectorResult = queryProfileResult.getCollectorResult(); // <1>
472+
String collectorName = collectorResult.getName(); // <2>
473+
Long collectorTimeInMillis = collectorResult.getTime(); // <3>
474+
List<CollectorResult> profiledChildren = collectorResult.getProfiledChildren(); // <4>
475+
// end::search-request-profiling-queries-collectors
476+
}
477+
478+
// tag::search-request-profiling-aggs
479+
AggregationProfileShardResult aggsProfileResults = profileShardResult.getAggregationProfileResults(); // <1>
480+
for (ProfileResult profileResult : aggsProfileResults.getProfileResults()) { // <2>
481+
String aggName = profileResult.getQueryName(); // <3>
482+
long aggTimeInMillis = profileResult.getTime(); // <4>
483+
List<ProfileResult> profiledChildren = profileResult.getProfiledChildren(); // <5>
484+
}
485+
// end::search-request-profiling-aggs
486+
assertThat(aggsProfileResults.getProfileResults().size(), equalTo(1));
487+
}
488+
}
489+
415490
public void testScroll() throws IOException {
416491
RestHighLevelClient client = highLevelClient();
417492
{
@@ -424,7 +499,7 @@ public void testScroll() throws IOException {
424499
.source(XContentType.JSON, "title", "The Future of Federated Search in Elasticsearch"));
425500
request.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE);
426501
BulkResponse bulkResponse = client.bulk(request);
427-
assertSame(bulkResponse.status(), RestStatus.OK);
502+
assertSame(RestStatus.OK, bulkResponse.status());
428503
assertFalse(bulkResponse.hasFailures());
429504
}
430505
{

docs/java-rest/high-level/apis/search.asciidoc

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,19 @@ the text `kmichy`
163163
We will later see how to <<java-rest-high-retrieve-suggestions,retrieve suggestions>> from the
164164
`SearchResponse`.
165165

166+
===== Profiling Queries and Aggregations
167+
168+
The {ref}/search-profile.html[Profile API] can be used to profile the execution of queries and aggregations for
169+
a specific search request. in order to use it, the profile flag must be set to true on the `SearchSourceBuilder`:
170+
171+
["source","java",subs="attributes,callouts,macros"]
172+
--------------------------------------------------
173+
include-tagged::{doc-tests}/SearchDocumentationIT.java[search-request-profiling]
174+
--------------------------------------------------
175+
176+
Once the `SearchRequest` is executed the corresponding `SearchResponse` will
177+
<<java-rest-high-retrieve-profile-results,contain the profiling results>>.
178+
166179
[[java-rest-high-document-search-sync]]
167180
==== Synchronous Execution
168181

@@ -339,3 +352,77 @@ include-tagged::{doc-tests}/SearchDocumentationIT.java[search-request-suggestion
339352
type of Suggestion class (here `TermSuggestion`), otherwise a `ClassCastException` is thrown
340353
<3> Iterate over the suggestion entries
341354
<4> Iterate over the options in one entry
355+
356+
[[java-rest-high-retrieve-profile-results]]
357+
===== Retrieving Profiling Results
358+
359+
Profiling results are retrieved from a `SearchResponse` using the `getProfileResults()` method. This
360+
method returns a `Map` containing a `ProfileShardResult` object for every shard involved in the
361+
`SearchRequest` execution. `ProfileShardResult` are stored in the `Map` using a key that uniquely
362+
identifies the shard the profile result corresponds to.
363+
364+
Here is a sample code that shows how to iterate over all the profiling results of every shard:
365+
366+
["source","java",subs="attributes,callouts,macros"]
367+
--------------------------------------------------
368+
include-tagged::{doc-tests}/SearchDocumentationIT.java[search-request-profiling-get]
369+
--------------------------------------------------
370+
<1> Retrieve the `Map` of `ProfileShardResult` from the `SearchResponse`
371+
<2> Profiling results can be retrieved by shard's key if the key is known, otherwise it might be simpler
372+
to iterate over all the profiling results
373+
<3> Retrieve the key that identifies which shard the `ProfileShardResult` belongs to
374+
<4> Retrieve the `ProfileShardResult` for the given shard
375+
376+
The `ProfileShardResult` object itself contains one or more query profile results, one for each query
377+
executed against the underlying Lucene index:
378+
379+
["source","java",subs="attributes,callouts,macros"]
380+
--------------------------------------------------
381+
include-tagged::{doc-tests}/SearchDocumentationIT.java[search-request-profiling-queries]
382+
--------------------------------------------------
383+
<1> Retrieve the list of `QueryProfileShardResult`
384+
<2> Iterate over each `QueryProfileShardResult`
385+
386+
Each `QueryProfileShardResult` gives access to the detailed query tree execution, returned as a list of
387+
`ProfileResult` objects:
388+
389+
["source","java",subs="attributes,callouts,macros"]
390+
--------------------------------------------------
391+
include-tagged::{doc-tests}/SearchDocumentationIT.java[search-request-profiling-queries-results]
392+
--------------------------------------------------
393+
<1> Iterate over the profile results
394+
<2> Retrieve the name of the Lucene query
395+
<3> Retrieve the time in millis spent executing the Lucene query
396+
<4> Retrieve the profile results for the sub-queries (if any)
397+
398+
The Rest API documentation contains more information about {ref}/_profiling_queries.html[Profiling Queries] with
399+
a description of the {ref}/_profiling_queries.html#_literal_query_literal_section[query profiling information]
400+
401+
The `QueryProfileShardResult` also gives access to the profiling information for the Lucene collectors:
402+
403+
["source","java",subs="attributes,callouts,macros"]
404+
--------------------------------------------------
405+
include-tagged::{doc-tests}/SearchDocumentationIT.java[search-request-profiling-queries-collectors]
406+
--------------------------------------------------
407+
<1> Retrieve the profiling result of the Lucene collector
408+
<2> Retrieve the name of the Lucene collector
409+
<3> Retrieve the time in millis spent executing the Lucene collector
410+
<4> Retrieve the profile results for the sub-collectors (if any)
411+
412+
The Rest API documentation contains more information about profiling information
413+
{ref}/_profiling_queries.html#_literal_collectors_literal_section[for Lucene collectors].
414+
415+
In a very similar manner to the query tree execution, the `QueryProfileShardResult` objects gives access
416+
to the detailed aggregations tree execution:
417+
418+
["source","java",subs="attributes,callouts,macros"]
419+
--------------------------------------------------
420+
include-tagged::{doc-tests}/SearchDocumentationIT.java[search-request-profiling-aggs]
421+
--------------------------------------------------
422+
<1> Retrieve the `AggregationProfileShardResult`
423+
<2> Iterate over the aggregation profile results
424+
<3> Retrieve the type of the aggregation (corresponds to Java class used to execute the aggregation)
425+
<4> Retrieve the time in millis spent executing the Lucene collector
426+
<5> Retrieve the profile results for the sub-aggregations (if any)
427+
428+
The Rest API documentation contains more information about {ref}/_profiling_aggregations.html[Profiling Aggregations]

0 commit comments

Comments
 (0)