diff --git a/docs/maps/heatmap-layer.asciidoc b/docs/maps/heatmap-layer.asciidoc index 9d456c59b69e..77b6d929a931 100644 --- a/docs/maps/heatmap-layer.asciidoc +++ b/docs/maps/heatmap-layer.asciidoc @@ -13,6 +13,6 @@ You can create a heat map layer from the following data source: Set *Show as* to *heat map*. The index must contain at least one field mapped as {ref}/geo-point.html[geo_point]. -NOTE: Only count and sum metric aggregations are available with the grid aggregation source and heat map layers. -Mean, median, min, and max are turned off because the heat map will blend nearby values. +NOTE: Only count, sum, unique count metric aggregations are available with the grid aggregation source and heat map layers. +Average, min, and max are turned off because the heat map will blend nearby values. Blending two average values would make the cluster more prominent, even though it just might literally mean that these nearby areas are average. diff --git a/x-pack/legacy/plugins/maps/common/constants.js b/x-pack/legacy/plugins/maps/common/constants.js index 1fd1f4b43bbd..942d0a21123c 100644 --- a/x-pack/legacy/plugins/maps/common/constants.js +++ b/x-pack/legacy/plugins/maps/common/constants.js @@ -102,3 +102,12 @@ export const DRAW_TYPE = { BOUNDS: 'BOUNDS', POLYGON: 'POLYGON' }; + +export const METRIC_TYPE = { + AVG: 'avg', + COUNT: 'count', + MAX: 'max', + MIN: 'min', + SUM: 'sum', + UNIQUE_COUNT: 'cardinality', +}; diff --git a/x-pack/legacy/plugins/maps/public/components/metric_editor.js b/x-pack/legacy/plugins/maps/public/components/metric_editor.js index f3123d5645cc..03d364f3d84a 100644 --- a/x-pack/legacy/plugins/maps/public/components/metric_editor.js +++ b/x-pack/legacy/plugins/maps/public/components/metric_editor.js @@ -12,6 +12,7 @@ import { EuiFieldText, EuiFormRow } from '@elastic/eui'; import { MetricSelect, METRIC_AGGREGATION_VALUES } from './metric_select'; import { SingleFieldSelect } from './single_field_select'; +import { METRIC_TYPE } from '../../common/constants'; export function MetricEditor({ fields, metricsFilter, metric, onChange, removeButton }) { const onAggChange = metricAggregationType => { @@ -34,10 +35,12 @@ export function MetricEditor({ fields, metricsFilter, metric, onChange, removeBu }; let fieldSelect; - if (metric.type && metric.type !== 'count') { - const filterNumberFields = field => { - return field.type === 'number'; - }; + if (metric.type && metric.type !== METRIC_TYPE.COUNT) { + const filterField = metric.type !== METRIC_TYPE.UNIQUE_COUNT + ? field => { + return field.type === 'number'; + } + : undefined; fieldSelect = ( { - if (type === 'count') { + if (type === METRIC_TYPE.COUNT) { return true; } @@ -69,7 +71,7 @@ export class MetricsExpression extends Component { }) .map(({ type, field }) => { // do not use metric label so field and aggregation are not obscured. - if (type === 'count') { + if (type === METRIC_TYPE.COUNT) { return 'count'; } @@ -127,6 +129,6 @@ MetricsExpression.propTypes = { MetricsExpression.defaultProps = { metrics: [ - { type: 'count' } + { type: METRIC_TYPE.COUNT } ] }; diff --git a/x-pack/legacy/plugins/maps/public/layers/sources/es_geo_grid_source/es_geo_grid_source.js b/x-pack/legacy/plugins/maps/public/layers/sources/es_geo_grid_source/es_geo_grid_source.js index 8416ef5709e3..776980e17bb1 100644 --- a/x-pack/legacy/plugins/maps/public/layers/sources/es_geo_grid_source/es_geo_grid_source.js +++ b/x-pack/legacy/plugins/maps/public/layers/sources/es_geo_grid_source/es_geo_grid_source.js @@ -21,7 +21,7 @@ import { RENDER_AS } from './render_as'; import { CreateSourceEditor } from './create_source_editor'; import { UpdateSourceEditor } from './update_source_editor'; import { GRID_RESOLUTION } from '../../grid_resolution'; -import { SOURCE_DATA_ID_ORIGIN, ES_GEO_GRID } from '../../../../common/constants'; +import { SOURCE_DATA_ID_ORIGIN, ES_GEO_GRID, METRIC_TYPE } from '../../../../common/constants'; import { i18n } from '@kbn/i18n'; import { getDataSourceLabel } from '../../../../common/i18n_getters'; @@ -36,9 +36,16 @@ const aggSchemas = new Schemas([ title: 'Value', min: 1, max: Infinity, - aggFilter: ['avg', 'count', 'max', 'min', 'sum'], + aggFilter: [ + METRIC_TYPE.AVG, + METRIC_TYPE.COUNT, + METRIC_TYPE.MAX, + METRIC_TYPE.MIN, + METRIC_TYPE.SUM, + METRIC_TYPE.UNIQUE_COUNT + ], defaults: [ - { schema: 'metric', type: 'count' } + { schema: 'metric', type: METRIC_TYPE.COUNT } ] }, { @@ -215,11 +222,11 @@ export class ESGeoGridSource extends AbstractESSource { } _formatMetricKey(metric) { - return metric.type !== 'count' ? `${metric.type}_of_${metric.field}` : COUNT_PROP_NAME; + return metric.type !== METRIC_TYPE.COUNT ? `${metric.type}_of_${metric.field}` : COUNT_PROP_NAME; } _formatMetricLabel(metric) { - return metric.type !== 'count' ? `${metric.type} of ${metric.field}` : COUNT_PROP_LABEL; + return metric.type !== METRIC_TYPE.COUNT ? `${metric.type} of ${metric.field}` : COUNT_PROP_LABEL; } _makeAggConfigs(precision) { @@ -231,7 +238,7 @@ export class ESGeoGridSource extends AbstractESSource { schema: 'metric', params: {} }; - if (metric.type !== 'count') { + if (metric.type !== METRIC_TYPE.COUNT) { metricAggConfig.params = { field: metric.field }; } return metricAggConfig; diff --git a/x-pack/legacy/plugins/maps/public/layers/sources/es_geo_grid_source/update_source_editor.js b/x-pack/legacy/plugins/maps/public/layers/sources/es_geo_grid_source/update_source_editor.js index bed8236da1be..9ea5093724ed 100644 --- a/x-pack/legacy/plugins/maps/public/layers/sources/es_geo_grid_source/update_source_editor.js +++ b/x-pack/legacy/plugins/maps/public/layers/sources/es_geo_grid_source/update_source_editor.js @@ -8,6 +8,7 @@ import React, { Fragment, Component } from 'react'; import { RENDER_AS } from './render_as'; import { MetricsEditor } from '../../../components/metrics_editor'; +import { METRIC_TYPE } from '../../../../common/constants'; import { indexPatternService } from '../../../kibana_services'; import { ResolutionEditor } from './resolution_editor'; import { i18n } from '@kbn/i18n'; @@ -66,7 +67,7 @@ export class UpdateSourceEditor extends Component { this.props.renderAs === RENDER_AS.HEATMAP ? metric => { //these are countable metrics, where blending heatmap color blobs make sense - return ['count', 'sum'].includes(metric.value); + return [METRIC_TYPE.COUNT, METRIC_TYPE.SUM, METRIC_TYPE.UNIQUE_COUNT].includes(metric.value); } : null; const allowMultipleMetrics = this.props.renderAs !== RENDER_AS.HEATMAP; diff --git a/x-pack/legacy/plugins/maps/public/layers/sources/es_pew_pew_source/es_pew_pew_source.js b/x-pack/legacy/plugins/maps/public/layers/sources/es_pew_pew_source/es_pew_pew_source.js index 4c081d386b3d..3debfdf1541f 100644 --- a/x-pack/legacy/plugins/maps/public/layers/sources/es_pew_pew_source/es_pew_pew_source.js +++ b/x-pack/legacy/plugins/maps/public/layers/sources/es_pew_pew_source/es_pew_pew_source.js @@ -15,7 +15,7 @@ import { UpdateSourceEditor } from './update_source_editor'; import { VectorStyle } from '../../styles/vector_style'; import { vectorStyles } from '../../styles/vector_style_defaults'; import { i18n } from '@kbn/i18n'; -import { SOURCE_DATA_ID_ORIGIN, ES_PEW_PEW } from '../../../../common/constants'; +import { SOURCE_DATA_ID_ORIGIN, ES_PEW_PEW, METRIC_TYPE } from '../../../../common/constants'; import { getDataSourceLabel } from '../../../../common/i18n_getters'; import { convertToLines } from './convert_to_lines'; import { Schemas } from 'ui/vis/editors/default/schemas'; @@ -32,9 +32,16 @@ const aggSchemas = new Schemas([ title: 'Value', min: 1, max: Infinity, - aggFilter: ['avg', 'count', 'max', 'min', 'sum'], + aggFilter: [ + METRIC_TYPE.AVG, + METRIC_TYPE.COUNT, + METRIC_TYPE.MAX, + METRIC_TYPE.MIN, + METRIC_TYPE.SUM, + METRIC_TYPE.UNIQUE_COUNT + ], defaults: [ - { schema: 'metric', type: 'count' } + { schema: 'metric', type: METRIC_TYPE.COUNT } ] } ]); @@ -193,7 +200,7 @@ export class ESPewPewSource extends AbstractESSource { schema: 'metric', params: {} }; - if (metric.type !== 'count') { + if (metric.type !== METRIC_TYPE.COUNT) { metricAggConfig.params = { field: metric.field }; } return metricAggConfig; @@ -252,11 +259,11 @@ export class ESPewPewSource extends AbstractESSource { } _formatMetricKey(metric) { - return metric.type !== 'count' ? `${metric.type}_of_${metric.field}` : COUNT_PROP_NAME; + return metric.type !== METRIC_TYPE.COUNT ? `${metric.type}_of_${metric.field}` : COUNT_PROP_NAME; } _formatMetricLabel(metric) { - return metric.type !== 'count' ? `${metric.type} of ${metric.field}` : COUNT_PROP_LABEL; + return metric.type !== METRIC_TYPE.COUNT ? `${metric.type} of ${metric.field}` : COUNT_PROP_LABEL; } async _getGeoField() { diff --git a/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/es_search_source.js b/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/es_search_source.js index 7c248e332d40..d9c48424bb77 100644 --- a/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/es_search_source.js +++ b/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/es_search_source.js @@ -512,9 +512,4 @@ export class ESSearchSource extends AbstractESSource { path: geoField.name, }; } - - _getRawFieldName(fieldName) { - // fieldName is rawFieldName for documents source since the source uses raw documents instead of aggregated metrics - return fieldName; - } } diff --git a/x-pack/legacy/plugins/maps/public/layers/sources/es_source.js b/x-pack/legacy/plugins/maps/public/layers/sources/es_source.js index 0670474df89b..85c866479a6b 100644 --- a/x-pack/legacy/plugins/maps/public/layers/sources/es_source.js +++ b/x-pack/legacy/plugins/maps/public/layers/sources/es_source.js @@ -19,7 +19,7 @@ import { ESAggMetricTooltipProperty } from '../tooltips/es_aggmetric_tooltip_pro import uuid from 'uuid/v4'; import { copyPersistentState } from '../../reducers/util'; -import { ES_GEO_FIELD_TYPE } from '../../../common/constants'; +import { ES_GEO_FIELD_TYPE, METRIC_TYPE } from '../../../common/constants'; import { DataRequestAbortError } from '../util/data_request'; export class AbstractESSource extends AbstractVectorSource { @@ -59,7 +59,7 @@ export class AbstractESSource extends AbstractVectorSource { _getValidMetrics() { const metrics = _.get(this._descriptor, 'metrics', []).filter(({ type, field }) => { - if (type === 'count') { + if (type === METRIC_TYPE.COUNT) { return true; } @@ -69,7 +69,7 @@ export class AbstractESSource extends AbstractVectorSource { return false; }); if (metrics.length === 0) { - metrics.push({ type: 'count' }); + metrics.push({ type: METRIC_TYPE.COUNT }); } return metrics; } @@ -300,18 +300,13 @@ export class AbstractESSource extends AbstractVectorSource { return this._descriptor.id; } - _getRawFieldName(fieldName) { + async getFieldFormatter(fieldName) { const metricField = this.getMetricFields().find(({ propertyKey }) => { return propertyKey === fieldName; }); - return metricField ? metricField.field : null; - } - - async getFieldFormatter(fieldName) { - // fieldName could be an aggregation so it needs to be unpacked to expose raw field. - const rawFieldName = this._getRawFieldName(fieldName); - if (!rawFieldName) { + // Do not use field formatters for counting metrics + if (metricField && metricField.type === METRIC_TYPE.COUNT || metricField.type === METRIC_TYPE.UNIQUE_COUNT) { return null; } @@ -322,7 +317,10 @@ export class AbstractESSource extends AbstractVectorSource { return null; } - const fieldFromIndexPattern = indexPattern.fields.getByName(rawFieldName); + const realFieldName = metricField + ? metricField.field + : fieldName; + const fieldFromIndexPattern = indexPattern.fields.getByName(realFieldName); if (!fieldFromIndexPattern) { return null; } diff --git a/x-pack/legacy/plugins/maps/public/layers/sources/es_term_source.js b/x-pack/legacy/plugins/maps/public/layers/sources/es_term_source.js index 5d876dbbd011..1f5adc00cca6 100644 --- a/x-pack/legacy/plugins/maps/public/layers/sources/es_term_source.js +++ b/x-pack/legacy/plugins/maps/public/layers/sources/es_term_source.js @@ -11,7 +11,7 @@ import { Schemas } from 'ui/vis/editors/default/schemas'; import { AggConfigs } from 'ui/agg_types'; import { i18n } from '@kbn/i18n'; import { ESTooltipProperty } from '../tooltips/es_tooltip_property'; -import { ES_SIZE_LIMIT } from '../../../common/constants'; +import { ES_SIZE_LIMIT, METRIC_TYPE } from '../../../common/constants'; const TERMS_AGG_NAME = 'join'; @@ -22,9 +22,16 @@ const aggSchemas = new Schemas([ title: 'Value', min: 1, max: Infinity, - aggFilter: ['avg', 'count', 'max', 'min', 'sum'], + aggFilter: [ + METRIC_TYPE.AVG, + METRIC_TYPE.COUNT, + METRIC_TYPE.MAX, + METRIC_TYPE.MIN, + METRIC_TYPE.SUM, + METRIC_TYPE.UNIQUE_COUNT + ], defaults: [ - { schema: 'metric', type: 'count' } + { schema: 'metric', type: METRIC_TYPE.COUNT } ] }, { @@ -81,12 +88,12 @@ export class ESTermSource extends AbstractESSource { } _formatMetricKey(metric) { - const metricKey = metric.type !== 'count' ? `${metric.type}_of_${metric.field}` : metric.type; + const metricKey = metric.type !== METRIC_TYPE.COUNT ? `${metric.type}_of_${metric.field}` : metric.type; return `__kbnjoin__${metricKey}_groupby_${this._descriptor.indexPatternTitle}.${this._descriptor.term}`; } _formatMetricLabel(metric) { - const metricLabel = metric.type !== 'count' ? `${metric.type} ${metric.field}` : 'count'; + const metricLabel = metric.type !== METRIC_TYPE.COUNT ? `${metric.type} ${metric.field}` : 'count'; return `${metricLabel} of ${this._descriptor.indexPatternTitle}:${this._descriptor.term}`; } @@ -108,13 +115,13 @@ export class ESTermSource extends AbstractESSource { const metricPropertyNames = configStates .filter(configState => { - return configState.schema === 'metric' && configState.type !== 'count'; + return configState.schema === 'metric' && configState.type !== METRIC_TYPE.COUNT; }) .map(configState => { return configState.id; }); const countConfigState = configStates.find(configState => { - return configState.type === 'count'; + return configState.type === METRIC_TYPE.COUNT; }); const countPropertyName = _.get(countConfigState, 'id'); return { @@ -128,7 +135,7 @@ export class ESTermSource extends AbstractESSource { _getRequestDescription(leftSourceName, leftFieldName) { const metrics = this._getValidMetrics().map(metric => { - return metric.type !== 'count' ? `${metric.type} ${metric.field}` : 'count'; + return metric.type !== METRIC_TYPE.COUNT ? `${metric.type} ${metric.field}` : 'count'; }); const joinStatement = []; joinStatement.push(i18n.translate('xpack.maps.source.esJoin.joinLeftDescription', { @@ -157,7 +164,7 @@ export class ESTermSource extends AbstractESSource { schema: 'metric', params: {} }; - if (metric.type !== 'count') { + if (metric.type !== METRIC_TYPE.COUNT) { metricAggConfig.params = { field: metric.field }; } return metricAggConfig; diff --git a/x-pack/legacy/plugins/maps/public/layers/tooltips/es_aggmetric_tooltip_property.js b/x-pack/legacy/plugins/maps/public/layers/tooltips/es_aggmetric_tooltip_property.js index 11cbb36f4959..42629e192c27 100644 --- a/x-pack/legacy/plugins/maps/public/layers/tooltips/es_aggmetric_tooltip_property.js +++ b/x-pack/legacy/plugins/maps/public/layers/tooltips/es_aggmetric_tooltip_property.js @@ -6,6 +6,7 @@ import { ESTooltipProperty } from './es_tooltip_property'; +import { METRIC_TYPE } from '../../../common/constants'; export class ESAggMetricTooltipProperty extends ESTooltipProperty { @@ -21,7 +22,7 @@ export class ESAggMetricTooltipProperty extends ESTooltipProperty { if (typeof this._rawValue === 'undefined') { return '-'; } - if (this._metricField.type === 'count') { + if (this._metricField.type === METRIC_TYPE.COUNT || this._metricField.type === METRIC_TYPE.UNIQUE_COUNT) { return this._rawValue; } const indexPatternField = this._indexPattern.fields.getByName(this._metricField.field);