Skip to content

[Backport 8.0] Fixes and tests relating to aggregations #6742

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 13, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@

namespace Elastic.Clients.Elasticsearch.Aggregations;

public interface IAggregation
// This is marked as internal for now, until we are ready to support plugin aggregations.
internal interface IAggregation
{
string? Name { get; }
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@

namespace Elastic.Clients.Elasticsearch
{

internal static class AggregationContainerSerializationHelper
{
public static AggregationContainer ReadContainer<T>(ref Utf8JsonReader reader, JsonSerializerOptions options) where T : Aggregation
Expand All @@ -21,13 +20,12 @@ public static AggregationContainer ReadContainer<T>(ref Utf8JsonReader reader, J

public static AggregationContainer ReadContainer<T>(string variantName, ref Utf8JsonReader reader, JsonSerializerOptions options) where T : Aggregation
{
var variant = JsonSerializer.Deserialize<T?>(ref reader, options);

//variant.Name = variantName;
var variant = JsonSerializer.Deserialize<T>(ref reader, options);

var container = new AggregationContainer(variant);

//reader.Read();
if (container.Variant is Aggregation agg)
agg.Name = variantName;

return container;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@ public override void Write(Utf8JsonWriter writer, TType value, JsonSerializerOpt
}
}


internal interface IUnionVerifiable
{
bool IsSuccessful { get; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,34 +30,7 @@ public partial class AggregationContainer
JsonSerializer.Serialize(writer, descriptor, options);
};

public static implicit operator AggregationContainer(Aggregation aggregator)
{
if (aggregator == null)
return null;

// TODO: Reimplement this fully - as neccesary!

var container = new AggregationContainer(aggregator)
{
//Meta = aggregator.Meta
};

//aggregator.WrapInContainer(container);

//var bucket = aggregator as BucketAggregationBase;

//container.Aggregations = bucket?.Aggregations;

var combinator = aggregator as AggregationCombinator;
if (combinator?.Aggregations != null)
{
var dict = new AggregationDictionary();
// foreach (var agg in combinator.Aggregations)
// dict.Add(((IAggregation)agg).Name, agg);
// container.Aggregations = dict;
}

return container;
}
public static implicit operator AggregationContainer(Aggregation aggregator) =>
aggregator == null ? null : new AggregationContainer(aggregator);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ namespace Elastic.Clients.Elasticsearch.Aggregations
[JsonConverter(typeof(AggregationContainerConverter))]
public sealed partial class AggregationContainer
{
public AggregationContainer(IAggregation variant) => Variant = variant ?? throw new ArgumentNullException(nameof(variant));
internal AggregationContainer(IAggregation variant) => Variant = variant ?? throw new ArgumentNullException(nameof(variant));
internal IAggregation Variant { get; }
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ namespace Elastic.Clients.Elasticsearch.IndexManagement
{
public sealed partial class MappingLimitSettings
{
[JsonInclude]
[JsonPropertyName("coerce")]
public bool? Coerce { get; set; }

[JsonInclude]
[JsonPropertyName("depth")]
public Elastic.Clients.Elasticsearch.IndexManagement.MappingLimitSettingsDepth? Depth { get; set; }
Expand Down Expand Up @@ -62,6 +66,8 @@ public MappingLimitSettingsDescriptor() : base()
{
}

private bool? CoerceValue { get; set; }

private Elastic.Clients.Elasticsearch.IndexManagement.MappingLimitSettingsDepth? DepthValue { get; set; }

private MappingLimitSettingsDepthDescriptor DepthDescriptor { get; set; }
Expand Down Expand Up @@ -100,6 +106,12 @@ public MappingLimitSettingsDescriptor() : base()

private Action<MappingLimitSettingsTotalFieldsDescriptor> TotalFieldsDescriptorAction { get; set; }

public MappingLimitSettingsDescriptor Coerce(bool? coerce = true)
{
CoerceValue = coerce;
return Self;
}

public MappingLimitSettingsDescriptor Depth(Elastic.Clients.Elasticsearch.IndexManagement.MappingLimitSettingsDepth? depth)
{
DepthDescriptor = null;
Expand Down Expand Up @@ -253,6 +265,12 @@ public MappingLimitSettingsDescriptor TotalFields(Action<MappingLimitSettingsTot
protected override void Serialize(Utf8JsonWriter writer, JsonSerializerOptions options, IElasticsearchClientSettings settings)
{
writer.WriteStartObject();
if (CoerceValue.HasValue)
{
writer.WritePropertyName("coerce");
writer.WriteBooleanValue(CoerceValue.Value);
}

if (DepthDescriptor is not null)
{
writer.WritePropertyName("depth");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,9 @@ public sealed partial class RolloverConditions
[JsonPropertyName("max_primary_shard_size")]
public Elastic.Clients.Elasticsearch.ByteSize? MaxPrimaryShardSize { get; set; }

[JsonInclude]
[JsonPropertyName("max_primary_shard_size_bytes")]
public Elastic.Clients.Elasticsearch.ByteSize? MaxPrimaryShardSizeBytes { get; set; }

[JsonInclude]
[JsonPropertyName("max_size")]
public string? MaxSize { get; set; }
public Elastic.Clients.Elasticsearch.ByteSize? MaxSize { get; set; }

[JsonInclude]
[JsonPropertyName("max_size_bytes")]
Expand All @@ -69,6 +65,14 @@ public sealed partial class RolloverConditions
[JsonInclude]
[JsonPropertyName("min_primary_shard_docs")]
public long? MinPrimaryShardDocs { get; set; }

[JsonInclude]
[JsonPropertyName("min_primary_shard_size")]
public Elastic.Clients.Elasticsearch.ByteSize? MinPrimaryShardSize { get; set; }

[JsonInclude]
[JsonPropertyName("min_size")]
public Elastic.Clients.Elasticsearch.ByteSize? MinSize { get; set; }
}

public sealed partial class RolloverConditionsDescriptor : SerializableDescriptorBase<RolloverConditionsDescriptor>
Expand All @@ -88,9 +92,7 @@ public RolloverConditionsDescriptor() : base()

private Elastic.Clients.Elasticsearch.ByteSize? MaxPrimaryShardSizeValue { get; set; }

private Elastic.Clients.Elasticsearch.ByteSize? MaxPrimaryShardSizeBytesValue { get; set; }

private string? MaxSizeValue { get; set; }
private Elastic.Clients.Elasticsearch.ByteSize? MaxSizeValue { get; set; }

private Elastic.Clients.Elasticsearch.ByteSize? MaxSizeBytesValue { get; set; }

Expand All @@ -100,6 +102,10 @@ public RolloverConditionsDescriptor() : base()

private long? MinPrimaryShardDocsValue { get; set; }

private Elastic.Clients.Elasticsearch.ByteSize? MinPrimaryShardSizeValue { get; set; }

private Elastic.Clients.Elasticsearch.ByteSize? MinSizeValue { get; set; }

public RolloverConditionsDescriptor MaxAge(Elastic.Clients.Elasticsearch.Duration? maxAge)
{
MaxAgeValue = maxAge;
Expand Down Expand Up @@ -130,13 +136,7 @@ public RolloverConditionsDescriptor MaxPrimaryShardSize(Elastic.Clients.Elastics
return Self;
}

public RolloverConditionsDescriptor MaxPrimaryShardSizeBytes(Elastic.Clients.Elasticsearch.ByteSize? maxPrimaryShardSizeBytes)
{
MaxPrimaryShardSizeBytesValue = maxPrimaryShardSizeBytes;
return Self;
}

public RolloverConditionsDescriptor MaxSize(string? maxSize)
public RolloverConditionsDescriptor MaxSize(Elastic.Clients.Elasticsearch.ByteSize? maxSize)
{
MaxSizeValue = maxSize;
return Self;
Expand Down Expand Up @@ -166,6 +166,18 @@ public RolloverConditionsDescriptor MinPrimaryShardDocs(long? minPrimaryShardDoc
return Self;
}

public RolloverConditionsDescriptor MinPrimaryShardSize(Elastic.Clients.Elasticsearch.ByteSize? minPrimaryShardSize)
{
MinPrimaryShardSizeValue = minPrimaryShardSize;
return Self;
}

public RolloverConditionsDescriptor MinSize(Elastic.Clients.Elasticsearch.ByteSize? minSize)
{
MinSizeValue = minSize;
return Self;
}

protected override void Serialize(Utf8JsonWriter writer, JsonSerializerOptions options, IElasticsearchClientSettings settings)
{
writer.WriteStartObject();
Expand Down Expand Up @@ -199,16 +211,10 @@ protected override void Serialize(Utf8JsonWriter writer, JsonSerializerOptions o
JsonSerializer.Serialize(writer, MaxPrimaryShardSizeValue, options);
}

if (MaxPrimaryShardSizeBytesValue is not null)
{
writer.WritePropertyName("max_primary_shard_size_bytes");
JsonSerializer.Serialize(writer, MaxPrimaryShardSizeBytesValue, options);
}

if (!string.IsNullOrEmpty(MaxSizeValue))
if (MaxSizeValue is not null)
{
writer.WritePropertyName("max_size");
writer.WriteStringValue(MaxSizeValue);
JsonSerializer.Serialize(writer, MaxSizeValue, options);
}

if (MaxSizeBytesValue is not null)
Expand All @@ -235,6 +241,18 @@ protected override void Serialize(Utf8JsonWriter writer, JsonSerializerOptions o
writer.WriteNumberValue(MinPrimaryShardDocsValue.Value);
}

if (MinPrimaryShardSizeValue is not null)
{
writer.WritePropertyName("min_primary_shard_size");
JsonSerializer.Serialize(writer, MinPrimaryShardSizeValue, options);
}

if (MinSizeValue is not null)
{
writer.WritePropertyName("min_size");
JsonSerializer.Serialize(writer, MinSizeValue, options);
}

writer.WriteEndObject();
}
}
Expand Down
3 changes: 3 additions & 0 deletions src/Playground/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,15 @@
// See the LICENSE file in the project root for more information.

using Elastic.Clients.Elasticsearch;
using Elastic.Clients.Elasticsearch.Aggregations;
using Elastic.Clients.Elasticsearch.IndexManagement;
using Elastic.Transport;
using Playground;

// const string IndexName = "stock-demo-v1";

AggregationContainer a = new TermsAggregation("test");

var settings = new ElasticsearchClientSettings(new InMemoryConnection())
.DefaultIndex("default-index")
.DefaultMappingFor<Person>(m => m
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@

using System.Linq;
using Elastic.Clients.Elasticsearch.Experimental;
using VerifyXunit;

namespace Tests.Serialization;

[UsesVerify]
public class ChildrenAggregateSerializationTests : SerializerTestBase
{
[U]
Expand Down
77 changes: 77 additions & 0 deletions tests/Tests/Serialization/Aggregations/WritingAggregationsTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
// Licensed to Elasticsearch B.V under one or more agreements.
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
// See the LICENSE file in the project root for more information.

using System.Threading.Tasks;
using Elastic.Clients.Elasticsearch.Aggregations;
using Tests.Domain;
using VerifyXunit;

namespace Tests.Serialization;

[UsesVerify]
public class WritingAggregationsTests : SerializerTestBase
{
[U]
public async Task CanSerializeAggregationsWrittenInVariousWays_WhichIncludeMultipleSubAggregations()
{
// TODO - Test other cases from https://www.elastic.co/guide/en/elasticsearch/client/net-api/7.17/writing-aggregations.html#writing-aggregations

// ** First test that the descriptor produces the expected JSON.

var descriptor = new AggregationContainerDescriptor(aggs => aggs
.Children<CommitActivity>("name_of_child_agg", child => child
.Type("commits")
.Aggregations(childAggs => childAggs
.Avg("average_per_child", avg => avg.Field(p => p.ConfidenceFactor))
.Max("max_per_child", max => max.Field(p => p.ConfidenceFactor))
.Min("min_per_child", min => min.Field(p => p.ConfidenceFactor))
)));

var json = await SerializeAndGetJsonStringAsync(descriptor);

await Verifier.VerifyJson(json);

// ** Then test that the object initializer dictionary approach produces the expected (and same) JSON.

var aggs = new AggregationDictionary
{
{
"name_of_child_agg", new ChildrenAggregation("name_of_child_agg")
{
Type = "commits",
Aggregations = new AggregationDictionary
{
{"average_per_child", new AverageAggregation("average_per_child", "confidenceFactor")},
{"max_per_child", new MaxAggregation("max_per_child", "confidenceFactor")},
{"min_per_child", new MinAggregation("min_per_child", "confidenceFactor")},
}
}
}
};

var objectInitializerJson = await SerializeAndGetJsonStringAsync(aggs);

json.Should().Be(objectInitializerJson);

// ** Next test the terser object initializer syntax produces the expected (and same) JSON.

AggregationDictionary terseAggs = new ChildrenAggregation("name_of_child_agg") // NOTE: Must assign to AggregationDictionary.
{
Type = "commits",
Aggregations =
new AverageAggregation("average_per_child", Infer.Field<CommitActivity>(p => p.ConfidenceFactor))
&& new MaxAggregation("max_per_child", Infer.Field<CommitActivity>(p => p.ConfidenceFactor))
&& new MinAggregation("min_per_child", Infer.Field<CommitActivity>(p => p.ConfidenceFactor))
};

var terseAggsJson = await SerializeAndGetJsonStringAsync(terseAggs);

json.Should().Be(terseAggsJson);

// ** Test we can deserialise the JSON as an AggregationDictionary

// TODO
// var result = DeserializeJsonString<AggregationDictionary>(json);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
name_of_child_agg: {
aggregations: {
average_per_child: {
avg: {
field: confidenceFactor
}
},
max_per_child: {
max: {
field: confidenceFactor
}
},
min_per_child: {
min: {
field: confidenceFactor
}
}
},
children: {
type: commits
}
}
}