diff --git a/src/Nest/Nest.csproj b/src/Nest/Nest.csproj
index 63ffa7c9b67..d67ce8f7459 100644
--- a/src/Nest/Nest.csproj
+++ b/src/Nest/Nest.csproj
@@ -1275,6 +1275,8 @@
+
+
diff --git a/src/Nest/Search/Search/Profile/AggregationBreakdown.cs b/src/Nest/Search/Search/Profile/AggregationBreakdown.cs
new file mode 100644
index 00000000000..e8512cc8cbd
--- /dev/null
+++ b/src/Nest/Search/Search/Profile/AggregationBreakdown.cs
@@ -0,0 +1,32 @@
+using System.Collections.Generic;
+using Newtonsoft.Json;
+
+namespace Nest
+{
+ public class AggregationBreakdown
+ {
+ [JsonProperty("reduce")]
+ public long Reduce { get; internal set; }
+
+ [JsonProperty("build_aggregation")]
+ public long BuildAggregation { get; internal set; }
+
+ [JsonProperty("build_aggregation_count")]
+ public long BuildAggregationCount { get; internal set; }
+
+ [JsonProperty("initialize")]
+ public long Initialize { get; internal set; }
+
+ [JsonProperty("intialize_count")]
+ public long InitializeCount { get; internal set; }
+
+ [JsonProperty("reduce_count")]
+ public long ReduceCount { get; internal set; }
+
+ [JsonProperty("collect")]
+ public long Collect { get; internal set; }
+
+ [JsonProperty("collect_count")]
+ public long CollectCount { get; internal set; }
+ }
+}
diff --git a/src/Nest/Search/Search/Profile/AggregationProfile.cs b/src/Nest/Search/Search/Profile/AggregationProfile.cs
new file mode 100644
index 00000000000..ce5094e043a
--- /dev/null
+++ b/src/Nest/Search/Search/Profile/AggregationProfile.cs
@@ -0,0 +1,38 @@
+using System.Collections.Generic;
+using Newtonsoft.Json;
+
+namespace Nest
+{
+ public class AggregationProfile
+ {
+ ///
+ /// The Elasticsearch aggregation type
+ ///
+ [JsonProperty("type")]
+ public string Type { get; internal set; }
+
+ ///
+ /// The user defined name of the aggregation
+ ///
+ [JsonProperty("description")]
+ public string Description { get; internal set; }
+
+ ///
+ /// The time this aggregation took
+ ///
+ [JsonProperty("time")]
+ public Time Time { get; internal set; }
+
+ ///
+ /// The time this aggregation took, in nanoseconds
+ ///
+ [JsonProperty("time_in_nanos")]
+ public long TimeInNanoseconds { get; internal set; }
+
+ ///
+ /// Detailed stats about how the time was spent
+ ///
+ [JsonProperty("breakdown")]
+ public AggregationBreakdown Breakdown { get; internal set; }
+ }
+}
diff --git a/src/Nest/Search/Search/Profile/Collector.cs b/src/Nest/Search/Search/Profile/Collector.cs
index 9889e3a65ee..daecc987250 100644
--- a/src/Nest/Search/Search/Profile/Collector.cs
+++ b/src/Nest/Search/Search/Profile/Collector.cs
@@ -14,7 +14,10 @@ public class Collector
[JsonProperty("time")]
public Time Time { get; internal set; }
- [JsonProperty("children")]
+ [JsonProperty("time_in_nanos")]
+ public long TimeInNanoseconds { get; internal set; }
+
+ [JsonProperty("children")]
public IReadOnlyCollection Children { get; internal set; } =
EmptyReadOnly.Collection;
diff --git a/src/Nest/Search/Search/Profile/QueryProfile.cs b/src/Nest/Search/Search/Profile/QueryProfile.cs
index f0ecf5b7dd1..226fb0d038d 100644
--- a/src/Nest/Search/Search/Profile/QueryProfile.cs
+++ b/src/Nest/Search/Search/Profile/QueryProfile.cs
@@ -23,6 +23,12 @@ public class QueryProfile
[JsonProperty("time")]
public Time Time { get; internal set; }
+ ///
+ /// The time that this query took in nanoseconds
+ ///
+ [JsonProperty("time_in_nanos")]
+ public long TimeInNanoseconds { get; internal set; }
+
///
/// Detailed stats about how the time was spent
///
diff --git a/src/Nest/Search/Search/Profile/ShardProfile.cs b/src/Nest/Search/Search/Profile/ShardProfile.cs
index 5f1d366faaf..5771ca7410d 100644
--- a/src/Nest/Search/Search/Profile/ShardProfile.cs
+++ b/src/Nest/Search/Search/Profile/ShardProfile.cs
@@ -12,5 +12,8 @@ public class ShardProfile
public IReadOnlyCollection Searches { get; internal set; } =
EmptyReadOnly.Collection;
+ [JsonProperty("aggregations")]
+ public IReadOnlyCollection Aggregations { get; internal set; } =
+ EmptyReadOnly.Collection;
}
}
diff --git a/src/Tests/Search/Search/SearchProfileApiTests.cs b/src/Tests/Search/Search/SearchProfileApiTests.cs
new file mode 100644
index 00000000000..ecad822e7a5
--- /dev/null
+++ b/src/Tests/Search/Search/SearchProfileApiTests.cs
@@ -0,0 +1,140 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Elasticsearch.Net;
+using FluentAssertions;
+using Nest;
+using Tests.Framework;
+using Tests.Framework.Integration;
+using Tests.Framework.MockData;
+
+namespace Tests.Search.Search
+{
+ public class SearchProfileApiTests : ApiIntegrationTestBase, ISearchRequest,
+ SearchDescriptor, SearchRequest>
+ {
+ public SearchProfileApiTests(ReadOnlyCluster cluster, EndpointUsage usage) : base(cluster, usage)
+ {
+ }
+
+ protected override LazyResponses ClientUsage() => Calls(
+ fluent: (c, f) => c.Search(f),
+ fluentAsync: (c, f) => c.SearchAsync(f),
+ request: (c, r) => c.Search(r),
+ requestAsync: (c, r) => c.SearchAsync(r)
+ );
+
+ protected override int ExpectStatusCode => 200;
+ protected override bool ExpectIsValid => true;
+ protected override HttpMethod HttpMethod => HttpMethod.POST;
+ protected override string UrlPath => $"/project/project/_search";
+
+ protected override object ExpectJson => new
+ {
+ profile = true,
+ query = new
+ {
+ match_all = new { }
+ },
+ aggs = new
+ {
+ startDates = new
+ {
+ terms = new
+ {
+ field = "startedOn"
+ }
+ }
+ }
+ };
+
+ protected override void ExpectResponse(ISearchResponse response)
+ {
+ response.Hits.Count().Should().BeGreaterThan(0);
+ var profile = response.Profile;
+ profile.Should().NotBeNull();
+ var shardProfiles = profile.Shards;
+ shardProfiles.Should().NotBeNullOrEmpty();
+ foreach (var shardProfile in shardProfiles)
+ {
+ shardProfile.Id.Should().NotBeNullOrEmpty();
+ var searches = shardProfile.Searches;
+ searches.Should().NotBeNullOrEmpty();
+ foreach (var search in searches)
+ {
+ var queries = search.Query;
+ queries.Should().NotBeNullOrEmpty();
+ foreach (var query in queries)
+ {
+ query.Should().NotBeNull();
+ query.Type.Should().NotBeNullOrEmpty();
+ query.Description.Should().NotBeNullOrEmpty();
+ query.Time.Should().NotBeNull();
+ query.TimeInNanoseconds.Should().BeGreaterThan(0);
+ query.Breakdown.Should().NotBeNull();
+ }
+ search.RewriteTime.Should().BeGreaterThan(0);
+ var collectors = search.Collector;
+ foreach (var collector in collectors)
+ {
+ collector.Name.Should().NotBeNullOrEmpty();
+ collector.Reason.Should().NotBeNullOrEmpty();
+ collector.Time.Should().NotBeNull();
+ collector.TimeInNanoseconds.Should().BeGreaterThan(0);
+ var children = collector.Children;
+ children.Should().NotBeNull();
+ foreach (var child in children)
+ {
+ child.Should().NotBeNull();
+ child.Name.Should().NotBeNullOrEmpty();
+ child.Reason.Should().NotBeNullOrEmpty();
+ child.Time.Should().NotBeNull();
+ child.TimeInNanoseconds.Should().BeGreaterThan(0);
+ var grandchildren = child.Children;
+ grandchildren.Should().NotBeNull();
+ foreach (var grandchild in grandchildren)
+ {
+ grandchild.Name.Should().NotBeNullOrEmpty();
+ grandchild.Reason.Should().NotBeNullOrEmpty();
+ grandchild.Time.Should().NotBeNull();
+ grandchild.TimeInNanoseconds.Should().BeGreaterThan(0);
+ }
+ }
+ }
+ }
+ var aggregations = shardProfile.Aggregations;
+ aggregations.Should().NotBeNull();
+ foreach (var aggregation in aggregations)
+ {
+ aggregation.Should().NotBeNull();
+ aggregation.Type.Should().NotBeNullOrEmpty();
+ aggregation.Description.Should().NotBeNullOrEmpty();
+ aggregation.Time.Should().NotBeNull();
+ aggregation.TimeInNanoseconds.Should().BeGreaterThan(0);
+ aggregation.Breakdown.Should().NotBeNull();
+ }
+ }
+ }
+
+ protected override Func, ISearchRequest> Fluent => s => s
+ .Profile()
+ .Query(q => q
+ .MatchAll()
+ )
+ .Aggregations(aggs => aggs
+ .Terms("startDates", t => t
+ .Field(p => p.StartedOn)
+ )
+ );
+
+ protected override SearchRequest Initializer => new SearchRequest()
+ {
+ Profile = true,
+ Query = new QueryContainer(new MatchAllQuery()),
+ Aggregations = new TermsAggregation("startDates")
+ {
+ Field = "startedOn"
+ }
+ };
+ }
+}
diff --git a/src/Tests/Tests.csproj b/src/Tests/Tests.csproj
index 7097763b35e..6e7f3510a61 100644
--- a/src/Tests/Tests.csproj
+++ b/src/Tests/Tests.csproj
@@ -722,6 +722,7 @@
+
diff --git a/src/Tests/tests.yaml b/src/Tests/tests.yaml
index a0fe32db5de..13a6a91c3bd 100644
--- a/src/Tests/tests.yaml
+++ b/src/Tests/tests.yaml
@@ -2,7 +2,7 @@
mode: m
# the elasticsearch version that should be started
# Can be a snapshot version of sonatype or "latest" to get the latest snapshot of sonatype
-elasticsearch_version: latest
+elasticsearch_version: 5.3.0-SNAPSHOT
# cluster filter allows you to only run the integration tests of a particular cluster (cluster suffix not needed)
# cluster_filter:
# whether we want to forcefully reseed on the node, if you are starting the tests with a node already running