Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
merged 5 commits into from
Oct 17, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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);
})
Expand Down Expand Up @@ -342,16 +343,17 @@ 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);
})
.on('mouseout', () => mlChartTooltipService.hide());

// 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 ';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
})
Expand Down Expand Up @@ -277,16 +278,17 @@ 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);
})
.on('mouseout', () => mlChartTooltipService.hide());

// 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)}`;
Expand All @@ -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);
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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.
Expand Down
17 changes: 10 additions & 7 deletions x-pack/plugins/ml/public/services/results_service.js
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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([]);
}

Expand Down Expand Up @@ -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: {
Expand All @@ -1475,7 +1476,8 @@ function getEventDistributionData(
entities: {
terms: {
field: splitField.fieldName,
size: 10
size: ENTITY_AGGREGATION_SIZE,
min_doc_count: AGGREGATION_MIN_DOC_COUNT
}
}
}
Expand All @@ -1491,7 +1493,7 @@ function getEventDistributionData(
}

if (metricFieldName !== undefined && metricFieldName !== '') {
body.aggs.byTime.aggs = {};
body.aggs.byTime.aggs.sample.aggs.entities.aggs = {};
walterra marked this conversation as resolved.
Show resolved Hide resolved

const metricAgg = {
[metricFunction]: {
Expand All @@ -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({
Expand All @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion x-pack/plugins/ml/public/util/chart_utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down