diff --git a/packages/kbn-es-query/src/expressions/types.ts b/packages/kbn-es-query/src/expressions/types.ts index 42dc021c9b752..ed367adc7973a 100644 --- a/packages/kbn-es-query/src/expressions/types.ts +++ b/packages/kbn-es-query/src/expressions/types.ts @@ -9,6 +9,7 @@ import { Filter, Query, TimeRange } from '../filters'; export interface ExecutionContextSearch { + now?: number; filters?: Filter[]; query?: Query | Query[]; timeRange?: TimeRange; diff --git a/packages/kbn-optimizer/limits.yml b/packages/kbn-optimizer/limits.yml index 764fe35dd759d..ec8e4f47effd2 100644 --- a/packages/kbn-optimizer/limits.yml +++ b/packages/kbn-optimizer/limits.yml @@ -86,7 +86,7 @@ pageLoadAssetSize: kibanaUsageCollection: 16463 kibanaUtils: 79713 kubernetesSecurity: 77234 - lens: 39000 + lens: 41000 licenseManagement: 41817 licensing: 29004 links: 44490 diff --git a/src/plugins/data/common/search/expressions/__snapshots__/kibana.test.ts.snap b/src/plugins/data/common/search/expressions/__snapshots__/kibana.test.ts.snap index 2400f7a1f67d6..7bcf782fbbbc2 100644 --- a/src/plugins/data/common/search/expressions/__snapshots__/kibana.test.ts.snap +++ b/src/plugins/data/common/search/expressions/__snapshots__/kibana.test.ts.snap @@ -14,6 +14,7 @@ Object { }, }, ], + "now": 0, "query": Array [ Object { "language": "lucene", diff --git a/src/plugins/data/common/search/expressions/kibana.test.ts b/src/plugins/data/common/search/expressions/kibana.test.ts index c82bc0293cefe..4992a345bd0d2 100644 --- a/src/plugins/data/common/search/expressions/kibana.test.ts +++ b/src/plugins/data/common/search/expressions/kibana.test.ts @@ -20,6 +20,7 @@ describe('interpreter/functions#kibana', () => { beforeEach(() => { input = { timeRange: { from: '0', to: '1' } }; search = { + now: 0, type: 'kibana_context', query: { language: 'lucene', query: 'geo.src:US' }, filters: [ diff --git a/src/plugins/data/common/search/expressions/kibana.ts b/src/plugins/data/common/search/expressions/kibana.ts index 83d2cdc1c64b9..ad8405a51418c 100644 --- a/src/plugins/data/common/search/expressions/kibana.ts +++ b/src/plugins/data/common/search/expressions/kibana.ts @@ -41,6 +41,7 @@ export const kibana: ExpressionFunctionKibana = { // TODO: But it shouldn't be need. ...input, type: 'kibana_context', + now: getSearchContext().now ?? Date.now(), query: [...toArray(getSearchContext().query), ...toArray((input || {}).query)], filters: [...(getSearchContext().filters || []), ...((input || {}).filters || [])], timeRange: getSearchContext().timeRange || (input ? input.timeRange : undefined), diff --git a/src/plugins/expressions/common/expression_functions/specs/index.ts b/src/plugins/expressions/common/expression_functions/specs/index.ts index 0e473e4a79e5a..37af3ede5ebe0 100644 --- a/src/plugins/expressions/common/expression_functions/specs/index.ts +++ b/src/plugins/expressions/common/expression_functions/specs/index.ts @@ -17,6 +17,7 @@ export * from './overall_metric'; export * from './derivative'; export * from './moving_average'; export * from './ui_setting'; +export * from './math_column'; export type { MapColumnArguments } from './map_column'; export { mapColumn } from './map_column'; export type { MathArguments, MathInput } from './math'; diff --git a/src/plugins/expressions/common/expression_functions/specs/math_column.ts b/src/plugins/expressions/common/expression_functions/specs/math_column.ts index e056bc6b876e1..6b75af7de4ca9 100644 --- a/src/plugins/expressions/common/expression_functions/specs/math_column.ts +++ b/src/plugins/expressions/common/expression_functions/specs/math_column.ts @@ -18,12 +18,14 @@ export type MathColumnArguments = MathArguments & { copyMetaFrom?: string | null; }; -export const mathColumn: ExpressionFunctionDefinition< +export type ExpressionFunctionMathColumn = ExpressionFunctionDefinition< 'mathColumn', Datatable, MathColumnArguments, Promise -> = { +>; + +export const mathColumn: ExpressionFunctionMathColumn = { name: 'mathColumn', type: 'datatable', inputTypes: ['datatable'], diff --git a/src/plugins/expressions/common/expression_functions/types.ts b/src/plugins/expressions/common/expression_functions/types.ts index 018ee9e9fac0c..c59169ccf04ab 100644 --- a/src/plugins/expressions/common/expression_functions/types.ts +++ b/src/plugins/expressions/common/expression_functions/types.ts @@ -20,6 +20,7 @@ import { ExpressionFunctionDerivative, ExpressionFunctionMovingAverage, ExpressionFunctionOverallMetric, + ExpressionFunctionMathColumn, } from './specs'; import { ExpressionAstFunction } from '../ast'; @@ -132,4 +133,5 @@ export interface ExpressionFunctionDefinitions { overall_metric: ExpressionFunctionOverallMetric; derivative: ExpressionFunctionDerivative; moving_average: ExpressionFunctionMovingAverage; + math_column: ExpressionFunctionMathColumn; } diff --git a/x-pack/plugins/lens/common/expressions/formula_context/context_fns.test.ts b/x-pack/plugins/lens/common/expressions/formula_context/context_fns.test.ts new file mode 100644 index 0000000000000..f064238992b07 --- /dev/null +++ b/x-pack/plugins/lens/common/expressions/formula_context/context_fns.test.ts @@ -0,0 +1,91 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { ExecutionContext } from '@kbn/expressions-plugin/common'; +import { Adapters } from '@kbn/inspector-plugin/common'; +import { formulaIntervalFn, formulaNowFn, formulaTimeRangeFn } from './context_fns'; + +describe('interval', () => { + it('should return 0 if no time range available', () => { + // (not sure if this case is actually possible) + const result = formulaIntervalFn.fn(undefined, { targetBars: 100 }, { + getSearchContext: () => ({ + /* no time range */ + }), + } as ExecutionContext); + expect(result).toEqual(0); + }); + + it('should return 0 if no targetBars is passed', () => { + const result = formulaIntervalFn.fn( + undefined, + { + /* no targetBars */ + }, + { + getSearchContext: () => ({ + timeRange: { + from: 'now-15m', + to: 'now', + }, + }), + } as ExecutionContext + ); + expect(result).toEqual(0); + }); + + it('should return a valid value > 0 if both timeRange and targetBars is passed', () => { + const result = formulaIntervalFn.fn(undefined, { targetBars: 100 }, { + getSearchContext: () => ({ + timeRange: { + from: 'now-15m', + to: 'now', + }, + }), + } as ExecutionContext); + expect(result).toEqual(10000); + }); +}); + +describe('time range', () => { + it('should return 0 if no time range is available', () => { + // (not sure if this case is actually possible) + const result = formulaTimeRangeFn.fn(undefined, {}, { + getSearchContext: () => ({ + /* no time range */ + }), + } as ExecutionContext); + expect(result).toEqual(0); + }); + + it('should return a valid value > 0 if time range is available', () => { + const result = formulaTimeRangeFn.fn(undefined, {}, { + getSearchContext: () => ({ + timeRange: { + from: 'now-15m', + to: 'now', + }, + now: 1000000, // important to provide this to make the result consistent + }), + } as ExecutionContext); + + expect(result).toBe(900000); + }); +}); + +describe('now', () => { + it('should return the now value when passed', () => { + const now = 123456789; + expect( + formulaNowFn.fn(undefined, {}, { + getSearchContext: () => ({ + now, + }), + } as ExecutionContext) + ).toEqual(now); + }); +}); diff --git a/x-pack/plugins/lens/common/expressions/formula_context/context_fns.ts b/x-pack/plugins/lens/common/expressions/formula_context/context_fns.ts new file mode 100644 index 0000000000000..2f77d1142f7d1 --- /dev/null +++ b/x-pack/plugins/lens/common/expressions/formula_context/context_fns.ts @@ -0,0 +1,97 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { getAbsoluteTimeRange, calcAutoIntervalNear } from '@kbn/data-plugin/common'; +import type { TimeRange } from '@kbn/es-query'; +import type { ExpressionFunctionDefinition } from '@kbn/expressions-plugin/common'; +import moment from 'moment'; +import { i18n } from '@kbn/i18n'; + +export type ExpressionFunctionFormulaTimeRange = ExpressionFunctionDefinition< + 'formula_time_range', + undefined, + object, + number +>; + +const getTimeRangeAsNumber = (timeRange: TimeRange | undefined, now: number | undefined) => { + if (!timeRange) return 0; + const absoluteTimeRange = getAbsoluteTimeRange( + timeRange, + now != null ? { forceNow: new Date(now) } : {} + ); + return timeRange ? moment(absoluteTimeRange.to).diff(moment(absoluteTimeRange.from)) : 0; +}; + +export const formulaTimeRangeFn: ExpressionFunctionFormulaTimeRange = { + name: 'formula_time_range', + + help: i18n.translate('xpack.lens.formula.timeRange.help', { + defaultMessage: 'The specified time range, in milliseconds (ms).', + }), + + args: {}, + + fn(_input, _args, { getSearchContext }) { + const { timeRange, now } = getSearchContext(); + return getTimeRangeAsNumber(timeRange, now); + }, +}; + +export type ExpressionFunctionFormulaInterval = ExpressionFunctionDefinition< + 'formula_interval', + undefined, + { + targetBars?: number; + }, + number +>; + +export const formulaIntervalFn: ExpressionFunctionFormulaInterval = { + name: 'formula_interval', + + help: i18n.translate('xpack.lens.formula.interval.help', { + defaultMessage: 'The specified minimum interval for the date histogram, in milliseconds (ms).', + }), + + args: { + targetBars: { + types: ['number'], + help: i18n.translate('xpack.lens.formula.interval.targetBars.help', { + defaultMessage: 'The target number of bars for the date histogram.', + }), + }, + }, + + fn(_input, args, { getSearchContext }) { + const { timeRange, now } = getSearchContext(); + return timeRange && args.targetBars + ? calcAutoIntervalNear(args.targetBars, getTimeRangeAsNumber(timeRange, now)).asMilliseconds() + : 0; + }, +}; + +export type ExpressionFunctionFormulaNow = ExpressionFunctionDefinition< + 'formula_now', + undefined, + object, + number +>; + +export const formulaNowFn: ExpressionFunctionFormulaNow = { + name: 'formula_now', + + help: i18n.translate('xpack.lens.formula.now.help', { + defaultMessage: 'The current now moment used in Kibana expressed in milliseconds (ms).', + }), + + args: {}, + + fn(_input, _args, { getSearchContext }) { + return getSearchContext().now ?? Date.now(); + }, +}; diff --git a/x-pack/plugins/lens/common/expressions/formula_context/index.ts b/x-pack/plugins/lens/common/expressions/formula_context/index.ts new file mode 100644 index 0000000000000..da8931779cfbe --- /dev/null +++ b/x-pack/plugins/lens/common/expressions/formula_context/index.ts @@ -0,0 +1,8 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export * from './context_fns'; diff --git a/x-pack/plugins/lens/common/expressions/index.ts b/x-pack/plugins/lens/common/expressions/index.ts index ccb6343334d62..c3ccaddac9fd3 100644 --- a/x-pack/plugins/lens/common/expressions/index.ts +++ b/x-pack/plugins/lens/common/expressions/index.ts @@ -11,3 +11,4 @@ export * from './format_column'; export * from './map_to_columns'; export * from './time_scale'; export * from './datatable'; +export * from './formula_context'; diff --git a/x-pack/plugins/lens/public/datasources/form_based/operations/definitions/formula/context_variables.test.ts b/x-pack/plugins/lens/public/datasources/form_based/operations/definitions/formula/context_variables.test.ts index 407f458a11e3e..db38e18d3bd19 100644 --- a/x-pack/plugins/lens/public/datasources/form_based/operations/definitions/formula/context_variables.test.ts +++ b/x-pack/plugins/lens/public/datasources/form_based/operations/definitions/formula/context_variables.test.ts @@ -34,20 +34,6 @@ function createLayer( }; } -function createExpression(type: 'interval' | 'now' | 'time_range', value: number) { - return [ - { - type: 'function', - function: 'mathColumn', - arguments: { - id: ['col1'], - name: [`Constant: ${type}`], - expression: [String(value)], - }, - }, - ]; -} - describe('context variables', () => { describe('interval', () => { describe('getErrorMessages', () => { @@ -124,53 +110,6 @@ describe('context variables', () => { ).toBeUndefined(); }); }); - describe('toExpression', () => { - it('should return 0 if no dateRange is passed', () => { - expect( - intervalOperation.toExpression( - createLayer('interval'), - 'col1', - createMockedIndexPattern(), - { now: new Date(), targetBars: 100 } - ) - ).toEqual(expect.arrayContaining(createExpression('interval', 0))); - }); - - it('should return 0 if no targetBars is passed', () => { - expect( - intervalOperation.toExpression( - createLayer('interval'), - 'col1', - createMockedIndexPattern(), - { - dateRange: { - fromDate: new Date(2022, 0, 1).toISOString(), - toDate: new Date(2023, 0, 1).toISOString(), - }, - now: new Date(), - } - ) - ).toEqual(expect.arrayContaining(createExpression('interval', 0))); - }); - - it('should return a valid value > 0 if both dateRange and targetBars is passed', () => { - expect( - intervalOperation.toExpression( - createLayer('interval'), - 'col1', - createMockedIndexPattern(), - { - dateRange: { - fromDate: new Date(2022, 0, 1).toISOString(), - toDate: new Date(2023, 0, 1).toISOString(), - }, - now: new Date(), - targetBars: 100, - } - ) - ).toEqual(expect.arrayContaining(createExpression('interval', 86400000))); - }); - }); }); describe('time_range', () => { describe('getErrorMessages', () => { @@ -202,35 +141,6 @@ describe('context variables', () => { ).toEqual(expect.arrayContaining(['The current time range interval is not available'])); }); }); - - describe('toExpression', () => { - it('should return 0 if no dateRange is passed', () => { - expect( - timeRangeOperation.toExpression( - createLayer('time_range'), - 'col1', - createMockedIndexPattern(), - { now: new Date(), targetBars: 100 } - ) - ).toEqual(expect.arrayContaining(createExpression('time_range', 0))); - }); - - it('should return a valid value > 0 if dateRange is passed', () => { - expect( - timeRangeOperation.toExpression( - createLayer('time_range'), - 'col1', - createMockedIndexPattern(), - { - dateRange: { - fromDate: new Date(2022, 0, 1).toISOString(), - toDate: new Date(2023, 0, 1).toISOString(), - }, - } - ) - ).toEqual(expect.arrayContaining(createExpression('time_range', 31536000000))); - }); - }); }); describe('now', () => { describe('getErrorMessages', () => { @@ -240,16 +150,5 @@ describe('context variables', () => { ).toBeUndefined(); }); }); - - describe('toExpression', () => { - it('should return the now value when passed', () => { - const now = new Date(); - expect( - nowOperation.toExpression(createLayer('now'), 'col1', createMockedIndexPattern(), { - now, - }) - ).toEqual(expect.arrayContaining(createExpression('now', +now))); - }); - }); }); }); diff --git a/x-pack/plugins/lens/public/datasources/form_based/operations/definitions/formula/context_variables.tsx b/x-pack/plugins/lens/public/datasources/form_based/operations/definitions/formula/context_variables.tsx index 4b7b5b94b493b..f5f28d94ad228 100644 --- a/x-pack/plugins/lens/public/datasources/form_based/operations/definitions/formula/context_variables.tsx +++ b/x-pack/plugins/lens/public/datasources/form_based/operations/definitions/formula/context_variables.tsx @@ -6,9 +6,18 @@ */ import { i18n } from '@kbn/i18n'; -import moment from 'moment'; -import { calcAutoIntervalNear, UI_SETTINGS } from '@kbn/data-plugin/common'; +import { UI_SETTINGS } from '@kbn/data-plugin/common'; import { partition } from 'lodash'; +import { + buildExpressionFunction, + buildExpression, + ExpressionFunctionDefinitions, +} from '@kbn/expressions-plugin/common'; +import { + ExpressionFunctionFormulaInterval, + ExpressionFunctionFormulaNow, + ExpressionFunctionFormulaTimeRange, +} from '../../../../../../common/expressions/formula_context/context_fns'; import type { DateHistogramIndexPatternColumn, FormBasedLayer, @@ -58,13 +67,9 @@ export interface TimeRangeIndexPatternColumn extends ReferenceBasedIndexPatternC operationType: 'time_range'; } -function getTimeRangeFromContext({ dateRange }: ContextValues) { - return dateRange ? moment(dateRange.toDate).diff(moment(dateRange.fromDate)) : 0; -} - function getTimeRangeErrorMessages( - layer: FormBasedLayer, - columnId: string, + _layer: FormBasedLayer, + _columnId: string, indexPattern: IndexPattern, dateRange?: DateRange | undefined ) { @@ -89,12 +94,11 @@ function getTimeRangeErrorMessages( export const timeRangeOperation = createContextValueBasedOperation({ type: 'time_range', label: 'Time range', - description: i18n.translate('xpack.lens.indexPattern.timeRange.documentation.markdown', { - defaultMessage: ` -The specified time range, in milliseconds (ms). - `, + description: i18n.translate('xpack.lens.formula.timeRange.help', { + defaultMessage: 'The specified time range, in milliseconds (ms).', }), - getContextValue: getTimeRangeFromContext, + getExpressionFunction: (_context: ContextValues) => + buildExpressionFunction('formula_time_range', {}), getErrorMessage: getTimeRangeErrorMessages, }); @@ -102,9 +106,6 @@ export interface NowIndexPatternColumn extends ReferenceBasedIndexPatternColumn operationType: 'now'; } -function getNowFromContext({ now }: ContextValues) { - return now == null ? Date.now() : +now; -} function getNowErrorMessage() { return undefined; } @@ -112,12 +113,11 @@ function getNowErrorMessage() { export const nowOperation = createContextValueBasedOperation({ type: 'now', label: 'Current now', - description: i18n.translate('xpack.lens.indexPattern.now.documentation.markdown', { - defaultMessage: ` - The current now moment used in Kibana expressed in milliseconds (ms). - `, + description: i18n.translate('xpack.lens.formula.now.help', { + defaultMessage: 'The current now moment used in Kibana expressed in milliseconds (ms).', }), - getContextValue: getNowFromContext, + getExpressionFunction: (_context: ContextValues) => + buildExpressionFunction('formula_now', {}), getErrorMessage: getNowErrorMessage, }); @@ -125,12 +125,6 @@ export interface IntervalIndexPatternColumn extends ReferenceBasedIndexPatternCo operationType: 'interval'; } -function getIntervalFromContext(context: ContextValues) { - return context.dateRange && context.targetBars - ? calcAutoIntervalNear(context.targetBars, getTimeRangeFromContext(context)).asMilliseconds() - : 0; -} - function getIntervalErrorMessages( layer: FormBasedLayer, columnId: string, @@ -174,12 +168,13 @@ function getIntervalErrorMessages( export const intervalOperation = createContextValueBasedOperation({ type: 'interval', label: 'Date histogram interval', - description: i18n.translate('xpack.lens.indexPattern.interval.documentation.markdown', { - defaultMessage: ` -The specified minimum interval for the date histogram, in milliseconds (ms). - `, + description: i18n.translate('xpack.lens.formula.interval.help', { + defaultMessage: 'The specified minimum interval for the date histogram, in milliseconds (ms).', }), - getContextValue: getIntervalFromContext, + getExpressionFunction: ({ targetBars }: ContextValues) => + buildExpressionFunction('formula_interval', { + targetBars, + }), getErrorMessage: getIntervalErrorMessages, }); @@ -191,14 +186,14 @@ export type ConstantsIndexPatternColumn = function createContextValueBasedOperation({ label, type, - getContextValue, + getExpressionFunction, getErrorMessage, description, }: { label: string; type: ColumnType['operationType']; description: string; - getContextValue: (context: ContextValues) => number; + getExpressionFunction: (context: ContextValues) => ReturnType; getErrorMessage: OperationDefinition['getErrorMessage']; }): OperationDefinition { return { @@ -233,15 +228,11 @@ function createContextValueBasedOperation { const column = layer.columns[columnId] as ColumnType; return [ - { - type: 'function', - function: 'mathColumn', - arguments: { - id: [columnId], - name: [column.label], - expression: [String(getContextValue(context))], - }, - }, + buildExpressionFunction('mathColumn', { + id: columnId, + name: column.label, + expression: buildExpression([getExpressionFunction(context)]), + }).toAst(), ]; }, createCopy(layers, source, target) { diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/config_panel.test.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/config_panel.test.tsx index b0729cb489ba7..04d69c1afc571 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/config_panel.test.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/config_panel.test.tsx @@ -484,6 +484,7 @@ describe('ConfigPanel', () => { }, dateRange: expect.anything(), filters: [], + now: expect.anything(), query: undefined, }, groupId: 'a', diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.tsx index 73a4ef853390d..bc3b71c08487a 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.tsx @@ -24,7 +24,6 @@ import { } from '@elastic/eui'; import type { CoreStart } from '@kbn/core/public'; import type { DataPublicPluginStart } from '@kbn/data-plugin/public'; -import type { ExecutionContextSearch } from '@kbn/es-query'; import type { ExpressionRendererEvent, ExpressionRenderError, @@ -66,7 +65,6 @@ import { editVisualizationAction, setSaveable, useLensSelector, - selectExecutionContext, selectIsFullscreenDatasource, selectVisualization, selectDatasourceStates, @@ -80,6 +78,7 @@ import { VisualizationState, DatasourceStates, DataViewsState, + selectExecutionContextSearch, } from '../../../state_management'; import type { LensInspector } from '../../../lens_inspector_service'; import { inferTimeField, DONT_CLOSE_DIMENSION_CONTAINER_ON_CLICK_CLASS } from '../../../utils'; @@ -712,7 +711,7 @@ export const VisualizationWrapper = ({ // eslint-disable-next-line react-hooks/exhaustive-deps }, []); - const context = useLensSelector(selectExecutionContext); + const searchContext = useLensSelector(selectExecutionContextSearch); // Used for reporting const { isRenderComplete, hasDynamicError, setIsRenderComplete, setDynamicError, nodeRef } = useReportingState(errors); @@ -722,18 +721,6 @@ export const VisualizationWrapper = ({ onRender$(); }, [setIsRenderComplete, onRender$]); - const searchContext: ExecutionContextSearch = useMemo( - () => ({ - query: context.query, - timeRange: { - from: context.dateRange.fromDate, - to: context.dateRange.toDate, - }, - filters: context.filters, - disableWarningToasts: true, - }), - [context] - ); const searchSessionId = useLensSelector(selectSearchSessionId); if (errors.length) { diff --git a/x-pack/plugins/lens/public/embeddable/embeddable.tsx b/x-pack/plugins/lens/public/embeddable/embeddable.tsx index 9851a10c8641c..e5d34db62ba75 100644 --- a/x-pack/plugins/lens/public/embeddable/embeddable.tsx +++ b/x-pack/plugins/lens/public/embeddable/embeddable.tsx @@ -1253,6 +1253,7 @@ export class Embeddable const input = this.getInput(); const context: ExecutionContextSearch = { + now: this.deps.data.nowProvider.get().getTime(), timeRange: input.timeslice !== undefined ? { diff --git a/x-pack/plugins/lens/public/expressions.ts b/x-pack/plugins/lens/public/expressions.ts index ef12b43bec71d..32856175db1b0 100644 --- a/x-pack/plugins/lens/public/expressions.ts +++ b/x-pack/plugins/lens/public/expressions.ts @@ -14,6 +14,11 @@ import { formatColumn } from '../common/expressions/format_column'; import { counterRate } from '../common/expressions/counter_rate'; import { getTimeScale } from '../common/expressions/time_scale/time_scale'; import { collapse } from '../common/expressions/collapse'; +import { + formulaIntervalFn, + formulaNowFn, + formulaTimeRangeFn, +} from '../common/expressions/formula_context'; type TimeScaleArguments = Parameters; @@ -25,6 +30,9 @@ export const setupExpressions = ( getForceNow: TimeScaleArguments[2] ) => { [ + formulaTimeRangeFn, + formulaNowFn, + formulaIntervalFn, collapse, counterRate, formatColumn, diff --git a/x-pack/plugins/lens/public/state_management/selectors.ts b/x-pack/plugins/lens/public/state_management/selectors.ts index 7572c31287297..44121c4d064c7 100644 --- a/x-pack/plugins/lens/public/state_management/selectors.ts +++ b/x-pack/plugins/lens/public/state_management/selectors.ts @@ -46,9 +46,11 @@ export const selectTriggerApplyChanges = (state: LensState) => { return shouldApply; }; +// TODO - is there any point to keeping this around since we have selectExecutionSearchContext? export const selectExecutionContext = createSelector( [selectQuery, selectFilters, selectResolvedDateRange], (query, filters, dateRange) => ({ + now: Date.now(), dateRange, query, filters, @@ -56,6 +58,7 @@ export const selectExecutionContext = createSelector( ); export const selectExecutionContextSearch = createSelector(selectExecutionContext, (res) => ({ + now: res.now, query: res.query, timeRange: { from: res.dateRange.fromDate, diff --git a/x-pack/plugins/lens/server/expressions/expressions.ts b/x-pack/plugins/lens/server/expressions/expressions.ts index 1e80fc5bb49a3..b5e8fc2851608 100644 --- a/x-pack/plugins/lens/server/expressions/expressions.ts +++ b/x-pack/plugins/lens/server/expressions/expressions.ts @@ -13,6 +13,9 @@ import { mapToColumns, getTimeScale, getDatatable, + formulaIntervalFn, + formulaNowFn, + formulaTimeRangeFn, } from '../../common/expressions'; import { getDatatableUtilitiesFactory, getFormatFactory, getTimeZoneFactory } from './utils'; @@ -23,6 +26,9 @@ export const setupExpressions = ( expressions: ExpressionsServerSetup ) => { [ + formulaNowFn, + formulaIntervalFn, + formulaTimeRangeFn, counterRate, formatColumn, mapToColumns, diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json index 1c0f90d9ad92e..b770fe9cde9fa 100644 --- a/x-pack/plugins/translations/translations/fr-FR.json +++ b/x-pack/plugins/translations/translations/fr-FR.json @@ -21982,11 +21982,9 @@ "xpack.lens.indexPattern.counterRate.documentation.markdown": "\nCalcule le taux d'un compteur toujours croissant. Cette fonction renvoie uniquement des résultats utiles inhérents aux champs d'indicateurs de compteur qui contiennent une mesure quelconque à croissance régulière.\nSi la valeur diminue, elle est interprétée comme une mesure de réinitialisation de compteur. Pour obtenir des résultats plus précis, \"counter_rate\" doit être calculé d’après la valeur \"max\" du champ.\n\nCe calcul est réalisé séparément pour des séries distinctes définies par des filtres ou des dimensions de valeurs supérieures.\nIl utilise l'intervalle en cours utilisé dans la formule.\n\nExemple : visualiser le taux d'octets reçus au fil du temps par un serveur Memcached :\n`counter_rate(max(memcached.stats.read.bytes))`\n ", "xpack.lens.indexPattern.cumulativeSum.documentation.markdown": "\nCalcule la somme cumulée d'un indicateur au fil du temps, en ajoutant toutes les valeurs précédentes d'une série à chaque valeur. Pour utiliser cette fonction, vous devez également configurer une dimension de l'histogramme de dates.\n\nCe calcul est réalisé séparément pour des séries distinctes définies par des filtres ou des dimensions de valeurs supérieures.\n\nExemple : visualiser les octets reçus cumulés au fil du temps :\n`cumulative_sum(sum(bytes))`\n ", "xpack.lens.indexPattern.differences.documentation.markdown": "\nCalcule la différence par rapport à la dernière valeur d'un indicateur au fil du temps. Pour utiliser cette fonction, vous devez également configurer une dimension de l'histogramme de dates.\nLes données doivent être séquentielles pour les différences. Si vos données sont vides lorsque vous utilisez des différences, essayez d'augmenter l'intervalle de l'histogramme de dates.\n\nCe calcul est réalisé séparément pour des séries distinctes définies par des filtres ou des dimensions de valeurs supérieures.\n\nExemple : visualiser la modification des octets reçus au fil du temps :\n`differences(sum(bytes))`\n ", - "xpack.lens.indexPattern.interval.documentation.markdown": "\nL’intervalle minimum spécifié pour l’histogramme de date, en millisecondes (ms).\n ", "xpack.lens.indexPattern.lastValue.documentation.markdown": "\nRenvoie la valeur d'un champ du dernier document, triée par le champ d'heure par défaut de la vue de données.\n\nCette fonction permet de récupérer le dernier état d'une entité.\n\nExemple : obtenir le statut actuel du serveur A :\n`last_value(server.status, kql='server.name=\"A\"')`\n ", "xpack.lens.indexPattern.metric.documentation.markdown": "\nRenvoie l'indicateur {metric} d'un champ. Cette fonction fonctionne uniquement pour les champs numériques.\n\nExemple : obtenir l'indicateur {metric} d'un prix :\n\"{metric}(price)\"\n\nExemple : obtenir l'indicateur {metric} d'un prix pour des commandes du Royaume-Uni :\n\"{metric}(price, kql='location:UK')\"\n ", "xpack.lens.indexPattern.movingAverage.documentation.markdown": "\nCalcule la moyenne mobile d'un indicateur au fil du temps, en prenant la moyenne des n dernières valeurs pour calculer la valeur actuelle. Pour utiliser cette fonction, vous devez également configurer une dimension de l'histogramme de dates.\nLa valeur de fenêtre par défaut est {defaultValue}.\n\nCe calcul est réalisé séparément pour des séries distinctes définies par des filtres ou des dimensions de valeurs supérieures.\n\nPrend un paramètre nommé \"window\" qui spécifie le nombre de dernières valeurs à inclure dans le calcul de la moyenne de la valeur actuelle.\n\nExemple : lisser une ligne de mesures :\n`moving_average(sum(bytes), window=5)`\n ", - "xpack.lens.indexPattern.now.documentation.markdown": "\n La durée actuelle passée dans Kibana exprimée en millisecondes (ms).\n ", "xpack.lens.indexPattern.overall_average.documentation.markdown": "\nCalcule la moyenne d'un indicateur pour tous les points de données d'une série dans le graphique actuel. Une série est définie par une dimension à l'aide d'un histogramme de dates ou d'une fonction d'intervalle.\nD'autres dimensions permettant de répartir les données telles que les valeurs supérieures ou les filtres sont traitées en tant que séries distinctes.\n\nSi le graphique actuel n'utilise aucun histogramme de dates ou aucune fonction d'intervalle, \"overall_average\" calcule la moyenne pour toutes les dimensions, quelle que soit la fonction utilisée.\n\nExemple : écart par rapport à la moyenne :\n\"sum(bytes) - overall_average(sum(bytes))\"\n ", "xpack.lens.indexPattern.overall_max.documentation.markdown": "\nCalcule la valeur maximale d'un indicateur pour tous les points de données d'une série dans le graphique actuel. Une série est définie par une dimension à l'aide d'un histogramme de dates ou d'une fonction d'intervalle.\nD'autres dimensions permettant de répartir les données telles que les valeurs supérieures ou les filtres sont traitées en tant que séries distinctes.\n\nSi le graphique actuel n'utilise aucun histogramme de dates ou aucune fonction d'intervalle, \"overall_max\" calcule la valeur maximale pour toutes les dimensions, quelle que soit la fonction utilisée.\n\nExemple : pourcentage de plage\n\"(sum(bytes) - overall_min(sum(bytes))) / (overall_max(sum(bytes)) - overall_min(sum(bytes)))\"\n ", "xpack.lens.indexPattern.overall_min.documentation.markdown": "\nCalcule la valeur minimale d'un indicateur pour tous les points de données d'une série dans le graphique actuel. Une série est définie par une dimension à l'aide d'un histogramme de dates ou d'une fonction d'intervalle.\nD'autres dimensions permettant de répartir les données telles que les valeurs supérieures ou les filtres sont traitées en tant que séries distinctes.\n\nSi le graphique actuel n'utilise aucun histogramme de dates ou aucune fonction d'intervalle, \"overall_min\" calcule la valeur minimale pour toutes les dimensions, quelle que soit la fonction utilisée.\n\nExemple : pourcentage de plage\n\"(sum(bytes) - overall_min(sum(bytes)) / (overall_max(sum(bytes)) - overall_min(sum(bytes)))\"\n ", @@ -21995,7 +21993,6 @@ "xpack.lens.indexPattern.percentileRanks.documentation.markdown": "\nRetourne le pourcentage de valeurs qui sont en dessous d'une certaine valeur. Par exemple, si une valeur est supérieure à 95 % des valeurs observées, elle est placée au 95e rang centile.\n\nExemple : Obtenir le pourcentage de valeurs qui sont en dessous de 100 :\n\"percentile_rank(bytes, value=100)\"\n ", "xpack.lens.indexPattern.standardDeviation.documentation.markdown": "\nRetourne la taille de la variation ou de la dispersion du champ. Cette fonction ne s’applique qu’aux champs numériques.\n\n#### Exemples\n\nPour obtenir l'écart type d'un prix, utilisez standard_deviation(price).\n\nPour obtenir la variance du prix des commandes passées au Royaume-Uni, utilisez `square(standard_deviation(price, kql='location:UK'))`.\n ", "xpack.lens.indexPattern.time_scale.documentation.markdown": "\n\nCette fonction avancée est utile pour normaliser les comptes et les sommes sur un intervalle de temps spécifique. Elle permet l'intégration avec les indicateurs qui sont stockés déjà normalisés sur un intervalle de temps spécifique.\n\nVous pouvez faire appel à cette fonction uniquement si une fonction d'histogramme des dates est utilisée dans le graphique actuel.\n\nExemple : Un rapport comparant un indicateur déjà normalisé à un autre indicateur devant être normalisé.\n\"normalize_by_unit(counter_rate(max(system.diskio.write.bytes)), unit='s') / last_value(apache.status.bytes_per_second)\"\n ", - "xpack.lens.indexPattern.timeRange.documentation.markdown": "\nL'intervalle de temps spécifié, en millisecondes (ms).\n ", "xpack.lens.AggBasedLabel": "visualisation basée sur l'agrégation", "xpack.lens.app.addToLibrary": "Enregistrer dans la bibliothèque", "xpack.lens.app.cancel": "Annuler", diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index cc52a3743aca8..4d88ea32e314e 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -21997,11 +21997,9 @@ "xpack.lens.indexPattern.counterRate.documentation.markdown": "\n増加し続けるカウンターのレートを計算します。この関数は、経時的に単調に増加する種類の測定を含むカウンターメトリックフィールドでのみ結果を生成します。\n値が小さくなる場合は、カウンターリセットであると解釈されます。最も正確な結果を得るには、フィールドの「max`」で「counter_rate」を計算してください。\n\nこの計算はフィルターで定義された別の系列または上位値のディメンションに対して個別に実行されます。\n式で使用されるときには、現在の間隔を使用します。\n\n例:Memcachedサーバーで経時的に受信されたバイトの比率を可視化します。\n`counter_rate(max(memcached.stats.read.bytes))`\n ", "xpack.lens.indexPattern.cumulativeSum.documentation.markdown": "\n経時的なメトリックの累計値を計算し、系列のすべての前の値を各値に追加します。この関数を使用するには、日付ヒストグラムディメンションも構成する必要があります。\n\nこの計算はフィルターで定義された別の系列または上位値のディメンションに対して個別に実行されます。\n\n例:経時的に累積された受信バイト数を可視化します。\n`cumulative_sum(sum(bytes))`\n ", "xpack.lens.indexPattern.differences.documentation.markdown": "\n経時的にメトリックの最後の値に対する差異を計算します。この関数を使用するには、日付ヒストグラムディメンションも構成する必要があります。\n差異ではデータが連続する必要があります。差異を使用するときにデータが空の場合は、データヒストグラム間隔を大きくしてみてください。\n\nこの計算はフィルターで定義された別の系列または上位値のディメンションに対して個別に実行されます。\n\n例:経時的に受信したバイト数の変化を可視化します。\n`differences(sum(bytes))`\n ", - "xpack.lens.indexPattern.interval.documentation.markdown": "\nミリ秒(ms)で指定した、日付ヒストグラムの最小間隔。\n ", "xpack.lens.indexPattern.lastValue.documentation.markdown": "\n最後のドキュメントからフィールドの値を返し、データビューのデフォルト時刻フィールドで並べ替えます。\n\nこの関数はエンティティの最新の状態を取得する際に役立ちます。\n\n例:サーバーAの現在のステータスを取得:\n`last_value(server.status, kql='server.name=\"A\"')`\n ", "xpack.lens.indexPattern.metric.documentation.markdown": "\nフィールドの{metric}を返します。この関数は数値フィールドでのみ動作します。\n\n例:価格の{metric}を取得:\n`{metric}(price)`\n\n例:英国からの注文の価格の{metric}を取得:\n`{metric}(price, kql='location:UK')`\n ", "xpack.lens.indexPattern.movingAverage.documentation.markdown": "\n経時的なメトリックの移動平均を計算します。最後のn番目の値を平均化し、現在の値を計算します。この関数を使用するには、日付ヒストグラムディメンションも構成する必要があります。\nデフォルトウィンドウ値は{defaultValue}です\n\nこの計算はフィルターで定義された別の系列または上位値のディメンションに対して個別に実行されます。\n\n指名パラメーター「window」を取ります。これは現在値の平均計算に含める最後の値の数を指定します。\n\n例:測定の線を平滑化:\n`moving_average(sum(bytes), window=5)`\n ", - "xpack.lens.indexPattern.now.documentation.markdown": "\n ミリ秒(ms)で表された、Kibanaで使用される現在の日時。\n ", "xpack.lens.indexPattern.overall_average.documentation.markdown": "\n現在のグラフの系列のすべてのデータポイントのメトリックの平均を計算します。系列は日付ヒストグラムまたは間隔関数を使用してディメンションによって定義されます。\n上位の値やフィルターなどのデータを分解する他のディメンションは別の系列として処理されます。\n\n日付ヒストグラムまたは間隔関数が現在のグラフで使用されている場合、使用されている関数に関係なく、「overall_average」はすべてのディメンションで平均値を計算します。\n\n例:平均からの収束:\n`sum(bytes) - overall_average(sum(bytes))`\n ", "xpack.lens.indexPattern.overall_max.documentation.markdown": "\n現在のグラフの系列のすべてのデータポイントのメトリックの最大値を計算します。系列は日付ヒストグラムまたは間隔関数を使用してディメンションによって定義されます。\n上位の値やフィルターなどのデータを分解する他のディメンションは別の系列として処理されます。\n\n日付ヒストグラムまたは間隔関数が現在のグラフで使用されている場合、使用されている関数に関係なく、「overall_max」はすべてのディメンションで最大値を計算します。\n\n例:範囲の割合\n`(sum(bytes) - overall_min(sum(bytes))) / (overall_max(sum(bytes)) - overall_min(sum(bytes)))`\n ", "xpack.lens.indexPattern.overall_min.documentation.markdown": "\n現在のグラフの系列のすべてのデータポイントのメトリックの最小値を計算します。系列は日付ヒストグラムまたは間隔関数を使用してディメンションによって定義されます。\n上位の値やフィルターなどのデータを分解する他のディメンションは別の系列として処理されます。\n\n日付ヒストグラムまたは間隔関数が現在のグラフで使用されている場合、使用されている関数に関係なく、「overall_min」はすべてのディメンションで最小値を計算します。\n\n例:範囲の割合\n`(sum(bytes) - overall_min(sum(bytes)) / (overall_max(sum(bytes)) - overall_min(sum(bytes)))`\n ", @@ -22010,7 +22008,6 @@ "xpack.lens.indexPattern.percentileRanks.documentation.markdown": "\n特定の値未満の値の割合が返されます。たとえば、値が観察された値の95%以上の場合、95パーセンタイルランクであるとされます。\n\n例:100未満の値のパーセンタイルを取得します。\n`percentile_rank(bytes, value=100)`\n ", "xpack.lens.indexPattern.standardDeviation.documentation.markdown": "\nフィールドの分散または散布度が返されます。この関数は数値フィールドでのみ動作します。\n\n#### 例\n\n価格の標準偏差を取得するには、standard_deviation(price)を使用します。\n\n英国からの注文書の価格の分散を取得するには、square(standard_deviation(price, kql='location:UK'))を使用します。\n ", "xpack.lens.indexPattern.time_scale.documentation.markdown": "\n\nこの高度な機能は、特定の期間に対してカウントと合計を正規化する際に役立ちます。すでに特定の期間に対して正規化され、保存されたメトリックとの統合が可能です。\n\nこの機能は、現在のグラフで日付ヒストグラム関数が使用されている場合にのみ使用できます。\n\n例:すでに正規化されているメトリックを、正規化が必要な別のメトリックと比較した比率。\n`normalize_by_unit(counter_rate(max(system.diskio.write.bytes)), unit='s') / last_value(apache.status.bytes_per_second)`\n ", - "xpack.lens.indexPattern.timeRange.documentation.markdown": "\nミリ秒(ms)で指定された時間範囲。\n ", "xpack.lens.AggBasedLabel": "集約に基づく可視化", "xpack.lens.app.addToLibrary": "ライブラリに保存", "xpack.lens.app.cancel": "キャンセル", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 4a724bbb7c4a6..422b5a4be2330 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -21996,11 +21996,9 @@ "xpack.lens.indexPattern.counterRate.documentation.markdown": "\n计算不断增大的计数器的速率。此函数将仅基于计数器指标字段生成有帮助的结果,包括随着时间的推移度量某种单调递增。\n如果值确实变小,则其将此解析为计数器重置。要获取很精确的结果,应基于字段的 `max`计算 `counter_rate`。\n\n筛选或排名最前值维度定义的不同序列将分别执行此计算。\n用于公式中时,其使用当前时间间隔。\n\n例如:可视化随着时间的推移 Memcached 服务器接收的字节速率:\n`counter_rate(max(memcached.stats.read.bytes))`\n ", "xpack.lens.indexPattern.cumulativeSum.documentation.markdown": "\n计算随着时间的推移指标的累计和,即序列的所有以前值相加得出每个值。要使用此函数,您还需要配置 Date Histogram 维度。\n\n筛选或排名最前值维度定义的不同序列将分别执行此计算。\n\n例如:可视化随着时间的推移累计接收的字节:\n`cumulative_sum(sum(bytes))`\n ", "xpack.lens.indexPattern.differences.documentation.markdown": "\n计算随着时间的推移与指标最后一个值的差异。要使用此函数,您还需要配置 Date Histogram 维度。\n差异需要数据是顺序的。如果使用差异时数据为空,请尝试增加 Date Histogram 时间间隔。\n\n筛选或排名最前值维度定义的不同序列将分别执行此计算。\n\n例如:可视化随着时间的推移接收的字节的变化:\n`differences(sum(bytes))`\n ", - "xpack.lens.indexPattern.interval.documentation.markdown": "\nDate Histogram 的指定最小时间间隔,单位为毫秒 (ms)。\n ", "xpack.lens.indexPattern.lastValue.documentation.markdown": "\n返回最后一个文档的字段值,按数据视图的默认时间字段排序。\n\n此函数用于检索实体的最新状态。\n\n例如:获取服务器 A 的当前状态:\n`last_value(server.status, kql='server.name=\"A\"')`\n ", "xpack.lens.indexPattern.metric.documentation.markdown": "\n返回字段的 {metric}。此函数仅适用于数字字段。\n\n例如:获取价格的 {metric}:\n`{metric}(price)`\n\n例如:获取英国订单价格的 {metric}:\n`{metric}(price, kql='location:UK')`\n ", "xpack.lens.indexPattern.movingAverage.documentation.markdown": "\n计算随着时间的推移指标的移动平均值,即计算最后 n 个值的平均值以得出当前值。要使用此函数,您还需要配置 Date Histogram 维度。\n默认窗口值为 {defaultValue}。\n\n筛选或排名最前值维度定义的不同序列将分别执行此计算。\n\n取已命名参数 `window`,其指定当前值的平均计算中要包括过去多少个值。\n\n例如:平滑度量线:\n`moving_average(sum(bytes), window=5)`\n ", - "xpack.lens.indexPattern.now.documentation.markdown": "\n Kibana 中使用的当前时刻,用毫秒 (ms) 表示。\n ", "xpack.lens.indexPattern.overall_average.documentation.markdown": "\n为当前图表中序列的所有数据点计算指标的平均值。序列由维度使用 Date Histogram 或时间间隔函数定义。\n分解数据的其他维度,如排名最前值或筛选,将被视为不同的序列。\n\n如果当前图表未使用 Date Histogram 或时间间隔函数,则无论使用什么函数,`overall_average` 都将计算所有维度的平均值\n\n例如:与平均值的偏离:\n`sum(bytes) - overall_average(sum(bytes))`\n ", "xpack.lens.indexPattern.overall_max.documentation.markdown": "\n为当前图表中序列的所有数据点计算指标的最大值。序列由维度使用 Date Histogram 或时间间隔函数定义。\n分解数据的其他维度,如排名最前值或筛选,将被视为不同的序列。\n\n如果当前图表未使用 Date Histogram 或内部函数,则无论使用什么函数,`overall_max` 都将计算所有维度的最大值\n\n例如:范围的百分比\n`(sum(bytes) - overall_min(sum(bytes))) / (overall_max(sum(bytes)) - overall_min(sum(bytes)))`\n ", "xpack.lens.indexPattern.overall_min.documentation.markdown": "\n为当前图表中序列的所有数据点计算指标的最小值。序列由维度使用 Date Histogram 或时间间隔函数定义。\n分解数据的其他维度,如排名最前值或筛选,将被视为不同的序列。\n\n如果当前图表未使用 Date Histogram 或时间间隔函数,则无论使用什么函数,`overall_min` 都将计算所有维度的最小值\n\n例如:范围的百分比\n`(sum(bytes) - overall_min(sum(bytes)) / (overall_max(sum(bytes)) - overall_min(sum(bytes)))`\n ", @@ -22009,7 +22007,6 @@ "xpack.lens.indexPattern.percentileRanks.documentation.markdown": "\n返回小于某个值的值的百分比。例如,如果某个值大于或等于 95% 的观察值,则称它处于第 95 个百分位等级\n\n例如:获取小于 100 的值的百分比:\n`percentile_rank(bytes, value=100)`\n ", "xpack.lens.indexPattern.standardDeviation.documentation.markdown": "\n返回字段的变量或差量数量。此函数仅适用于数字字段。\n\n#### 示例\n\n要获取价格的标准偏差,请使用 `standard_deviation(price)`。\n\n要获取来自英国的订单的价格方差,请使用 `square(standard_deviation(price, kql='location:UK'))`。\n ", "xpack.lens.indexPattern.time_scale.documentation.markdown": "\n\n此高级函数用于将计数和总和标准化为特定时间间隔。它允许集成所存储的已标准化为特定时间间隔的指标。\n\n此函数只能在当前图表中使用了日期直方图函数时使用。\n\n例如:将已标准化指标与其他需要标准化的指标进行比较的比率。\n`normalize_by_unit(counter_rate(max(system.diskio.write.bytes)), unit='s') / last_value(apache.status.bytes_per_second)`\n ", - "xpack.lens.indexPattern.timeRange.documentation.markdown": "\n指定的时间范围,单位为毫秒 (ms)。\n ", "xpack.lens.AggBasedLabel": "基于聚合的可视化", "xpack.lens.app.addToLibrary": "保存到库", "xpack.lens.app.cancel": "取消",