Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

[ML] Move Index Data Visualizer into separate plugin (Part 1) #100922

Merged
merged 59 commits into from
Jun 8, 2021
Merged
Show file tree
Hide file tree
Changes from 34 commits
Commits
Show all changes
59 commits
Select commit Hold shift + click to select a range
c0ad968
[ML] Add index visualizer
qn895 May 25, 2021
cb3408d
[ML] Readd support for global state
qn895 May 25, 2021
ed3e3dc
[ML] Add time buckets & fix dependencies
qn895 May 26, 2021
593d862
[ML] Working ver
qn895 May 26, 2021
751512b
[ML] Add back and boolean support
qn895 May 26, 2021
101f26b
[ML] Remove old files inside ml
qn895 May 26, 2021
aa35249
[ML] Rename files
qn895 May 27, 2021
f201863
[ML] Move field type icon
qn895 May 27, 2021
6630d2e
[ML] Create new folder structure
qn895 May 27, 2021
d0b713c
[ML] Organize index_data_visualizer
qn895 May 27, 2021
8b7d221
[ML] Move types into index_data_visualizer folder
qn895 May 27, 2021
c81c986
[ML] Move more files into file_data_visualizer
qn895 May 27, 2021
64a663e
[ML] Move more files into index_data_visualizer
qn895 May 27, 2021
8b7cb47
[ML] Add new data visualizer model
qn895 May 27, 2021
c3d1ad9
[ML] Remove getVisualizerFieldStats which is not used by dv
qn895 May 27, 2021
0d12c91
[ML] Delete redundant folder
qn895 May 27, 2021
f343a9e
[ML] Copy old data visualizer routes to new plugin
qn895 May 27, 2021
a8aaf36
[ML] Remove old routes
qn895 May 27, 2021
9e07266
[ML] Disable for ml job cards tests for now
qn895 May 27, 2021
89c916e
[ML] Remove todos
qn895 May 28, 2021
bd30435
[ML] Move the toast error to the UI component
qn895 May 28, 2021
df79e21
[ML] Fix map styling
qn895 May 28, 2021
adbcaac
[ML] Add runtime_mappings for internal/file_upload/time_field_range
qn895 May 28, 2021
ef65d20
[ML] Move routes into folder
qn895 May 28, 2021
25b0f57
[ML] Update permissions
qn895 May 28, 2021
21a460f
[ML] Update texts
qn895 May 28, 2021
7d4a71d
[ML] Update schemas import and api get_field_stats
qn895 May 28, 2021
6443020
[ML] Reorg folders into common
qn895 May 28, 2021
37b3854
Merge remote-tracking branch 'upstream/master' into ml-move-index-dat…
qn895 Jun 1, 2021
ebf33b4
[ML] Update types & tests
qn895 Jun 1, 2021
9512da4
[ML] Update internal/data_visualizer permissions and action panel tests
qn895 Jun 2, 2021
314dc01
Merge upstream/main into branch
qn895 Jun 2, 2021
5e81e92
[ML] Update imports after #100863
qn895 Jun 2, 2021
d501b6f
[ML] Fix CI
qn895 Jun 2, 2021
035b8b4
[ML] Rename folder from file_data_visualizer to data_visualizer
qn895 Jun 3, 2021
88e3ea9
[ML] Rename i18n ids
qn895 Jun 3, 2021
202a077
[ML] Update fileDataVisualizer -> dataVisualizer dependency name in m…
qn895 Jun 3, 2021
76b7dff
[ML] Remove ml prefix in data test subjs
qn895 Jun 3, 2021
9999339
[ML] Fix settings and docs
qn895 Jun 3, 2021
4345951
[ML] Update plugin description
qn895 Jun 4, 2021
30b0f77
[ML] Remove mlContext dependency completely
qn895 Jun 4, 2021
862dfde
[ML] Set query to optional
qn895 Jun 4, 2021
82b97e0
Revert "[ML] Update plugin description"
qn895 Jun 4, 2021
893c4ab
[ML] Update plugins list docs
qn895 Jun 4, 2021
e1ab287
[ML] Fix types and i18n
qn895 Jun 4, 2021
4eb627e
Merge remote-tracking branch 'upstream/master' into ml-move-index-dat…
qn895 Jun 4, 2021
200f874
Merge branch 'master' into ml-move-index-data-visualizer
kibanamachine Jun 6, 2021
aaf142c
[ML] Revert ml data test subj/class name changes
qn895 Jun 7, 2021
403a8e3
[ML] Split up data visualizer model, remove Logger
qn895 Jun 7, 2021
76a7b5b
[ML] Remove empty file and indexPatternFieldEditor
qn895 Jun 7, 2021
836b5eb
[ML] Move imports of file_upload
qn895 Jun 7, 2021
267d3b7
[ML] Update plugin dependencies
qn895 Jun 7, 2021
e976122
Merge upstream/main into branch
qn895 Jun 7, 2021
5149bf5
Re-add missing data_visualizer.json
qn895 Jun 7, 2021
b043d6e
Remove capabilities in data_visualizer
qn895 Jun 7, 2021
ee5f8ab
Fix test subjs
qn895 Jun 7, 2021
d978ee2
Update ownership for data_visualizer and file_upload code to be ml
qn895 Jun 8, 2021
a8e6fbd
Merge upstream/main into branch
qn895 Jun 8, 2021
71e4db8
Update estypes after 98266
qn895 Jun 8, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
2 changes: 2 additions & 0 deletions x-pack/plugins/file_data_visualizer/common/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,5 @@ export const JOB_FIELD_TYPES = {
TEXT: 'text',
UNKNOWN: 'unknown',
} as const;

