Skip to content

Commit 03b3a1a

Browse files
authored
[Transform] Handle missing geotile buckets (elastic#137476) (elastic#137697)
When the user configures missing buckets to be included in the geotile_grid, Transforms should create the null bucket for the missing bucket. This matches what a composite aggregation would return. Fix elastic#126591
1 parent 49e091e commit 03b3a1a

File tree

3 files changed

+116
-0
lines changed

3 files changed

+116
-0
lines changed

docs/changelog/137476.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
pr: 137476
2+
summary: Handle missing geotile buckets
3+
area: Transform
4+
type: bug
5+
issues:
6+
- 126591

x-pack/plugin/transform/qa/single-node-tests/src/javaRestTest/java/org/elasticsearch/xpack/transform/integration/TransformPivotRestIT.java

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import org.apache.http.HttpHost;
1111
import org.apache.http.entity.ContentType;
1212
import org.apache.http.entity.StringEntity;
13+
import org.apache.http.util.EntityUtils;
1314
import org.elasticsearch.client.Request;
1415
import org.elasticsearch.client.RequestOptions;
1516
import org.elasticsearch.client.Response;
@@ -19,6 +20,7 @@
1920
import org.elasticsearch.client.WarningsHandler;
2021
import org.elasticsearch.common.Strings;
2122
import org.elasticsearch.common.settings.Settings;
23+
import org.elasticsearch.common.xcontent.XContentHelper;
2224
import org.elasticsearch.common.xcontent.support.XContentMapValues;
2325
import org.elasticsearch.xcontent.XContentBuilder;
2426
import org.junit.Before;
@@ -1886,6 +1888,110 @@ public void testPivotWithGeotileGroupBy() throws Exception {
18861888
assertThat(coordinates.get(4), hasSize(2));
18871889
}
18881890

1891+
// https://github.com/elastic/elasticsearch/issues/126591
1892+
@SuppressWarnings("unchecked")
1893+
public void testGeotileWithMissingBuckets() throws IOException {
1894+
var sourceIndex = "geotile_with_missing_buckets_source";
1895+
setupDataAccessRole(DATA_ACCESS_ROLE, sourceIndex);
1896+
createIndex(client(), sourceIndex, Settings.EMPTY, """
1897+
{
1898+
"properties": {
1899+
"username": {
1900+
"type": "keyword"
1901+
},
1902+
"date": {
1903+
"type": "date"
1904+
},
1905+
"location": {
1906+
"type": "geo_point"
1907+
}
1908+
}
1909+
}
1910+
""");
1911+
doBulk(Strings.format("""
1912+
{"create":{"_index":"%s"}}
1913+
{ "username": "bob", "date": "2025-12-25", "location": "50.62096405029297,5.5580315589904785" }
1914+
{"create":{"_index":"%s"}}
1915+
{ "username": "bob", "date": "2024-12-25", "location": "50.62096405029297,5.5580315589904785" }
1916+
{"create":{"_index":"%s"}}
1917+
{ "username": "bob", "date": "2023-12-25" }
1918+
""", sourceIndex, sourceIndex, sourceIndex), true);
1919+
1920+
var createPreviewRequest = createRequestWithAuth("POST", getTransformEndpoint() + "_preview", null);
1921+
createPreviewRequest.setJsonEntity(Strings.format("""
1922+
{
1923+
"source": {
1924+
"index": "%s"
1925+
},
1926+
"pivot": {
1927+
"group_by": {
1928+
"user": {
1929+
"terms": {
1930+
"field": "username"
1931+
}
1932+
},
1933+
"pings": {
1934+
"geotile_grid": {
1935+
"field": "location",
1936+
"precision": 1,
1937+
"missing_bucket": true
1938+
}
1939+
}
1940+
},
1941+
"aggregations": {
1942+
"seen_first": {
1943+
"min": {
1944+
"field": "date"
1945+
}
1946+
}
1947+
}
1948+
}
1949+
}
1950+
""", sourceIndex));
1951+
var previewTransformResponse = EntityUtils.toString(client().performRequest(createPreviewRequest).getEntity());
1952+
1953+
assertNotNull(previewTransformResponse);
1954+
assertThat(previewTransformResponse, containsString(XContentHelper.stripWhitespace("""
1955+
{
1956+
"seen_first": "2023-12-25T00:00:00.000Z",
1957+
"pings": null,
1958+
"user": "bob"
1959+
},
1960+
{
1961+
"seen_first": "2024-12-25T00:00:00.000Z",
1962+
"pings": {
1963+
"type": "polygon",
1964+
"coordinates": [
1965+
[
1966+
[
1967+
180.0,
1968+
0.0
1969+
],
1970+
[
1971+
0.0,
1972+
0.0
1973+
],
1974+
[
1975+
0.0,
1976+
85.0511287798066
1977+
],
1978+
[
1979+
180.0,
1980+
85.0511287798066
1981+
],
1982+
[
1983+
180.0,
1984+
0.0
1985+
]
1986+
]
1987+
]
1988+
},
1989+
"user": "bob"
1990+
}
1991+
""")));
1992+
deleteIndex(sourceIndex);
1993+
}
1994+
18891995
public void testPivotWithWeightedAvgAgg() throws Exception {
18901996
String transformId = "weighted_avg_agg_transform";
18911997
String transformIndex = "weighted_avg_pivot_reviews";

x-pack/plugin/transform/src/main/java/org/elasticsearch/xpack/transform/transforms/pivot/AggregationResultUtils.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -494,6 +494,10 @@ static class GeoTileBucketKeyExtractor implements BucketKeyExtractor {
494494

495495
@Override
496496
public Object value(Object key, String type) {
497+
// if missing_buckets are true, we want to return the null bucket
498+
if (key == null) {
499+
return null;
500+
}
497501
assert key instanceof String;
498502
Rectangle rectangle = GeoTileUtils.toBoundingBox(key.toString());
499503
final Map<String, Object> geoShape = Maps.newLinkedHashMapWithExpectedSize(2);

0 commit comments

Comments
 (0)