From f92b33f5d81ea7be6d5c482c6a5e13995f65ec4f Mon Sep 17 00:00:00 2001 From: Walter Rafelsberger Date: Wed, 30 Jan 2019 10:29:10 +0100 Subject: [PATCH] [ML] Fixes caching/memoizing Anomaly Explorer data calls related to changed time ranges. --- x-pack/plugins/ml/public/explorer/explorer.js | 49 ++++++++++++------- .../ml/public/explorer/explorer_utils.js | 12 ++--- 2 files changed, 37 insertions(+), 24 deletions(-) diff --git a/x-pack/plugins/ml/public/explorer/explorer.js b/x-pack/plugins/ml/public/explorer/explorer.js index e598d41e2f1b7..c34f91e78cfed 100644 --- a/x-pack/plugins/ml/public/explorer/explorer.js +++ b/x-pack/plugins/ml/public/explorer/explorer.js @@ -243,9 +243,11 @@ export const Explorer = injectI18n( const showCharts = mlCheckboxShowChartsService.state.get('showCharts'); const { selectedCells, selectedJobs } = this.state; + const bounds = timefilter.getActiveBounds(); const timerange = getSelectionTimeRange( selectedCells, - this.getSwimlaneBucketInterval(selectedJobs).asSeconds() + this.getSwimlaneBucketInterval(selectedJobs).asSeconds(), + bounds, ); if (showCharts && selectedCells !== null) { @@ -263,9 +265,11 @@ export const Explorer = injectI18n( const showCharts = mlCheckboxShowChartsService.state.get('showCharts'); const { anomalyChartRecords, selectedCells, selectedJobs } = this.state; if (showCharts && selectedCells !== null) { + const bounds = timefilter.getActiveBounds(); const timerange = getSelectionTimeRange( selectedCells, - this.getSwimlaneBucketInterval(selectedJobs).asSeconds() + this.getSwimlaneBucketInterval(selectedJobs).asSeconds(), + bounds, ); this.updateCharts( anomalyChartRecords, timerange.earliestMs, timerange.latestMs @@ -276,15 +280,16 @@ export const Explorer = injectI18n( tableControlsListener = async () => { const { dateFormatTz } = this.props; const { selectedCells, swimlaneViewByFieldName, selectedJobs } = this.state; - this.setState({ - tableData: await loadAnomaliesTableData( - selectedCells, - selectedJobs, - dateFormatTz, - this.getSwimlaneBucketInterval(selectedJobs).asSeconds(), - swimlaneViewByFieldName - ) - }); + const bounds = timefilter.getActiveBounds(); + const tableData = await loadAnomaliesTableData( + selectedCells, + selectedJobs, + dateFormatTz, + this.getSwimlaneBucketInterval(selectedJobs).asSeconds(), + bounds, + swimlaneViewByFieldName + ); + this.setState({ tableData }); }; swimlaneLimitListener = () => { @@ -355,7 +360,7 @@ export const Explorer = injectI18n( loadOverallDataPreviousArgs = null; loadOverallDataPreviousData = null; - loadOverallData(selectedJobs, interval, showLoadingIndicator = true) { + loadOverallData(selectedJobs, interval, bounds, showLoadingIndicator = true) { return new Promise((resolve) => { // Loads the overall data components i.e. the overall swimlane and influencers list. if (selectedJobs === null) { @@ -369,7 +374,9 @@ export const Explorer = injectI18n( // check if we can just return existing cached data const compareArgs = { selectedJobs, - intervalAsSeconds: interval.asSeconds() + intervalAsSeconds: interval.asSeconds(), + boundsMin: bounds.min.valueOf(), + boundsMax: bounds.max.valueOf(), }; if (_.isEqual(compareArgs, this.loadOverallDataPreviousArgs)) { @@ -391,7 +398,6 @@ export const Explorer = injectI18n( // Ensure the search bounds align to the bucketing interval used in the swimlane so // that the first and last buckets are complete. - const bounds = timefilter.getActiveBounds(); const searchBounds = getBoundsRoundedToInterval( bounds, interval, @@ -636,9 +642,11 @@ export const Explorer = injectI18n( ? selectedCells.lanes : selectedJobs.map(d => d.id); + const bounds = timefilter.getActiveBounds(); const timerange = getSelectionTimeRange( selectedCells, - this.getSwimlaneBucketInterval(selectedJobs).asSeconds() + this.getSwimlaneBucketInterval(selectedJobs).asSeconds(), + bounds, ); // Load the overall data - if the FieldFormats failed to populate @@ -648,6 +656,7 @@ export const Explorer = injectI18n( await this.loadOverallData( selectedJobs, this.getSwimlaneBucketInterval(selectedJobs), + bounds, showOverallLoadingIndicator, ) ); @@ -657,7 +666,9 @@ export const Explorer = injectI18n( const annotationsTableCompareArgs = { selectedCells, selectedJobs, - interval: this.getSwimlaneBucketInterval(selectedJobs).asSeconds() + interval: this.getSwimlaneBucketInterval(selectedJobs).asSeconds(), + boundsMin: bounds.min.valueOf(), + boundsMax: bounds.max.valueOf(), }; if (_.isEqual(annotationsTableCompareArgs, this.annotationsTablePreviousArgs)) { @@ -667,7 +678,8 @@ export const Explorer = injectI18n( stateUpdate.annotationsData = this.annotationsTablePreviousData = await loadAnnotationsTableData( selectedCells, selectedJobs, - this.getSwimlaneBucketInterval(selectedJobs).asSeconds() + this.getSwimlaneBucketInterval(selectedJobs).asSeconds(), + bounds, ); } @@ -770,6 +782,8 @@ export const Explorer = injectI18n( selectedJobs, dateFormatTz, interval: this.getSwimlaneBucketInterval(selectedJobs).asSeconds(), + boundsMin: bounds.min.valueOf(), + boundsMax: bounds.max.valueOf(), swimlaneViewByFieldName: viewBySwimlaneOptions.swimlaneViewByFieldName, }; @@ -782,6 +796,7 @@ export const Explorer = injectI18n( selectedJobs, dateFormatTz, this.getSwimlaneBucketInterval(selectedJobs).asSeconds(), + bounds, viewBySwimlaneOptions.swimlaneViewByFieldName ); this.setState({ tableData }); diff --git a/x-pack/plugins/ml/public/explorer/explorer_utils.js b/x-pack/plugins/ml/public/explorer/explorer_utils.js index 17453a8a69b28..6a116faa9962a 100644 --- a/x-pack/plugins/ml/public/explorer/explorer_utils.js +++ b/x-pack/plugins/ml/public/explorer/explorer_utils.js @@ -9,7 +9,6 @@ */ import { chain, each, get, union, uniq } from 'lodash'; -import { timefilter } from 'ui/timefilter'; import { parseInterval } from 'ui/utils/parse_interval'; import { isTimeSeriesViewDetector } from '../../common/util/job_utils'; @@ -165,10 +164,9 @@ export function getFieldsByJob() { }, { '*': [] }); } -export function getSelectionTimeRange(selectedCells, interval) { +export function getSelectionTimeRange(selectedCells, interval, bounds) { // Returns the time range of the cell(s) currently selected in the swimlane. // If no cell(s) are currently selected, returns the dashboard time range. - const bounds = timefilter.getActiveBounds(); let earliestMs = bounds.min.valueOf(); let latestMs = bounds.max.valueOf(); @@ -383,10 +381,10 @@ export function processViewByResults( return dataset; } -export async function loadAnnotationsTableData(selectedCells, selectedJobs, interval) { +export async function loadAnnotationsTableData(selectedCells, selectedJobs, interval, bounds) { const jobIds = (selectedCells !== null && selectedCells.viewByFieldName === VIEW_BY_JOB_LABEL) ? selectedCells.lanes : selectedJobs.map(d => d.id); - const timeRange = getSelectionTimeRange(selectedCells, interval); + const timeRange = getSelectionTimeRange(selectedCells, interval, bounds); if (mlAnnotationsEnabled === false) { return Promise.resolve([]); @@ -419,11 +417,11 @@ export async function loadAnnotationsTableData(selectedCells, selectedJobs, inte ); } -export async function loadAnomaliesTableData(selectedCells, selectedJobs, dateFormatTz, interval, fieldName) { +export async function loadAnomaliesTableData(selectedCells, selectedJobs, dateFormatTz, interval, bounds, fieldName) { const jobIds = (selectedCells !== null && selectedCells.viewByFieldName === VIEW_BY_JOB_LABEL) ? selectedCells.lanes : selectedJobs.map(d => d.id); const influencers = getSelectionInfluencers(selectedCells, fieldName); - const timeRange = getSelectionTimeRange(selectedCells, interval); + const timeRange = getSelectionTimeRange(selectedCells, interval, bounds); return new Promise((resolve, reject) => { ml.results.getAnomaliesTableData(