From f03037f3f0a63936229b01331ddeae3e00a04a4c Mon Sep 17 00:00:00 2001 From: Artyom Gospodarsky Date: Thu, 16 May 2019 14:05:02 +0300 Subject: [PATCH 01/20] Take model options away in a separate file --- .../metrics/common/model_options.js | 55 ++++++++ .../public/components/aggs/moving_average.js | 127 +++++------------- .../lib/vis_data/helpers/bucket_transform.js | 19 ++- 3 files changed, 94 insertions(+), 107 deletions(-) create mode 100644 src/legacy/core_plugins/metrics/common/model_options.js diff --git a/src/legacy/core_plugins/metrics/common/model_options.js b/src/legacy/core_plugins/metrics/common/model_options.js new file mode 100644 index 0000000000000..c1847a48bad61 --- /dev/null +++ b/src/legacy/core_plugins/metrics/common/model_options.js @@ -0,0 +1,55 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +export const MODEL_OPTIONS = { + UNWEIGHTED: { + NAME: 'Simple', + TYPE: 'simple', + }, + WEIGHTED_EXPONENTIAL: { + NAME: 'Exponentially Weighted', + TYPE: 'ewma', + }, + WEIGHTED_EXPONENTIAL_DOUBLE: { + NAME: 'Holt-Linear', + TYPE: 'holt', + }, + WEIGHTED_EXPONENTIAL_TRIPLE: { + NAME: 'Holt-Winters', + TYPE: 'holt_winters', + }, + WEIGHTED_LINEAR: { + NAME: 'Linear', + TYPE: 'linear', + }, +}; + +const MODEL_SCRIPTS = new Map(); + +MODEL_SCRIPTS.set(MODEL_OPTIONS.UNWEIGHTED.TYPE, 'MovingFunctions.unweightedAvg(values)'); +MODEL_SCRIPTS.set(MODEL_OPTIONS.WEIGHTED_EXPONENTIAL.TYPE, 'MovingFunctions.ewma(values)'); +MODEL_SCRIPTS.set(MODEL_OPTIONS.WEIGHTED_EXPONENTIAL_DOUBLE.TYPE, 'MovingFunctions.holt(values)'); +MODEL_SCRIPTS.set(MODEL_OPTIONS.WEIGHTED_EXPONENTIAL_TRIPLE.TYPE, 'MovingFunctions.holtWinters(values)'); +MODEL_SCRIPTS.set(MODEL_OPTIONS.WEIGHTED_LINEAR.TYPE, 'MovingFunctions.linearWeightedAvg(values)'); + +export function getModuleScript(type) { + return MODEL_SCRIPTS.get(type); +} + +export { MODEL_SCRIPTS }; diff --git a/src/legacy/core_plugins/metrics/public/components/aggs/moving_average.js b/src/legacy/core_plugins/metrics/public/components/aggs/moving_average.js index 9a3fc5b147df8..484058f06f323 100644 --- a/src/legacy/core_plugins/metrics/public/components/aggs/moving_average.js +++ b/src/legacy/core_plugins/metrics/public/components/aggs/moving_average.js @@ -24,7 +24,6 @@ import AggSelect from './agg_select'; import MetricSelect from './metric_select'; import createChangeHandler from '../lib/create_change_handler'; import createSelectHandler from '../lib/create_select_handler'; -import createTextHandler from '../lib/create_text_handler'; import createNumberHandler from '../lib/create_number_handler'; import { htmlIdGenerator, @@ -34,57 +33,56 @@ import { EuiComboBox, EuiSpacer, EuiFormRow, - EuiCode, - EuiTextArea, } from '@elastic/eui'; import { injectI18n, FormattedMessage } from '@kbn/i18n/react'; +import { MODEL_OPTIONS } from '../../../common/model_options'; const MovingAverageAggUi = props => { - const { siblings, intl } = props; - const defaults = { - settings: '', - minimize: 0, - window: '', - model: 'simple' - }; - const model = { ...defaults, ...props.model }; + const { siblings, intl, model } = props; + const handleChange = createChangeHandler(props.onChange, model); const handleSelectChange = createSelectHandler(handleChange); - const handleTextChange = createTextHandler(handleChange); const handleNumberChange = createNumberHandler(handleChange); const modelOptions = [ { - label: intl.formatMessage({ id: 'tsvb.movingAverage.modelOptions.simpleLabel', defaultMessage: 'Simple' }), - value: 'simple' + label: intl.formatMessage({ + id: 'tsvb.movingAverage.modelOptions.simpleLabel', + defaultMessage: MODEL_OPTIONS.UNWEIGHTED.NAME, + }), + value: MODEL_OPTIONS.UNWEIGHTED.TYPE, }, { - label: intl.formatMessage({ id: 'tsvb.movingAverage.modelOptions.linearLabel', defaultMessage: 'Linear' }), - value: 'linear' + label: intl.formatMessage({ + id: 'tsvb.movingAverage.modelOptions.linearLabel', + defaultMessage: MODEL_OPTIONS.WEIGHTED_LINEAR.NAME, + }), + value: MODEL_OPTIONS.WEIGHTED_LINEAR.TYPE, }, { label: intl.formatMessage({ - id: 'tsvb.movingAverage.modelOptions.exponentiallyWeightedLabel', defaultMessage: 'Exponentially Weighted' }), - value: 'ewma' + id: 'tsvb.movingAverage.modelOptions.exponentiallyWeightedLabel', + defaultMessage: MODEL_OPTIONS.WEIGHTED_EXPONENTIAL.NAME, + }), + value: MODEL_OPTIONS.WEIGHTED_EXPONENTIAL.TYPE, }, { - label: intl.formatMessage({ id: 'tsvb.movingAverage.modelOptions.holtLinearLabel', defaultMessage: 'Holt-Linear' }), - value: 'holt' + label: intl.formatMessage({ + id: 'tsvb.movingAverage.modelOptions.holtLinearLabel', + defaultMessage: MODEL_OPTIONS.WEIGHTED_EXPONENTIAL_DOUBLE.NAME, + }), + value: MODEL_OPTIONS.WEIGHTED_EXPONENTIAL_DOUBLE.TYPE, }, { - label: intl.formatMessage({ id: 'tsvb.movingAverage.modelOptions.holtWintersLabel', defaultMessage: 'Holt-Winters' }), - value: 'holt_winters' + label: intl.formatMessage({ + id: 'tsvb.movingAverage.modelOptions.holtWintersLabel', + defaultMessage: MODEL_OPTIONS.WEIGHTED_EXPONENTIAL_TRIPLE.NAME, + }), + value: MODEL_OPTIONS.WEIGHTED_EXPONENTIAL_TRIPLE.TYPE, } ]; - const minimizeOptions = [ - { label: 'True', value: 1 }, - { label: 'False', value: 0 } - ]; const htmlId = htmlIdGenerator(); const selectedModelOption = modelOptions.find(option => { - return model.model === option.value; - }); - const selectedMinimizeOption = minimizeOptions.find(option => { - return model.minimize === option.value; + return (model.model_type || MODEL_OPTIONS.UNWEIGHTED.TYPE) === option.value; }); return ( @@ -135,7 +133,7 @@ const MovingAverageAggUi = props => { { placeholder={intl.formatMessage({ id: 'tsvb.movingAverage.model.selectPlaceholder', defaultMessage: 'Select' })} options={modelOptions} selectedOptions={selectedModelOption ? [selectedModelOption] : []} - onChange={handleSelectChange('model')} + onChange={handleSelectChange('model_type')} singleSelection={{ asPlainText: true }} /> @@ -171,72 +169,7 @@ const MovingAverageAggUi = props => { /> - - )} - > - - - - - )} - > - {/* - EUITODO: The following input couldn't be converted to EUI because of type mis-match. - Should it be text or number? - */} - - - - - - - - )} - helpText={ - - Key=Value) }} - /> - - } - > - - - ); }; diff --git a/src/legacy/core_plugins/metrics/server/lib/vis_data/helpers/bucket_transform.js b/src/legacy/core_plugins/metrics/server/lib/vis_data/helpers/bucket_transform.js index 14981bed44ed4..bc3aea19e0f8a 100644 --- a/src/legacy/core_plugins/metrics/server/lib/vis_data/helpers/bucket_transform.js +++ b/src/legacy/core_plugins/metrics/server/lib/vis_data/helpers/bucket_transform.js @@ -17,11 +17,11 @@ * under the License. */ -import parseSettings from './parse_settings'; import getBucketsPath from './get_buckets_path'; import { parseInterval } from './parse_interval'; import { set, isEmpty } from 'lodash'; import { i18n } from '@kbn/i18n'; +import { getModuleScript, MODEL_SCRIPTS, MODEL_OPTIONS } from '../../../../common/model_options'; function checkMetric(metric, fields) { fields.forEach(field => { @@ -205,20 +205,19 @@ export default { moving_average: (bucket, metrics) => { checkMetric(bucket, ['type', 'field']); + const body = { - moving_avg: { + moving_fn: { buckets_path: getBucketsPath(bucket.field, metrics), - model: bucket.model || 'simple', - gap_policy: 'skip', // seems sane + window: 10, + script: getModuleScript(bucket.model_type) || MODEL_SCRIPTS.get(MODEL_OPTIONS.UNWEIGHTED.TYPE), }, }; - if (bucket.gap_policy) body.moving_avg.gap_policy = bucket.gap_policy; - if (bucket.window) body.moving_avg.window = Number(bucket.window); - if (bucket.minimize) body.moving_avg.minimize = Boolean(bucket.minimize); - if (bucket.predict) body.moving_avg.predict = Number(bucket.predict); - if (bucket.settings) { - body.moving_avg.settings = parseSettings(bucket.settings); + + if (bucket.window) { + body.moving_fn.window = bucket.window; } + return body; }, From 23fd119212402942b68c497d188f4557b0a0080c Mon Sep 17 00:00:00 2001 From: Artyom Gospodarsky Date: Thu, 16 May 2019 18:03:33 +0300 Subject: [PATCH 02/20] Connect user scripting to models --- .../metrics/common/model_options.js | 58 ++++---- .../public/components/aggs/moving_average.js | 135 +++++++++++++++--- .../lib/vis_data/helpers/bucket_transform.js | 14 +- 3 files changed, 145 insertions(+), 62 deletions(-) diff --git a/src/legacy/core_plugins/metrics/common/model_options.js b/src/legacy/core_plugins/metrics/common/model_options.js index c1847a48bad61..9bb6a0a1e7bef 100644 --- a/src/legacy/core_plugins/metrics/common/model_options.js +++ b/src/legacy/core_plugins/metrics/common/model_options.js @@ -17,39 +17,29 @@ * under the License. */ -export const MODEL_OPTIONS = { - UNWEIGHTED: { - NAME: 'Simple', - TYPE: 'simple', - }, - WEIGHTED_EXPONENTIAL: { - NAME: 'Exponentially Weighted', - TYPE: 'ewma', - }, - WEIGHTED_EXPONENTIAL_DOUBLE: { - NAME: 'Holt-Linear', - TYPE: 'holt', - }, - WEIGHTED_EXPONENTIAL_TRIPLE: { - NAME: 'Holt-Winters', - TYPE: 'holt_winters', - }, - WEIGHTED_LINEAR: { - NAME: 'Linear', - TYPE: 'linear', - }, +export const MODEL_TYPES = { + UNWEIGHTED: 'simple', + WEIGHTED_EXPONENTIAL: 'ewma', + WEIGHTED_EXPONENTIAL_DOUBLE: 'holt', + WEIGHTED_EXPONENTIAL_TRIPLE: 'holt_winters', + WEIGHTED_LINEAR: 'linear', }; -const MODEL_SCRIPTS = new Map(); - -MODEL_SCRIPTS.set(MODEL_OPTIONS.UNWEIGHTED.TYPE, 'MovingFunctions.unweightedAvg(values)'); -MODEL_SCRIPTS.set(MODEL_OPTIONS.WEIGHTED_EXPONENTIAL.TYPE, 'MovingFunctions.ewma(values)'); -MODEL_SCRIPTS.set(MODEL_OPTIONS.WEIGHTED_EXPONENTIAL_DOUBLE.TYPE, 'MovingFunctions.holt(values)'); -MODEL_SCRIPTS.set(MODEL_OPTIONS.WEIGHTED_EXPONENTIAL_TRIPLE.TYPE, 'MovingFunctions.holtWinters(values)'); -MODEL_SCRIPTS.set(MODEL_OPTIONS.WEIGHTED_LINEAR.TYPE, 'MovingFunctions.linearWeightedAvg(values)'); - -export function getModuleScript(type) { - return MODEL_SCRIPTS.get(type); -} - -export { MODEL_SCRIPTS }; +export const MODEL_SCRIPTS = { + [MODEL_TYPES.UNWEIGHTED]: () => 'MovingFunctions.unweightedAvg(values)', + [MODEL_TYPES.WEIGHTED_EXPONENTIAL]: ({ + alpha + }) => `MovingFunctions.ewma(values, ${alpha})`, + [MODEL_TYPES.WEIGHTED_EXPONENTIAL_DOUBLE]: ({ + alpha, + beta + }) => `MovingFunctions.holt(values, ${alpha}, ${beta})`, + [MODEL_TYPES.WEIGHTED_EXPONENTIAL_TRIPLE]: ({ + alpha, + beta, + gamma, + period, + multiplicative + }) => `if (values.length > ${period}*2) {MovingFunctions.holtWinters(values, ${alpha}, ${beta}, ${gamma}, ${period}, ${multiplicative})}`, + [MODEL_TYPES.WEIGHTED_LINEAR]: () => 'MovingFunctions.linearWeightedAvg(values)', +}; diff --git a/src/legacy/core_plugins/metrics/public/components/aggs/moving_average.js b/src/legacy/core_plugins/metrics/public/components/aggs/moving_average.js index 484058f06f323..4a73f4e785ff1 100644 --- a/src/legacy/core_plugins/metrics/public/components/aggs/moving_average.js +++ b/src/legacy/core_plugins/metrics/public/components/aggs/moving_average.js @@ -33,57 +33,75 @@ import { EuiComboBox, EuiSpacer, EuiFormRow, + EuiFieldNumber, } from '@elastic/eui'; import { injectI18n, FormattedMessage } from '@kbn/i18n/react'; -import { MODEL_OPTIONS } from '../../../common/model_options'; +import { MODEL_TYPES } from '../../../common/model_options'; + +const DEFAULTS = { + model_type: MODEL_TYPES.UNWEIGHTED, + alpha: 0.3, + beta: 0.1, + gamma: 0.1, + period: 5, + multiplicative: true, + window: 10, +}; const MovingAverageAggUi = props => { - const { siblings, intl, model } = props; + const { siblings, intl } = props; - const handleChange = createChangeHandler(props.onChange, model); - const handleSelectChange = createSelectHandler(handleChange); - const handleNumberChange = createNumberHandler(handleChange); + const model = { ...DEFAULTS, ...props.model }; const modelOptions = [ { label: intl.formatMessage({ id: 'tsvb.movingAverage.modelOptions.simpleLabel', - defaultMessage: MODEL_OPTIONS.UNWEIGHTED.NAME, + defaultMessage: 'Simple', }), - value: MODEL_OPTIONS.UNWEIGHTED.TYPE, + value: MODEL_TYPES.UNWEIGHTED, }, { label: intl.formatMessage({ id: 'tsvb.movingAverage.modelOptions.linearLabel', - defaultMessage: MODEL_OPTIONS.WEIGHTED_LINEAR.NAME, + defaultMessage: 'Linear', }), - value: MODEL_OPTIONS.WEIGHTED_LINEAR.TYPE, + value: MODEL_TYPES.WEIGHTED_LINEAR, }, { label: intl.formatMessage({ id: 'tsvb.movingAverage.modelOptions.exponentiallyWeightedLabel', - defaultMessage: MODEL_OPTIONS.WEIGHTED_EXPONENTIAL.NAME, + defaultMessage: 'Exponentially Weighted', }), - value: MODEL_OPTIONS.WEIGHTED_EXPONENTIAL.TYPE, + value: MODEL_TYPES.WEIGHTED_EXPONENTIAL, }, { label: intl.formatMessage({ id: 'tsvb.movingAverage.modelOptions.holtLinearLabel', - defaultMessage: MODEL_OPTIONS.WEIGHTED_EXPONENTIAL_DOUBLE.NAME, + defaultMessage: 'Holt-Linear', }), - value: MODEL_OPTIONS.WEIGHTED_EXPONENTIAL_DOUBLE.TYPE, + value: MODEL_TYPES.WEIGHTED_EXPONENTIAL_DOUBLE, }, { label: intl.formatMessage({ id: 'tsvb.movingAverage.modelOptions.holtWintersLabel', - defaultMessage: MODEL_OPTIONS.WEIGHTED_EXPONENTIAL_TRIPLE.NAME, + defaultMessage: 'Holt-Winters', }), - value: MODEL_OPTIONS.WEIGHTED_EXPONENTIAL_TRIPLE.TYPE, + value: MODEL_TYPES.WEIGHTED_EXPONENTIAL_TRIPLE, } ]; + + const handleChange = createChangeHandler(props.onChange, model); + const handleSelectChange = createSelectHandler(handleChange); + const handleNumberChange = createNumberHandler(handleChange); + const htmlId = htmlIdGenerator(); - const selectedModelOption = modelOptions.find(option => { - return (model.model_type || MODEL_OPTIONS.UNWEIGHTED.TYPE) === option.value; - }); + const selectedModelOption = modelOptions.find(({ value }) => model.model_type === value); + + const multiplicativeOptions = [ + { label: 'True', value: true }, + { label: 'False', value: false }, + ]; + const selectedMultiplicative = multiplicativeOptions.find(({ value }) => model.multiplicative === value); return ( { + + + + + + )} + > + + + + + )} + > + + + + + )} + > + + + + + )} + > + + + + + )} + > + + + + ); }; diff --git a/src/legacy/core_plugins/metrics/server/lib/vis_data/helpers/bucket_transform.js b/src/legacy/core_plugins/metrics/server/lib/vis_data/helpers/bucket_transform.js index bc3aea19e0f8a..ebc7860af14c2 100644 --- a/src/legacy/core_plugins/metrics/server/lib/vis_data/helpers/bucket_transform.js +++ b/src/legacy/core_plugins/metrics/server/lib/vis_data/helpers/bucket_transform.js @@ -21,7 +21,7 @@ import getBucketsPath from './get_buckets_path'; import { parseInterval } from './parse_interval'; import { set, isEmpty } from 'lodash'; import { i18n } from '@kbn/i18n'; -import { getModuleScript, MODEL_SCRIPTS, MODEL_OPTIONS } from '../../../../common/model_options'; +import { MODEL_SCRIPTS } from '../../../../common/model_options'; function checkMetric(metric, fields) { fields.forEach(field => { @@ -206,19 +206,13 @@ export default { moving_average: (bucket, metrics) => { checkMetric(bucket, ['type', 'field']); - const body = { + return { moving_fn: { buckets_path: getBucketsPath(bucket.field, metrics), - window: 10, - script: getModuleScript(bucket.model_type) || MODEL_SCRIPTS.get(MODEL_OPTIONS.UNWEIGHTED.TYPE), + window: bucket.window, + script: MODEL_SCRIPTS[bucket.model_type](bucket), }, }; - - if (bucket.window) { - body.moving_fn.window = bucket.window; - } - - return body; }, calculation: (bucket, metrics, bucketSize) => { From f7d01818c43cdcb56a5f157ffd32dd5e9c806351 Mon Sep 17 00:00:00 2001 From: Artyom Gospodarsky Date: Fri, 17 May 2019 12:03:53 +0300 Subject: [PATCH 03/20] Add inputs to the panel for managing alpha, beta, gamma params --- .../public/components/aggs/moving_average.js | 195 +++++++++++------- 1 file changed, 115 insertions(+), 80 deletions(-) diff --git a/src/legacy/core_plugins/metrics/public/components/aggs/moving_average.js b/src/legacy/core_plugins/metrics/public/components/aggs/moving_average.js index 4a73f4e785ff1..244c8b6ea26d5 100644 --- a/src/legacy/core_plugins/metrics/public/components/aggs/moving_average.js +++ b/src/legacy/core_plugins/metrics/public/components/aggs/moving_average.js @@ -18,7 +18,7 @@ */ import PropTypes from 'prop-types'; -import React from 'react'; +import React, { Fragment } from 'react'; import AggRow from './agg_row'; import AggSelect from './agg_select'; import MetricSelect from './metric_select'; @@ -189,86 +189,121 @@ const MovingAverageAggUi = props => { - + { + ( + model.model_type === MODEL_TYPES.WEIGHTED_EXPONENTIAL || + model.model_type === MODEL_TYPES.WEIGHTED_EXPONENTIAL_DOUBLE || + model.model_type === MODEL_TYPES.WEIGHTED_EXPONENTIAL_TRIPLE + ) && ( + + - - - )} - > - - - - - )} - > - - - - - )} - > - - - - - )} - > - - - - - )} - > - - - - + + { + ( + model.model_type === MODEL_TYPES.WEIGHTED_EXPONENTIAL || + model.model_type === MODEL_TYPES.WEIGHTED_EXPONENTIAL_DOUBLE || + model.model_type === MODEL_TYPES.WEIGHTED_EXPONENTIAL_TRIPLE + ) && ( + + )} + > + + + + ) + } + { + ( + model.model_type === MODEL_TYPES.WEIGHTED_EXPONENTIAL_DOUBLE || + model.model_type === MODEL_TYPES.WEIGHTED_EXPONENTIAL_TRIPLE + ) && ( + + )} + > + + + + ) + } + { + model.model_type === MODEL_TYPES.WEIGHTED_EXPONENTIAL_TRIPLE && ( + + + )} + > + + + + + )} + > + + + + + )} + > + + + + + ) + } + + + ) + } ); }; From fa139aedb19bc30563952559038b51af7a79ade8 Mon Sep 17 00:00:00 2001 From: Artyom Gospodarsky Date: Fri, 17 May 2019 12:22:08 +0300 Subject: [PATCH 04/20] Cover model types and scripts by tests --- .../__snapshots__/model_options.test.js.snap | 11 +++ .../metrics/common/model_options.test.js | 90 +++++++++++++++++++ 2 files changed, 101 insertions(+) create mode 100644 src/legacy/core_plugins/metrics/common/__snapshots__/model_options.test.js.snap create mode 100644 src/legacy/core_plugins/metrics/common/model_options.test.js diff --git a/src/legacy/core_plugins/metrics/common/__snapshots__/model_options.test.js.snap b/src/legacy/core_plugins/metrics/common/__snapshots__/model_options.test.js.snap new file mode 100644 index 0000000000000..0fca2a017b911 --- /dev/null +++ b/src/legacy/core_plugins/metrics/common/__snapshots__/model_options.test.js.snap @@ -0,0 +1,11 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`src/legacy/core_plugins/metrics/common/model_options.js MODEL_TYPES should match a snapshot of constants 1`] = ` +Object { + "UNWEIGHTED": "simple", + "WEIGHTED_EXPONENTIAL": "ewma", + "WEIGHTED_EXPONENTIAL_DOUBLE": "holt", + "WEIGHTED_EXPONENTIAL_TRIPLE": "holt_winters", + "WEIGHTED_LINEAR": "linear", +} +`; diff --git a/src/legacy/core_plugins/metrics/common/model_options.test.js b/src/legacy/core_plugins/metrics/common/model_options.test.js new file mode 100644 index 0000000000000..73a344d0312d8 --- /dev/null +++ b/src/legacy/core_plugins/metrics/common/model_options.test.js @@ -0,0 +1,90 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { MODEL_TYPES, MODEL_SCRIPTS } from './model_options'; + +describe('src/legacy/core_plugins/metrics/common/model_options.js', () => { + describe('MODEL_TYPES', () => { + test('should match a snapshot of constants', () => { + expect(MODEL_TYPES).toMatchSnapshot(); + }); + }); + + describe('MODEL_SCRIPTS', () => { + let bucket; + + beforeEach(() => { + bucket = { + alpha: 0.1, + beta: 0.2, + gamma: 0.3, + period: 5, + multiplicative: true, + }; + }); + + test('should return an expected result of the UNWEIGHTED model type', () => { + expect(MODEL_SCRIPTS[MODEL_TYPES.UNWEIGHTED](bucket)).toBe('MovingFunctions.unweightedAvg(values)'); + }); + + test('should return an expected result of the WEIGHTED_LINEAR model type', () => { + expect(MODEL_SCRIPTS[MODEL_TYPES.WEIGHTED_LINEAR](bucket)).toBe('MovingFunctions.linearWeightedAvg(values)'); + }); + + test('should return an expected result of the WEIGHTED_EXPONENTIAL model type', () => { + const { alpha } = bucket; + + expect(MODEL_SCRIPTS[MODEL_TYPES.WEIGHTED_EXPONENTIAL](bucket)).toBe(`MovingFunctions.ewma(values, ${alpha})`); + }); + + test('should return an expected result of the WEIGHTED_EXPONENTIAL_DOUBLE model type', () => { + const { alpha, beta } = bucket; + + expect(MODEL_SCRIPTS[MODEL_TYPES.WEIGHTED_EXPONENTIAL_DOUBLE](bucket)).toBe(`MovingFunctions.holt(values, ${alpha}, ${beta})`); + }); + + test('should return an expected result of the WEIGHTED_EXPONENTIAL_TRIPLE model type', () => { + const { alpha, beta, gamma, period, multiplicative } = bucket; + + expect(MODEL_SCRIPTS[MODEL_TYPES.WEIGHTED_EXPONENTIAL_TRIPLE](bucket)).toBe( + `if (values.length > ${period}*2) {MovingFunctions.holtWinters(values, ${alpha}, ${beta}, ${gamma}, ${period}, ${multiplicative})}` + ); + }); + }); +}); + From 5a55fd44815c145e72d66779fcd8399c733932dd Mon Sep 17 00:00:00 2001 From: Artyom Gospodarsky Date: Fri, 17 May 2019 13:12:25 +0300 Subject: [PATCH 05/20] Change default export of the bucket transform to the permanent one and write tests for moving_average --- .../__tests__/helpers/bucket_transform.js | 2 +- .../bucket_transform.test.js.snap | 11 +++ .../lib/vis_data/helpers/bucket_transform.js | 2 +- .../vis_data/helpers/bucket_transform.test.js | 87 +++++++++++++++++++ .../server/lib/vis_data/helpers/index.js | 2 +- .../series/filter_ratios.js | 2 +- .../series/metric_buckets.js | 2 +- .../series/sibling_buckets.js | 2 +- .../series/split_by_terms.js | 2 +- .../request_processors/table/filter_ratios.js | 2 +- .../table/metric_buckets.js | 2 +- .../request_processors/table/pivot.js | 2 +- .../table/sibling_buckets.js | 2 +- 13 files changed, 109 insertions(+), 11 deletions(-) create mode 100644 src/legacy/core_plugins/metrics/server/lib/vis_data/helpers/__snapshots__/bucket_transform.test.js.snap create mode 100644 src/legacy/core_plugins/metrics/server/lib/vis_data/helpers/bucket_transform.test.js diff --git a/src/legacy/core_plugins/metrics/server/lib/vis_data/__tests__/helpers/bucket_transform.js b/src/legacy/core_plugins/metrics/server/lib/vis_data/__tests__/helpers/bucket_transform.js index 3981af4e0c361..7de3244274277 100644 --- a/src/legacy/core_plugins/metrics/server/lib/vis_data/__tests__/helpers/bucket_transform.js +++ b/src/legacy/core_plugins/metrics/server/lib/vis_data/__tests__/helpers/bucket_transform.js @@ -18,7 +18,7 @@ */ import { expect } from 'chai'; -import bucketTransform from '../../helpers/bucket_transform'; +import { bucketTransform } from '../../helpers/bucket_transform'; describe('bucketTransform', () => { describe('count', () => { diff --git a/src/legacy/core_plugins/metrics/server/lib/vis_data/helpers/__snapshots__/bucket_transform.test.js.snap b/src/legacy/core_plugins/metrics/server/lib/vis_data/helpers/__snapshots__/bucket_transform.test.js.snap new file mode 100644 index 0000000000000..cb377871cee28 --- /dev/null +++ b/src/legacy/core_plugins/metrics/server/lib/vis_data/helpers/__snapshots__/bucket_transform.test.js.snap @@ -0,0 +1,11 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`src/legacy/core_plugins/metrics/server/lib/vis_data/helpers/bucket_transform.js bucketTransform moving_average should return a moving function aggregation API and match a snapshot 1`] = ` +Object { + "moving_fn": Object { + "buckets_path": "61ca57f2-469d-11e7-af02-69e470af7417", + "script": "if (values.length > 1*2) {MovingFunctions.holtWinters(values, 0.6, 0.3, 0.3, 1, true)}", + "window": 10, + }, +} +`; diff --git a/src/legacy/core_plugins/metrics/server/lib/vis_data/helpers/bucket_transform.js b/src/legacy/core_plugins/metrics/server/lib/vis_data/helpers/bucket_transform.js index ebc7860af14c2..54ca5c3bedb3f 100644 --- a/src/legacy/core_plugins/metrics/server/lib/vis_data/helpers/bucket_transform.js +++ b/src/legacy/core_plugins/metrics/server/lib/vis_data/helpers/bucket_transform.js @@ -63,7 +63,7 @@ function extendStatsBucket(bucket, metrics) { return body; } -export default { +export const bucketTransform = { count: () => { return { bucket_script: { diff --git a/src/legacy/core_plugins/metrics/server/lib/vis_data/helpers/bucket_transform.test.js b/src/legacy/core_plugins/metrics/server/lib/vis_data/helpers/bucket_transform.test.js new file mode 100644 index 0000000000000..b353ef8bc84fc --- /dev/null +++ b/src/legacy/core_plugins/metrics/server/lib/vis_data/helpers/bucket_transform.test.js @@ -0,0 +1,87 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { bucketTransform } from './bucket_transform'; + +describe('src/legacy/core_plugins/metrics/server/lib/vis_data/helpers/bucket_transform.js', () => { + describe('bucketTransform', () => { + let bucket; + let metrics; + + beforeEach(() => { + bucket = { + model_type: 'holt_winters', + alpha: 0.6, + beta: 0.3, + gamma: 0.3, + period: 1, + multiplicative: true, + window: 10, + field: '61ca57f2-469d-11e7-af02-69e470af7417', + id: 'e815ae00-7881-11e9-9392-cbca66a4cf76', + type: 'moving_average' + }; + metrics = [ + { + id: '61ca57f2-469d-11e7-af02-69e470af7417', + numerator: 'FlightDelay:true', + type: 'count' + }, + { + model_type: 'holt_winters', + alpha: 0.6, + beta: 0.3, + gamma: 0.3, + period: 1, + multiplicative: true, + window: 10, + field: '61ca57f2-469d-11e7-af02-69e470af7417', + id: 'e815ae00-7881-11e9-9392-cbca66a4cf76', + type: 'moving_average' + } + ]; + }); + + describe('moving_average', () => { + test('should return a moving function aggregation API and match a snapshot', () => { + expect(bucketTransform.moving_average(bucket, metrics)).toMatchSnapshot(); + }); + }); + }); +}); + diff --git a/src/legacy/core_plugins/metrics/server/lib/vis_data/helpers/index.js b/src/legacy/core_plugins/metrics/server/lib/vis_data/helpers/index.js index 01df1a6f54acd..1fc9ba412583e 100644 --- a/src/legacy/core_plugins/metrics/server/lib/vis_data/helpers/index.js +++ b/src/legacy/core_plugins/metrics/server/lib/vis_data/helpers/index.js @@ -17,7 +17,7 @@ * under the License. */ -import bucketTransform from './bucket_transform'; +import { bucketTransform } from './bucket_transform'; import getAggValue from './get_agg_value'; import getBucketSize from './get_bucket_size'; import getBucketPath from './get_buckets_path'; diff --git a/src/legacy/core_plugins/metrics/server/lib/vis_data/request_processors/series/filter_ratios.js b/src/legacy/core_plugins/metrics/server/lib/vis_data/request_processors/series/filter_ratios.js index 8b8ccd24ba380..b2ddf191ed05d 100644 --- a/src/legacy/core_plugins/metrics/server/lib/vis_data/request_processors/series/filter_ratios.js +++ b/src/legacy/core_plugins/metrics/server/lib/vis_data/request_processors/series/filter_ratios.js @@ -19,7 +19,7 @@ /* eslint max-len:0 */ const filter = metric => metric.type === 'filter_ratio'; -import bucketTransform from '../../helpers/bucket_transform'; +import { bucketTransform } from '../../helpers/bucket_transform'; import _ from 'lodash'; export default function ratios(req, panel, series) { return next => doc => { diff --git a/src/legacy/core_plugins/metrics/server/lib/vis_data/request_processors/series/metric_buckets.js b/src/legacy/core_plugins/metrics/server/lib/vis_data/request_processors/series/metric_buckets.js index 19aad8f37d825..971d6f27451d4 100644 --- a/src/legacy/core_plugins/metrics/server/lib/vis_data/request_processors/series/metric_buckets.js +++ b/src/legacy/core_plugins/metrics/server/lib/vis_data/request_processors/series/metric_buckets.js @@ -19,7 +19,7 @@ import _ from 'lodash'; import getBucketSize from '../../helpers/get_bucket_size'; -import bucketTransform from '../../helpers/bucket_transform'; +import { bucketTransform } from '../../helpers/bucket_transform'; import getIntervalAndTimefield from '../../get_interval_and_timefield'; export default function metricBuckets(req, panel, series, esQueryConfig, indexPatternObject, capabilities) { return next => doc => { diff --git a/src/legacy/core_plugins/metrics/server/lib/vis_data/request_processors/series/sibling_buckets.js b/src/legacy/core_plugins/metrics/server/lib/vis_data/request_processors/series/sibling_buckets.js index 351ff2bf27f62..1aa30b0a1ec25 100644 --- a/src/legacy/core_plugins/metrics/server/lib/vis_data/request_processors/series/sibling_buckets.js +++ b/src/legacy/core_plugins/metrics/server/lib/vis_data/request_processors/series/sibling_buckets.js @@ -19,7 +19,7 @@ import _ from 'lodash'; import getBucketSize from '../../helpers/get_bucket_size'; -import bucketTransform from '../../helpers/bucket_transform'; +import { bucketTransform } from '../../helpers/bucket_transform'; import getIntervalAndTimefield from '../../get_interval_and_timefield'; export default function siblingBuckets(req, panel, series, esQueryConfig, indexPatternObject, capabilities) { return next => doc => { diff --git a/src/legacy/core_plugins/metrics/server/lib/vis_data/request_processors/series/split_by_terms.js b/src/legacy/core_plugins/metrics/server/lib/vis_data/request_processors/series/split_by_terms.js index 6ee9b801cf6fa..1caa71b791c7b 100644 --- a/src/legacy/core_plugins/metrics/server/lib/vis_data/request_processors/series/split_by_terms.js +++ b/src/legacy/core_plugins/metrics/server/lib/vis_data/request_processors/series/split_by_terms.js @@ -20,7 +20,7 @@ import { set } from 'lodash'; import basicAggs from '../../../../../common/basic_aggs'; import getBucketsPath from '../../helpers/get_buckets_path'; -import bucketTransform from '../../helpers/bucket_transform'; +import { bucketTransform } from '../../helpers/bucket_transform'; export default function splitByTerm(req, panel, series) { return next => doc => { diff --git a/src/legacy/core_plugins/metrics/server/lib/vis_data/request_processors/table/filter_ratios.js b/src/legacy/core_plugins/metrics/server/lib/vis_data/request_processors/table/filter_ratios.js index ef4bf22e14c0f..f69070c09d509 100644 --- a/src/legacy/core_plugins/metrics/server/lib/vis_data/request_processors/table/filter_ratios.js +++ b/src/legacy/core_plugins/metrics/server/lib/vis_data/request_processors/table/filter_ratios.js @@ -19,7 +19,7 @@ /* eslint max-len:0 */ const filter = metric => metric.type === 'filter_ratio'; -import bucketTransform from '../../helpers/bucket_transform'; +import { bucketTransform } from '../../helpers/bucket_transform'; import _ from 'lodash'; import { calculateAggRoot } from './calculate_agg_root'; export default function ratios(req, panel) { diff --git a/src/legacy/core_plugins/metrics/server/lib/vis_data/request_processors/table/metric_buckets.js b/src/legacy/core_plugins/metrics/server/lib/vis_data/request_processors/table/metric_buckets.js index 082ff319b5ee4..f056c4b45c06e 100644 --- a/src/legacy/core_plugins/metrics/server/lib/vis_data/request_processors/table/metric_buckets.js +++ b/src/legacy/core_plugins/metrics/server/lib/vis_data/request_processors/table/metric_buckets.js @@ -19,7 +19,7 @@ import _ from 'lodash'; import getBucketSize from '../../helpers/get_bucket_size'; -import bucketTransform from '../../helpers/bucket_transform'; +import { bucketTransform } from '../../helpers/bucket_transform'; import getIntervalAndTimefield from '../../get_interval_and_timefield'; import { calculateAggRoot } from './calculate_agg_root'; export default function metricBuckets(req, panel) { diff --git a/src/legacy/core_plugins/metrics/server/lib/vis_data/request_processors/table/pivot.js b/src/legacy/core_plugins/metrics/server/lib/vis_data/request_processors/table/pivot.js index c3563d636a19b..0cb4fb22bbd1d 100644 --- a/src/legacy/core_plugins/metrics/server/lib/vis_data/request_processors/table/pivot.js +++ b/src/legacy/core_plugins/metrics/server/lib/vis_data/request_processors/table/pivot.js @@ -21,7 +21,7 @@ import { get, set, last } from 'lodash'; import basicAggs from '../../../../../common/basic_aggs'; import getBucketsPath from '../../helpers/get_buckets_path'; -import bucketTransform from '../../helpers/bucket_transform'; +import { bucketTransform } from '../../helpers/bucket_transform'; export default function pivot(req, panel) { return next => doc => { diff --git a/src/legacy/core_plugins/metrics/server/lib/vis_data/request_processors/table/sibling_buckets.js b/src/legacy/core_plugins/metrics/server/lib/vis_data/request_processors/table/sibling_buckets.js index 9cd1af9898053..8f16b22615f58 100644 --- a/src/legacy/core_plugins/metrics/server/lib/vis_data/request_processors/table/sibling_buckets.js +++ b/src/legacy/core_plugins/metrics/server/lib/vis_data/request_processors/table/sibling_buckets.js @@ -19,7 +19,7 @@ import _ from 'lodash'; import getBucketSize from '../../helpers/get_bucket_size'; -import bucketTransform from '../../helpers/bucket_transform'; +import { bucketTransform } from '../../helpers/bucket_transform'; import getIntervalAndTimefield from '../../get_interval_and_timefield'; import { calculateAggRoot } from './calculate_agg_root'; export default function siblingBuckets(req, panel) { From 18e79876965b509958db25dd36773401f266a4f7 Mon Sep 17 00:00:00 2001 From: Artyom Gospodarsky Date: Fri, 17 May 2019 17:29:58 +0300 Subject: [PATCH 06/20] Add a migration script from mov_avg to mov_fn --- src/legacy/core_plugins/kibana/migrations.js | 48 +++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) diff --git a/src/legacy/core_plugins/kibana/migrations.js b/src/legacy/core_plugins/kibana/migrations.js index 2ef85b9165b94..4fd6f2fd7078f 100644 --- a/src/legacy/core_plugins/kibana/migrations.js +++ b/src/legacy/core_plugins/kibana/migrations.js @@ -163,6 +163,51 @@ function removeDateHistogramTimeZones(doc) { return doc; } +function replaceMovAvgToMovFn(doc) { + const visState = get(doc, 'attributes.visState'); + let newVisState; + + if (visState) { + try { + newVisState = JSON.parse(visState); + } catch (e) { + // Let it go, the data is invalid and we'll leave it as is + } + + if (newVisState.type === 'metrics') { + const series = get(newVisState, 'params.series', []); + + series.forEach(part => { + (part.metrics || []).forEach(metric => { + if (metric.type === 'moving_average') { + metric.model_type = metric.model; + metric.alpha = 0.3; + metric.beta = 0.1; + metric.gamma = 0.1; + metric.period = 1; + metric.multiplicative = true; + + delete metric.minimize; + delete metric.model; + delete metric.settings; + delete metric.predict; + } + }); + }); + + return { + ...doc, + attributes: { + ...doc.attributes, + visState: JSON.stringify(newVisState), + }, + }; + } + } + + return doc; +} + export const migrations = { 'index-pattern': { '6.5.0': (doc) => { @@ -264,7 +309,8 @@ export const migrations = { } }, '7.0.1': removeDateHistogramTimeZones, - '7.1.0': doc => executeMigrations710(doc) + '7.1.0': doc => executeMigrations710(doc), + '7.2.0': replaceMovAvgToMovFn, }, dashboard: { '7.0.0': (doc) => { From cfe619d4a8474f41d584c3fecb223d3c8129d067 Mon Sep 17 00:00:00 2001 From: Artyom Gospodarsky Date: Mon, 20 May 2019 11:37:33 +0300 Subject: [PATCH 07/20] Remove redundant translations --- x-pack/plugins/translations/translations/zh-CN.json | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index bd7e86c25526d..68aff61571120 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -2883,8 +2883,6 @@ "tsvb.missingPanelConfigDescription": "缺少 “{modelType}” 的面板配置", "tsvb.movingAverage.aggregationLabel": "聚合", "tsvb.movingAverage.metricLabel": "指标", - "tsvb.movingAverage.minimize.selectPlaceholder": "选择", - "tsvb.movingAverage.minimizeLabel": "最小化", "tsvb.movingAverage.model.selectPlaceholder": "选择", "tsvb.movingAverage.modelLabel": "模型", "tsvb.movingAverage.modelOptions.exponentiallyWeightedLabel": "指数加权", @@ -2892,9 +2890,6 @@ "tsvb.movingAverage.modelOptions.holtWintersLabel": "Holt-Winters", "tsvb.movingAverage.modelOptions.linearLabel": "线性", "tsvb.movingAverage.modelOptions.simpleLabel": "简单", - "tsvb.movingAverage.predictLabel": "预测", - "tsvb.movingAverage.settingsDescription": "{keyValue} 空格分隔", - "tsvb.movingAverage.settingsLabel": "设置", "tsvb.movingAverage.windowSizeLabel": "窗口大小", "tsvb.noButtonLabel": "否", "tsvb.noDataDescription": "所选指标没有可显示的数据", @@ -7950,4 +7945,4 @@ "xpack.watcher.watchActionsTitle": "满足后将执行 {watchActionsCount, plural, one{# 个操作} other {# 个操作}}", "xpack.watcher.watcherDescription": "通过创建、管理和监测警报来检测数据中的更改。" } -} \ No newline at end of file +} From 6d5886597fa3993c5e5e69cd9e4585158aed4c55 Mon Sep 17 00:00:00 2001 From: Artyom Gospodarsky Date: Mon, 20 May 2019 12:30:21 +0300 Subject: [PATCH 08/20] Remove old tests --- .../__tests__/helpers/bucket_transform.js | 73 ------------------- 1 file changed, 73 deletions(-) diff --git a/src/legacy/core_plugins/metrics/server/lib/vis_data/__tests__/helpers/bucket_transform.js b/src/legacy/core_plugins/metrics/server/lib/vis_data/__tests__/helpers/bucket_transform.js index 7de3244274277..24ef1e6522d60 100644 --- a/src/legacy/core_plugins/metrics/server/lib/vis_data/__tests__/helpers/bucket_transform.js +++ b/src/legacy/core_plugins/metrics/server/lib/vis_data/__tests__/helpers/bucket_transform.js @@ -322,79 +322,6 @@ describe('bucketTransform', () => { }); }); - describe('moving_average', () => { - it('returns moving_average agg with defaults', () => { - const metric = { id: '2', type: 'moving_average', field: '1' }; - const metrics = [{ id: '1', type: 'avg', field: 'cpu.pct' }, metric]; - const fn = bucketTransform.moving_average; - expect(fn(metric, metrics, '10s')).is.eql({ - moving_avg: { - buckets_path: '1', - model: 'simple', - gap_policy: 'skip' - } - }); - }); - - it('returns moving_average agg with predict', () => { - const metric = { - id: '2', - type: 'moving_average', - field: '1', - predict: 10 - }; - const metrics = [{ id: '1', type: 'avg', field: 'cpu.pct' }, metric]; - const fn = bucketTransform.moving_average; - expect(fn(metric, metrics, '10s')).is.eql({ - moving_avg: { - buckets_path: '1', - model: 'simple', - gap_policy: 'skip', - predict: 10 - } - }); - }); - - it('returns moving_average agg with options', () => { - const metric = { - id: '2', - type: 'moving_average', - field: '1', - model: 'holt_winters', - window: 10, - minimize: 1, - settings: 'alpha=0.9 beta=0.5' - }; - const metrics = [{ id: '1', type: 'avg', field: 'cpu.pct' }, metric]; - const fn = bucketTransform.moving_average; - expect(fn(metric, metrics, '10s')).is.eql({ - moving_avg: { - buckets_path: '1', - model: 'holt_winters', - gap_policy: 'skip', - window: 10, - minimize: true, - settings: { - alpha: 0.9, - beta: 0.5 - } - } - }); - }); - - it('throws error if type is missing', () => { - const run = () => - bucketTransform.moving_average({ id: 'test', field: 'cpu.pct' }); - expect(run).to.throw(Error, 'Metric missing type'); - }); - - it('throws error if field is missing', () => { - const run = () => - bucketTransform.moving_average({ id: 'test', type: 'moving_average' }); - expect(run).to.throw(Error, 'Metric missing field'); - }); - }); - describe('calculation', () => { it('returns calculation(bucket_script)', () => { const metric = { From e726be56a4167935ae54b88afa199880ad707200 Mon Sep 17 00:00:00 2001 From: Artyom Gospodarsky Date: Tue, 21 May 2019 12:35:03 +0300 Subject: [PATCH 09/20] Fix issues of PR --- .../metrics/common/model_options.js | 19 ----- .../metrics/common/model_options.test.js | 44 +--------- .../public/components/aggs/moving_average.js | 60 +++++++------ .../lib/vis_data/helpers/bucket_transform.js | 2 +- .../lib/vis_data/helpers/moving_fn_scripts.js | 40 +++++++++ .../helpers/moving_fn_scripts.test.js | 85 +++++++++++++++++++ yarn.lock | 6 +- 7 files changed, 163 insertions(+), 93 deletions(-) create mode 100644 src/legacy/core_plugins/metrics/server/lib/vis_data/helpers/moving_fn_scripts.js create mode 100644 src/legacy/core_plugins/metrics/server/lib/vis_data/helpers/moving_fn_scripts.test.js diff --git a/src/legacy/core_plugins/metrics/common/model_options.js b/src/legacy/core_plugins/metrics/common/model_options.js index 9bb6a0a1e7bef..22fe7a0abc842 100644 --- a/src/legacy/core_plugins/metrics/common/model_options.js +++ b/src/legacy/core_plugins/metrics/common/model_options.js @@ -24,22 +24,3 @@ export const MODEL_TYPES = { WEIGHTED_EXPONENTIAL_TRIPLE: 'holt_winters', WEIGHTED_LINEAR: 'linear', }; - -export const MODEL_SCRIPTS = { - [MODEL_TYPES.UNWEIGHTED]: () => 'MovingFunctions.unweightedAvg(values)', - [MODEL_TYPES.WEIGHTED_EXPONENTIAL]: ({ - alpha - }) => `MovingFunctions.ewma(values, ${alpha})`, - [MODEL_TYPES.WEIGHTED_EXPONENTIAL_DOUBLE]: ({ - alpha, - beta - }) => `MovingFunctions.holt(values, ${alpha}, ${beta})`, - [MODEL_TYPES.WEIGHTED_EXPONENTIAL_TRIPLE]: ({ - alpha, - beta, - gamma, - period, - multiplicative - }) => `if (values.length > ${period}*2) {MovingFunctions.holtWinters(values, ${alpha}, ${beta}, ${gamma}, ${period}, ${multiplicative})}`, - [MODEL_TYPES.WEIGHTED_LINEAR]: () => 'MovingFunctions.linearWeightedAvg(values)', -}; diff --git a/src/legacy/core_plugins/metrics/common/model_options.test.js b/src/legacy/core_plugins/metrics/common/model_options.test.js index 73a344d0312d8..ec07108736d25 100644 --- a/src/legacy/core_plugins/metrics/common/model_options.test.js +++ b/src/legacy/core_plugins/metrics/common/model_options.test.js @@ -36,7 +36,7 @@ * under the License. */ -import { MODEL_TYPES, MODEL_SCRIPTS } from './model_options'; +import { MODEL_TYPES } from './model_options'; describe('src/legacy/core_plugins/metrics/common/model_options.js', () => { describe('MODEL_TYPES', () => { @@ -44,47 +44,5 @@ describe('src/legacy/core_plugins/metrics/common/model_options.js', () => { expect(MODEL_TYPES).toMatchSnapshot(); }); }); - - describe('MODEL_SCRIPTS', () => { - let bucket; - - beforeEach(() => { - bucket = { - alpha: 0.1, - beta: 0.2, - gamma: 0.3, - period: 5, - multiplicative: true, - }; - }); - - test('should return an expected result of the UNWEIGHTED model type', () => { - expect(MODEL_SCRIPTS[MODEL_TYPES.UNWEIGHTED](bucket)).toBe('MovingFunctions.unweightedAvg(values)'); - }); - - test('should return an expected result of the WEIGHTED_LINEAR model type', () => { - expect(MODEL_SCRIPTS[MODEL_TYPES.WEIGHTED_LINEAR](bucket)).toBe('MovingFunctions.linearWeightedAvg(values)'); - }); - - test('should return an expected result of the WEIGHTED_EXPONENTIAL model type', () => { - const { alpha } = bucket; - - expect(MODEL_SCRIPTS[MODEL_TYPES.WEIGHTED_EXPONENTIAL](bucket)).toBe(`MovingFunctions.ewma(values, ${alpha})`); - }); - - test('should return an expected result of the WEIGHTED_EXPONENTIAL_DOUBLE model type', () => { - const { alpha, beta } = bucket; - - expect(MODEL_SCRIPTS[MODEL_TYPES.WEIGHTED_EXPONENTIAL_DOUBLE](bucket)).toBe(`MovingFunctions.holt(values, ${alpha}, ${beta})`); - }); - - test('should return an expected result of the WEIGHTED_EXPONENTIAL_TRIPLE model type', () => { - const { alpha, beta, gamma, period, multiplicative } = bucket; - - expect(MODEL_SCRIPTS[MODEL_TYPES.WEIGHTED_EXPONENTIAL_TRIPLE](bucket)).toBe( - `if (values.length > ${period}*2) {MovingFunctions.holtWinters(values, ${alpha}, ${beta}, ${gamma}, ${period}, ${multiplicative})}` - ); - }); - }); }); diff --git a/src/legacy/core_plugins/metrics/public/components/aggs/moving_average.js b/src/legacy/core_plugins/metrics/public/components/aggs/moving_average.js index 244c8b6ea26d5..54b0f4c4188b8 100644 --- a/src/legacy/core_plugins/metrics/public/components/aggs/moving_average.js +++ b/src/legacy/core_plugins/metrics/public/components/aggs/moving_average.js @@ -40,10 +40,10 @@ import { MODEL_TYPES } from '../../../common/model_options'; const DEFAULTS = { model_type: MODEL_TYPES.UNWEIGHTED, - alpha: 0.3, - beta: 0.1, - gamma: 0.1, - period: 5, + alpha: 0, + beta: 0, + gamma: 0, + period: 1, multiplicative: true, window: 10, }; @@ -98,8 +98,20 @@ const MovingAverageAggUi = props => { const selectedModelOption = modelOptions.find(({ value }) => model.model_type === value); const multiplicativeOptions = [ - { label: 'True', value: true }, - { label: 'False', value: false }, + { + label: intl.formatMessage({ + id: 'tsvb.movingAverage.multiplicativeOptions.true', + defaultMessage: 'True', + }), + value: true + }, + { + label: intl.formatMessage({ + id: 'tsvb.movingAverage.multiplicativeOptions.false', + defaultMessage: 'False', + }), + value: false + }, ]; const selectedMultiplicative = multiplicativeOptions.find(({ value }) => model.multiplicative === value); @@ -200,27 +212,21 @@ const MovingAverageAggUi = props => { { - ( - model.model_type === MODEL_TYPES.WEIGHTED_EXPONENTIAL || - model.model_type === MODEL_TYPES.WEIGHTED_EXPONENTIAL_DOUBLE || - model.model_type === MODEL_TYPES.WEIGHTED_EXPONENTIAL_TRIPLE - ) && ( - - )} - > - - - - ) + + )} + > + + + } { ( diff --git a/src/legacy/core_plugins/metrics/server/lib/vis_data/helpers/bucket_transform.js b/src/legacy/core_plugins/metrics/server/lib/vis_data/helpers/bucket_transform.js index 54ca5c3bedb3f..ee5811a52fde0 100644 --- a/src/legacy/core_plugins/metrics/server/lib/vis_data/helpers/bucket_transform.js +++ b/src/legacy/core_plugins/metrics/server/lib/vis_data/helpers/bucket_transform.js @@ -21,7 +21,7 @@ import getBucketsPath from './get_buckets_path'; import { parseInterval } from './parse_interval'; import { set, isEmpty } from 'lodash'; import { i18n } from '@kbn/i18n'; -import { MODEL_SCRIPTS } from '../../../../common/model_options'; +import { MODEL_SCRIPTS } from './moving_fn_scripts'; function checkMetric(metric, fields) { fields.forEach(field => { diff --git a/src/legacy/core_plugins/metrics/server/lib/vis_data/helpers/moving_fn_scripts.js b/src/legacy/core_plugins/metrics/server/lib/vis_data/helpers/moving_fn_scripts.js new file mode 100644 index 0000000000000..eb7af73467dd6 --- /dev/null +++ b/src/legacy/core_plugins/metrics/server/lib/vis_data/helpers/moving_fn_scripts.js @@ -0,0 +1,40 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + + +import { MODEL_TYPES } from '../../../../common/model_options'; + +export const MODEL_SCRIPTS = { + [MODEL_TYPES.UNWEIGHTED]: () => 'MovingFunctions.unweightedAvg(values)', + [MODEL_TYPES.WEIGHTED_EXPONENTIAL]: ({ + alpha + }) => `MovingFunctions.ewma(values, ${alpha})`, + [MODEL_TYPES.WEIGHTED_EXPONENTIAL_DOUBLE]: ({ + alpha, + beta + }) => `MovingFunctions.holt(values, ${alpha}, ${beta})`, + [MODEL_TYPES.WEIGHTED_EXPONENTIAL_TRIPLE]: ({ + alpha, + beta, + gamma, + period, + multiplicative + }) => `if (values.length > ${period}*2) {MovingFunctions.holtWinters(values, ${alpha}, ${beta}, ${gamma}, ${period}, ${multiplicative})}`, + [MODEL_TYPES.WEIGHTED_LINEAR]: () => 'MovingFunctions.linearWeightedAvg(values)', +}; diff --git a/src/legacy/core_plugins/metrics/server/lib/vis_data/helpers/moving_fn_scripts.test.js b/src/legacy/core_plugins/metrics/server/lib/vis_data/helpers/moving_fn_scripts.test.js new file mode 100644 index 0000000000000..1810733013f44 --- /dev/null +++ b/src/legacy/core_plugins/metrics/server/lib/vis_data/helpers/moving_fn_scripts.test.js @@ -0,0 +1,85 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { MODEL_TYPES } from '../../../../common/model_options'; +import { MODEL_SCRIPTS } from './moving_fn_scripts'; + +describe('src/legacy/core_plugins/metrics/server/lib/vis_data/helpers/moving_fn_scripts.js', () => { + describe('MODEL_SCRIPTS', () => { + let bucket; + + beforeEach(() => { + bucket = { + alpha: 0.1, + beta: 0.2, + gamma: 0.3, + period: 5, + multiplicative: true, + }; + }); + + test('should return an expected result of the UNWEIGHTED model type', () => { + expect(MODEL_SCRIPTS[MODEL_TYPES.UNWEIGHTED](bucket)).toBe('MovingFunctions.unweightedAvg(values)'); + }); + + test('should return an expected result of the WEIGHTED_LINEAR model type', () => { + expect(MODEL_SCRIPTS[MODEL_TYPES.WEIGHTED_LINEAR](bucket)).toBe('MovingFunctions.linearWeightedAvg(values)'); + }); + + test('should return an expected result of the WEIGHTED_EXPONENTIAL model type', () => { + const { alpha } = bucket; + + expect(MODEL_SCRIPTS[MODEL_TYPES.WEIGHTED_EXPONENTIAL](bucket)).toBe(`MovingFunctions.ewma(values, ${alpha})`); + }); + + test('should return an expected result of the WEIGHTED_EXPONENTIAL_DOUBLE model type', () => { + const { alpha, beta } = bucket; + + expect(MODEL_SCRIPTS[MODEL_TYPES.WEIGHTED_EXPONENTIAL_DOUBLE](bucket)).toBe(`MovingFunctions.holt(values, ${alpha}, ${beta})`); + }); + + test('should return an expected result of the WEIGHTED_EXPONENTIAL_TRIPLE model type', () => { + const { alpha, beta, gamma, period, multiplicative } = bucket; + + expect(MODEL_SCRIPTS[MODEL_TYPES.WEIGHTED_EXPONENTIAL_TRIPLE](bucket)).toBe( + `if (values.length > ${period}*2) {MovingFunctions.holtWinters(values, ${alpha}, ${beta}, ${gamma}, ${period}, ${multiplicative})}` + ); + }); + }); +}); + diff --git a/yarn.lock b/yarn.lock index 2ecf502fa4698..ea83cfb132cea 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8457,9 +8457,9 @@ core-js@^2.5.3, core-js@^2.5.7: integrity sha512-RszJCAxg/PP6uzXVXL6BsxSXx/B05oJAQ2vkJRjyjrEcNVycaqOmNb5OTxZPE3xa5gwZduqza6L9JOCenh/Ecw== core-js@^2.6.5: - version "2.6.5" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.5.tgz#44bc8d249e7fb2ff5d00e0341a7ffb94fbf67895" - integrity sha512-klh/kDpwX8hryYL14M9w/xei6vrv6sE8gTHDG7/T/+SEovB/G4ejwcfE/CBzO6Edsu+OETZMZ3wcX/EjUkrl5A== + version "2.6.6" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.6.tgz#00eb6d6bf815471cc16d8563edd7d38786dec50b" + integrity sha512-Mt/LaAym54NXnrjEMdo918cT2h70tqb/Yl7T3uPHQHRm5SxVoqlKmerUy4mL11k8saSBDWQ7ULIHxmeFyT3pfg== core-util-is@1.0.2, core-util-is@~1.0.0: version "1.0.2" From 54f0009944a280783fad6865af9a901261361c83 Mon Sep 17 00:00:00 2001 From: Artyom Gospodarsky Date: Tue, 21 May 2019 12:40:35 +0300 Subject: [PATCH 10/20] Revert yarn.lock --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index ea83cfb132cea..2ecf502fa4698 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8457,9 +8457,9 @@ core-js@^2.5.3, core-js@^2.5.7: integrity sha512-RszJCAxg/PP6uzXVXL6BsxSXx/B05oJAQ2vkJRjyjrEcNVycaqOmNb5OTxZPE3xa5gwZduqza6L9JOCenh/Ecw== core-js@^2.6.5: - version "2.6.6" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.6.tgz#00eb6d6bf815471cc16d8563edd7d38786dec50b" - integrity sha512-Mt/LaAym54NXnrjEMdo918cT2h70tqb/Yl7T3uPHQHRm5SxVoqlKmerUy4mL11k8saSBDWQ7ULIHxmeFyT3pfg== + version "2.6.5" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.5.tgz#44bc8d249e7fb2ff5d00e0341a7ffb94fbf67895" + integrity sha512-klh/kDpwX8hryYL14M9w/xei6vrv6sE8gTHDG7/T/+SEovB/G4ejwcfE/CBzO6Edsu+OETZMZ3wcX/EjUkrl5A== core-util-is@1.0.2, core-util-is@~1.0.0: version "1.0.2" From 418d61b5cbfe6f660d3479094f6e92cfd3be8270 Mon Sep 17 00:00:00 2001 From: Artyom Gospodarsky Date: Tue, 21 May 2019 16:40:02 +0300 Subject: [PATCH 11/20] Fix issues regarding localization --- src/legacy/core_plugins/kibana/migrations.js | 6 +- .../public/components/aggs/moving_average.js | 99 ++++++++----------- 2 files changed, 43 insertions(+), 62 deletions(-) diff --git a/src/legacy/core_plugins/kibana/migrations.js b/src/legacy/core_plugins/kibana/migrations.js index 4fd6f2fd7078f..0d07e3d9ae025 100644 --- a/src/legacy/core_plugins/kibana/migrations.js +++ b/src/legacy/core_plugins/kibana/migrations.js @@ -181,9 +181,9 @@ function replaceMovAvgToMovFn(doc) { (part.metrics || []).forEach(metric => { if (metric.type === 'moving_average') { metric.model_type = metric.model; - metric.alpha = 0.3; - metric.beta = 0.1; - metric.gamma = 0.1; + metric.alpha = 0; + metric.beta = 0; + metric.gamma = 0; metric.period = 1; metric.multiplicative = true; diff --git a/src/legacy/core_plugins/metrics/public/components/aggs/moving_average.js b/src/legacy/core_plugins/metrics/public/components/aggs/moving_average.js index 54b0f4c4188b8..8baf44f517c6d 100644 --- a/src/legacy/core_plugins/metrics/public/components/aggs/moving_average.js +++ b/src/legacy/core_plugins/metrics/public/components/aggs/moving_average.js @@ -35,7 +35,7 @@ import { EuiFormRow, EuiFieldNumber, } from '@elastic/eui'; -import { injectI18n, FormattedMessage } from '@kbn/i18n/react'; +import { i18n } from '@kbn/i18n'; import { MODEL_TYPES } from '../../../common/model_options'; const DEFAULTS = { @@ -48,42 +48,37 @@ const DEFAULTS = { window: 10, }; -const MovingAverageAggUi = props => { - const { siblings, intl } = props; +export const MovingAverageAgg = props => { + const { siblings } = props; const model = { ...DEFAULTS, ...props.model }; const modelOptions = [ { - label: intl.formatMessage({ - id: 'tsvb.movingAverage.modelOptions.simpleLabel', + label: i18n.translate('tsvb.movingAverage.modelOptions.simpleLabel', { defaultMessage: 'Simple', }), value: MODEL_TYPES.UNWEIGHTED, }, { - label: intl.formatMessage({ - id: 'tsvb.movingAverage.modelOptions.linearLabel', + label: i18n.translate('tsvb.movingAverage.modelOptions.linearLabel', { defaultMessage: 'Linear', }), value: MODEL_TYPES.WEIGHTED_LINEAR, }, { - label: intl.formatMessage({ - id: 'tsvb.movingAverage.modelOptions.exponentiallyWeightedLabel', + label: i18n.translate('tsvb.movingAverage.modelOptions.exponentiallyWeightedLabel', { defaultMessage: 'Exponentially Weighted', }), value: MODEL_TYPES.WEIGHTED_EXPONENTIAL, }, { - label: intl.formatMessage({ - id: 'tsvb.movingAverage.modelOptions.holtLinearLabel', + label: i18n.translate('tsvb.movingAverage.modelOptions.holtLinearLabel', { defaultMessage: 'Holt-Linear', }), value: MODEL_TYPES.WEIGHTED_EXPONENTIAL_DOUBLE, }, { - label: intl.formatMessage({ - id: 'tsvb.movingAverage.modelOptions.holtWintersLabel', + label: i18n.translate('tsvb.movingAverage.modelOptions.holtWintersLabel', { defaultMessage: 'Holt-Winters', }), value: MODEL_TYPES.WEIGHTED_EXPONENTIAL_TRIPLE, @@ -99,15 +94,13 @@ const MovingAverageAggUi = props => { const multiplicativeOptions = [ { - label: intl.formatMessage({ - id: 'tsvb.movingAverage.multiplicativeOptions.true', + label: i18n.translate('tsvb.movingAverage.multiplicativeOptions.true', { defaultMessage: 'True', }), value: true }, { - label: intl.formatMessage({ - id: 'tsvb.movingAverage.multiplicativeOptions.false', + label: i18n.translate('tsvb.movingAverage.multiplicativeOptions.false', { defaultMessage: 'False', }), value: false @@ -127,10 +120,9 @@ const MovingAverageAggUi = props => { - + {i18n.translate('tsvb.movingAverage.aggregationLabel', { + defaultMessage: 'Aggregation', + })} { )} + label={i18n.translate('tsvb.movingAverage.metricLabel', { + defaultMessage: 'Metric', + })} > { )} + label={i18n.translate('tsvb.movingAverage.modelLabel', { + defaultMessage: 'Model', + })} > { )} + label={i18n.translate('tsvb.movingAverage.windowSizeLabel', { + defaultMessage: 'Window Size', + })} > {/* EUITODO: The following input couldn't be converted to EUI because of type mis-match. @@ -215,10 +204,9 @@ const MovingAverageAggUi = props => { )} + label={i18n.translate('tsvb.movingAverage.alpha', { + defaultMessage: 'Alpha', + })} > { )} + label={i18n.translate('tsvb.movingAverage.beta', { + defaultMessage: 'Beta', + })} > { )} + label={i18n.translate('tsvb.movingAverage.gamma', { + defaultMessage: 'Gamma', + })} > { )} + label={i18n.translate('tsvb.movingAverage.period', { + defaultMessage: 'Period (days)', + })} > { )} + label={i18n.translate('tsvb.movingAverage.multiplicative', { + defaultMessage: 'Multiplicative', + })} > { ); }; -MovingAverageAggUi.propTypes = { +MovingAverageAgg.propTypes = { disableDelete: PropTypes.bool, fields: PropTypes.object, model: PropTypes.object, @@ -325,5 +308,3 @@ MovingAverageAggUi.propTypes = { series: PropTypes.object, siblings: PropTypes.array, }; - -export const MovingAverageAgg = injectI18n(MovingAverageAggUi); From f4b2dc436370002e9fcde84a7c0cecd6def4ed9d Mon Sep 17 00:00:00 2001 From: Artyom Gospodarsky Date: Wed, 22 May 2019 17:34:58 +0300 Subject: [PATCH 12/20] Remove extra license --- .../metrics/common/model_options.test.js | 19 ------------------- .../vis_data/helpers/bucket_transform.test.js | 19 ------------------- .../helpers/moving_fn_scripts.test.js | 19 ------------------- 3 files changed, 57 deletions(-) diff --git a/src/legacy/core_plugins/metrics/common/model_options.test.js b/src/legacy/core_plugins/metrics/common/model_options.test.js index ec07108736d25..6d1f62c1b3e48 100644 --- a/src/legacy/core_plugins/metrics/common/model_options.test.js +++ b/src/legacy/core_plugins/metrics/common/model_options.test.js @@ -17,25 +17,6 @@ * under the License. */ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - import { MODEL_TYPES } from './model_options'; describe('src/legacy/core_plugins/metrics/common/model_options.js', () => { diff --git a/src/legacy/core_plugins/metrics/server/lib/vis_data/helpers/bucket_transform.test.js b/src/legacy/core_plugins/metrics/server/lib/vis_data/helpers/bucket_transform.test.js index b353ef8bc84fc..24d02ff5d1270 100644 --- a/src/legacy/core_plugins/metrics/server/lib/vis_data/helpers/bucket_transform.test.js +++ b/src/legacy/core_plugins/metrics/server/lib/vis_data/helpers/bucket_transform.test.js @@ -17,25 +17,6 @@ * under the License. */ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - import { bucketTransform } from './bucket_transform'; describe('src/legacy/core_plugins/metrics/server/lib/vis_data/helpers/bucket_transform.js', () => { diff --git a/src/legacy/core_plugins/metrics/server/lib/vis_data/helpers/moving_fn_scripts.test.js b/src/legacy/core_plugins/metrics/server/lib/vis_data/helpers/moving_fn_scripts.test.js index 1810733013f44..1d269d999b883 100644 --- a/src/legacy/core_plugins/metrics/server/lib/vis_data/helpers/moving_fn_scripts.test.js +++ b/src/legacy/core_plugins/metrics/server/lib/vis_data/helpers/moving_fn_scripts.test.js @@ -17,25 +17,6 @@ * under the License. */ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - import { MODEL_TYPES } from '../../../../common/model_options'; import { MODEL_SCRIPTS } from './moving_fn_scripts'; From be1701c1a9dd6e66dee9fbb9f5d5c447171a8ad5 Mon Sep 17 00:00:00 2001 From: Artyom Gospodarsky Date: Thu, 23 May 2019 15:27:27 +0300 Subject: [PATCH 13/20] Remove redundant translations --- x-pack/plugins/translations/translations/ja-JP.json | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 36dca19b37081..50051bf777d74 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -3342,8 +3342,6 @@ "tsvb.missingPanelConfigDescription": "「{modelType}」にパネル構成が欠けています", "tsvb.movingAverage.aggregationLabel": "集約", "tsvb.movingAverage.metricLabel": "メトリック", - "tsvb.movingAverage.minimize.selectPlaceholder": "選択", - "tsvb.movingAverage.minimizeLabel": "最小化", "tsvb.movingAverage.model.selectPlaceholder": "選択", "tsvb.movingAverage.modelLabel": "モデル", "tsvb.movingAverage.modelOptions.exponentiallyWeightedLabel": "指数加重", @@ -3351,9 +3349,6 @@ "tsvb.movingAverage.modelOptions.holtWintersLabel": "Holt-Winters", "tsvb.movingAverage.modelOptions.linearLabel": "直線", "tsvb.movingAverage.modelOptions.simpleLabel": "シンプル", - "tsvb.movingAverage.predictLabel": "予想", - "tsvb.movingAverage.settingsDescription": "{keyValue} スペース区切り", - "tsvb.movingAverage.settingsLabel": "設定", "tsvb.movingAverage.windowSizeLabel": "ウィンドウサイズ", "tsvb.multivalueRow.valueLabel": "値:", "tsvb.noButtonLabel": "いいえ", @@ -10036,4 +10031,4 @@ "xpack.watcher.watchActionsTitle": "条件が満たされた際に {watchActionsCount, plural, one{# アクション} other {# アクション}} を実行します", "xpack.watcher.watcherDescription": "アラートの作成、管理、監視によりデータへの変更を検知します。" } -} \ No newline at end of file +} From 82bee4e9eaa3a3ebaaf84fc0a93c612340805927 Mon Sep 17 00:00:00 2001 From: Artyom Gospodarsky Date: Fri, 24 May 2019 11:09:00 +0300 Subject: [PATCH 14/20] Move the replaceMovAvgToMovFn hook to 7.3.0 --- src/legacy/core_plugins/kibana/migrations.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/legacy/core_plugins/kibana/migrations.js b/src/legacy/core_plugins/kibana/migrations.js index 375ed45aa81f3..63db394915506 100644 --- a/src/legacy/core_plugins/kibana/migrations.js +++ b/src/legacy/core_plugins/kibana/migrations.js @@ -134,7 +134,7 @@ const migrateDateHistogramAggregation = doc => { return doc; }; -const executeMigrations720 = flow(migratePercentileRankAggregation, migrateDateHistogramAggregation, replaceMovAvgToMovFn); +const executeMigrations720 = flow(migratePercentileRankAggregation, migrateDateHistogramAggregation); function removeDateHistogramTimeZones(doc) { const visStateJSON = get(doc, 'attributes.visState'); @@ -310,6 +310,7 @@ export const migrations = { }, '7.0.1': removeDateHistogramTimeZones, '7.2.0': doc => executeMigrations720(doc), + '7.3.0': replaceMovAvgToMovFn, }, dashboard: { '7.0.0': (doc) => { From d7498ce4e659a85b34e7093eb4a4192b08a81b47 Mon Sep 17 00:00:00 2001 From: Artyom Gospodarsky Date: Thu, 6 Jun 2019 16:54:26 +0300 Subject: [PATCH 15/20] Fix reviews --- src/legacy/core_plugins/kibana/migrations.js | 34 ++++++++++--------- .../public/components/aggs/moving_average.js | 7 +++- 2 files changed, 24 insertions(+), 17 deletions(-) diff --git a/src/legacy/core_plugins/kibana/migrations.js b/src/legacy/core_plugins/kibana/migrations.js index f4830eb8e9b7a..7a2eddd2b5c5e 100644 --- a/src/legacy/core_plugins/kibana/migrations.js +++ b/src/legacy/core_plugins/kibana/migrations.js @@ -293,25 +293,27 @@ function replaceMovAvgToMovFn(doc) { // Let it go, the data is invalid and we'll leave it as is } - if (newVisState.type === 'metrics') { + if (newVisState && newVisState.type === 'metrics') { const series = get(newVisState, 'params.series', []); series.forEach(part => { - (part.metrics || []).forEach(metric => { - if (metric.type === 'moving_average') { - metric.model_type = metric.model; - metric.alpha = 0; - metric.beta = 0; - metric.gamma = 0; - metric.period = 1; - metric.multiplicative = true; - - delete metric.minimize; - delete metric.model; - delete metric.settings; - delete metric.predict; - } - }); + if (part.metrics && Array.isArray(part.metrics)) { + part.forEach(metric => { + if (metric.type === 'moving_average') { + metric.model_type = metric.model; + metric.alpha = 0; + metric.beta = 0; + metric.gamma = 0; + metric.period = 1; + metric.multiplicative = true; + + delete metric.minimize; + delete metric.model; + delete metric.settings; + delete metric.predict; + } + }); + } }); return { diff --git a/src/legacy/core_plugins/metrics/public/components/aggs/moving_average.js b/src/legacy/core_plugins/metrics/public/components/aggs/moving_average.js index 46ffae82e90cf..5aa787cf0323d 100644 --- a/src/legacy/core_plugins/metrics/public/components/aggs/moving_average.js +++ b/src/legacy/core_plugins/metrics/public/components/aggs/moving_average.js @@ -48,6 +48,8 @@ const DEFAULTS = { window: 10, }; +const isProperWindowValue = ({ window, period }) => window > (period * 2); + export const MovingAverageAgg = props => { const { siblings } = props; @@ -175,6 +177,9 @@ export const MovingAverageAgg = props => { label={i18n.translate('tsvb.movingAverage.windowSizeLabel', { defaultMessage: 'Window Size', })} + helpText={!isProperWindowValue(model) && i18n.translate('tsvb.movingAverage.windowSizeHint', { + defaultMessage: 'Window must be more than twice the size of the period', + })} > {/* EUITODO: The following input couldn't be converted to EUI because of type mis-match. @@ -258,7 +263,7 @@ export const MovingAverageAgg = props => { Date: Fri, 7 Jun 2019 17:43:02 +0300 Subject: [PATCH 16/20] Add a migration test --- src/legacy/core_plugins/kibana/migrations.js | 17 +- .../core_plugins/kibana/migrations.test.js | 307 +++++++++++------- 2 files changed, 192 insertions(+), 132 deletions(-) diff --git a/src/legacy/core_plugins/kibana/migrations.js b/src/legacy/core_plugins/kibana/migrations.js index 7a2eddd2b5c5e..02623caf2c306 100644 --- a/src/legacy/core_plugins/kibana/migrations.js +++ b/src/legacy/core_plugins/kibana/migrations.js @@ -283,23 +283,24 @@ const executeMigrations720 = flow(migratePercentileRankAggregation, migrateDateH const executeMigrations730 = flow(migrateGaugeVerticalSplitToAlignment, transformFilterStringToQueryObject, replaceMovAvgToMovFn); function replaceMovAvgToMovFn(doc) { - const visState = get(doc, 'attributes.visState'); - let newVisState; + const visStateJSON = get(doc, 'attributes.visState'); + let visState; - if (visState) { + if (visStateJSON) { try { - newVisState = JSON.parse(visState); + visState = JSON.parse(visStateJSON); } catch (e) { // Let it go, the data is invalid and we'll leave it as is } - if (newVisState && newVisState.type === 'metrics') { - const series = get(newVisState, 'params.series', []); + if (visState && visState.type === 'metrics') { + const series = get(visState, 'params.series', []); series.forEach(part => { if (part.metrics && Array.isArray(part.metrics)) { - part.forEach(metric => { + part.metrics.forEach(metric => { if (metric.type === 'moving_average') { + metric.model_type = metric.model; metric.alpha = 0; metric.beta = 0; @@ -320,7 +321,7 @@ function replaceMovAvgToMovFn(doc) { ...doc, attributes: { ...doc.attributes, - visState: JSON.stringify(newVisState), + visState: JSON.stringify(visState), }, }; } diff --git a/src/legacy/core_plugins/kibana/migrations.test.js b/src/legacy/core_plugins/kibana/migrations.test.js index 530bb7aa1662d..ff711c96bc301 100644 --- a/src/legacy/core_plugins/kibana/migrations.test.js +++ b/src/legacy/core_plugins/kibana/migrations.test.js @@ -68,78 +68,78 @@ describe('visualization', () => { visState: JSON.stringify({ aggs: [ { - 'enabled': true, - 'id': '1', - 'params': { + enabled: true, + id: '1', + params: { // Doesn't make much sense but we want to test it's not removing it from anything else time_zone: 'Europe/Berlin', }, - 'schema': 'metric', - 'type': 'count' + schema: 'metric', + type: 'count', }, { - 'enabled': true, - 'id': '2', - 'params': { - 'customInterval': '2h', - 'drop_partials': false, - 'extended_bounds': {}, - 'field': 'timestamp', - 'time_zone': 'Europe/Berlin', - 'interval': 'auto', - 'min_doc_count': 1, - 'useNormalizedEsInterval': true + enabled: true, + id: '2', + params: { + customInterval: '2h', + drop_partials: false, + extended_bounds: {}, + field: 'timestamp', + time_zone: 'Europe/Berlin', + interval: 'auto', + min_doc_count: 1, + useNormalizedEsInterval: true, }, - 'schema': 'segment', - 'type': 'date_histogram' + schema: 'segment', + type: 'date_histogram', }, { - 'enabled': true, - 'id': '4', - 'params': { - 'customInterval': '2h', - 'drop_partials': false, - 'extended_bounds': {}, - 'field': 'timestamp', - 'interval': 'auto', - 'min_doc_count': 1, - 'useNormalizedEsInterval': true + enabled: true, + id: '4', + params: { + customInterval: '2h', + drop_partials: false, + extended_bounds: {}, + field: 'timestamp', + interval: 'auto', + min_doc_count: 1, + useNormalizedEsInterval: true, }, - 'schema': 'segment', - 'type': 'date_histogram' + schema: 'segment', + type: 'date_histogram', }, { - 'enabled': true, - 'id': '3', - 'params': { - 'customBucket': { - 'enabled': true, - 'id': '1-bucket', - 'params': { - 'customInterval': '2h', - 'drop_partials': false, - 'extended_bounds': {}, - 'field': 'timestamp', - 'interval': 'auto', - 'min_doc_count': 1, - 'time_zone': 'Europe/Berlin', - 'useNormalizedEsInterval': true + enabled: true, + id: '3', + params: { + customBucket: { + enabled: true, + id: '1-bucket', + params: { + customInterval: '2h', + drop_partials: false, + extended_bounds: {}, + field: 'timestamp', + interval: 'auto', + min_doc_count: 1, + time_zone: 'Europe/Berlin', + useNormalizedEsInterval: true, }, - 'type': 'date_histogram' + type: 'date_histogram', + }, + customMetric: { + enabled: true, + id: '1-metric', + params: {}, + type: 'count', }, - 'customMetric': { - 'enabled': true, - 'id': '1-metric', - 'params': {}, - 'type': 'count' - } }, - 'schema': 'metric', - 'type': 'max_bucket' + schema: 'metric', + type: 'max_bucket', }, - ] + ], }), - } + }, }; }); @@ -726,75 +726,75 @@ Object { visState: JSON.stringify({ aggs: [ { - 'enabled': true, - 'id': '1', - 'params': { - 'customInterval': '1h' + enabled: true, + id: '1', + params: { + customInterval: '1h', }, - 'schema': 'metric', - 'type': 'count' + schema: 'metric', + type: 'count', }, { - 'enabled': true, - 'id': '2', - 'params': { - 'customInterval': '2h', - 'drop_partials': false, - 'extended_bounds': {}, - 'field': 'timestamp', - 'interval': 'auto', - 'min_doc_count': 1, - 'useNormalizedEsInterval': true + enabled: true, + id: '2', + params: { + customInterval: '2h', + drop_partials: false, + extended_bounds: {}, + field: 'timestamp', + interval: 'auto', + min_doc_count: 1, + useNormalizedEsInterval: true, }, - 'schema': 'segment', - 'type': 'date_histogram' + schema: 'segment', + type: 'date_histogram', }, { - 'enabled': true, - 'id': '4', - 'params': { - 'customInterval': '2h', - 'drop_partials': false, - 'extended_bounds': {}, - 'field': 'timestamp', - 'interval': 'custom', - 'min_doc_count': 1, - 'useNormalizedEsInterval': true + enabled: true, + id: '4', + params: { + customInterval: '2h', + drop_partials: false, + extended_bounds: {}, + field: 'timestamp', + interval: 'custom', + min_doc_count: 1, + useNormalizedEsInterval: true, }, - 'schema': 'segment', - 'type': 'date_histogram' + schema: 'segment', + type: 'date_histogram', }, { - 'enabled': true, - 'id': '3', - 'params': { - 'customBucket': { - 'enabled': true, - 'id': '1-bucket', - 'params': { - 'customInterval': '2h', - 'drop_partials': false, - 'extended_bounds': {}, - 'field': 'timestamp', - 'interval': 'custom', - 'min_doc_count': 1, - 'useNormalizedEsInterval': true + enabled: true, + id: '3', + params: { + customBucket: { + enabled: true, + id: '1-bucket', + params: { + customInterval: '2h', + drop_partials: false, + extended_bounds: {}, + field: 'timestamp', + interval: 'custom', + min_doc_count: 1, + useNormalizedEsInterval: true, }, - 'type': 'date_histogram' + type: 'date_histogram', + }, + customMetric: { + enabled: true, + id: '1-metric', + params: {}, + type: 'count', }, - 'customMetric': { - 'enabled': true, - 'id': '1-metric', - 'params': {}, - 'type': 'count' - } }, - 'schema': 'metric', - 'type': 'max_bucket' + schema: 'metric', + type: 'max_bucket', }, - ] + ], }), - } + }, }; }); @@ -807,7 +807,9 @@ Object { it('should not change interval from date_histogram aggregations', () => { const migratedDoc = migrate(doc); const aggs = JSON.parse(migratedDoc.attributes.visState).aggs; - expect(aggs[1].params.interval).toBe(JSON.parse(doc.attributes.visState).aggs[1].params.interval); + expect(aggs[1].params.interval).toBe( + JSON.parse(doc.attributes.visState).aggs[1].params.interval + ); }); it('should not remove customInterval from non date_histogram aggregations', () => { @@ -819,7 +821,9 @@ Object { it('should set interval with customInterval value and remove customInterval when interval equals "custom"', () => { const migratedDoc = migrate(doc); const aggs = JSON.parse(migratedDoc.attributes.visState).aggs; - expect(aggs[2].params.interval).toBe(JSON.parse(doc.attributes.visState).aggs[2].params.customInterval); + expect(aggs[2].params.interval).toBe( + JSON.parse(doc.attributes.visState).aggs[2].params.customInterval + ); expect(aggs[2]).not.toHaveProperty('params.customInterval'); }); @@ -832,8 +836,9 @@ Object { it('should remove customInterval from nested aggregations and set interval with customInterval value', () => { const migratedDoc = migrate(doc); const aggs = JSON.parse(migratedDoc.attributes.visState).aggs; - expect(aggs[3].params.customBucket.params.interval) - .toBe(JSON.parse(doc.attributes.visState).aggs[3].params.customBucket.params.customInterval); + expect(aggs[3].params.customBucket.params.interval).toBe( + JSON.parse(doc.attributes.visState).aggs[3].params.customBucket.params.customInterval + ); expect(aggs[3]).not.toHaveProperty('params.customBucket.params.customInterval'); }); @@ -890,6 +895,51 @@ Object { } `); }); + + describe('replaceMovAvgToMovFn()', () => { + let doc; + + beforeEach(() => { + doc = { + attributes: { + title: 'VIS', + visState: `{"title":"VIS","type":"metrics","params":{"id":"61ca57f0-469d-11e7-af02-69e470af7417", + "type":"timeseries","series":[{"id":"61ca57f1-469d-11e7-af02-69e470af7417","color":"rgba(0,156,224,1)", + "split_mode":"terms","metrics":[{"id":"61ca57f2-469d-11e7-af02-69e470af7417","type":"count", + "numerator":"FlightDelay:true"},{"settings":"","minimize":0,"window":5,"model": + "holt_winters","id":"23054fe0-8915-11e9-9b86-d3f94982620f","type":"moving_average","field": + "61ca57f2-469d-11e7-af02-69e470af7417","predict":1}],"separate_axis":0,"axis_position":"right", + "formatter":"number","chart_type":"line","line_width":"2","point_size":"0","fill":0.5,"stacked":"none", + "label":"Percent Delays","terms_size":"2","terms_field":"OriginCityName"}],"time_field":"timestamp", + "index_pattern":"kibana_sample_data_flights","interval":">=12h","axis_position":"left","axis_formatter": + "number","show_legend":1,"show_grid":1,"annotations":[{"fields":"FlightDelay,Cancelled,Carrier", + "template":"{{Carrier}}: Flight Delayed and Cancelled!","index_pattern":"kibana_sample_data_flights", + "query_string":"FlightDelay:true AND Cancelled:true","id":"53b7dff0-4c89-11e8-a66a-6989ad5a0a39", + "color":"rgba(0,98,177,1)","time_field":"timestamp","icon":"fa-exclamation-triangle", + "ignore_global_filters":1,"ignore_panel_filters":1,"hidden":true}],"legend_position":"bottom", + "axis_scale":"normal","default_index_pattern":"kibana_sample_data_flights","default_timefield":"timestamp"}, + "aggs":[]}`, + }, + migrationVersion: { + visualization: '7.2.0', + }, + type: 'visualization', + }; + }); + + test('should add some necessary moving_fn fields', () => { + const migratedDoc = migrate(doc); + const visState = JSON.parse(migratedDoc.attributes.visState); + const metric = visState.params.series[0].metrics[1]; + + expect(metric).toHaveProperty('model_type'); + expect(metric).toHaveProperty('alpha'); + expect(metric).toHaveProperty('beta'); + expect(metric).toHaveProperty('gamma'); + expect(metric).toHaveProperty('period'); + expect(metric).toHaveProperty('multiplicative'); + }); + }); }); describe('7.3.0 tsvb', () => { const migrate = doc => migrations.visualization['7.3.0'](doc); @@ -920,15 +970,18 @@ Object { { filter: 'Filter Bytes Test:>1000', split_filters: [{ filter: 'bytes:>1000' }], - } - ] + }, + ], }; const markdownDoc = generateDoc({ params: markdownParams }); const migratedMarkdownDoc = migrate(markdownDoc); const markdownSeries = JSON.parse(migratedMarkdownDoc.attributes.visState).params.series; - expect(markdownSeries[0].filter.query).toBe(JSON.parse(markdownDoc.attributes.visState).params.series[0].filter); - expect(markdownSeries[0].split_filters[0].filter.query) - .toBe(JSON.parse(markdownDoc.attributes.visState).params.series[0].split_filters[0].filter); + expect(markdownSeries[0].filter.query).toBe( + JSON.parse(markdownDoc.attributes.visState).params.series[0].filter + ); + expect(markdownSeries[0].split_filters[0].filter.query).toBe( + JSON.parse(markdownDoc.attributes.visState).params.series[0].split_filters[0].filter + ); }); it('should change series item filters from a string into an object for all filters', () => { const params = { @@ -938,16 +991,22 @@ Object { { filter: 'Filter Bytes Test:>1000', split_filters: [{ filter: 'bytes:>1000' }], - } + }, ], annotations: [{ query_string: 'bytes:>1000' }], }; const timeSeriesDoc = generateDoc({ params: params }); const migratedtimeSeriesDoc = migrate(timeSeriesDoc); const timeSeriesParams = JSON.parse(migratedtimeSeriesDoc.attributes.visState).params; - expect(Object.keys(timeSeriesParams.series[0].filter)).toEqual(expect.arrayContaining(['query', 'language'])); - expect(Object.keys(timeSeriesParams.series[0].split_filters[0].filter)).toEqual(expect.arrayContaining(['query', 'language'])); - expect(Object.keys(timeSeriesParams.annotations[0].query_string)).toEqual(expect.arrayContaining(['query', 'language'])); + expect(Object.keys(timeSeriesParams.series[0].filter)).toEqual( + expect.arrayContaining(['query', 'language']) + ); + expect(Object.keys(timeSeriesParams.series[0].split_filters[0].filter)).toEqual( + expect.arrayContaining(['query', 'language']) + ); + expect(Object.keys(timeSeriesParams.annotations[0].query_string)).toEqual( + expect.arrayContaining(['query', 'language']) + ); }); it('should not fail on a metric visualization without a filter in a series item', () => { const params = { type: 'metric', series: [{}, {}, {}] }; From 048996086ff4afa2288271bbf92981955563428b Mon Sep 17 00:00:00 2001 From: Artyom Gospodarsky Date: Tue, 11 Jun 2019 12:22:51 +0300 Subject: [PATCH 17/20] Set proper default values and turn hint on for holt-winter only --- src/legacy/core_plugins/kibana/migrations.js | 6 +- .../public/components/aggs/moving_average.js | 213 +++++++++--------- 2 files changed, 110 insertions(+), 109 deletions(-) diff --git a/src/legacy/core_plugins/kibana/migrations.js b/src/legacy/core_plugins/kibana/migrations.js index 2d8bad5a1bf04..b9a79b9086d82 100644 --- a/src/legacy/core_plugins/kibana/migrations.js +++ b/src/legacy/core_plugins/kibana/migrations.js @@ -334,9 +334,9 @@ function replaceMovAvgToMovFn(doc) { part.metrics.forEach(metric => { if (metric.type === 'moving_average') { metric.model_type = metric.model; - metric.alpha = 0; - metric.beta = 0; - metric.gamma = 0; + metric.alpha = 0.3; + metric.beta = 0.1; + metric.gamma = 0.3; metric.period = 1; metric.multiplicative = true; diff --git a/src/legacy/core_plugins/metrics/public/components/aggs/moving_average.js b/src/legacy/core_plugins/metrics/public/components/aggs/moving_average.js index 5aa787cf0323d..f3dbb9266befc 100644 --- a/src/legacy/core_plugins/metrics/public/components/aggs/moving_average.js +++ b/src/legacy/core_plugins/metrics/public/components/aggs/moving_average.js @@ -40,15 +40,16 @@ import { MODEL_TYPES } from '../../../common/model_options'; const DEFAULTS = { model_type: MODEL_TYPES.UNWEIGHTED, - alpha: 0, - beta: 0, - gamma: 0, + alpha: 0.3, + beta: 0.1, + gamma: 0.3, period: 1, multiplicative: true, - window: 10, + window: 5, }; -const isProperWindowValue = ({ window, period }) => window > (period * 2); +const shouldShowHint = ({ model_type: type, window, period }) => + type === MODEL_TYPES.WEIGHTED_EXPONENTIAL_TRIPLE && period * 2 > window; export const MovingAverageAgg = props => { const { siblings } = props; @@ -84,7 +85,7 @@ export const MovingAverageAgg = props => { defaultMessage: 'Holt-Winters', }), value: MODEL_TYPES.WEIGHTED_EXPONENTIAL_TRIPLE, - } + }, ]; const handleChange = createChangeHandler(props.onChange, model); @@ -99,16 +100,18 @@ export const MovingAverageAgg = props => { label: i18n.translate('tsvb.movingAverage.multiplicativeOptions.true', { defaultMessage: 'True', }), - value: true + value: true, }, { label: i18n.translate('tsvb.movingAverage.multiplicativeOptions.false', { defaultMessage: 'False', }), - value: false + value: false, }, ]; - const selectedMultiplicative = multiplicativeOptions.find(({ value }) => model.multiplicative === value); + const selectedMultiplicative = multiplicativeOptions.find( + ({ value }) => model.multiplicative === value + ); return ( { > { label={i18n.translate('tsvb.movingAverage.windowSizeLabel', { defaultMessage: 'Window Size', })} - helpText={!isProperWindowValue(model) && i18n.translate('tsvb.movingAverage.windowSizeHint', { - defaultMessage: 'Window must be more than twice the size of the period', - })} + helpText={ + shouldShowHint(model) && + i18n.translate('tsvb.movingAverage.windowSizeHint', { + defaultMessage: 'Window must always be at least twice the size of your period', + }) + } > {/* EUITODO: The following input couldn't be converted to EUI because of type mis-match. @@ -195,109 +203,102 @@ export const MovingAverageAgg = props => { - { - ( - model.model_type === MODEL_TYPES.WEIGHTED_EXPONENTIAL || - model.model_type === MODEL_TYPES.WEIGHTED_EXPONENTIAL_DOUBLE || - model.model_type === MODEL_TYPES.WEIGHTED_EXPONENTIAL_TRIPLE - ) && ( - - + {(model.model_type === MODEL_TYPES.WEIGHTED_EXPONENTIAL || + model.model_type === MODEL_TYPES.WEIGHTED_EXPONENTIAL_DOUBLE || + model.model_type === MODEL_TYPES.WEIGHTED_EXPONENTIAL_TRIPLE) && ( + + - - { + + { + + + + + + } + {(model.model_type === MODEL_TYPES.WEIGHTED_EXPONENTIAL_DOUBLE || + model.model_type === MODEL_TYPES.WEIGHTED_EXPONENTIAL_TRIPLE) && ( + + + + + + )} + {model.model_type === MODEL_TYPES.WEIGHTED_EXPONENTIAL_TRIPLE && ( + + + + + + + + + + + - } - { - ( - model.model_type === MODEL_TYPES.WEIGHTED_EXPONENTIAL_DOUBLE || - model.model_type === MODEL_TYPES.WEIGHTED_EXPONENTIAL_TRIPLE - ) && ( - - - - - - ) - } - { - model.model_type === MODEL_TYPES.WEIGHTED_EXPONENTIAL_TRIPLE && ( - - - - - - - - - - - - - - - - - - ) - } - - - ) - } + + )} + + + )} ); }; From c94d829c8935ba048b5283a012c47d646a63f6fa Mon Sep 17 00:00:00 2001 From: Artyom Gospodarsky Date: Fri, 14 Jun 2019 13:25:01 +0300 Subject: [PATCH 18/20] Format touched files by Prettier --- .../metrics/common/model_options.test.js | 1 - .../vis_data/helpers/bucket_transform.test.js | 9 ++++----- .../lib/vis_data/helpers/moving_fn_scripts.js | 20 +++++-------------- .../helpers/moving_fn_scripts.test.js | 17 +++++++++++----- 4 files changed, 21 insertions(+), 26 deletions(-) diff --git a/src/legacy/core_plugins/metrics/common/model_options.test.js b/src/legacy/core_plugins/metrics/common/model_options.test.js index 6d1f62c1b3e48..7d01226bdc040 100644 --- a/src/legacy/core_plugins/metrics/common/model_options.test.js +++ b/src/legacy/core_plugins/metrics/common/model_options.test.js @@ -26,4 +26,3 @@ describe('src/legacy/core_plugins/metrics/common/model_options.js', () => { }); }); }); - diff --git a/src/legacy/core_plugins/metrics/server/lib/vis_data/helpers/bucket_transform.test.js b/src/legacy/core_plugins/metrics/server/lib/vis_data/helpers/bucket_transform.test.js index 24d02ff5d1270..186baf73a86c7 100644 --- a/src/legacy/core_plugins/metrics/server/lib/vis_data/helpers/bucket_transform.test.js +++ b/src/legacy/core_plugins/metrics/server/lib/vis_data/helpers/bucket_transform.test.js @@ -35,13 +35,13 @@ describe('src/legacy/core_plugins/metrics/server/lib/vis_data/helpers/bucket_tra window: 10, field: '61ca57f2-469d-11e7-af02-69e470af7417', id: 'e815ae00-7881-11e9-9392-cbca66a4cf76', - type: 'moving_average' + type: 'moving_average', }; metrics = [ { id: '61ca57f2-469d-11e7-af02-69e470af7417', numerator: 'FlightDelay:true', - type: 'count' + type: 'count', }, { model_type: 'holt_winters', @@ -53,8 +53,8 @@ describe('src/legacy/core_plugins/metrics/server/lib/vis_data/helpers/bucket_tra window: 10, field: '61ca57f2-469d-11e7-af02-69e470af7417', id: 'e815ae00-7881-11e9-9392-cbca66a4cf76', - type: 'moving_average' - } + type: 'moving_average', + }, ]; }); @@ -65,4 +65,3 @@ describe('src/legacy/core_plugins/metrics/server/lib/vis_data/helpers/bucket_tra }); }); }); - diff --git a/src/legacy/core_plugins/metrics/server/lib/vis_data/helpers/moving_fn_scripts.js b/src/legacy/core_plugins/metrics/server/lib/vis_data/helpers/moving_fn_scripts.js index eb7af73467dd6..32bec6aea93ae 100644 --- a/src/legacy/core_plugins/metrics/server/lib/vis_data/helpers/moving_fn_scripts.js +++ b/src/legacy/core_plugins/metrics/server/lib/vis_data/helpers/moving_fn_scripts.js @@ -17,24 +17,14 @@ * under the License. */ - import { MODEL_TYPES } from '../../../../common/model_options'; export const MODEL_SCRIPTS = { [MODEL_TYPES.UNWEIGHTED]: () => 'MovingFunctions.unweightedAvg(values)', - [MODEL_TYPES.WEIGHTED_EXPONENTIAL]: ({ - alpha - }) => `MovingFunctions.ewma(values, ${alpha})`, - [MODEL_TYPES.WEIGHTED_EXPONENTIAL_DOUBLE]: ({ - alpha, - beta - }) => `MovingFunctions.holt(values, ${alpha}, ${beta})`, - [MODEL_TYPES.WEIGHTED_EXPONENTIAL_TRIPLE]: ({ - alpha, - beta, - gamma, - period, - multiplicative - }) => `if (values.length > ${period}*2) {MovingFunctions.holtWinters(values, ${alpha}, ${beta}, ${gamma}, ${period}, ${multiplicative})}`, + [MODEL_TYPES.WEIGHTED_EXPONENTIAL]: ({ alpha }) => `MovingFunctions.ewma(values, ${alpha})`, + [MODEL_TYPES.WEIGHTED_EXPONENTIAL_DOUBLE]: ({ alpha, beta }) => + `MovingFunctions.holt(values, ${alpha}, ${beta})`, + [MODEL_TYPES.WEIGHTED_EXPONENTIAL_TRIPLE]: ({ alpha, beta, gamma, period, multiplicative }) => + `if (values.length > ${period}*2) {MovingFunctions.holtWinters(values, ${alpha}, ${beta}, ${gamma}, ${period}, ${multiplicative})}`, [MODEL_TYPES.WEIGHTED_LINEAR]: () => 'MovingFunctions.linearWeightedAvg(values)', }; diff --git a/src/legacy/core_plugins/metrics/server/lib/vis_data/helpers/moving_fn_scripts.test.js b/src/legacy/core_plugins/metrics/server/lib/vis_data/helpers/moving_fn_scripts.test.js index 1d269d999b883..858e3d30b8ebc 100644 --- a/src/legacy/core_plugins/metrics/server/lib/vis_data/helpers/moving_fn_scripts.test.js +++ b/src/legacy/core_plugins/metrics/server/lib/vis_data/helpers/moving_fn_scripts.test.js @@ -35,23 +35,31 @@ describe('src/legacy/core_plugins/metrics/server/lib/vis_data/helpers/moving_fn_ }); test('should return an expected result of the UNWEIGHTED model type', () => { - expect(MODEL_SCRIPTS[MODEL_TYPES.UNWEIGHTED](bucket)).toBe('MovingFunctions.unweightedAvg(values)'); + expect(MODEL_SCRIPTS[MODEL_TYPES.UNWEIGHTED](bucket)).toBe( + 'MovingFunctions.unweightedAvg(values)' + ); }); test('should return an expected result of the WEIGHTED_LINEAR model type', () => { - expect(MODEL_SCRIPTS[MODEL_TYPES.WEIGHTED_LINEAR](bucket)).toBe('MovingFunctions.linearWeightedAvg(values)'); + expect(MODEL_SCRIPTS[MODEL_TYPES.WEIGHTED_LINEAR](bucket)).toBe( + 'MovingFunctions.linearWeightedAvg(values)' + ); }); test('should return an expected result of the WEIGHTED_EXPONENTIAL model type', () => { const { alpha } = bucket; - expect(MODEL_SCRIPTS[MODEL_TYPES.WEIGHTED_EXPONENTIAL](bucket)).toBe(`MovingFunctions.ewma(values, ${alpha})`); + expect(MODEL_SCRIPTS[MODEL_TYPES.WEIGHTED_EXPONENTIAL](bucket)).toBe( + `MovingFunctions.ewma(values, ${alpha})` + ); }); test('should return an expected result of the WEIGHTED_EXPONENTIAL_DOUBLE model type', () => { const { alpha, beta } = bucket; - expect(MODEL_SCRIPTS[MODEL_TYPES.WEIGHTED_EXPONENTIAL_DOUBLE](bucket)).toBe(`MovingFunctions.holt(values, ${alpha}, ${beta})`); + expect(MODEL_SCRIPTS[MODEL_TYPES.WEIGHTED_EXPONENTIAL_DOUBLE](bucket)).toBe( + `MovingFunctions.holt(values, ${alpha}, ${beta})` + ); }); test('should return an expected result of the WEIGHTED_EXPONENTIAL_TRIPLE model type', () => { @@ -63,4 +71,3 @@ describe('src/legacy/core_plugins/metrics/server/lib/vis_data/helpers/moving_fn_ }); }); }); - From 45a79595038815571defa08b309766663c704270 Mon Sep 17 00:00:00 2001 From: Artyom Gospodarsky Date: Fri, 14 Jun 2019 15:21:02 +0300 Subject: [PATCH 19/20] Import settings from moving_avg --- src/legacy/core_plugins/kibana/migrations.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/legacy/core_plugins/kibana/migrations.js b/src/legacy/core_plugins/kibana/migrations.js index 74c284b8b4b5e..d1cfbd1ddeace 100644 --- a/src/legacy/core_plugins/kibana/migrations.js +++ b/src/legacy/core_plugins/kibana/migrations.js @@ -335,11 +335,11 @@ function replaceMovAvgToMovFn(doc) { part.metrics.forEach(metric => { if (metric.type === 'moving_average') { metric.model_type = metric.model; - metric.alpha = 0.3; - metric.beta = 0.1; - metric.gamma = 0.3; - metric.period = 1; - metric.multiplicative = true; + metric.alpha = get(metric, 'settings.alpha', 0.3); + metric.beta = get(metric, 'settings.beta', 0.1); + metric.gamma = get(metric, 'settings.gamma', 0.3); + metric.period = get(metric, 'settings.period', 1); + metric.multiplicative = get(metric, 'settings.type') === 'mult'; delete metric.minimize; delete metric.model; From bb7cf9e3e9242ebb15990e53b47cb25b96927415 Mon Sep 17 00:00:00 2001 From: Artyom Gospodarsky Date: Mon, 17 Jun 2019 13:33:13 +0300 Subject: [PATCH 20/20] Wrap changes to the try/catch statement and log exceptions --- src/legacy/core_plugins/kibana/migrations.js | 67 ++++++++++---------- 1 file changed, 34 insertions(+), 33 deletions(-) diff --git a/src/legacy/core_plugins/kibana/migrations.js b/src/legacy/core_plugins/kibana/migrations.js index d1cfbd1ddeace..20fb69c88d6b6 100644 --- a/src/legacy/core_plugins/kibana/migrations.js +++ b/src/legacy/core_plugins/kibana/migrations.js @@ -316,47 +316,48 @@ function migrateFiltersAggQuery(doc) { return doc; } -function replaceMovAvgToMovFn(doc) { +function replaceMovAvgToMovFn(doc, logger) { const visStateJSON = get(doc, 'attributes.visState'); let visState; if (visStateJSON) { try { visState = JSON.parse(visStateJSON); - } catch (e) { - // Let it go, the data is invalid and we'll leave it as is - } - - if (visState && visState.type === 'metrics') { - const series = get(visState, 'params.series', []); - series.forEach(part => { - if (part.metrics && Array.isArray(part.metrics)) { - part.metrics.forEach(metric => { - if (metric.type === 'moving_average') { - metric.model_type = metric.model; - metric.alpha = get(metric, 'settings.alpha', 0.3); - metric.beta = get(metric, 'settings.beta', 0.1); - metric.gamma = get(metric, 'settings.gamma', 0.3); - metric.period = get(metric, 'settings.period', 1); - metric.multiplicative = get(metric, 'settings.type') === 'mult'; - - delete metric.minimize; - delete metric.model; - delete metric.settings; - delete metric.predict; - } - }); - } - }); + if (visState && visState.type === 'metrics') { + const series = get(visState, 'params.series', []); + + series.forEach(part => { + if (part.metrics && Array.isArray(part.metrics)) { + part.metrics.forEach(metric => { + if (metric.type === 'moving_average') { + metric.model_type = metric.model; + metric.alpha = get(metric, 'settings.alpha', 0.3); + metric.beta = get(metric, 'settings.beta', 0.1); + metric.gamma = get(metric, 'settings.gamma', 0.3); + metric.period = get(metric, 'settings.period', 1); + metric.multiplicative = get(metric, 'settings.type') === 'mult'; + + delete metric.minimize; + delete metric.model; + delete metric.settings; + delete metric.predict; + } + }); + } + }); - return { - ...doc, - attributes: { - ...doc.attributes, - visState: JSON.stringify(visState), - }, - }; + return { + ...doc, + attributes: { + ...doc.attributes, + visState: JSON.stringify(visState), + }, + }; + } + } catch (e) { + logger.warning(`Exception @ replaceMovAvgToMovFn! ${e}`); + logger.warning(`Exception @ replaceMovAvgToMovFn! Payload: ${visStateJSON}`); } }