export const OMIT_FIELDS: string[] = ['_source', '_type', '_index', '_id', '_version', '_score'];
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
* 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 { JobFieldType } from './index';

export interface Percentile {
percent: number;
minValue: number;
maxValue: number;
}

export interface FieldRequestConfig {
fieldName?: string;
type: JobFieldType;
cardinality: number;
}

export interface DocumentCountBuckets {
[key: string]: number;
}

export interface DocumentCounts {
buckets?: DocumentCountBuckets;
interval?: number;
}

export interface FieldVisStats {
cardinality?: number;
count?: number;
sampleCount?: number;
trueCount?: number;
falseCount?: number;
earliest?: number;
latest?: number;
documentCounts?: {
buckets?: DocumentCountBuckets;
interval?: number;
};
avg?: number;
distribution?: {
percentiles: Percentile[];
maxPercentile: number;
minPercentile: 0;
};
fieldName?: string;
isTopValuesSampled?: boolean;
max?: number;
median?: number;
min?: number;
topValues?: Array<{ key: number | string; doc_count: number }>;
topValuesSampleSize?: number;
topValuesSamplerShardSize?: number;
examples?: Array<string | object>;
timeRangeEarliest?: number;
timeRangeLatest?: number;
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,17 @@
* 2.0.
*/

import { JOB_FIELD_TYPES } from './constants';

import type { SimpleSavedObject } from 'kibana/public';
export type { JobFieldType } from './job_field_type';
export type {
FieldRequestConfig,
DocumentCountBuckets,
DocumentCounts,
FieldVisStats,
Percentile,
} from './field_request_config';
export type InputData = any[];

export type JobFieldType = typeof JOB_FIELD_TYPES[keyof typeof JOB_FIELD_TYPES];

export interface DataVisualizerTableState {
pageSize: number;
pageIndex: number;
Expand All @@ -20,3 +25,5 @@ export interface DataVisualizerTableState {
visibleFieldNames: string[];
showDistributions: boolean;
}

export type SavedSearchSavedObject = SimpleSavedObject<any>;
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@
* 2.0.
*/

import type { FieldVisConfig, FileBasedFieldVisConfig } from './field_vis_config';
import { estypes } from '@elastic/elasticsearch';

export interface FieldDataRowProps {
config: FieldVisConfig | FileBasedFieldVisConfig;
export interface IndicesOptions {
allow_no_indices?: boolean;
expand_wildcards?: estypes.ExpandWildcards;
ignore_unavailable?: boolean;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/*
* 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 { JOB_FIELD_TYPES } from '../constants';
export type JobFieldType = typeof JOB_FIELD_TYPES[keyof typeof JOB_FIELD_TYPES];
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/*
* 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 interface GetTimeFieldRangeResponse {
success: boolean;
start: { epoch: number; string: string };
end: { epoch: number; string: string };
}
23 changes: 23 additions & 0 deletions x-pack/plugins/file_data_visualizer/common/utils/datafeed_utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/*
* 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 { estypes } from '@elastic/elasticsearch';

export type Datafeed = estypes.Datafeed;
export type Aggregation = Record<string, estypes.AggregationContainer>;

export function getAggregations<T>(obj: any): T | undefined {
if (obj?.aggregations !== undefined) return obj.aggregations;
if (obj?.aggs !== undefined) return obj.aggs;
return undefined;
}

export const getDatafeedAggregations = (
datafeedConfig: Partial<Datafeed> | undefined
): Aggregation | undefined => {
return getAggregations<Aggregation>(datafeedConfig);
};
36 changes: 36 additions & 0 deletions x-pack/plugins/file_data_visualizer/common/utils/object_utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* 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.
*/

/*
* A type guard to check record like object structures.
*
* Examples:
* - `isPopulatedObject({...})`
* Limits type to Record<string, unknown>
*
* - `isPopulatedObject({...}, ['attribute'])`
* Limits type to Record<'attribute', unknown>
*
* - `isPopulatedObject<keyof MyInterface>({...})`
* Limits type to a record with keys of the given interface.
* Note that you might want to add keys from the interface to the
* array of requiredAttributes to satisfy runtime requirements.
* Otherwise you'd just satisfy TS requirements but might still
* run into runtime issues.
*/
export const isPopulatedObject = <U extends string = string>(
arg: unknown,
requiredAttributes: U[] = []
): arg is Record<U, unknown> => {
return (
typeof arg === 'object' &&
arg !== null &&
Object.keys(arg).length > 0 &&
(requiredAttributes.length === 0 ||
requiredAttributes.every((d) => ({}.hasOwnProperty.call(arg, d))))
);
};
76 changes: 76 additions & 0 deletions x-pack/plugins/file_data_visualizer/common/utils/query_utils.ts
Original file line number Diff line number Diff line change
@@ -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 { estypes } from '@elastic/elasticsearch';
/*
* Contains utility functions for building and processing queries.
*/

// Builds the base filter criteria used in queries,
// adding criteria for the time range and an optional query.
export function buildBaseFilterCriteria(
timeFieldName?: string,
earliestMs?: number,
latestMs?: number,
query?: object
) {
const filterCriteria = [];
if (timeFieldName && earliestMs && latestMs) {
filterCriteria.push({
range: {
[timeFieldName]: {
gte: earliestMs,
lte: latestMs,
format: 'epoch_millis',
},
},
});
}

if (query) {
filterCriteria.push(query);
}

return filterCriteria;
}

// Wraps the supplied aggregations in a sampler aggregation.
// A supplied samplerShardSize (the shard_size parameter of the sampler aggregation)
// of less than 1 indicates no sampling, and the aggs are returned as-is.
export function buildSamplerAggregation(
aggs: any,
samplerShardSize: number
): Record<string, estypes.AggregationContainer> {
if (samplerShardSize < 1) {
return aggs;
}

return {
sample: {
sampler: {
shard_size: samplerShardSize,
},
aggs,
},
};
}

// Returns the path of aggregations in the elasticsearch response, as an array,
// depending on whether sampling is being used.
// A supplied samplerShardSize (the shard_size parameter of the sampler aggregation)
// of less than 1 indicates no sampling, and an empty array is returned.
export function getSamplerAggregationsResponsePath(samplerShardSize: number): string[] {
return samplerShardSize > 0 ? ['sample'] : [];
}

// Returns a name which is safe to use in elasticsearch aggregations for the supplied
// field name. Aggregation names must be alpha-numeric and can only contain '_' and '-' characters,
// so if the supplied field names contains disallowed characters, the provided index
// identifier is used to return a safe 'dummy' name in the format 'field_index' e.g. field_0, field_1
export function getSafeAggregationName(fieldName: string, index: number): string {
return fieldName.match(/^[a-zA-Z0-9-_.]+$/) ? fieldName : `field_${index}`;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* 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 { estypes } from '@elastic/elasticsearch';
import { isPopulatedObject } from './object_utils';
import { RUNTIME_FIELD_TYPES } from '../../../../../src/plugins/data/common';

type RuntimeType = typeof RUNTIME_FIELD_TYPES[number];

export function isRuntimeField(arg: unknown): arg is estypes.RuntimeField {
return (
((isPopulatedObject(arg, ['type']) && Object.keys(arg).length === 1) ||
(isPopulatedObject(arg, ['type', 'script']) &&
Object.keys(arg).length === 2 &&
(typeof arg.script === 'string' ||
(isPopulatedObject(arg.script, ['source']) &&
Object.keys(arg.script).length === 1 &&
typeof arg.script.source === 'string')))) &&
RUNTIME_FIELD_TYPES.includes(arg.type as RuntimeType)
);
}

export function isRuntimeMappings(arg: unknown): arg is estypes.RuntimeFields {
return isPopulatedObject(arg) && Object.values(arg).every((d) => isRuntimeField(d));
}
23 changes: 23 additions & 0 deletions x-pack/plugins/file_data_visualizer/common/utils/string_utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/*
* 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.
*/

/**
* Creates a deterministic number based hash out of a string.
*/
export function stringHash(str: string): number {
let hash = 0;
let chr = 0;
if (str.length === 0) {
return hash;
}
for (let i = 0; i < str.length; i++) {
chr = str.charCodeAt(i);
hash = (hash << 5) - hash + chr; // eslint-disable-line no-bitwise
hash |= 0; // eslint-disable-line no-bitwise
}
return hash < 0 ? hash * -2 : hash;
}
3 changes: 2 additions & 1 deletion x-pack/plugins/file_data_visualizer/kibana.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@
"optionalPlugins": [
"security",
"maps",
"home"
"home",
"lens"
],
"requiredBundles": [
"kibanaReact",
Expand Down
8 changes: 6 additions & 2 deletions x-pack/plugins/file_data_visualizer/public/api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,13 @@
*/

import { lazyLoadModules } from '../lazy_load_bundle';
import { FileDataVisualizer } from '../application';
import type { FileDataVisualizerSpec, IndexDataVisualizerSpec } from '../application';

export async function getFileDataVisualizerComponent(): Promise<typeof FileDataVisualizer> {
export async function getFileDataVisualizerComponent(): Promise<FileDataVisualizerSpec> {
const modules = await lazyLoadModules();
return modules.FileDataVisualizer;
}
export async function getIndexDataVisualizerComponent(): Promise<IndexDataVisualizerSpec> {
const modules = await lazyLoadModules();
return modules.IndexDataVisualizer;
}
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
@import 'components/index';
@import 'common/components/index';
@import 'file_data_visualizer/index';
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
@import 'about_panel/index';
@import 'embedded_map/index';
@import 'experimental_badge/index';
@import 'stats_table/index';
@import 'top_values/top_values';
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import {

import { ExperimentalBadge } from '../experimental_badge';

import { useFileDataVisualizerKibana } from '../../kibana_context';
import { useDataVisualizerKibana } from '../../../kibana_context';

export const WelcomeContent: FC = () => {
const toolTipContent = i18n.translate(
Expand All @@ -35,7 +35,7 @@ export const WelcomeContent: FC = () => {
services: {
fileUpload: { getMaxBytesFormatted },
},
} = useFileDataVisualizerKibana();
} = useDataVisualizerKibana();
const maxFileSize = getMaxBytesFormatted();

return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import {
removeCombinedFieldsFromMappings,
removeCombinedFieldsFromPipeline,
} from './utils';
import { FindFileStructureResponse } from '../../../../../file_upload/common';
import { FindFileStructureResponse } from '../../../../../../file_upload/common';

interface Props {
mappingsString: string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import {
getFieldNames,
getNameCollisionMsg,
} from './utils';
import { FindFileStructureResponse } from '../../../../../file_upload/common';
import { FindFileStructureResponse } from '../../../../../../file_upload/common';

interface Props {
addCombinedField: (combinedField: CombinedField) => void;
Expand Down
Loading