[Maps] Elasticsearch document source - flatten hit using indexPattern.flattenHit (#27912) (#27932)

This commit is contained in:
Nathan Reese 2019-01-02 16:21:28 -07:00 committed by GitHub
parent 8fdea1ab74
commit e874b404da
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 40 additions and 41 deletions

View file

@ -6,7 +6,17 @@
import _ from 'lodash';
export function hitsToGeoJson(hits, geoFieldName, geoFieldType) {
/**
* Converts Elasticsearch search results into GeoJson FeatureCollection
*
* @param {array} hits Elasticsearch search response hits array
* @param {function} flattenHit Method to flatten hits._source and hits.fields into properties object.
* Should just be IndexPattern.flattenHit but wanted to avoid coupling this method to IndexPattern.
* @param {string} geoFieldName Geometry field name
* @param {string} geoFieldType Geometry field type ["geo_point", "geo_shape"]
* @returns {number}
*/
export function hitsToGeoJson(hits, flattenHit, geoFieldName, geoFieldType) {
const features = [];
hits.forEach(hit => {
const value = _.get(hit, `_source[${geoFieldName}]`);
@ -19,22 +29,9 @@ export function hitsToGeoJson(hits, geoFieldName, geoFieldType) {
throw new Error(`Unsupported field type, expected: geo_shape or geo_point, you provided: ${geoFieldType}`);
}
const properties = {};
for (const fieldName in hit._source) {
if (hit._source.hasOwnProperty(fieldName)) {
if (fieldName !== geoFieldName) {
properties[fieldName] = hit._source[fieldName];
}
}
}
// hit.fields contains calculated values from docvalue_fields and script_fields
for (const fieldName in hit.fields) {
if (hit.fields.hasOwnProperty(fieldName)) {
const val = hit.fields[fieldName];
properties[fieldName] = Array.isArray(val) && val.length === 1 ? val[0] : val;
}
}
const properties = flattenHit(hit);
// don't include geometry field value in properties
delete properties[geoFieldName];
return geometries.map(geometry => {
features.push({

View file

@ -20,6 +20,18 @@ const mapExtent = {
minLon: -89,
};
const flattenHitMock = hit => {
const properties = {};
for (const fieldName in hit._source) {
if (hit._source.hasOwnProperty(fieldName)) {
if (fieldName !== geoFieldName) {
properties[fieldName] = hit._source[fieldName];
}
}
}
return properties;
};
describe('hitsToGeoJson', () => {
it('Should convert elasitcsearch hits to geojson', () => {
const hits = [
@ -34,7 +46,7 @@ describe('hitsToGeoJson', () => {
}
},
];
const geojson = hitsToGeoJson(hits, geoFieldName, 'geo_point');
const geojson = hitsToGeoJson(hits, flattenHitMock, geoFieldName, 'geo_point');
expect(geojson.type).toBe('FeatureCollection');
expect(geojson.features.length).toBe(2);
expect(geojson.features[0]).toEqual({
@ -58,12 +70,12 @@ describe('hitsToGeoJson', () => {
_source: {}
},
];
const geojson = hitsToGeoJson(hits, geoFieldName, 'geo_point');
const geojson = hitsToGeoJson(hits, flattenHitMock, geoFieldName, 'geo_point');
expect(geojson.type).toBe('FeatureCollection');
expect(geojson.features.length).toBe(1);
});
it('Should populate properties from _source and fields', () => {
it('Should populate properties from hit', () => {
const hits = [
{
_source: {
@ -75,28 +87,10 @@ describe('hitsToGeoJson', () => {
}
}
];
const geojson = hitsToGeoJson(hits, geoFieldName, 'geo_point');
const geojson = hitsToGeoJson(hits, flattenHitMock, geoFieldName, 'geo_point');
expect(geojson.features.length).toBe(1);
const feature = geojson.features[0];
expect(feature.properties.myField).toBe(8);
expect(feature.properties.myScriptedField).toBe(10);
});
it('Should unwrap computed fields', () => {
const hits = [
{
_source: {
[geoFieldName]: { lat: 20, lon: 100 },
},
fields: {
myScriptedField: [ 10 ] // script_fields are returned in an array
}
}
];
const geojson = hitsToGeoJson(hits, geoFieldName, 'geo_point');
expect(geojson.features.length).toBe(1);
const feature = geojson.features[0];
expect(feature.properties.myScriptedField).toBe(10);
});
it('Should create feature per item when geometry value is an array', () => {
@ -111,7 +105,7 @@ describe('hitsToGeoJson', () => {
}
},
];
const geojson = hitsToGeoJson(hits, geoFieldName, 'geo_point');
const geojson = hitsToGeoJson(hits, flattenHitMock, geoFieldName, 'geo_point');
expect(geojson.type).toBe('FeatureCollection');
expect(geojson.features.length).toBe(2);
expect(geojson.features[0]).toEqual({

View file

@ -149,8 +149,16 @@ export class ESSearchSource extends VectorSource {
}
let featureCollection;
const flattenHit = hit => {
const properties = indexPattern.flattenHit(hit);
// remove metaFields
indexPattern.metaFields.forEach(metaField => {
delete properties[metaField];
});
return properties;
};
try {
featureCollection = hitsToGeoJson(resp.hits.hits, geoField.name, geoField.type);
featureCollection = hitsToGeoJson(resp.hits.hits, flattenHit, geoField.name, geoField.type);
} catch(error) {
throw new Error(`Unable to convert search response to geoJson feature collection, error: ${error.message}`);
}