Skip to content

Commit

Permalink
Add support for bounds in geohash_grid aggregation (#4403)
Browse files Browse the repository at this point in the history
Relates: #4341, elastic/elasticsearch#50002

This commit adds support for supplying bounds on a geohash_grid
aggregation, similar to how bounds are supplied on
geo_bounding_box query.
  • Loading branch information
russcam authored and github-actions[bot] committed Feb 21, 2020
1 parent 54bfe83 commit 72f590a
Show file tree
Hide file tree
Showing 2 changed files with 110 additions and 3 deletions.
54 changes: 51 additions & 3 deletions src/Nest/Aggregations/Bucket/GeoHashGrid/GeoHashGridAggregation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,34 +5,74 @@

namespace Nest
{
/// <summary>
/// A multi-bucket aggregation that 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.
/// Each cell is labeled using a geohash which is of user-definable precision.
/// </summary>
[InterfaceDataContract]
[ReadAs(typeof(GeoHashGridAggregation))]
public interface IGeoHashGridAggregation : IBucketAggregation
{
/// <summary>
/// The name of the field indexed with geopoints.
/// </summary>
[DataMember(Name ="field")]
Field Field { get; set; }

/// <summary>
/// The string length of the geohashes used to define cells/buckets in the results.
/// Defaults to <see cref="GeoHashPrecision.Precision5"/>.
/// </summary>
[DataMember(Name ="precision")]
GeoHashPrecision? Precision { get; set; }

/// <summary>
/// To allow for more accurate counting of the top cells returned in the final result the aggregation defaults to returning
/// <c>max(10,(size x number-of-shards))</c> buckets from each shard. If this heuristic is undesirable,
/// the number considered from each shard can be over-ridden using this parameter.
/// </summary>
[DataMember(Name ="shard_size")]
int? ShardSize { get; set; }

/// <summary>
/// The maximum number of geohash buckets to return. Defaults to <c>10,000</c>. When results are trimmed,
/// buckets are prioritised based on the volumes of documents they contain.
/// </summary>
[DataMember(Name ="size")]
int? Size { get; set; }

/// <summary>
/// Restricts the points considered to those that fall within the bounds provided.
/// <para />
/// Available in Elasticsearch 7.6.0+.
/// </summary>
[DataMember(Name = "bounds")]
IBoundingBox Bounds { get; set; }
}

/// <inheritdoc cref="IGeoHashGridAggregation"/>
public class GeoHashGridAggregation : BucketAggregationBase, IGeoHashGridAggregation
{
internal GeoHashGridAggregation() { }

public GeoHashGridAggregation(string name) : base(name) { }

/// <inheritdoc cref="IGeoHashGridAggregation.Field"/>
public Field Field { get; set; }

/// <inheritdoc cref="IGeoHashGridAggregation.Precision"/>
public GeoHashPrecision? Precision { get; set; }

/// <inheritdoc cref="IGeoHashGridAggregation.ShardSize"/>
public int? ShardSize { get; set; }

/// <inheritdoc cref="IGeoHashGridAggregation.Size"/>
public int? Size { get; set; }

/// <inheritdoc cref="IGeoHashGridAggregation.Bounds"/>
public IBoundingBox Bounds { get; set; }

internal override void WrapInContainer(AggregationContainer c) => c.GeoHash = this;
}

Expand All @@ -42,22 +82,30 @@ public class GeoHashGridAggregationDescriptor<T>
where T : class
{
Field IGeoHashGridAggregation.Field { get; set; }

GeoHashPrecision? IGeoHashGridAggregation.Precision { get; set; }

int? IGeoHashGridAggregation.ShardSize { get; set; }

int? IGeoHashGridAggregation.Size { get; set; }
IBoundingBox IGeoHashGridAggregation.Bounds { get; set; }

/// <inheritdoc cref="IGeoHashGridAggregation.Field"/>
public GeoHashGridAggregationDescriptor<T> Field(Field field) => Assign(field, (a, v) => a.Field = v);

/// <inheritdoc cref="IGeoHashGridAggregation.Field"/>
public GeoHashGridAggregationDescriptor<T> Field<TValue>(Expression<Func<T, TValue>> field) => Assign(field, (a, v) => a.Field = v);

/// <inheritdoc cref="IGeoHashGridAggregation.Size"/>
public GeoHashGridAggregationDescriptor<T> Size(int? size) => Assign(size, (a, v) => a.Size = v);

/// <inheritdoc cref="IGeoHashGridAggregation.ShardSize"/>
public GeoHashGridAggregationDescriptor<T> ShardSize(int? shardSize) => Assign(shardSize, (a, v) => a.ShardSize = v);

/// <inheritdoc cref="IGeoHashGridAggregation.Precision"/>
// TODO: Rename to precision in next major.
public GeoHashGridAggregationDescriptor<T> GeoHashPrecision(GeoHashPrecision? precision) =>
Assign(precision, (a, v) => a.Precision = v);

/// <inheritdoc cref="IGeoHashGridAggregation.Bounds"/>
public GeoHashGridAggregationDescriptor<T> Bounds(Func<BoundingBoxDescriptor, IBoundingBox> selector) =>
Assign(selector, (a, v) => a.Bounds = v?.Invoke(new BoundingBoxDescriptor()));
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using Elastic.Xunit.XunitPlumbing;
using FluentAssertions;
using Nest;
using Tests.Core.Extensions;
Expand Down Expand Up @@ -51,4 +52,62 @@ protected override void ExpectResponse(ISearchResponse<Project> response)
myGeoHashGrid.Should().NotBeNull();
}
}

[SkipVersion("<7.6.0", "bounds introduced in 7.6.0")]
// hide
public class GeoHashGridAggregationWithBoundsUsageTests : AggregationUsageTestBase
{
public GeoHashGridAggregationWithBoundsUsageTests(ReadOnlyCluster i, EndpointUsage usage) : base(i, usage) { }

protected override object AggregationJson => new
{
my_geohash_grid = new
{
geohash_grid = new
{
field = "locationPoint",
bounds = new
{
top_left = new
{
lat = 90.0,
lon = -180.0
},
bottom_right = new
{
lat = -90.0,
lon = 180.0
}
}
}
}
};

protected override Func<AggregationContainerDescriptor<Project>, IAggregationContainer> FluentAggs => a => a
.GeoHash("my_geohash_grid", g => g
.Field(p => p.LocationPoint)
.Bounds(b => b
.TopLeft(90,-180)
.BottomRight(-90, 180)
)
);

protected override AggregationDictionary InitializerAggs =>
new GeoHashGridAggregation("my_geohash_grid")
{
Field = Field<Project>(p => p.LocationPoint),
Bounds = new BoundingBox
{
TopLeft = new GeoLocation(90, -180),
BottomRight = new GeoLocation(-90, 180)
}
};

protected override void ExpectResponse(ISearchResponse<Project> response)
{
response.ShouldBeValid();
var myGeoHashGrid = response.Aggregations.GeoHash("my_geohash_grid");
myGeoHashGrid.Should().NotBeNull();
}
}
}

0 comments on commit 72f590a

Please sign in to comment.