[ML] Enables display of contextual data for population charts using other metrics than count. (#24083)

- Enables support for showing contextual sampled data in population charts which use detector functions other than just count.
- Use arrow functions where applicable in Anomaly Explorer Charts code.
This commit is contained in:
Walter Rafelsberger 2018-10-17 16:52:48 +02:00 committed by GitHub
parent 6b22cd3a92
commit 82e97dd8e0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 23 additions and 20 deletions

View file

@ -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 ';

View file

@ -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 => `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);
})

View file

@ -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.

View file

@ -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;

View file

@ -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;