Skip to content

Commit

Permalink
[Maps] use geo-tile aggregation instead of geohash precision (#29776)
Browse files Browse the repository at this point in the history
  • Loading branch information
thomasneirynck authored Feb 5, 2019
1 parent cdf3266 commit 3ccf679
Show file tree
Hide file tree
Showing 17 changed files with 286 additions and 163 deletions.
63 changes: 63 additions & 0 deletions src/ui/public/agg_types/buckets/geo_tile.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

import _ from 'lodash';
import { BucketAggType } from './_bucket_agg_type';
import { i18n } from '@kbn/i18n';

export const geoTileBucketAgg = new BucketAggType({
name: 'geotile_grid',
title: i18n.translate('common.ui.aggTypes.buckets.geotileGridTitle', {
defaultMessage: 'Geotile',
}),
params: [
{
name: 'field',
type: 'field',
filterFieldTypes: 'geo_point'
},
{
name: 'useGeocentroid',
default: true,
write: _.noop
},
{
name: 'precision',
default: 0,
}
],
getRequestAggs: function (agg) {
const aggs = [];
const params = agg.params;

aggs.push(agg);

if (params.useGeocentroid) {
aggs.push(agg.aggConfigs.createAggConfig({
type: 'geo_centroid',
enabled: true,
params: {
field: agg.getField()
}
}, { addToAggConfigs: false }));
}

return aggs;
}
});
4 changes: 3 additions & 1 deletion src/ui/public/agg_types/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ import { filterBucketAgg } from './buckets/filter';
import { filtersBucketAgg } from './buckets/filters';
import { significantTermsBucketAgg } from './buckets/significant_terms';
import { geoHashBucketAgg } from './buckets/geo_hash';
import { geoTileBucketAgg } from './buckets/geo_tile';
import { bucketSumMetricAgg } from './metrics/bucket_sum';
import { bucketAvgMetricAgg } from './metrics/bucket_avg';
import { bucketMinMetricAgg } from './metrics/bucket_min';
Expand Down Expand Up @@ -86,7 +87,8 @@ const aggs = {
filterBucketAgg,
filtersBucketAgg,
significantTermsBucketAgg,
geoHashBucketAgg
geoHashBucketAgg,
geoTileBucketAgg,
]
};

Expand Down
17 changes: 0 additions & 17 deletions x-pack/plugins/maps/public/elasticsearch_geo_utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -99,23 +99,6 @@ export function geoPointToGeometry(value) {
);
}


export function makeGeohashGridPolygon(geohashGridFeature) {
const esBbox = geohashGridFeature.properties.geohash_meta.rectangle;
return {
type: 'Polygon',
coordinates: [
[
[esBbox[0][1], esBbox[0][0]],
[esBbox[1][1], esBbox[1][0]],
[esBbox[2][1], esBbox[2][0]],
[esBbox[3][1], esBbox[3][0]],
[esBbox[0][1], esBbox[0][0]],
]
]
};
}

