diff --git a/src/Nest/XPack/Transform/Pivot/GeoTileGridGroupSource.cs b/src/Nest/XPack/Transform/Pivot/GeoTileGridGroupSource.cs
new file mode 100644
index 00000000000..f3b262ef2d0
--- /dev/null
+++ b/src/Nest/XPack/Transform/Pivot/GeoTileGridGroupSource.cs
@@ -0,0 +1,59 @@
+using System;
+using System.Runtime.Serialization;
+using Elasticsearch.Net.Utf8Json;
+
+namespace Nest
+{
+ ///
+ /// The geotile grid value source works on geo_point fields and groups points into buckets that represent
+ /// cells in a grid. The resulting grid can be sparse and only contains cells that have matching data.
+ ///
+ /// Available in Elasticsearch 7.9.0+
+ ///
+ [InterfaceDataContract]
+ public interface IGeoTileGridGroupSource : ISingleGroupSource
+ {
+ ///
+ /// The highest-precision geotile of length 29 produces cells that cover less than 10cm by 10cm of land.
+ /// This precision is uniquely suited for composite aggregations as each tile does not have to be
+ /// generated and loaded in memory.
+ ///
+ [DataMember(Name = "precision")]
+ GeoTilePrecision? Precision { get; set; }
+
+ ///
+ /// Constrained to a specific geo bounding box, which reduces the range of tiles used.
+ /// These bounds are useful when only a specific part of a geographical area needs high precision tiling.
+ ///
+ /// Available in Elasticsearch 7.6.0+.
+ ///
+ [DataMember(Name = "bounds")]
+ IBoundingBox Bounds { get; set; }
+ }
+
+ ///
+ public class GeoTileGridGroupSource : SingleGroupSourceBase, IGeoTileGridGroupSource
+ {
+ ///
+ public GeoTilePrecision? Precision { get; set; }
+ ///
+ public IBoundingBox Bounds { get; set; }
+ }
+
+ ///
+ public class GeoTileGridGroupSourceDescriptor
+ : SingleGroupSourceDescriptorBase, IGeoTileGridGroupSource, T>,
+ IGeoTileGridGroupSource
+ {
+ GeoTilePrecision? IGeoTileGridGroupSource.Precision { get; set; }
+ IBoundingBox IGeoTileGridGroupSource.Bounds { get; set; }
+
+ ///
+ public GeoTileGridGroupSourceDescriptor Precision(GeoTilePrecision? precision) =>
+ Assign(precision, (a, v) => a.Precision = v);
+
+ ///
+ public GeoTileGridGroupSourceDescriptor Bounds(Func selector) =>
+ Assign(selector, (a, v) => a.Bounds = v?.Invoke(new BoundingBoxDescriptor()));
+ }
+}
diff --git a/src/Nest/XPack/Transform/Pivot/SingleGroupSource.cs b/src/Nest/XPack/Transform/Pivot/SingleGroupSource.cs
index b9973b48862..25f0a6b53a8 100644
--- a/src/Nest/XPack/Transform/Pivot/SingleGroupSource.cs
+++ b/src/Nest/XPack/Transform/Pivot/SingleGroupSource.cs
@@ -86,6 +86,12 @@ public SingleGroupSourcesDescriptor DateHistogram(string name,
Func, IDateHistogramGroupSource> selector
) =>
Assign(new Tuple(name, selector?.Invoke(new DateHistogramGroupSourceDescriptor())), (a, v) => a.Add(v.Item1, v.Item2));
+
+ ///
+ public SingleGroupSourcesDescriptor GeoTileGrid(string name,
+ Func, IGeoTileGridGroupSource> selector
+ ) =>
+ Assign(new Tuple(name, selector?.Invoke(new GeoTileGridGroupSourceDescriptor())), (a, v) => a.Add(v.Item1, v.Item2));
}
internal class SingleGroupSourceFormatter : IJsonFormatter
@@ -95,6 +101,7 @@ internal class SingleGroupSourceFormatter : IJsonFormatter
{ "terms", 0 },
{ "date_histogram", 1 },
{ "histogram", 2 },
+ { "geotile_grid", 3 },
};
public void Serialize(ref JsonWriter writer, ISingleGroupSource value, IJsonFormatterResolver formatterResolver)
@@ -121,6 +128,10 @@ public void Serialize(ref JsonWriter writer, ISingleGroupSource value, IJsonForm
writer.WritePropertyName("histogram");
Serialize(ref writer, histogramGroupSource, formatterResolver);
break;
+ case IGeoTileGridGroupSource geoTileGridGroupSource:
+ writer.WritePropertyName("geotile_grid");
+ Serialize(ref writer, geoTileGridGroupSource, formatterResolver);
+ break;
default:
throw new JsonParsingException($"Unknown {nameof(ISingleGroupSource)}: {value.GetType().Name}");
}
@@ -164,6 +175,10 @@ public ISingleGroupSource Deserialize(ref JsonReader reader, IJsonFormatterResol
groupSource = formatterResolver.GetFormatter()
.Deserialize(ref reader, formatterResolver);
break;
+ case 3:
+ groupSource = formatterResolver.GetFormatter()
+ .Deserialize(ref reader, formatterResolver);
+ break;
}
}
else
diff --git a/tests/Tests/XPack/Transform/TransformApiTests.cs b/tests/Tests/XPack/Transform/TransformApiTests.cs
index 10f9b13704e..7f1ccd5fe05 100644
--- a/tests/Tests/XPack/Transform/TransformApiTests.cs
+++ b/tests/Tests/XPack/Transform/TransformApiTests.cs
@@ -13,7 +13,7 @@
namespace Tests.XPack.Transform
{
- [SkipVersion("<7.7.0", "Introduced in 7.7.0")]
+ [SkipVersion("<7.9.0", "Geotile grid group by introduced in 7.9.0")]
public class TransformApiTests : CoordinatedIntegrationTestBase
{
private const string PutTransformStep = nameof(PutTransformStep);
@@ -61,6 +61,18 @@ public TransformApiTests(WritableCluster cluster, EndpointUsage usage) : base(ne
Field = Field(f => f.StartedOn),
CalendarInterval = DateInterval.Week
}
+ },
+ {
+ "geotile", new GeoTileGridGroupSource
+ {
+ Field = Field(f => f.LocationPoint),
+ Precision = GeoTilePrecision.Precision6,
+ Bounds = new BoundingBox
+ {
+ TopLeft = new GeoLocation(-90, 180),
+ BottomRight = new GeoLocation(90, -180)
+ }
+ }
}
}
}
@@ -92,6 +104,14 @@ public TransformApiTests(WritableCluster cluster, EndpointUsage usage) : base(ne
.Field(f => f.StartedOn)
.CalendarInterval(DateInterval.Week)
)
+ .GeoTileGrid("geotile", gtg => gtg
+ .Field(f => f.LocationPoint)
+ .Precision(GeoTilePrecision.Precision6)
+ .Bounds(b => b
+ .TopLeft(-90, 180)
+ .BottomRight(90, -180)
+ )
+ )
)
),
(v, c, f) => c.Transform.Put(v, f),