@@ -155,7 +155,7 @@ public CompositeAggregationUsageTests(ReadOnlyCluster i, EndpointUsage usage) :
155
155
} ;
156
156
157
157
/**==== Handling Responses
158
- * Each Composite aggregation bucket key is an `CompositeKey`, a specialized
158
+ * Each Composite aggregation bucket key is a `CompositeKey` type , a specialized
159
159
* `IReadOnlyDictionary<string, object>` type with methods to convert values to supported types
160
160
*/
161
161
protected override void ExpectResponse ( ISearchResponse < Project > response )
@@ -196,6 +196,130 @@ protected override void ExpectResponse(ISearchResponse<Project> response)
196
196
}
197
197
}
198
198
199
+ /**[float]
200
+ * == Missing buckets
201
+ * By default documents without a value for a given source are ignored.
202
+ * It is possible to include them in the response by setting missing_bucket to `true` (defaults to `false`):
203
+ *
204
+ * NOTE: Only available in Elasticsearch 6.4.0+
205
+ */
206
+ [ SkipVersion ( "<6.4.0" , "Missing buckets added to Composite Aggregation Elasticsearch 6.4.0+" ) ]
207
+ public class CompositeAggregationMissingBucketUsageTests : ProjectsOnlyAggregationUsageTestBase
208
+ {
209
+ public CompositeAggregationMissingBucketUsageTests ( ReadOnlyCluster i , EndpointUsage usage ) : base ( i , usage ) { }
210
+
211
+ protected override object AggregationJson => new
212
+ {
213
+ my_buckets = new
214
+ {
215
+ composite = new
216
+ {
217
+ sources = new object [ ]
218
+ {
219
+ new
220
+ {
221
+ branches = new
222
+ {
223
+ terms = new
224
+ {
225
+ field = "branches.keyword" ,
226
+ order = "asc" ,
227
+ missing_bucket = true
228
+ }
229
+ }
230
+ } ,
231
+ }
232
+ } ,
233
+ aggs = new
234
+ {
235
+ project_tags = new
236
+ {
237
+ nested = new { path = "tags" } ,
238
+ aggs = new
239
+ {
240
+ tags = new { terms = new { field = "tags.name" } }
241
+ }
242
+ }
243
+ }
244
+ }
245
+ } ;
246
+
247
+ protected override Func < AggregationContainerDescriptor < Project > , IAggregationContainer > FluentAggs => a => a
248
+ . Composite ( "my_buckets" , date => date
249
+ . Sources ( s => s
250
+ . Terms ( "branches" , t => t
251
+ . Field ( f => f . Branches . Suffix ( "keyword" ) )
252
+ . MissingBucket ( )
253
+ . Order ( SortOrder . Ascending )
254
+ )
255
+ )
256
+ . Aggregations ( childAggs => childAggs
257
+ . Nested ( "project_tags" , n => n
258
+ . Path ( p => p . Tags )
259
+ . Aggregations ( nestedAggs => nestedAggs
260
+ . Terms ( "tags" , avg => avg . Field ( p => p . Tags . First ( ) . Name ) )
261
+ )
262
+ )
263
+ )
264
+ ) ;
265
+
266
+ protected override AggregationDictionary InitializerAggs =>
267
+ new CompositeAggregation ( "my_buckets" )
268
+ {
269
+ Sources = new List < ICompositeAggregationSource >
270
+ {
271
+ new TermsCompositeAggregationSource ( "branches" )
272
+ {
273
+ Field = Infer . Field < Project > ( f => f . Branches . Suffix ( "keyword" ) ) ,
274
+ MissingBucket = true ,
275
+ Order = SortOrder . Ascending
276
+ }
277
+ } ,
278
+ Aggregations = new NestedAggregation ( "project_tags" )
279
+ {
280
+ Path = Field < Project > ( p => p . Tags ) ,
281
+ Aggregations = new TermsAggregation ( "tags" )
282
+ {
283
+ Field = Field < Project > ( p => p . Tags . First ( ) . Name )
284
+ }
285
+ }
286
+ } ;
287
+
288
+ /**==== Handling Responses
289
+ * Each Composite aggregation bucket key is an `CompositeKey`, a specialized
290
+ * `IReadOnlyDictionary<string, object>` type with methods to convert values to supported types
291
+ */
292
+ protected override void ExpectResponse ( ISearchResponse < Project > response )
293
+ {
294
+ response . ShouldBeValid ( ) ;
295
+
296
+ var composite = response . Aggregations . Composite ( "my_buckets" ) ;
297
+ composite . Should ( ) . NotBeNull ( ) ;
298
+ composite . Buckets . Should ( ) . NotBeNullOrEmpty ( ) ;
299
+ composite . AfterKey . Should ( ) . NotBeNull ( ) ;
300
+
301
+ if ( TestConfiguration . Instance . InRange ( ">=6.3.0" ) )
302
+ composite . AfterKey . Should ( ) . HaveCount ( 1 ) . And . ContainKeys ( "branches" ) ;
303
+
304
+ var i = 0 ;
305
+ foreach ( var item in composite . Buckets )
306
+ {
307
+ var key = item . Key ;
308
+ key . Should ( ) . NotBeNull ( ) ;
309
+
310
+ key . TryGetValue ( "branches" , out string branches ) . Should ( ) . BeTrue ( "expected to find 'branches' in composite bucket" ) ;
311
+ if ( i == 0 ) branches . Should ( ) . BeNull ( "First key should be null as we expect to have some projects with no branches" ) ;
312
+ else branches . Should ( ) . NotBeNullOrEmpty ( ) ;
313
+
314
+ var nested = item . Nested ( "project_tags" ) ;
315
+ nested . Should ( ) . NotBeNull ( ) ;
316
+
317
+ var nestedTerms = nested . Terms ( "tags" ) ;
318
+ nestedTerms . Buckets . Count . Should ( ) . BeGreaterThan ( 0 ) ;
319
+ i ++ ;
320
+ }
321
+ }
322
+ }
199
323
200
324
//hide
201
325
[ SkipVersion ( "<6.3.0" , "Date histogram source only supports format starting from Elasticsearch 6.3.0+" ) ]
@@ -286,10 +410,6 @@ public DateFormatCompositeAggregationUsageTests(ReadOnlyCluster i, EndpointUsage
286
410
}
287
411
} ;
288
412
289
- /**==== Handling Responses
290
- * Each Composite aggregation bucket key is an `CompositeKey`, a specialized
291
- * `IReadOnlyDictionary<string, object>` type with methods to convert values to supported types
292
- */
293
413
protected override void ExpectResponse ( ISearchResponse < Project > response )
294
414
{
295
415
response . ShouldBeValid ( ) ;
0 commit comments