export function geoShapeToGeometry(value) {
if (!value) {
return [];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,113 +4,98 @@
* you may not use this file except in compliance with the Elastic License.
*/

import { decodeGeoHash } from 'ui/utils/decode_geo_hash';
import { gridDimensions } from 'ui/vis/map/grid_dimensions';
import { RENDER_AS } from './render_as';
import { getTileBoundingBox } from './geo_tile_utils';

/*
* Fork of ui/public/vis/map/convert_to_geojson.js that supports multiple metrics
*/
export function convertToGeoJson(tabifiedResponse) {

let features;
const min = Infinity;
const max = -Infinity;
let geoAgg;

if (tabifiedResponse && tabifiedResponse.rows) {

const table = tabifiedResponse;
const geohashColumn = table.columns.find(column => column.aggConfig.type.dslName === 'geohash_grid');

if (!geohashColumn) {
features = [];
} else {

geoAgg = geohashColumn.aggConfig;

const metricColumns = table.columns.filter(column => {
return column.aggConfig.type.type === 'metrics'
&& column.aggConfig.type.dslName !== 'geo_centroid';
});
const geocentroidColumn = table.columns.find(column => column.aggConfig.type.dslName === 'geo_centroid');

features = table.rows.map(row => {

const geohash = row[geohashColumn.id];
if (!geohash) return false;
const geohashLocation = decodeGeoHash(geohash);

let pointCoordinates;
if (geocentroidColumn) {
const location = row[geocentroidColumn.id];
pointCoordinates = [location.lon, location.lat];
} else {
pointCoordinates = [geohashLocation.longitude[2], geohashLocation.latitude[2]];
}
const EMPTY_FEATURE_COLLECTION = {
type: 'FeatureCollection',
features: []
};

const rectangle = [
[geohashLocation.latitude[0], geohashLocation.longitude[0]],
[geohashLocation.latitude[0], geohashLocation.longitude[1]],
[geohashLocation.latitude[1], geohashLocation.longitude[1]],
[geohashLocation.latitude[1], geohashLocation.longitude[0]],
];
export function convertToGeoJson({ table, renderAs }) {

const centerLatLng = [
geohashLocation.latitude[2],
geohashLocation.longitude[2]
];

if (geoAgg.params.useGeocentroid) {
// see https://github.com/elastic/elasticsearch/issues/24694 for why clampGrid is used
pointCoordinates[0] = clampGrid(pointCoordinates[0], geohashLocation.longitude[0], geohashLocation.longitude[1]);
pointCoordinates[1] = clampGrid(pointCoordinates[1], geohashLocation.latitude[0], geohashLocation.latitude[1]);
}
if (!table || !table.rows) {
return EMPTY_FEATURE_COLLECTION;
}

const metrics = {};
metricColumns.forEach(metricColumn => {
metrics[metricColumn.aggConfig.id] = row[metricColumn.id];
});
//const value = row[metricColumn.id];
//min = Math.min(min, value);
//max = Math.max(max, value);
const geoGridColumn = table.columns.find(column => column.aggConfig.type.dslName === 'geotile_grid');
if (!geoGridColumn) {
return EMPTY_FEATURE_COLLECTION;
}

return {
type: 'Feature',
geometry: {
type: 'Point',
coordinates: pointCoordinates
},
properties: {
geohash: geohash,
geohash_meta: {
center: centerLatLng,
rectangle: rectangle
},
...metrics
}
};
const metricColumns = table.columns.filter(column => {
return column.aggConfig.type.type === 'metrics'
&& column.aggConfig.type.dslName !== 'geo_centroid';
});
const geocentroidColumn = table.columns.find(column => column.aggConfig.type.dslName === 'geo_centroid');
if (!geocentroidColumn) {
return EMPTY_FEATURE_COLLECTION;
}

const features = [];
table.rows.forEach(row => {
const gridKey = row[geoGridColumn.id];
if (!gridKey) {
return;
}

}).filter(row => row);
const properties = {};
metricColumns.forEach(metricColumn => {
properties[metricColumn.aggConfig.id] = row[metricColumn.id];
});

features.push({
type: 'Feature',
geometry: rowToGeometry({
row,
gridKey,
geocentroidColumn,
renderAs,
}),
properties
});
});

return {
featureCollection: {
type: 'FeatureCollection',
features: features
}
};
}

} else {
features = [];
function rowToGeometry({
row,
gridKey,
geocentroidColumn,
renderAs,
}) {
const { top, bottom, right, left } = getTileBoundingBox(gridKey);

if (renderAs === RENDER_AS.GRID) {
return {
type: 'Polygon',
coordinates: [
[
[right, top],
[left, top],
[left, bottom],
[right, bottom],
[right, top],
]
]
};
}

const featureCollection = {
type: 'FeatureCollection',
features: features
};
// see https://github.com/elastic/elasticsearch/issues/24694 for why clampGrid is used
const pointCoordinates = [
clampGrid(row[geocentroidColumn.id].lon, left, right),
clampGrid(row[geocentroidColumn.id].lat, bottom, top)
];

return {
featureCollection: featureCollection,
meta: {
min: min,
max: max,
geohashGridDimensionsAtEquator: geoAgg && gridDimensions(geoAgg.params.precision)
}
type: 'Point',
coordinates: pointCoordinates
};
}

Expand Down
Loading

0 comments on commit 3ccf679

Please sign in to comment.