From c60385f1c4b467ebe43a1ca39399cdd87b6d9ef6 Mon Sep 17 00:00:00 2001 From: Walter Rafelsberger Date: Mon, 15 Oct 2018 13:19:45 +0200 Subject: [PATCH 1/2] [ML] Use arrow functions where applicable. --- .../explorer_charts/explorer_chart_distribution.js | 8 +++++--- .../explorer_charts/explorer_chart_single_metric.js | 9 ++++++--- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/x-pack/plugins/ml/public/explorer/explorer_charts/explorer_chart_distribution.js b/x-pack/plugins/ml/public/explorer/explorer_charts/explorer_chart_distribution.js index 1ffa0f9ed3757..8fc6a6a272823 100644 --- a/x-pack/plugins/ml/public/explorer/explorer_charts/explorer_chart_distribution.js +++ b/x-pack/plugins/ml/public/explorer/explorer_charts/explorer_chart_distribution.js @@ -182,6 +182,7 @@ export class ExplorerChartDistribution extends React.Component { return d; } }) + // Don't use an arrow function since we need access to `this`. .each(function () { maxYAxisLabelWidth = Math.max(this.getBBox().width + yAxis.tickPadding(), maxYAxisLabelWidth); }) @@ -342,6 +343,7 @@ export class ExplorerChartDistribution extends React.Component { // Create any new dots that are needed i.e. if number of chart points has increased. dots.enter().append('circle') .attr('r', LINE_CHART_ANOMALY_RADIUS) + // Don't use an arrow function since we need access to `this`. .on('mouseover', function (d) { showLineChartTooltip(d, this); }) @@ -349,9 +351,9 @@ export class ExplorerChartDistribution extends React.Component { // Update all dots to new positions. const threshold = mlSelectSeverityService.state.get('threshold'); - dots.attr('cx', function (d) { return lineChartXScale(d.date); }) - .attr('cy', function (d) { return lineChartYScale(d[CHART_Y_ATTRIBUTE]); }) - .attr('class', function (d) { + dots.attr('cx', d => lineChartXScale(d.date)) + .attr('cy', d => lineChartYScale(d[CHART_Y_ATTRIBUTE])) + .attr('class', (d) => { let markerClass = 'metric-value'; if (_.has(d, 'anomalyScore') && Number(d.anomalyScore) >= threshold.val) { markerClass += ' anomaly-marker '; diff --git a/x-pack/plugins/ml/public/explorer/explorer_charts/explorer_chart_single_metric.js b/x-pack/plugins/ml/public/explorer/explorer_charts/explorer_chart_single_metric.js index 2b04b3de05723..2d4e64abf89b1 100644 --- a/x-pack/plugins/ml/public/explorer/explorer_charts/explorer_chart_single_metric.js +++ b/x-pack/plugins/ml/public/explorer/explorer_charts/explorer_chart_single_metric.js @@ -138,6 +138,7 @@ export class ExplorerChartSingleMetric extends React.Component { return lineChartYScale.tickFormat()(d); } }) + // Don't use an arrow function since we need access to `this`. .each(function () { maxYAxisLabelWidth = Math.max(this.getBBox().width + yAxis.tickPadding(), maxYAxisLabelWidth); }) @@ -277,6 +278,7 @@ export class ExplorerChartSingleMetric extends React.Component { // Create any new dots that are needed i.e. if number of chart points has increased. dots.enter().append('circle') .attr('r', LINE_CHART_ANOMALY_RADIUS) + // Don't use an arrow function since we need access to `this`. .on('mouseover', function (d) { showLineChartTooltip(d, this); }) @@ -284,9 +286,9 @@ export class ExplorerChartSingleMetric extends React.Component { // Update all dots to new positions. const threshold = mlSelectSeverityService.state.get('threshold'); - dots.attr('cx', function (d) { return lineChartXScale(d.date); }) - .attr('cy', function (d) { return lineChartYScale(d.value); }) - .attr('class', function (d) { + dots.attr('cx', d => lineChartXScale(d.date)) + .attr('cy', d => lineChartYScale(d.value)) + .attr('class', (d) => { let markerClass = 'metric-value'; if (_.has(d, 'anomalyScore') && Number(d.anomalyScore) >= threshold.val) { markerClass += ` anomaly-marker ${getSeverityWithLow(d.anomalyScore)}`; @@ -306,6 +308,7 @@ export class ExplorerChartSingleMetric extends React.Component { .attr('d', d3.svg.symbol().size(MULTI_BUCKET_SYMBOL_SIZE).type('cross')) .attr('transform', d => `translate(${lineChartXScale(d.date)}, ${lineChartYScale(d.value)})`) .attr('class', d => `metric-value anomaly-marker multi-bucket ${getSeverityWithLow(d.anomalyScore)}`) + // Don't use an arrow function since we need access to `this`. .on('mouseover', function (d) { showLineChartTooltip(d, this); }) From 33cbdb311701a74d3efe35ce7139d6a24351d0cc Mon Sep 17 00:00:00 2001 From: Walter Rafelsberger Date: Mon, 15 Oct 2018 16:02:33 +0200 Subject: [PATCH 2/2] [ML] Support detector functions other than count for population chart. --- .../explorer_charts_container_service.js | 7 +------ .../ml/public/services/results_service.js | 17 ++++++++++------- x-pack/plugins/ml/public/util/chart_utils.js | 2 +- 3 files changed, 12 insertions(+), 14 deletions(-) diff --git a/x-pack/plugins/ml/public/explorer/explorer_charts/explorer_charts_container_service.js b/x-pack/plugins/ml/public/explorer/explorer_charts/explorer_charts_container_service.js index 11b1f14bec36e..7e78b2fc8fcda 100644 --- a/x-pack/plugins/ml/public/explorer/explorer_charts/explorer_charts_container_service.js +++ b/x-pack/plugins/ml/public/explorer/explorer_charts/explorer_charts_container_service.js @@ -76,7 +76,7 @@ export function explorerChartsContainerServiceFactory( // For now just take first 6 (or 8 if 4 charts per row). const maxSeriesToPlot = Math.max(chartsPerRow * 2, 6); const recordsToPlot = allSeriesRecords.slice(0, maxSeriesToPlot); - const seriesConfigs = buildDataConfigs(recordsToPlot); + const seriesConfigs = recordsToPlot.map(buildConfig); // Calculate the time range of the charts, which is a function of the chart width and max job bucket span. data.tooManyBuckets = false; @@ -504,11 +504,6 @@ export function explorerChartsContainerServiceFactory( return recordsForSeries; } - function buildDataConfigs(anomalyRecords) { - // Build the chart configuration for each anomaly record. - return anomalyRecords.map(buildConfig); - } - function calculateChartRange(seriesConfigs, earliestMs, latestMs, chartWidth, recordsToPlot, timeFieldName) { let tooManyBuckets = false; // Calculate the time range for the charts. diff --git a/x-pack/plugins/ml/public/services/results_service.js b/x-pack/plugins/ml/public/services/results_service.js index 5973d94e724be..7ca03ab84c29a 100644 --- a/x-pack/plugins/ml/public/services/results_service.js +++ b/x-pack/plugins/ml/public/services/results_service.js @@ -1399,6 +1399,8 @@ function getEventRateData( // Returned response contains a results property, which is an object // of document counts against time (epoch millis). const SAMPLER_TOP_TERMS_SHARD_SIZE = 200; +const ENTITY_AGGREGATION_SIZE = 10; +const AGGREGATION_MIN_DOC_COUNT = 1; function getEventDistributionData( index, types, @@ -1412,8 +1414,7 @@ function getEventDistributionData( latestMs, interval) { return new Promise((resolve, reject) => { - // only get this data for count (used by rare chart) - if (metricFunction !== 'count' || splitField === undefined) { + if (splitField === undefined) { return resolve([]); } @@ -1464,7 +1465,7 @@ function getEventDistributionData( date_histogram: { field: timeFieldName, interval: interval, - min_doc_count: 0 + min_doc_count: AGGREGATION_MIN_DOC_COUNT }, aggs: { sample: { @@ -1475,7 +1476,8 @@ function getEventDistributionData( entities: { terms: { field: splitField.fieldName, - size: 10 + size: ENTITY_AGGREGATION_SIZE, + min_doc_count: AGGREGATION_MIN_DOC_COUNT } } } @@ -1491,7 +1493,7 @@ function getEventDistributionData( } if (metricFieldName !== undefined && metricFieldName !== '') { - body.aggs.byTime.aggs = {}; + body.aggs.byTime.aggs.sample.aggs.entities.aggs = {}; const metricAgg = { [metricFunction]: { @@ -1502,7 +1504,7 @@ function getEventDistributionData( if (metricFunction === 'percentiles') { metricAgg[metricFunction].percents = [ML_MEDIAN_PERCENTS]; } - body.aggs.byTime.aggs.metric = metricAgg; + body.aggs.byTime.aggs.sample.aggs.entities.aggs.metric = metricAgg; } ml.esSearch({ @@ -1516,10 +1518,11 @@ function getEventDistributionData( const date = +dataForTime.key; const entities = _.get(dataForTime, ['sample', 'entities', 'buckets'], []); entities.forEach((entity) => { + const value = (metricFunction === 'count') ? entity.doc_count : entity.metric.value; d.push({ date, entity: entity.key, - value: entity.doc_count + value }); }); return d; diff --git a/x-pack/plugins/ml/public/util/chart_utils.js b/x-pack/plugins/ml/public/util/chart_utils.js index 4cf3293db01fd..09de9966ae8eb 100644 --- a/x-pack/plugins/ml/public/util/chart_utils.js +++ b/x-pack/plugins/ml/public/util/chart_utils.js @@ -142,7 +142,7 @@ export function getChartType(config) { return CHART_TYPE.EVENT_DISTRIBUTION; } else if ( POPULATION_DISTRIBUTION_ENABLED && - config.functionDescription === 'count' && + config.functionDescription !== 'rare' && config.entityFields.some(f => f.fieldType === 'over') ) { return CHART_TYPE.POPULATION_DISTRIBUTION;