mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 01:13:23 -04:00
[ML] Enhance support for counter fields in data visualizer / field statistics (#153893)
Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
8724518804
commit
ab1ac1b25d
32 changed files with 318 additions and 528 deletions
|
@ -35,4 +35,5 @@ export type { NumberValidationResult } from './src/validate_number';
|
|||
export {
|
||||
TIME_SERIES_METRIC_TYPES,
|
||||
isCounterTimeSeriesMetric,
|
||||
isGaugeTimeSeriesMetric,
|
||||
} from './src/time_series_metric_fields';
|
||||
|
|
|
@ -24,3 +24,11 @@ export enum TIME_SERIES_METRIC_TYPES {
|
|||
*/
|
||||
export const isCounterTimeSeriesMetric = (field?: DataViewField) =>
|
||||
field?.timeSeriesMetric === TIME_SERIES_METRIC_TYPES.COUNTER;
|
||||
|
||||
/**
|
||||
* Check if DataViewField is a 'gauge' time series metric field
|
||||
* @param field optional DataViewField
|
||||
* @returns a boolean
|
||||
*/
|
||||
export const isGaugeTimeSeriesMetric = (field?: DataViewField) =>
|
||||
field?.timeSeriesMetric === TIME_SERIES_METRIC_TYPES.GAUGE;
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { KBN_FIELD_TYPES } from '@kbn/field-types';
|
||||
import type { DocLinksStart } from '@kbn/core/public';
|
||||
|
||||
export const APP_ID = 'data_visualizer';
|
||||
export const UI_SETTING_MAX_FILE_SIZE = 'fileUpload:maxFileSize';
|
||||
|
@ -65,116 +64,3 @@ export const featureTitle = i18n.translate('xpack.dataVisualizer.title', {
|
|||
defaultMessage: 'Upload a file',
|
||||
});
|
||||
export const featureId = `file_data_visualizer`;
|
||||
|
||||
const UNKNOWN_FIELD_TYPE_DESC = i18n.translate(
|
||||
'xpack.dataVisualizer.index.fieldNameDescription.unknownField',
|
||||
{
|
||||
defaultMessage: 'Unknown field',
|
||||
}
|
||||
);
|
||||
|
||||
export function getFieldTypeDescription(type: string, docLinks: DocLinksStart) {
|
||||
switch (type) {
|
||||
case SUPPORTED_FIELD_TYPES.BOOLEAN:
|
||||
return i18n.translate('xpack.dataVisualizer.index.fieldNameDescription.booleanField', {
|
||||
defaultMessage: 'True and false values',
|
||||
});
|
||||
case SUPPORTED_FIELD_TYPES.CONFLICT:
|
||||
return i18n.translate('xpack.dataVisualizer.index.fieldNameDescription.conflictField', {
|
||||
defaultMessage: 'Field has values of different types. Resolve in Management > Data Views.',
|
||||
});
|
||||
case SUPPORTED_FIELD_TYPES.DATE:
|
||||
return i18n.translate('xpack.dataVisualizer.index.fieldNameDescription.dateField', {
|
||||
defaultMessage: 'A date string or the number of seconds or milliseconds since 1/1/1970',
|
||||
});
|
||||
case SUPPORTED_FIELD_TYPES.DATE_RANGE:
|
||||
return i18n.translate('xpack.dataVisualizer.index.fieldNameDescription.dateRangeField', {
|
||||
defaultMessage: 'Range of {dateFieldTypeLink} values. {viewSupportedDateFormatsLink}',
|
||||
values: {
|
||||
dateFieldTypeLink:
|
||||
`<a href=${docLinks.links.discover.dateFieldTypeDocs}
|
||||
target="_blank" rel="noopener">` +
|
||||
i18n.translate(
|
||||
'xpack.dataVisualizer.index.fieldNameDescription.dateRangeFieldLinkText',
|
||||
{
|
||||
defaultMessage: 'date',
|
||||
}
|
||||
) +
|
||||
'</a>',
|
||||
viewSupportedDateFormatsLink:
|
||||
`<a href=${docLinks.links.discover.dateFormatsDocs}
|
||||
target="_blank" rel="noopener">` +
|
||||
i18n.translate(
|
||||
'xpack.dataVisualizer.index.fieldNameDescription.viewSupportedDateFormatsLinkText',
|
||||
{
|
||||
defaultMessage: 'View supported date formats.',
|
||||
}
|
||||
) +
|
||||
'</a>',
|
||||
},
|
||||
});
|
||||
case SUPPORTED_FIELD_TYPES.GEO_POINT:
|
||||
return i18n.translate('xpack.dataVisualizer.index.fieldNameDescription.geoPointField', {
|
||||
defaultMessage: 'Latitude and longitude points',
|
||||
});
|
||||
case SUPPORTED_FIELD_TYPES.GEO_SHAPE:
|
||||
return i18n.translate('xpack.dataVisualizer.index.fieldNameDescription.geoShapeField', {
|
||||
defaultMessage: 'Complex shapes such as polygons',
|
||||
});
|
||||
case SUPPORTED_FIELD_TYPES.HISTOGRAM:
|
||||
return i18n.translate('xpack.dataVisualizer.index.fieldNameDescription.histogramField', {
|
||||
defaultMessage: 'Pre-aggregated numerical values in the form of a histogram',
|
||||
});
|
||||
case SUPPORTED_FIELD_TYPES.IP:
|
||||
return i18n.translate('xpack.dataVisualizer.index.fieldNameDescription.ipAddressField', {
|
||||
defaultMessage: 'IPv4 and IPv6 addresses',
|
||||
});
|
||||
case SUPPORTED_FIELD_TYPES.IP_RANGE:
|
||||
return i18n.translate('xpack.dataVisualizer.index.fieldNameDescription.ipAddressRangeField', {
|
||||
defaultMessage: 'Range of IP values supporting either IPv4 or IPv6 (or mixed) addresses',
|
||||
});
|
||||
case SUPPORTED_FIELD_TYPES.MURMUR3:
|
||||
return i18n.translate('xpack.dataVisualizer.index.fieldNameDescription.murmur3Field', {
|
||||
defaultMessage: 'Field that computes and stores hashes of values',
|
||||
});
|
||||
case SUPPORTED_FIELD_TYPES.NESTED:
|
||||
return i18n.translate('xpack.dataVisualizer.index.fieldNameDescription.nestedField', {
|
||||
defaultMessage: 'JSON object that preserves the relationship between its subfields',
|
||||
});
|
||||
case SUPPORTED_FIELD_TYPES.NUMBER:
|
||||
return i18n.translate('xpack.dataVisualizer.index.fieldNameDescription.numberField', {
|
||||
defaultMessage: 'Long, integer, short, byte, double, and float values',
|
||||
});
|
||||
case SUPPORTED_FIELD_TYPES.STRING:
|
||||
return i18n.translate('xpack.dataVisualizer.index.fieldNameDescription.stringField', {
|
||||
defaultMessage: 'Full text such as the body of an email or a product description',
|
||||
});
|
||||
case SUPPORTED_FIELD_TYPES.TEXT:
|
||||
return i18n.translate('xpack.dataVisualizer.index.fieldNameDescription.textField', {
|
||||
defaultMessage: 'Full text such as the body of an email or a product description',
|
||||
});
|
||||
case SUPPORTED_FIELD_TYPES.KEYWORD:
|
||||
return i18n.translate('xpack.dataVisualizer.index.fieldNameDescription.keywordField', {
|
||||
defaultMessage:
|
||||
'Structured content such as an ID, email address, hostname, status code, or tag',
|
||||
});
|
||||
case SUPPORTED_FIELD_TYPES.VERSION:
|
||||
return i18n.translate('xpack.dataVisualizer.index.fieldNameDescription.versionField', {
|
||||
defaultMessage: 'Software versions. Supports {SemanticVersioningLink} precedence rules',
|
||||
values: {
|
||||
SemanticVersioningLink:
|
||||
`<a href="https://semver.org/"
|
||||
target="_blank" rel="noopener">` +
|
||||
i18n.translate(
|
||||
'xpack.dataVisualizer.index.advancedSettings.discover.fieldNameDescription.versionFieldLinkText',
|
||||
{
|
||||
defaultMessage: 'Semantic Versioning',
|
||||
}
|
||||
) +
|
||||
'</a>',
|
||||
},
|
||||
});
|
||||
default:
|
||||
return UNKNOWN_FIELD_TYPE_DESC;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ export interface FieldRequestConfig {
|
|||
type: SupportedFieldType;
|
||||
cardinality: number;
|
||||
existsInDocs: boolean;
|
||||
supportedAggs?: Set<string>;
|
||||
}
|
||||
|
||||
export interface DocumentCountBuckets {
|
||||
|
|
|
@ -74,9 +74,9 @@ export const isIKibanaSearchResponse = (arg: unknown): arg is IKibanaSearchRespo
|
|||
export interface NumericFieldStats {
|
||||
fieldName: string;
|
||||
count?: number;
|
||||
min: number;
|
||||
max: number;
|
||||
avg: number;
|
||||
min?: number;
|
||||
max?: number;
|
||||
avg?: number;
|
||||
isTopValuesSampled: boolean;
|
||||
topValues: Bucket[];
|
||||
topValuesSampleSize: number;
|
||||
|
@ -211,6 +211,8 @@ export interface FieldStatsCommonRequestParams {
|
|||
samplingOption: SamplingOption;
|
||||
}
|
||||
|
||||
export type SupportedAggs = Set<string>;
|
||||
|
||||
export interface OverallStatsSearchStrategyParams {
|
||||
sessionId?: string;
|
||||
earliest?: number;
|
||||
|
@ -222,7 +224,10 @@ export interface OverallStatsSearchStrategyParams {
|
|||
index: string;
|
||||
timeFieldName?: string;
|
||||
runtimeFieldMap?: estypes.MappingRuntimeFields;
|
||||
aggregatableFields: string[];
|
||||
aggregatableFields: Array<{
|
||||
name: string;
|
||||
supportedAggs: SupportedAggs;
|
||||
}>;
|
||||
nonAggregatableFields: string[];
|
||||
fieldsToFetch?: string[];
|
||||
browserSessionSeed: number;
|
||||
|
@ -258,6 +263,7 @@ export interface Field {
|
|||
type: string;
|
||||
cardinality: number;
|
||||
safeFieldName: string;
|
||||
supportedAggs?: Set<string>;
|
||||
}
|
||||
|
||||
export interface Aggs {
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import type { SupportedAggs } from './field_stats';
|
||||
import type { Percentile, SupportedFieldType, FieldVisStats } from '.';
|
||||
export interface MetricFieldVisStats {
|
||||
avg?: number;
|
||||
|
@ -27,16 +28,19 @@ export interface FieldVisConfig {
|
|||
existsInDocs: boolean;
|
||||
aggregatable: boolean;
|
||||
loading: boolean;
|
||||
secondaryType: string;
|
||||
stats?: FieldVisStats;
|
||||
fieldFormat?: any;
|
||||
isUnsupportedType?: boolean;
|
||||
deletable?: boolean;
|
||||
supportedAggs?: SupportedAggs;
|
||||
}
|
||||
|
||||
export interface FileBasedFieldVisConfig {
|
||||
type: SupportedFieldType;
|
||||
fieldName?: string;
|
||||
displayName?: string;
|
||||
secondaryType?: string;
|
||||
stats?: FieldVisStats;
|
||||
format?: string;
|
||||
}
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
"esUiShared",
|
||||
"fieldFormats",
|
||||
"uiActions",
|
||||
"unifiedFieldList",
|
||||
"lens",
|
||||
"cloudChat",
|
||||
"savedSearch"
|
||||
|
|
|
@ -68,15 +68,24 @@ export function getNumberSettings(item: FieldVisConfig, defaultDataView: DataVie
|
|||
return { columns, layer };
|
||||
}
|
||||
|
||||
const operationType = item.supportedAggs?.has('avg') ? 'average' : 'max';
|
||||
const operationLabel =
|
||||
operationType === 'average'
|
||||
? i18n.translate('xpack.dataVisualizer.index.lensChart.averageOfLabel', {
|
||||
defaultMessage: 'Average of {fieldName}',
|
||||
values: { fieldName: item.fieldName },
|
||||
})
|
||||
: i18n.translate('xpack.dataVisualizer.index.lensChart.maximumOfLabel', {
|
||||
defaultMessage: 'Maximum of {fieldName}',
|
||||
values: { fieldName: item.fieldName },
|
||||
});
|
||||
|
||||
const columns: Record<string, GenericIndexPatternColumn> = {
|
||||
col2: {
|
||||
dataType: 'number',
|
||||
isBucketed: false,
|
||||
label: i18n.translate('xpack.dataVisualizer.index.lensChart.averageOfLabel', {
|
||||
defaultMessage: 'Average of {fieldName}',
|
||||
values: { fieldName: item.fieldName },
|
||||
}),
|
||||
operationType: 'average',
|
||||
label: operationLabel,
|
||||
operationType,
|
||||
sourceField: item.fieldName!,
|
||||
},
|
||||
col1: {
|
||||
|
|
|
@ -9,18 +9,17 @@ import React, { FC } from 'react';
|
|||
import { EuiToolTip } from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { FieldIcon } from '@kbn/react-field';
|
||||
import { getJobTypeLabel } from '../../util/field_types_utils';
|
||||
import type { SupportedFieldType } from '../../../../../common/types';
|
||||
import { getFieldTypeName } from '@kbn/unified-field-list-plugin/public';
|
||||
import './_index.scss';
|
||||
|
||||
interface FieldTypeIconProps {
|
||||
tooltipEnabled: boolean;
|
||||
type: SupportedFieldType;
|
||||
type: string;
|
||||
}
|
||||
|
||||
export const FieldTypeIcon: FC<FieldTypeIconProps> = ({ tooltipEnabled = false, type }) => {
|
||||
const label =
|
||||
getJobTypeLabel(type) ??
|
||||
getFieldTypeName(type) ??
|
||||
i18n.translate('xpack.dataVisualizer.fieldTypeIcon.fieldTypeTooltip', {
|
||||
defaultMessage: '{type} type',
|
||||
values: { type },
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
import React, { FC, useMemo } from 'react';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
|
||||
import { getFieldTypeName } from '@kbn/unified-field-list-plugin/public';
|
||||
import { FieldTypesHelpPopover } from './field_types_help_popover';
|
||||
import { MultiSelectPicker, Option } from '../multi_select_picker';
|
||||
import type {
|
||||
|
@ -15,7 +16,6 @@ import type {
|
|||
FileBasedUnknownFieldVisConfig,
|
||||
} from '../../../../../common/types/field_vis_config';
|
||||
import { FieldTypeIcon } from '../field_type_icon';
|
||||
import { jobTypeLabels } from '../../util/field_types_utils';
|
||||
|
||||
interface Props {
|
||||
fields: Array<FileBasedFieldVisConfig | FileBasedUnknownFieldVisConfig>;
|
||||
|
@ -40,9 +40,8 @@ export const DataVisualizerFieldTypesFilter: FC<Props> = ({
|
|||
const fieldTypesTracker = new Set();
|
||||
const fieldTypes: Option[] = [];
|
||||
fields.forEach(({ type }) => {
|
||||
if (type !== undefined && !fieldTypesTracker.has(type) && jobTypeLabels[type] !== undefined) {
|
||||
const label = jobTypeLabels[type];
|
||||
|
||||
const label = getFieldTypeName(type);
|
||||
if (type !== undefined && !fieldTypesTracker.has(type) && label !== undefined) {
|
||||
fieldTypesTracker.add(type);
|
||||
fieldTypes.push({
|
||||
value: type,
|
||||
|
|
|
@ -22,7 +22,7 @@ import React, { FC, useMemo, useState } from 'react';
|
|||
import { i18n } from '@kbn/i18n';
|
||||
import { FieldIcon } from '@kbn/react-field';
|
||||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
import { getFieldTypeDescription } from '../../../../../common/constants';
|
||||
import { getFieldTypeDescription } from '@kbn/unified-field-list-plugin/public';
|
||||
import { useDataVisualizerKibana } from '../../../kibana_context';
|
||||
|
||||
interface FieldTypeTableItem {
|
||||
|
@ -49,9 +49,9 @@ export const FieldTypesHelpPopover: FC<{
|
|||
fieldTypes.map((type, index) => ({
|
||||
id: index,
|
||||
dataType: type,
|
||||
description: getFieldTypeDescription(type, docLinks),
|
||||
description: getFieldTypeDescription(type),
|
||||
})),
|
||||
[fieldTypes, docLinks]
|
||||
[fieldTypes]
|
||||
);
|
||||
|
||||
const columnsSidebar = [
|
||||
|
|
|
@ -10,6 +10,11 @@ import { SUPPORTED_FIELD_TYPES } from '../../../../../common/constants';
|
|||
interface CommonFieldConfig {
|
||||
type: string;
|
||||
fieldName?: string;
|
||||
secondaryType?: string;
|
||||
}
|
||||
|
||||
export function matchFieldType<T extends CommonFieldConfig>(fieldType: string, config: T) {
|
||||
return fieldType === config.secondaryType || fieldType === config.type;
|
||||
}
|
||||
export function filterFields<T extends CommonFieldConfig>(
|
||||
fields: T[],
|
||||
|
@ -20,12 +25,12 @@ export function filterFields<T extends CommonFieldConfig>(
|
|||
|
||||
if (visibleFieldTypes && visibleFieldTypes.length > 0) {
|
||||
items = items.filter(
|
||||
(config) => visibleFieldTypes.findIndex((field) => field === config.type) > -1
|
||||
(config) => visibleFieldTypes.findIndex((fieldType) => matchFieldType(fieldType, config)) > -1
|
||||
);
|
||||
}
|
||||
if (visibleFieldNames && visibleFieldNames.length > 0) {
|
||||
items = items.filter((config) => {
|
||||
return visibleFieldNames.findIndex((field) => field === config.fieldName) > -1;
|
||||
return visibleFieldNames.findIndex((fieldName) => fieldName === config.fieldName) > -1;
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@ import { ES_FIELD_TYPES } from '@kbn/field-types';
|
|||
import type { FindFileStructureResponse } from '@kbn/file-upload-plugin/common';
|
||||
import type { SupportedFieldType } from '../../../../../common/types';
|
||||
import { SUPPORTED_FIELD_TYPES } from '../../../../../common/constants';
|
||||
|
||||
export function getFieldNames(results: FindFileStructureResponse) {
|
||||
const { mappings, field_stats: fieldStats, column_names: columnNames } = results;
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@ import {
|
|||
|
||||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { isDefined } from '@kbn/ml-is-defined';
|
||||
import type { FieldDataRowProps } from '../../types/field_data_row';
|
||||
import { kibanaFieldFormat, numberAsOrdinal } from '../../../utils';
|
||||
import { MetricDistributionChart, buildChartDataFromStats } from '../metric_distribution_chart';
|
||||
|
@ -58,16 +59,20 @@ export const NumberContent: FC<FieldDataRowProps> = ({ config, onAddFilter }) =>
|
|||
),
|
||||
value: kibanaFieldFormat(min, fieldFormat),
|
||||
},
|
||||
{
|
||||
function: 'median',
|
||||
display: (
|
||||
<FormattedMessage
|
||||
id="xpack.dataVisualizer.dataGrid.fieldExpandedRow.numberContent.medianLabel"
|
||||
defaultMessage="median"
|
||||
/>
|
||||
),
|
||||
value: kibanaFieldFormat(median, fieldFormat),
|
||||
},
|
||||
...(isDefined(median)
|
||||
? [
|
||||
{
|
||||
function: 'median',
|
||||
display: (
|
||||
<FormattedMessage
|
||||
id="xpack.dataVisualizer.dataGrid.fieldExpandedRow.numberContent.medianLabel"
|
||||
defaultMessage="median"
|
||||
/>
|
||||
),
|
||||
value: kibanaFieldFormat(median, fieldFormat),
|
||||
},
|
||||
]
|
||||
: []),
|
||||
{
|
||||
function: 'max',
|
||||
display: (
|
||||
|
|
|
@ -193,8 +193,8 @@ export const DataVisualizerTable = <T extends DataVisualizerTableItem>({
|
|||
name: i18n.translate('xpack.dataVisualizer.dataGrid.typeColumnName', {
|
||||
defaultMessage: 'Type',
|
||||
}),
|
||||
render: (fieldType: SupportedFieldType) => {
|
||||
return <FieldTypeIcon type={fieldType} tooltipEnabled={true} />;
|
||||
render: (fieldType: SupportedFieldType, item: DataVisualizerTableItem) => {
|
||||
return <FieldTypeIcon type={item.secondaryType ?? fieldType} tooltipEnabled={true} />;
|
||||
},
|
||||
width: dimensions.type,
|
||||
sortable: true,
|
||||
|
@ -396,7 +396,7 @@ export const DataVisualizerTable = <T extends DataVisualizerTableItem>({
|
|||
boxShadow: `inset 0 0px 0, inset 0 -1px 0 ${euiTheme.border.color}`,
|
||||
},
|
||||
'.euiTableRow > .euiTableRowCel': {
|
||||
'border-top': 0,
|
||||
borderTop: 0,
|
||||
},
|
||||
[useEuiMinBreakpoint('s')]: {
|
||||
'& .columnHeader__title': {
|
||||
|
|
|
@ -54,6 +54,7 @@ export const TopValues: FC<Props> = ({ stats, fieldFormat, barColor, compressed,
|
|||
if (stats === undefined || !stats.topValues) return null;
|
||||
const { topValues, fieldName, sampleCount } = stats;
|
||||
|
||||
if (topValues?.length === 0) return null;
|
||||
const totalDocuments = stats.totalDocuments ?? sampleCount ?? 0;
|
||||
const topValuesOtherCountPercent =
|
||||
1 - (topValues ? topValues.reduce((acc, bucket) => acc + bucket.percent, 0) : 0);
|
||||
|
|
|
@ -1,30 +0,0 @@
|
|||
/*
|
||||
* 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 { SUPPORTED_FIELD_TYPES } from '../../../../common/constants';
|
||||
import { getJobTypeLabel, jobTypeLabels } from './field_types_utils';
|
||||
|
||||
describe('field type utils', () => {
|
||||
describe('getJobTypeLabel: Getting a field type aria label by passing what it is stored in constants', () => {
|
||||
test('should returns all SUPPORTED_FIELD_TYPES labels exactly as it is for each correct value', () => {
|
||||
const keys = Object.keys(SUPPORTED_FIELD_TYPES);
|
||||
const receivedLabels: Record<string, string | null> = {};
|
||||
const testStorage = jobTypeLabels;
|
||||
keys.forEach((key) => {
|
||||
const constant = key as keyof typeof SUPPORTED_FIELD_TYPES;
|
||||
receivedLabels[SUPPORTED_FIELD_TYPES[constant]] = getJobTypeLabel(
|
||||
SUPPORTED_FIELD_TYPES[constant]
|
||||
);
|
||||
});
|
||||
|
||||
expect(receivedLabels).toEqual(testStorage);
|
||||
});
|
||||
test('should returns NULL as SUPPORTED_FIELD_TYPES does not contain such a keyword', () => {
|
||||
expect(getJobTypeLabel('SUPPORTED_FIELD_TYPES')).toBe(null);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -5,116 +5,15 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { DataViewField } from '@kbn/data-views-plugin/public';
|
||||
import { ES_FIELD_TYPES, KBN_FIELD_TYPES } from '@kbn/field-types';
|
||||
import type { SupportedFieldType } from '../../../../common/types';
|
||||
import { KBN_FIELD_TYPES } from '@kbn/field-types';
|
||||
import { getFieldType } from '@kbn/unified-field-list-plugin/public';
|
||||
import { SUPPORTED_FIELD_TYPES } from '../../../../common/constants';
|
||||
|
||||
export const getJobTypeLabel = (type: string) => {
|
||||
return type in jobTypeLabels ? jobTypeLabels[type as keyof typeof jobTypeLabels] : null;
|
||||
};
|
||||
|
||||
export const jobTypeLabels: Record<SupportedFieldType, string> = {
|
||||
[SUPPORTED_FIELD_TYPES.BOOLEAN]: i18n.translate(
|
||||
'xpack.dataVisualizer.fieldTypeIcon.booleanTypeLabel',
|
||||
{
|
||||
defaultMessage: 'Boolean',
|
||||
}
|
||||
),
|
||||
[SUPPORTED_FIELD_TYPES.CONFLICT]: i18n.translate(
|
||||
'xpack.dataVisualizer.fieldTypeIcon.conflictTypeLabel',
|
||||
{
|
||||
defaultMessage: 'Conflict',
|
||||
}
|
||||
),
|
||||
[SUPPORTED_FIELD_TYPES.DATE]: i18n.translate('xpack.dataVisualizer.fieldTypeIcon.dateTypeLabel', {
|
||||
defaultMessage: 'Date',
|
||||
}),
|
||||
[SUPPORTED_FIELD_TYPES.DATE_RANGE]: i18n.translate(
|
||||
'xpack.dataVisualizer.fieldTypeIcon.dateRangeTypeLabel',
|
||||
{
|
||||
defaultMessage: 'Date range',
|
||||
}
|
||||
),
|
||||
[SUPPORTED_FIELD_TYPES.GEO_POINT]: i18n.translate(
|
||||
'xpack.dataVisualizer.fieldTypeIcon.geoPointTypeLabel',
|
||||
{
|
||||
defaultMessage: 'Geo point',
|
||||
}
|
||||
),
|
||||
[SUPPORTED_FIELD_TYPES.GEO_SHAPE]: i18n.translate(
|
||||
'xpack.dataVisualizer.fieldTypeIcon.geoShapeTypeLabel',
|
||||
{
|
||||
defaultMessage: 'Geo shape',
|
||||
}
|
||||
),
|
||||
[SUPPORTED_FIELD_TYPES.HISTOGRAM]: i18n.translate(
|
||||
'xpack.dataVisualizer.fieldTypeIcon.histogramTypeLabel',
|
||||
{
|
||||
defaultMessage: 'Histogram',
|
||||
}
|
||||
),
|
||||
[SUPPORTED_FIELD_TYPES.IP]: i18n.translate('xpack.dataVisualizer.fieldTypeIcon.ipTypeLabel', {
|
||||
defaultMessage: 'IP',
|
||||
}),
|
||||
[SUPPORTED_FIELD_TYPES.IP_RANGE]: i18n.translate(
|
||||
'xpack.dataVisualizer.fieldTypeIcon.ipRangeTypeLabel',
|
||||
{
|
||||
defaultMessage: 'IP range',
|
||||
}
|
||||
),
|
||||
[SUPPORTED_FIELD_TYPES.MURMUR3]: i18n.translate(
|
||||
'xpack.dataVisualizer.fieldTypeIcon.murmur3TypeLabel',
|
||||
{
|
||||
defaultMessage: 'Murmur3',
|
||||
}
|
||||
),
|
||||
[SUPPORTED_FIELD_TYPES.NESTED]: i18n.translate(
|
||||
'xpack.dataVisualizer.fieldTypeIcon.numberTypeLabel',
|
||||
{
|
||||
defaultMessage: 'Number',
|
||||
}
|
||||
),
|
||||
[SUPPORTED_FIELD_TYPES.NUMBER]: i18n.translate(
|
||||
'xpack.dataVisualizer.fieldTypeIcon.numberTypeLabel',
|
||||
{
|
||||
defaultMessage: 'Number',
|
||||
}
|
||||
),
|
||||
[SUPPORTED_FIELD_TYPES.STRING]: i18n.translate(
|
||||
'xpack.dataVisualizer.fieldTypeIcon.stringTypeLabel',
|
||||
{
|
||||
defaultMessage: 'String',
|
||||
}
|
||||
),
|
||||
[SUPPORTED_FIELD_TYPES.TEXT]: i18n.translate('xpack.dataVisualizer.fieldTypeIcon.textTypeLabel', {
|
||||
defaultMessage: 'Text',
|
||||
}),
|
||||
[SUPPORTED_FIELD_TYPES.KEYWORD]: i18n.translate(
|
||||
'xpack.dataVisualizer.fieldTypeIcon.keywordTypeLabel',
|
||||
{
|
||||
defaultMessage: 'Keyword',
|
||||
}
|
||||
),
|
||||
[SUPPORTED_FIELD_TYPES.VERSION]: i18n.translate(
|
||||
'xpack.dataVisualizer.fieldTypeIcon.versionTypeLabel',
|
||||
{
|
||||
defaultMessage: 'Version',
|
||||
}
|
||||
),
|
||||
[SUPPORTED_FIELD_TYPES.UNKNOWN]: i18n.translate(
|
||||
'xpack.dataVisualizer.fieldTypeIcon.unknownTypeLabel',
|
||||
{
|
||||
defaultMessage: 'Unknown',
|
||||
}
|
||||
),
|
||||
};
|
||||
|
||||
// convert kibana types to ML Job types
|
||||
// this is needed because kibana types only have string and not text and keyword.
|
||||
// and we can't use ES_FIELD_TYPES because it has no NUMBER type
|
||||
export function kbnTypeToJobType(field: DataViewField) {
|
||||
export function kbnTypeToSupportedType(field: DataViewField) {
|
||||
// Return undefined if not one of the supported data visualizer field types.
|
||||
let type;
|
||||
|
||||
|
@ -126,32 +25,9 @@ export function kbnTypeToJobType(field: DataViewField) {
|
|||
type = SUPPORTED_FIELD_TYPES.VERSION;
|
||||
}
|
||||
break;
|
||||
case KBN_FIELD_TYPES.NUMBER:
|
||||
if (field.esTypes?.some((d) => d === ES_FIELD_TYPES.AGGREGATE_METRIC_DOUBLE)) {
|
||||
break;
|
||||
}
|
||||
type = SUPPORTED_FIELD_TYPES.NUMBER;
|
||||
break;
|
||||
case KBN_FIELD_TYPES.DATE:
|
||||
type = SUPPORTED_FIELD_TYPES.DATE;
|
||||
break;
|
||||
case KBN_FIELD_TYPES.IP:
|
||||
type = SUPPORTED_FIELD_TYPES.IP;
|
||||
break;
|
||||
case KBN_FIELD_TYPES.BOOLEAN:
|
||||
type = SUPPORTED_FIELD_TYPES.BOOLEAN;
|
||||
break;
|
||||
case KBN_FIELD_TYPES.GEO_POINT:
|
||||
type = SUPPORTED_FIELD_TYPES.GEO_POINT;
|
||||
break;
|
||||
case KBN_FIELD_TYPES.GEO_SHAPE:
|
||||
type = SUPPORTED_FIELD_TYPES.GEO_SHAPE;
|
||||
break;
|
||||
case KBN_FIELD_TYPES.HISTOGRAM:
|
||||
type = SUPPORTED_FIELD_TYPES.HISTOGRAM;
|
||||
break;
|
||||
|
||||
default:
|
||||
type = getFieldType(field);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -37,6 +37,7 @@ import {
|
|||
import { useStorage } from '@kbn/ml-local-storage';
|
||||
|
||||
import type { SavedSearch } from '@kbn/saved-search-plugin/public';
|
||||
import { kbnTypeToSupportedType } from '../../../common/util/field_types_utils';
|
||||
import { useCurrentEuiTheme } from '../../../common/hooks/use_current_eui_theme';
|
||||
import {
|
||||
DV_FROZEN_TIER_PREFERENCE,
|
||||
|
@ -59,12 +60,10 @@ import {
|
|||
DataVisualizerIndexBasedPageUrlState,
|
||||
} from '../../types/index_data_visualizer_state';
|
||||
import { SEARCH_QUERY_LANGUAGE, SearchQueryLanguage } from '../../types/combined_query';
|
||||
import type { SupportedFieldType } from '../../../../../common/types';
|
||||
import { useDataVisualizerKibana } from '../../../kibana_context';
|
||||
import { FieldCountPanel } from '../../../common/components/field_count_panel';
|
||||
import { DocumentCountContent } from '../../../common/components/document_count_content';
|
||||
import { OMIT_FIELDS } from '../../../../../common/constants';
|
||||
import { kbnTypeToJobType } from '../../../common/util/field_types_utils';
|
||||
import { SearchPanel } from '../search_panel';
|
||||
import { ActionsPanel } from '../actions_panel';
|
||||
import { createMergedEsQuery } from '../../utils/saved_search_utils';
|
||||
|
@ -214,10 +213,10 @@ export const IndexDataVisualizerView: FC<IndexDataVisualizerViewProps> = (dataVi
|
|||
|
||||
const fieldTypes = useMemo(() => {
|
||||
// Obtain the list of non metric field types which appear in the index pattern.
|
||||
const indexedFieldTypes: SupportedFieldType[] = [];
|
||||
const indexedFieldTypes: string[] = [];
|
||||
dataViewFields.forEach((field) => {
|
||||
if (!OMIT_FIELDS.includes(field.name) && field.scripted !== true) {
|
||||
const dataVisualizerType: SupportedFieldType | undefined = kbnTypeToJobType(field);
|
||||
const dataVisualizerType = kbnTypeToSupportedType(field);
|
||||
if (dataVisualizerType !== undefined && !indexedFieldTypes.includes(dataVisualizerType)) {
|
||||
indexedFieldTypes.push(dataVisualizerType);
|
||||
}
|
||||
|
|
|
@ -9,22 +9,21 @@ import React, { FC, useMemo } from 'react';
|
|||
import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { css } from '@emotion/react';
|
||||
import { getFieldTypeName } from '@kbn/unified-field-list-plugin/public';
|
||||
import { useCurrentEuiTheme } from '../../../common/hooks/use_current_eui_theme';
|
||||
import { FieldTypesHelpPopover } from '../../../common/components/field_types_filter/field_types_help_popover';
|
||||
import type { SupportedFieldType } from '../../../../../common/types';
|
||||
import { FieldTypeIcon } from '../../../common/components/field_type_icon';
|
||||
import { MultiSelectPicker, Option } from '../../../common/components/multi_select_picker';
|
||||
import { jobTypeLabels } from '../../../common/util/field_types_utils';
|
||||
|
||||
export const DataVisualizerFieldTypeFilter: FC<{
|
||||
indexedFieldTypes: SupportedFieldType[];
|
||||
indexedFieldTypes: string[];
|
||||
setVisibleFieldTypes(q: string[]): void;
|
||||
visibleFieldTypes: string[];
|
||||
}> = ({ indexedFieldTypes, setVisibleFieldTypes, visibleFieldTypes }) => {
|
||||
const euiTheme = useCurrentEuiTheme();
|
||||
const options: Option[] = useMemo(() => {
|
||||
return indexedFieldTypes.map((indexedFieldName) => {
|
||||
const label = jobTypeLabels[indexedFieldName] ?? '';
|
||||
const label = getFieldTypeName(indexedFieldName) ?? indexedFieldName;
|
||||
|
||||
return {
|
||||
value: indexedFieldName,
|
||||
|
|
|
@ -21,7 +21,6 @@ import { DataView, DataViewField } from '@kbn/data-views-plugin/public';
|
|||
import { isDefined } from '@kbn/ml-is-defined';
|
||||
import { DataVisualizerFieldNamesFilter } from './field_name_filter';
|
||||
import { DataVisualizerFieldTypeFilter } from './field_type_filter';
|
||||
import type { SupportedFieldType } from '../../../../../common/types';
|
||||
import { SearchQueryLanguage } from '../../types/combined_query';
|
||||
import { useDataVisualizerKibana } from '../../../kibana_context';
|
||||
import { createMergedEsQuery } from '../../utils/saved_search_utils';
|
||||
|
@ -33,7 +32,7 @@ interface Props {
|
|||
searchQuery: Query['query'];
|
||||
searchQueryLanguage: SearchQueryLanguage;
|
||||
overallStats: OverallStats;
|
||||
indexedFieldTypes: SupportedFieldType[];
|
||||
indexedFieldTypes: string[];
|
||||
setVisibleFieldTypes(q: string[]): void;
|
||||
visibleFieldTypes: string[];
|
||||
setVisibleFieldNames(q: string[]): void;
|
||||
|
|
|
@ -16,7 +16,7 @@ import seedrandom from 'seedrandom';
|
|||
import type { SamplingOption } from '@kbn/discover-plugin/public/application/main/components/field_stats_table/field_stats_table';
|
||||
import type { Dictionary } from '@kbn/ml-url-state';
|
||||
import { mlTimefilterRefresh$, useTimefilter } from '@kbn/ml-date-picker';
|
||||
import { isCounterTimeSeriesMetric } from '@kbn/ml-agg-utils';
|
||||
import { filterFields } from '../../common/components/fields_stats_grid/filter_fields';
|
||||
import type { RandomSamplerOption } from '../constants/random_sampler';
|
||||
import type { DataVisualizerIndexBasedAppState } from '../types/index_data_visualizer_state';
|
||||
import { useDataVisualizerKibana } from '../../kibana_context';
|
||||
|
@ -25,12 +25,12 @@ import type { MetricFieldsStats } from '../../common/components/stats_table/comp
|
|||
import { TimeBuckets } from '../../../../common/services/time_buckets';
|
||||
import type { FieldVisConfig } from '../../common/components/stats_table/types';
|
||||
import {
|
||||
SUPPORTED_FIELD_TYPES,
|
||||
NON_AGGREGATABLE_FIELD_TYPES,
|
||||
OMIT_FIELDS,
|
||||
SUPPORTED_FIELD_TYPES,
|
||||
} from '../../../../common/constants';
|
||||
import type { FieldRequestConfig, SupportedFieldType } from '../../../../common/types';
|
||||
import { kbnTypeToJobType } from '../../common/util/field_types_utils';
|
||||
import { kbnTypeToSupportedType } from '../../common/util/field_types_utils';
|
||||
import { getActions } from '../../common/components/field_data_row/action_menu';
|
||||
import type { DataVisualizerGridInput } from '../embeddables/grid_embeddable/grid_embeddable';
|
||||
import { getDefaultPageState } from '../components/index_data_visualizer_view/index_data_visualizer_view';
|
||||
|
@ -38,6 +38,7 @@ import { useFieldStatsSearchStrategy } from './use_field_stats';
|
|||
import { useOverallStats } from './use_overall_stats';
|
||||
import type { OverallStatsSearchStrategyParams } from '../../../../common/types/field_stats';
|
||||
import type { AggregatableField, NonAggregatableField } from '../types/overall_stats';
|
||||
import { getSupportedAggs } from '../utils/get_supported_aggs';
|
||||
|
||||
const defaults = getDefaultPageState();
|
||||
|
||||
|
@ -197,7 +198,7 @@ export const useDataVisualizerGridData = (
|
|||
|
||||
const aggInterval = buckets.getInterval();
|
||||
|
||||
const aggregatableFields: string[] = [];
|
||||
const aggregatableFields: OverallStatsSearchStrategyParams['aggregatableFields'] = [];
|
||||
const nonAggregatableFields: string[] = [];
|
||||
|
||||
const fields = currentDataView.fields;
|
||||
|
@ -212,7 +213,7 @@ export const useDataVisualizerGridData = (
|
|||
!NON_AGGREGATABLE_FIELD_TYPES.has(field.type) &&
|
||||
!field.esTypes?.some((d) => d === ES_FIELD_TYPES.AGGREGATE_METRIC_DOUBLE)
|
||||
) {
|
||||
aggregatableFields.push(field.name);
|
||||
aggregatableFields.push({ name: field.name, supportedAggs: getSupportedAggs(field) });
|
||||
} else {
|
||||
nonAggregatableFields.push(field.name);
|
||||
}
|
||||
|
@ -265,10 +266,8 @@ export const useDataVisualizerGridData = (
|
|||
const existMetricFields = metricConfigs
|
||||
.map((config) => {
|
||||
return {
|
||||
fieldName: config.fieldName,
|
||||
type: config.type,
|
||||
cardinality: config.stats?.cardinality ?? 0,
|
||||
existsInDocs: config.existsInDocs,
|
||||
...config,
|
||||
cardinality: config.stats?.cardinality,
|
||||
};
|
||||
})
|
||||
.filter((c) => c !== undefined) as FieldRequestConfig[];
|
||||
|
@ -278,10 +277,8 @@ export const useDataVisualizerGridData = (
|
|||
const existNonMetricFields: FieldRequestConfig[] = nonMetricConfigs
|
||||
.map((config) => {
|
||||
return {
|
||||
fieldName: config.fieldName,
|
||||
type: config.type,
|
||||
cardinality: config.stats?.cardinality ?? 0,
|
||||
existsInDocs: config.existsInDocs,
|
||||
...config,
|
||||
cardinality: config.stats?.cardinality,
|
||||
};
|
||||
})
|
||||
.filter((c) => c !== undefined) as FieldRequestConfig[];
|
||||
|
@ -372,9 +369,11 @@ export const useDataVisualizerGridData = (
|
|||
...fieldData,
|
||||
fieldFormat: currentDataView.getFormatterForField(field),
|
||||
type: SUPPORTED_FIELD_TYPES.NUMBER,
|
||||
secondaryType: kbnTypeToSupportedType(field),
|
||||
loading: fieldData?.existsInDocs ?? true,
|
||||
aggregatable: true,
|
||||
deletable: field.runtimeField !== undefined,
|
||||
supportedAggs: getSupportedAggs(field),
|
||||
};
|
||||
if (field.displayName !== metricConfig.fieldName) {
|
||||
metricConfig.displayName = field.displayName;
|
||||
|
@ -393,7 +392,7 @@ export const useDataVisualizerGridData = (
|
|||
const createNonMetricCards = useCallback(() => {
|
||||
const allNonMetricFields = dataViewFields.filter((f) => {
|
||||
return (
|
||||
(f.type !== KBN_FIELD_TYPES.NUMBER || isCounterTimeSeriesMetric(f)) &&
|
||||
f.type !== KBN_FIELD_TYPES.NUMBER &&
|
||||
f.displayName !== undefined &&
|
||||
isDisplayField(f.displayName) === true
|
||||
);
|
||||
|
@ -448,6 +447,7 @@ export const useDataVisualizerGridData = (
|
|||
const fieldData = nonMetricFieldData.find((f) => f.fieldName === field.spec.name);
|
||||
const nonMetricConfig: Partial<FieldVisConfig> = {
|
||||
...(fieldData ? fieldData : {}),
|
||||
secondaryType: kbnTypeToSupportedType(field),
|
||||
fieldFormat: currentDataView.getFormatterForField(field),
|
||||
aggregatable: field.aggregatable,
|
||||
loading: fieldData?.existsInDocs ?? true,
|
||||
|
@ -456,7 +456,7 @@ export const useDataVisualizerGridData = (
|
|||
|
||||
// Map the field type from the Kibana index pattern to the field type
|
||||
// used in the data visualizer.
|
||||
const dataVisualizerType = kbnTypeToJobType(field);
|
||||
const dataVisualizerType = kbnTypeToSupportedType(field) as SupportedFieldType;
|
||||
if (dataVisualizerType !== undefined) {
|
||||
nonMetricConfig.type = dataVisualizerType;
|
||||
} else {
|
||||
|
@ -486,16 +486,12 @@ export const useDataVisualizerGridData = (
|
|||
() => {
|
||||
const fieldStats = strategyResponse.fieldStats;
|
||||
let combinedConfigs = [...nonMetricConfigs, ...metricConfigs];
|
||||
if (visibleFieldTypes && visibleFieldTypes.length > 0) {
|
||||
combinedConfigs = combinedConfigs.filter(
|
||||
(config) => visibleFieldTypes.findIndex((field) => field === config.type) > -1
|
||||
);
|
||||
}
|
||||
if (visibleFieldNames && visibleFieldNames.length > 0) {
|
||||
combinedConfigs = combinedConfigs.filter(
|
||||
(config) => visibleFieldNames.findIndex((field) => field === config.fieldName) > -1
|
||||
);
|
||||
}
|
||||
|
||||
combinedConfigs = filterFields(
|
||||
combinedConfigs,
|
||||
visibleFieldNames,
|
||||
visibleFieldTypes
|
||||
).filteredFields;
|
||||
|
||||
if (fieldStats) {
|
||||
combinedConfigs = combinedConfigs.map((c) => {
|
||||
|
|
|
@ -177,9 +177,7 @@ export function useFieldStatsSearchStrategy(
|
|||
|
||||
const batches = createBatchedRequests(
|
||||
pageOfConfigs.map((config, idx) => ({
|
||||
fieldName: config.fieldName,
|
||||
type: config.type,
|
||||
cardinality: config.cardinality,
|
||||
...config,
|
||||
safeFieldName: getSafeAggregationName(config.fieldName, idx),
|
||||
})),
|
||||
10
|
||||
|
|
|
@ -7,8 +7,11 @@
|
|||
|
||||
import type { Observable } from 'rxjs';
|
||||
import type { ISearchOptions } from '@kbn/data-plugin/common';
|
||||
import { ISearchStart } from '@kbn/data-plugin/public';
|
||||
import type { FieldStatsCommonRequestParams } from '../../../../../common/types/field_stats';
|
||||
import type { ISearchStart } from '@kbn/data-plugin/public';
|
||||
import type {
|
||||
FieldStatsCommonRequestParams,
|
||||
SupportedAggs,
|
||||
} from '../../../../../common/types/field_stats';
|
||||
import type { FieldStatsError } from '../../../../../common/types/field_stats';
|
||||
import type { FieldStats } from '../../../../../common/types/field_stats';
|
||||
import { SUPPORTED_FIELD_TYPES } from '../../../../../common/constants';
|
||||
|
@ -26,6 +29,7 @@ export const getFieldsStats = (
|
|||
type: string;
|
||||
cardinality: number;
|
||||
safeFieldName: string;
|
||||
supportedAggs?: SupportedAggs;
|
||||
}>,
|
||||
options: ISearchOptions
|
||||
): Observable<FieldStats[] | FieldStatsError> | undefined => {
|
||||
|
|
|
@ -58,35 +58,58 @@ export const getNumericFieldsStatsRequest = (
|
|||
const aggs: Aggs = {};
|
||||
|
||||
fields.forEach((field, i) => {
|
||||
const { safeFieldName } = field;
|
||||
const { safeFieldName, supportedAggs } = field;
|
||||
|
||||
aggs[`${safeFieldName}_field_stats`] = {
|
||||
filter: { exists: { field: field.fieldName } },
|
||||
aggs: {
|
||||
actual_stats: {
|
||||
stats: { field: field.fieldName },
|
||||
const include = !isDefined(supportedAggs);
|
||||
|
||||
if (include || supportedAggs.has('stats')) {
|
||||
aggs[`${safeFieldName}_field_stats`] = {
|
||||
filter: { exists: { field: field.fieldName } },
|
||||
aggs: {
|
||||
actual_stats: {
|
||||
stats: { field: field.fieldName },
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
aggs[`${safeFieldName}_percentiles`] = {
|
||||
percentiles: {
|
||||
field: field.fieldName,
|
||||
percents,
|
||||
keyed: false,
|
||||
},
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
const top = {
|
||||
terms: {
|
||||
field: field.fieldName,
|
||||
size: 10,
|
||||
order: {
|
||||
_count: 'desc',
|
||||
if (include || (supportedAggs.has('min') && supportedAggs.has('max'))) {
|
||||
aggs[`${safeFieldName}_min_max`] = {
|
||||
filter: { exists: { field: field.fieldName } },
|
||||
aggs: {
|
||||
min: {
|
||||
min: { field: field.fieldName },
|
||||
},
|
||||
max: {
|
||||
max: { field: field.fieldName },
|
||||
},
|
||||
},
|
||||
} as AggregationsTermsAggregation,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
aggs[`${safeFieldName}_top`] = top;
|
||||
if (include || supportedAggs.has('percentiles')) {
|
||||
aggs[`${safeFieldName}_percentiles`] = {
|
||||
percentiles: {
|
||||
field: field.fieldName,
|
||||
percents,
|
||||
keyed: false,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
if (include || supportedAggs.has('terms')) {
|
||||
const top = {
|
||||
terms: {
|
||||
field: field.fieldName,
|
||||
size: 10,
|
||||
order: {
|
||||
_count: 'desc',
|
||||
},
|
||||
} as AggregationsTermsAggregation,
|
||||
};
|
||||
|
||||
aggs[`${safeFieldName}_top`] = top;
|
||||
}
|
||||
});
|
||||
|
||||
const searchBody = {
|
||||
|
@ -102,6 +125,29 @@ export const getNumericFieldsStatsRequest = (
|
|||
};
|
||||
};
|
||||
|
||||
const processStats = (safeFieldName: string, aggregations: object, aggsPath: string[]) => {
|
||||
const fieldStatsResp = get(
|
||||
aggregations,
|
||||
[...aggsPath, `${safeFieldName}_field_stats`, 'actual_stats'],
|
||||
undefined
|
||||
);
|
||||
if (fieldStatsResp) {
|
||||
return {
|
||||
min: get(fieldStatsResp, 'min'),
|
||||
max: get(fieldStatsResp, 'max'),
|
||||
avg: get(fieldStatsResp, 'avg'),
|
||||
};
|
||||
}
|
||||
const minMaxResp = get(aggregations, [...aggsPath, `${safeFieldName}_min_max`], {});
|
||||
if (minMaxResp) {
|
||||
return {
|
||||
min: get(minMaxResp, ['min', 'value']),
|
||||
max: get(minMaxResp, ['max', 'value']),
|
||||
};
|
||||
}
|
||||
return {};
|
||||
};
|
||||
|
||||
export const fetchNumericFieldsStats = (
|
||||
dataSearch: ISearchStart,
|
||||
params: FieldStatsCommonRequestParams,
|
||||
|
@ -135,11 +181,6 @@ export const fetchNumericFieldsStats = (
|
|||
[...aggsPath, `${safeFieldName}_field_stats`, 'doc_count'],
|
||||
0
|
||||
);
|
||||
const fieldStatsResp = get(
|
||||
aggregations,
|
||||
[...aggsPath, `${safeFieldName}_field_stats`, 'actual_stats'],
|
||||
{}
|
||||
);
|
||||
|
||||
const topAggsPath = [...aggsPath, `${safeFieldName}_top`];
|
||||
if (samplerShardSize < 1 && field.cardinality >= SAMPLER_TOP_TERMS_THRESHOLD) {
|
||||
|
@ -151,9 +192,7 @@ export const fetchNumericFieldsStats = (
|
|||
|
||||
const stats: NumericFieldStats = {
|
||||
fieldName: field.fieldName,
|
||||
min: get(fieldStatsResp, 'min', 0),
|
||||
max: get(fieldStatsResp, 'max', 0),
|
||||
avg: get(fieldStatsResp, 'avg', 0),
|
||||
...processStats(safeFieldName, aggregations, aggsPath),
|
||||
isTopValuesSampled:
|
||||
isNormalSamplingOption(params.samplingOption) ||
|
||||
(isDefined(params.samplingProbability) && params.samplingProbability < 1),
|
||||
|
@ -168,15 +207,21 @@ export const fetchNumericFieldsStats = (
|
|||
[...aggsPath, `${safeFieldName}_percentiles`, 'values'],
|
||||
[]
|
||||
);
|
||||
const medianPercentile: { value: number; key: number } | undefined = find(percentiles, {
|
||||
key: 50,
|
||||
});
|
||||
stats.median = medianPercentile !== undefined ? medianPercentile!.value : 0;
|
||||
stats.distribution = processDistributionData(
|
||||
percentiles,
|
||||
PERCENTILE_SPACING,
|
||||
stats.min
|
||||
);
|
||||
|
||||
if (percentiles && isDefined(stats.min)) {
|
||||
const medianPercentile: { value: number; key: number } | undefined = find(
|
||||
percentiles,
|
||||
{
|
||||
key: 50,
|
||||
}
|
||||
);
|
||||
stats.median = medianPercentile !== undefined ? medianPercentile!.value : 0;
|
||||
stats.distribution = processDistributionData(
|
||||
percentiles,
|
||||
PERCENTILE_SPACING,
|
||||
stats.min
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
batchStats.push(stats);
|
||||
|
|
|
@ -7,20 +7,24 @@
|
|||
|
||||
import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
|
||||
import { get } from 'lodash';
|
||||
import { Query } from '@kbn/es-query';
|
||||
import type { Query } from '@kbn/es-query';
|
||||
import type { IKibanaSearchResponse } from '@kbn/data-plugin/common';
|
||||
import type { AggCardinality } from '@kbn/ml-agg-utils';
|
||||
import { isPopulatedObject } from '@kbn/ml-is-populated-object';
|
||||
import { buildBaseFilterCriteria, getSafeAggregationName } from '@kbn/ml-query-utils';
|
||||
import { buildAggregationWithSamplingOption } from './build_random_sampler_agg';
|
||||
import { getDatafeedAggregations } from '../../../../../common/utils/datafeed_utils';
|
||||
import { AggregatableField, NonAggregatableField } from '../../types/overall_stats';
|
||||
import { Aggs, SamplingOption } from '../../../../../common/types/field_stats';
|
||||
import type { AggregatableField, NonAggregatableField } from '../../types/overall_stats';
|
||||
import type {
|
||||
Aggs,
|
||||
OverallStatsSearchStrategyParams,
|
||||
SamplingOption,
|
||||
} from '../../../../../common/types/field_stats';
|
||||
|
||||
export const checkAggregatableFieldsExistRequest = (
|
||||
dataViewTitle: string,
|
||||
query: Query['query'],
|
||||
aggregatableFields: string[],
|
||||
aggregatableFields: OverallStatsSearchStrategyParams['aggregatableFields'],
|
||||
samplingOption: SamplingOption,
|
||||
timeFieldName: string | undefined,
|
||||
earliestMs?: number,
|
||||
|
@ -45,23 +49,28 @@ export const checkAggregatableFieldsExistRequest = (
|
|||
: {}),
|
||||
};
|
||||
|
||||
aggregatableFields.forEach((field, i) => {
|
||||
aggregatableFields.forEach(({ name: field, supportedAggs }, i) => {
|
||||
const safeFieldName = getSafeAggregationName(field, i);
|
||||
aggs[`${safeFieldName}_count`] = {
|
||||
filter: { exists: { field } },
|
||||
};
|
||||
|
||||
let cardinalityField: AggCardinality;
|
||||
if (datafeedConfig?.script_fields?.hasOwnProperty(field)) {
|
||||
cardinalityField = aggs[`${safeFieldName}_cardinality`] = {
|
||||
cardinality: { script: datafeedConfig?.script_fields[field].script },
|
||||
};
|
||||
} else {
|
||||
cardinalityField = {
|
||||
cardinality: { field },
|
||||
if (supportedAggs.has('count')) {
|
||||
aggs[`${safeFieldName}_count`] = {
|
||||
filter: { exists: { field } },
|
||||
};
|
||||
}
|
||||
aggs[`${safeFieldName}_cardinality`] = cardinalityField;
|
||||
|
||||
if (supportedAggs.has('cardinality')) {
|
||||
let cardinalityField: AggCardinality;
|
||||
if (datafeedConfig?.script_fields?.hasOwnProperty(field)) {
|
||||
cardinalityField = aggs[`${safeFieldName}_cardinality`] = {
|
||||
cardinality: { script: datafeedConfig?.script_fields[field].script },
|
||||
};
|
||||
} else {
|
||||
cardinalityField = {
|
||||
cardinality: { field },
|
||||
};
|
||||
}
|
||||
aggs[`${safeFieldName}_cardinality`] = cardinalityField;
|
||||
}
|
||||
});
|
||||
|
||||
const searchBody = {
|
||||
|
@ -88,7 +97,7 @@ export const checkAggregatableFieldsExistRequest = (
|
|||
};
|
||||
|
||||
export interface AggregatableFieldOverallStats extends IKibanaSearchResponse {
|
||||
aggregatableFields: string[];
|
||||
aggregatableFields: OverallStatsSearchStrategyParams['aggregatableFields'];
|
||||
}
|
||||
|
||||
export type NonAggregatableFieldOverallStats = IKibanaSearchResponse;
|
||||
|
@ -107,7 +116,7 @@ export function isNonAggregatableFieldOverallStats(
|
|||
|
||||
export const processAggregatableFieldsExistResponse = (
|
||||
responses: AggregatableFieldOverallStats[] | undefined,
|
||||
aggregatableFields: string[],
|
||||
aggregatableFields: OverallStatsSearchStrategyParams['aggregatableFields'],
|
||||
datafeedConfig?: estypes.MlDatafeed
|
||||
) => {
|
||||
const stats = {
|
||||
|
@ -122,7 +131,7 @@ export const processAggregatableFieldsExistResponse = (
|
|||
|
||||
const aggsPath = ['sample'];
|
||||
const sampleCount = aggregations.sample.doc_count;
|
||||
aggregatableFieldsChunk.forEach((field, i) => {
|
||||
aggregatableFieldsChunk.forEach(({ name: field, supportedAggs }, i) => {
|
||||
const safeFieldName = getSafeAggregationName(field, i);
|
||||
// Sampler agg will yield doc_count that's bigger than the actual # of sampled records
|
||||
// because it uses the stored _doc_count if available
|
||||
|
@ -132,11 +141,11 @@ export const processAggregatableFieldsExistResponse = (
|
|||
const multiplier =
|
||||
count > sampleCount ? get(aggregations, [...aggsPath, 'probability'], 1) : 1;
|
||||
if (count > 0) {
|
||||
const cardinality = get(
|
||||
aggregations,
|
||||
[...aggsPath, `${safeFieldName}_cardinality`, 'value'],
|
||||
0
|
||||
);
|
||||
const cardinality = get(aggregations, [
|
||||
...aggsPath,
|
||||
`${safeFieldName}_cardinality`,
|
||||
'value',
|
||||
]);
|
||||
stats.aggregatableExistsFields.push({
|
||||
fieldName: field,
|
||||
existsInDocs: true,
|
||||
|
@ -151,11 +160,11 @@ export const processAggregatableFieldsExistResponse = (
|
|||
datafeedConfig?.script_fields?.hasOwnProperty(field) ||
|
||||
datafeedConfig?.runtime_mappings?.hasOwnProperty(field)
|
||||
) {
|
||||
const cardinality = get(
|
||||
aggregations,
|
||||
[...aggsPath, `${safeFieldName}_cardinality`, 'value'],
|
||||
0
|
||||
);
|
||||
const cardinality = get(aggregations, [
|
||||
...aggsPath,
|
||||
`${safeFieldName}_cardinality`,
|
||||
'value',
|
||||
]);
|
||||
stats.aggregatableExistsFields.push({
|
||||
fieldName: field,
|
||||
existsInDocs: true,
|
||||
|
|
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
* 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 type { DataViewField } from '@kbn/data-views-plugin/common';
|
||||
import { isCounterTimeSeriesMetric, isGaugeTimeSeriesMetric } from '@kbn/ml-agg-utils';
|
||||
|
||||
/**
|
||||
* Partial list of supported ES aggs that are used by Index data visualizer/Field stats
|
||||
*/
|
||||
const SUPPORTED_AGGS = {
|
||||
COUNTER: new Set([
|
||||
'count',
|
||||
'histogram',
|
||||
'variable_width_histogram',
|
||||
'rate',
|
||||
'min',
|
||||
'max',
|
||||
'top_metrics',
|
||||
'range',
|
||||
]),
|
||||
GAUGE: new Set([
|
||||
'count',
|
||||
'max',
|
||||
'top_metrics',
|
||||
'missing',
|
||||
'date_histogram',
|
||||
'sum',
|
||||
'rate',
|
||||
'boxplot',
|
||||
'value_count',
|
||||
'avg',
|
||||
'percentiles',
|
||||
'cardinality',
|
||||
'histogram',
|
||||
'variable_width_histogram',
|
||||
'frequent_item_sets',
|
||||
'min',
|
||||
'stats',
|
||||
'diversified_sampler',
|
||||
'percentile_ranks',
|
||||
'median_absolute_deviation',
|
||||
'multi_terms',
|
||||
'auto_date_histogram',
|
||||
'rare_terms',
|
||||
'range',
|
||||
'extended_stats',
|
||||
'date_range',
|
||||
'terms',
|
||||
'significant_terms',
|
||||
]),
|
||||
AGGREGATABLE: new Set([
|
||||
'count',
|
||||
'avg',
|
||||
'cardinality',
|
||||
'histogram',
|
||||
'percentiles',
|
||||
'stats',
|
||||
'terms',
|
||||
]),
|
||||
DEFAULT: new Set<string>(),
|
||||
};
|
||||
|
||||
/**
|
||||
* Temporarily add list of supported ES aggs until the PR below is merged
|
||||
* https://github.com/elastic/elasticsearch/pull/93884
|
||||
*/
|
||||
export const getSupportedAggs = (field: DataViewField) => {
|
||||
if (isCounterTimeSeriesMetric(field)) return SUPPORTED_AGGS.COUNTER;
|
||||
if (isGaugeTimeSeriesMetric(field)) return SUPPORTED_AGGS.GAUGE;
|
||||
if (field.aggregatable) return SUPPORTED_AGGS.AGGREGATABLE;
|
||||
return SUPPORTED_AGGS.DEFAULT;
|
||||
};
|
|
@ -57,6 +57,7 @@
|
|||
"@kbn/ml-is-defined",
|
||||
"@kbn/ml-query-utils",
|
||||
"@kbn/saved-search-plugin",
|
||||
"@kbn/unified-field-list-plugin",
|
||||
],
|
||||
"exclude": [
|
||||
"target/**/*",
|
||||
|
|
|
@ -10816,8 +10816,6 @@
|
|||
"xpack.dataVisualizer.index.dataLoader.internalServerErrorMessage": "Erreur lors du chargement des données dans l'index {index}. {message}. La requête a peut-être expiré. Essayez d'utiliser un échantillon d'une taille inférieure ou de réduire la plage temporelle.",
|
||||
"xpack.dataVisualizer.index.dataViewNotBasedOnTimeSeriesNotificationTitle": "La vue de données {dataViewTitle} n'est pas basée sur une série temporelle",
|
||||
"xpack.dataVisualizer.index.errorLoadingDataMessage": "Erreur lors du chargement des données dans l'index {index}. {message}.",
|
||||
"xpack.dataVisualizer.index.fieldNameDescription.dateRangeField": "Plage de valeurs {dateFieldTypeLink}. {viewSupportedDateFormatsLink}",
|
||||
"xpack.dataVisualizer.index.fieldNameDescription.versionField": "Versions des logiciels. Prend en charge les règles de priorité de {SemanticVersioningLink}",
|
||||
"xpack.dataVisualizer.index.lensChart.averageOfLabel": "Moyenne de {fieldName}",
|
||||
"xpack.dataVisualizer.index.lensChart.chartTitle": "Lens pour {fieldName}",
|
||||
"xpack.dataVisualizer.index.savedSearchErrorMessage": "Erreur lors de la récupération de la recherche enregistrée {savedSearchId}",
|
||||
|
@ -10882,22 +10880,6 @@
|
|||
"xpack.dataVisualizer.fieldStats.maxTitle": "max",
|
||||
"xpack.dataVisualizer.fieldStats.medianTitle": "médiane",
|
||||
"xpack.dataVisualizer.fieldStats.minTitle": "min",
|
||||
"xpack.dataVisualizer.fieldTypeIcon.booleanTypeLabel": "Booléen",
|
||||
"xpack.dataVisualizer.fieldTypeIcon.conflictTypeLabel": "Conflit",
|
||||
"xpack.dataVisualizer.fieldTypeIcon.dateRangeTypeLabel": "Plage de dates",
|
||||
"xpack.dataVisualizer.fieldTypeIcon.dateTypeLabel": "Date",
|
||||
"xpack.dataVisualizer.fieldTypeIcon.geoPointTypeLabel": "Point géographique",
|
||||
"xpack.dataVisualizer.fieldTypeIcon.geoShapeTypeLabel": "Forme géométrique",
|
||||
"xpack.dataVisualizer.fieldTypeIcon.histogramTypeLabel": "Histogramme",
|
||||
"xpack.dataVisualizer.fieldTypeIcon.ipRangeTypeLabel": "Plage d'IP",
|
||||
"xpack.dataVisualizer.fieldTypeIcon.ipTypeLabel": "IP",
|
||||
"xpack.dataVisualizer.fieldTypeIcon.keywordTypeLabel": "Mot-clé",
|
||||
"xpack.dataVisualizer.fieldTypeIcon.murmur3TypeLabel": "Murmur3",
|
||||
"xpack.dataVisualizer.fieldTypeIcon.numberTypeLabel": "Nombre",
|
||||
"xpack.dataVisualizer.fieldTypeIcon.stringTypeLabel": "Chaîne",
|
||||
"xpack.dataVisualizer.fieldTypeIcon.textTypeLabel": "Texte",
|
||||
"xpack.dataVisualizer.fieldTypeIcon.unknownTypeLabel": "Inconnu",
|
||||
"xpack.dataVisualizer.fieldTypeIcon.versionTypeLabel": "Version",
|
||||
"xpack.dataVisualizer.fieldTypeSelect": "Type du champ",
|
||||
"xpack.dataVisualizer.fieldTypesPopover.buttonAriaLabel": "Aide sur le type de filtre",
|
||||
"xpack.dataVisualizer.fieldTypesPopover.dataTypeColumnTitle": "Type de données",
|
||||
|
@ -11041,7 +11023,6 @@
|
|||
"xpack.dataVisualizer.index.actionsPanel.discoverAppTitle": "Découverte",
|
||||
"xpack.dataVisualizer.index.actionsPanel.exploreTitle": "Explorer vos données",
|
||||
"xpack.dataVisualizer.index.actionsPanel.viewIndexInDiscoverDescription": "Explorez les documents de votre index.",
|
||||
"xpack.dataVisualizer.index.advancedSettings.discover.fieldNameDescription.versionFieldLinkText": "Gestion sémantique des versions",
|
||||
"xpack.dataVisualizer.index.components.grid.description": "Visualiser les données",
|
||||
"xpack.dataVisualizer.index.components.grid.displayName": "Grille du visualiseur de données",
|
||||
"xpack.dataVisualizer.index.dataGrid.actionsColumnLabel": "Actions",
|
||||
|
@ -11062,23 +11043,6 @@
|
|||
"xpack.dataVisualizer.index.embeddableErrorTitle": "Erreur lors du chargement de l'incorporable",
|
||||
"xpack.dataVisualizer.index.embeddableNoResultsMessage": "Résultat introuvable",
|
||||
"xpack.dataVisualizer.index.errorFetchingFieldStatisticsMessage": "Erreur lors de la récupération des statistiques de champ",
|
||||
"xpack.dataVisualizer.index.fieldNameDescription.booleanField": "Valeurs vraies ou fausses",
|
||||
"xpack.dataVisualizer.index.fieldNameDescription.conflictField": "Le champ possède des valeurs de différents types. Corrigez le problème dans Gestion > Vues de données.",
|
||||
"xpack.dataVisualizer.index.fieldNameDescription.dateField": "Chaîne de date ou nombre de secondes ou de millisecondes depuis 1/1/1970",
|
||||
"xpack.dataVisualizer.index.fieldNameDescription.dateRangeFieldLinkText": "date",
|
||||
"xpack.dataVisualizer.index.fieldNameDescription.geoPointField": "Points de latitude et de longitude",
|
||||
"xpack.dataVisualizer.index.fieldNameDescription.geoShapeField": "Formes complexes, telles que des polygones",
|
||||
"xpack.dataVisualizer.index.fieldNameDescription.histogramField": "Valeurs numériques pré-agrégées sous forme d'histogramme",
|
||||
"xpack.dataVisualizer.index.fieldNameDescription.ipAddressField": "Adresses IPv4 et IPv6",
|
||||
"xpack.dataVisualizer.index.fieldNameDescription.ipAddressRangeField": "Plage de valeurs IP prenant en charge les adresses IPv4 ou IPv6 (ou les 2)",
|
||||
"xpack.dataVisualizer.index.fieldNameDescription.keywordField": "Contenu structuré tel qu'un ID, une adresse e-mail, un nom d'hôte, un code de statut, ou une balise",
|
||||
"xpack.dataVisualizer.index.fieldNameDescription.murmur3Field": "Champ qui calcule et stocke les hachages de valeurs",
|
||||
"xpack.dataVisualizer.index.fieldNameDescription.nestedField": "Objet JSON qui conserve la relation entre ses sous-champs",
|
||||
"xpack.dataVisualizer.index.fieldNameDescription.numberField": "Valeurs Long, Entier, Court, Octet, Double et Élément flottant",
|
||||
"xpack.dataVisualizer.index.fieldNameDescription.stringField": "Texte intégral tel que le corps d'un e-mail ou la description d'un produit",
|
||||
"xpack.dataVisualizer.index.fieldNameDescription.textField": "Texte intégral tel que le corps d'un e-mail ou la description d'un produit",
|
||||
"xpack.dataVisualizer.index.fieldNameDescription.unknownField": "Champ inconnu",
|
||||
"xpack.dataVisualizer.index.fieldNameDescription.viewSupportedDateFormatsLinkText": "Affichez les formats de date pris en charge.",
|
||||
"xpack.dataVisualizer.index.fieldNameSelect": "Nom du champ",
|
||||
"xpack.dataVisualizer.index.fieldTypeSelect": "Type du champ",
|
||||
"xpack.dataVisualizer.index.lensChart.countLabel": "Décompte",
|
||||
|
|
|
@ -10815,8 +10815,6 @@
|
|||
"xpack.dataVisualizer.index.dataLoader.internalServerErrorMessage": "インデックス{index}のデータの読み込み中にエラーが発生。{message}。リクエストがタイムアウトした可能性があります。小さなサンプルサイズを使うか、時間範囲を狭めてみてください。",
|
||||
"xpack.dataVisualizer.index.dataViewNotBasedOnTimeSeriesNotificationTitle": "データビュー{dataViewTitle}は時系列に基づいていません",
|
||||
"xpack.dataVisualizer.index.errorLoadingDataMessage": "インデックス{index}のデータの読み込み中にエラーが発生。{message}。",
|
||||
"xpack.dataVisualizer.index.fieldNameDescription.dateRangeField": "{dateFieldTypeLink}値の範囲。{viewSupportedDateFormatsLink}",
|
||||
"xpack.dataVisualizer.index.fieldNameDescription.versionField": "ソフトウェアバージョン。{SemanticVersioningLink}事前ルールをサポートします",
|
||||
"xpack.dataVisualizer.index.lensChart.averageOfLabel": "{fieldName} の平均",
|
||||
"xpack.dataVisualizer.index.lensChart.chartTitle": "{fieldName}のLens",
|
||||
"xpack.dataVisualizer.index.savedSearchErrorMessage": "保存された検索{savedSearchId}の取得エラー",
|
||||
|
@ -10881,22 +10879,6 @@
|
|||
"xpack.dataVisualizer.fieldStats.maxTitle": "最高",
|
||||
"xpack.dataVisualizer.fieldStats.medianTitle": "中間",
|
||||
"xpack.dataVisualizer.fieldStats.minTitle": "分",
|
||||
"xpack.dataVisualizer.fieldTypeIcon.booleanTypeLabel": "ブール",
|
||||
"xpack.dataVisualizer.fieldTypeIcon.conflictTypeLabel": "競合",
|
||||
"xpack.dataVisualizer.fieldTypeIcon.dateRangeTypeLabel": "日付範囲",
|
||||
"xpack.dataVisualizer.fieldTypeIcon.dateTypeLabel": "日付",
|
||||
"xpack.dataVisualizer.fieldTypeIcon.geoPointTypeLabel": "地理ポイント",
|
||||
"xpack.dataVisualizer.fieldTypeIcon.geoShapeTypeLabel": "地理情報図形",
|
||||
"xpack.dataVisualizer.fieldTypeIcon.histogramTypeLabel": "ヒストグラム",
|
||||
"xpack.dataVisualizer.fieldTypeIcon.ipRangeTypeLabel": "IP範囲",
|
||||
"xpack.dataVisualizer.fieldTypeIcon.ipTypeLabel": "IP",
|
||||
"xpack.dataVisualizer.fieldTypeIcon.keywordTypeLabel": "キーワード",
|
||||
"xpack.dataVisualizer.fieldTypeIcon.murmur3TypeLabel": "Murmur3",
|
||||
"xpack.dataVisualizer.fieldTypeIcon.numberTypeLabel": "数字",
|
||||
"xpack.dataVisualizer.fieldTypeIcon.stringTypeLabel": "文字列",
|
||||
"xpack.dataVisualizer.fieldTypeIcon.textTypeLabel": "テキスト",
|
||||
"xpack.dataVisualizer.fieldTypeIcon.unknownTypeLabel": "不明",
|
||||
"xpack.dataVisualizer.fieldTypeIcon.versionTypeLabel": "バージョン",
|
||||
"xpack.dataVisualizer.fieldTypeSelect": "フィールド型",
|
||||
"xpack.dataVisualizer.fieldTypesPopover.buttonAriaLabel": "フィルタータイプのヘルプ",
|
||||
"xpack.dataVisualizer.fieldTypesPopover.dataTypeColumnTitle": "データ型",
|
||||
|
@ -11040,7 +11022,6 @@
|
|||
"xpack.dataVisualizer.index.actionsPanel.discoverAppTitle": "Discover",
|
||||
"xpack.dataVisualizer.index.actionsPanel.exploreTitle": "データの調査",
|
||||
"xpack.dataVisualizer.index.actionsPanel.viewIndexInDiscoverDescription": "インデックスのドキュメントを調査します。",
|
||||
"xpack.dataVisualizer.index.advancedSettings.discover.fieldNameDescription.versionFieldLinkText": "セマンティックバージョニング",
|
||||
"xpack.dataVisualizer.index.components.grid.description": "データの可視化",
|
||||
"xpack.dataVisualizer.index.components.grid.displayName": "データビジュアライザーグリッド",
|
||||
"xpack.dataVisualizer.index.dataGrid.actionsColumnLabel": "アクション",
|
||||
|
@ -11061,23 +11042,6 @@
|
|||
"xpack.dataVisualizer.index.embeddableErrorTitle": "埋め込み可能オブジェクトの読み込みエラー",
|
||||
"xpack.dataVisualizer.index.embeddableNoResultsMessage": "結果が見つかりませんでした",
|
||||
"xpack.dataVisualizer.index.errorFetchingFieldStatisticsMessage": "フィールド統計情報の取得エラー",
|
||||
"xpack.dataVisualizer.index.fieldNameDescription.booleanField": "TrueおよびFalse値",
|
||||
"xpack.dataVisualizer.index.fieldNameDescription.conflictField": "フィールドには異なる型の値があります。[管理 > データビュー]で解決してください。",
|
||||
"xpack.dataVisualizer.index.fieldNameDescription.dateField": "日付文字列、または1/1/1970以降の秒またはミリ秒の数値",
|
||||
"xpack.dataVisualizer.index.fieldNameDescription.dateRangeFieldLinkText": "日付",
|
||||
"xpack.dataVisualizer.index.fieldNameDescription.geoPointField": "緯度および経度点",
|
||||
"xpack.dataVisualizer.index.fieldNameDescription.geoShapeField": "多角形などの複雑な図形",
|
||||
"xpack.dataVisualizer.index.fieldNameDescription.histogramField": "ヒストグラムの形式の集計された数値",
|
||||
"xpack.dataVisualizer.index.fieldNameDescription.ipAddressField": "IPv4およびIPv6アドレス",
|
||||
"xpack.dataVisualizer.index.fieldNameDescription.ipAddressRangeField": "IPv4またはIPv6(または混合)のアドレスをサポートするIP値の範囲",
|
||||
"xpack.dataVisualizer.index.fieldNameDescription.keywordField": "ID、電子メールアドレス、ホスト名、ステータスコード、タグなどの構造化されたコンテンツ",
|
||||
"xpack.dataVisualizer.index.fieldNameDescription.murmur3Field": "値のハッシュタグを計算して格納するフィールド",
|
||||
"xpack.dataVisualizer.index.fieldNameDescription.nestedField": "サブフィールド間の関係を保持するJSONオブジェクト",
|
||||
"xpack.dataVisualizer.index.fieldNameDescription.numberField": "長整数、整数、短整数、バイト、倍精度浮動小数点数、浮動小数点数の値",
|
||||
"xpack.dataVisualizer.index.fieldNameDescription.stringField": "電子メール本文や製品説明などの全文テキスト",
|
||||
"xpack.dataVisualizer.index.fieldNameDescription.textField": "電子メール本文や製品説明などの全文テキスト",
|
||||
"xpack.dataVisualizer.index.fieldNameDescription.unknownField": "不明なフィールド",
|
||||
"xpack.dataVisualizer.index.fieldNameDescription.viewSupportedDateFormatsLinkText": "サポートされている日付形式を表示します。",
|
||||
"xpack.dataVisualizer.index.fieldNameSelect": "フィールド名",
|
||||
"xpack.dataVisualizer.index.fieldTypeSelect": "フィールド型",
|
||||
"xpack.dataVisualizer.index.lensChart.countLabel": "カウント",
|
||||
|
|
|
@ -10816,8 +10816,6 @@
|
|||
"xpack.dataVisualizer.index.dataLoader.internalServerErrorMessage": "加载索引 {index} 中的数据时出错。{message}。请求可能已超时。请尝试使用较小的样例大小或缩小时间范围。",
|
||||
"xpack.dataVisualizer.index.dataViewNotBasedOnTimeSeriesNotificationTitle": "数据视图 {dataViewTitle} 并非基于时间序列",
|
||||
"xpack.dataVisualizer.index.errorLoadingDataMessage": "加载索引 {index} 中的数据时出错。{message}。",
|
||||
"xpack.dataVisualizer.index.fieldNameDescription.dateRangeField": "{dateFieldTypeLink} 值的范围。{viewSupportedDateFormatsLink}",
|
||||
"xpack.dataVisualizer.index.fieldNameDescription.versionField": "软件版本。支持 {SemanticVersioningLink} 优先规则",
|
||||
"xpack.dataVisualizer.index.lensChart.averageOfLabel": "{fieldName} 的平均值",
|
||||
"xpack.dataVisualizer.index.lensChart.chartTitle": "{fieldName} 的 Lens",
|
||||
"xpack.dataVisualizer.index.savedSearchErrorMessage": "检索已保存搜索 {savedSearchId} 时出错",
|
||||
|
@ -10882,22 +10880,6 @@
|
|||
"xpack.dataVisualizer.fieldStats.maxTitle": "最大值",
|
||||
"xpack.dataVisualizer.fieldStats.medianTitle": "中值",
|
||||
"xpack.dataVisualizer.fieldStats.minTitle": "最小值",
|
||||
"xpack.dataVisualizer.fieldTypeIcon.booleanTypeLabel": "布尔型",
|
||||
"xpack.dataVisualizer.fieldTypeIcon.conflictTypeLabel": "冲突",
|
||||
"xpack.dataVisualizer.fieldTypeIcon.dateRangeTypeLabel": "日期范围",
|
||||
"xpack.dataVisualizer.fieldTypeIcon.dateTypeLabel": "日期",
|
||||
"xpack.dataVisualizer.fieldTypeIcon.geoPointTypeLabel": "地理点",
|
||||
"xpack.dataVisualizer.fieldTypeIcon.geoShapeTypeLabel": "几何形状",
|
||||
"xpack.dataVisualizer.fieldTypeIcon.histogramTypeLabel": "直方图",
|
||||
"xpack.dataVisualizer.fieldTypeIcon.ipRangeTypeLabel": "IP 范围",
|
||||
"xpack.dataVisualizer.fieldTypeIcon.ipTypeLabel": "IP",
|
||||
"xpack.dataVisualizer.fieldTypeIcon.keywordTypeLabel": "关键字",
|
||||
"xpack.dataVisualizer.fieldTypeIcon.murmur3TypeLabel": "Murmur3",
|
||||
"xpack.dataVisualizer.fieldTypeIcon.numberTypeLabel": "数字",
|
||||
"xpack.dataVisualizer.fieldTypeIcon.stringTypeLabel": "字符串",
|
||||
"xpack.dataVisualizer.fieldTypeIcon.textTypeLabel": "文本",
|
||||
"xpack.dataVisualizer.fieldTypeIcon.unknownTypeLabel": "未知",
|
||||
"xpack.dataVisualizer.fieldTypeIcon.versionTypeLabel": "版本",
|
||||
"xpack.dataVisualizer.fieldTypeSelect": "字段类型",
|
||||
"xpack.dataVisualizer.fieldTypesPopover.buttonAriaLabel": "筛选类型帮助",
|
||||
"xpack.dataVisualizer.fieldTypesPopover.dataTypeColumnTitle": "数据类型",
|
||||
|
@ -11041,7 +11023,6 @@
|
|||
"xpack.dataVisualizer.index.actionsPanel.discoverAppTitle": "Discover",
|
||||
"xpack.dataVisualizer.index.actionsPanel.exploreTitle": "浏览您的数据",
|
||||
"xpack.dataVisualizer.index.actionsPanel.viewIndexInDiscoverDescription": "浏览您的索引中的文档。",
|
||||
"xpack.dataVisualizer.index.advancedSettings.discover.fieldNameDescription.versionFieldLinkText": "语义版本控制",
|
||||
"xpack.dataVisualizer.index.components.grid.description": "可视化数据",
|
||||
"xpack.dataVisualizer.index.components.grid.displayName": "数据可视化工具网格",
|
||||
"xpack.dataVisualizer.index.dataGrid.actionsColumnLabel": "操作",
|
||||
|
@ -11062,23 +11043,6 @@
|
|||
"xpack.dataVisualizer.index.embeddableErrorTitle": "加载可嵌入对象时出错",
|
||||
"xpack.dataVisualizer.index.embeddableNoResultsMessage": "找不到结果",
|
||||
"xpack.dataVisualizer.index.errorFetchingFieldStatisticsMessage": "提取字段统计信息时出错",
|
||||
"xpack.dataVisualizer.index.fieldNameDescription.booleanField": "True 和 False 值",
|
||||
"xpack.dataVisualizer.index.fieldNameDescription.conflictField": "字体具有不同类型的值。在“管理”>“数据视图”中解析。",
|
||||
"xpack.dataVisualizer.index.fieldNameDescription.dateField": "日期字符串或 1/1/1970 以来的秒数或毫秒数",
|
||||
"xpack.dataVisualizer.index.fieldNameDescription.dateRangeFieldLinkText": "日期",
|
||||
"xpack.dataVisualizer.index.fieldNameDescription.geoPointField": "纬度和经度点",
|
||||
"xpack.dataVisualizer.index.fieldNameDescription.geoShapeField": "复杂形状,如多边形",
|
||||
"xpack.dataVisualizer.index.fieldNameDescription.histogramField": "直方图形式的预聚合数字值",
|
||||
"xpack.dataVisualizer.index.fieldNameDescription.ipAddressField": "IPv4 和 IPv6 地址",
|
||||
"xpack.dataVisualizer.index.fieldNameDescription.ipAddressRangeField": "支持 IPv4 或 IPv6(或混合)地址的 IP 值的范围",
|
||||
"xpack.dataVisualizer.index.fieldNameDescription.keywordField": "结构化内容,如 ID、电子邮件地址、主机名、状态代码或标签",
|
||||
"xpack.dataVisualizer.index.fieldNameDescription.murmur3Field": "计算和存储值哈希的字段",
|
||||
"xpack.dataVisualizer.index.fieldNameDescription.nestedField": "保留其子字段之间关系的 JSON 对象",
|
||||
"xpack.dataVisualizer.index.fieldNameDescription.numberField": "长整型、整数、短整型、字节、双精度和浮点值",
|
||||
"xpack.dataVisualizer.index.fieldNameDescription.stringField": "全文本,如电子邮件正文或产品描述",
|
||||
"xpack.dataVisualizer.index.fieldNameDescription.textField": "全文本,如电子邮件正文或产品描述",
|
||||
"xpack.dataVisualizer.index.fieldNameDescription.unknownField": "未知字段",
|
||||
"xpack.dataVisualizer.index.fieldNameDescription.viewSupportedDateFormatsLinkText": "查看支持的日期格式。",
|
||||
"xpack.dataVisualizer.index.fieldNameSelect": "字段名称",
|
||||
"xpack.dataVisualizer.index.fieldTypeSelect": "字段类型",
|
||||
"xpack.dataVisualizer.index.lensChart.countLabel": "计数",
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
import type { FieldVisConfig } from '@kbn/data-visualizer-plugin/public/application/common/components/stats_table/types';
|
||||
|
||||
export interface MetricFieldVisConfig extends FieldVisConfig {
|
||||
export interface MetricFieldVisConfig extends Omit<FieldVisConfig, 'secondaryType'> {
|
||||
fieldName: string;
|
||||
statsMaxDecimalPlaces: number;
|
||||
docCountFormatted: string;
|
||||
|
@ -16,7 +16,7 @@ export interface MetricFieldVisConfig extends FieldVisConfig {
|
|||
hasActionMenu?: boolean;
|
||||
}
|
||||
|
||||
export interface NonMetricFieldVisConfig extends FieldVisConfig {
|
||||
export interface NonMetricFieldVisConfig extends Omit<FieldVisConfig, 'secondaryType'> {
|
||||
fieldName: string;
|
||||
docCountFormatted: string;
|
||||
exampleCount: number;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue