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] Data Frame Analytics: support custom urls in jobs #154287

Merged

Conversation

alvarezmelissa87
Copy link
Contributor

@alvarezmelissa87 alvarezmelissa87 commented Apr 3, 2023

Summary

Related meta issue: #150375

This PR:

  • adds the ability to create custom urls for data frame analytics job - accessible in the 'Edit' flyout in the jobs list
  • adds access to the created custom urls in the data frame analytics results table (in the 'Actions' column)
  • moves the custom url component to a shared directory and is used in both anomaly detection and data frame analytics
customUrls.mp4

image

Checklist

Delete any items that are not applicable to this PR.

@elasticmachine
Copy link
Contributor

Pinging @elastic/ml-ui (:ml)

@@ -10,6 +10,7 @@ import { runtimeMappingsSchema } from './runtime_mappings_schema';

export const dataAnalyticsJobConfigSchema = schema.object({
description: schema.maybe(schema.string()),
_meta: schema.maybe(schema.any()),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
_meta: schema.maybe(schema.any()),
_meta: schema.maybe(schema.object()),

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one I left as any because schema.object requires the properties to be defined and _meta can take whatever properties we want to add. So this could be problematic as it's volatile and for _meta properties that get added automatically on job creation, etc.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this is passed on to the corresponding ES API endpoint, does this one have any documentation about the expected structure of the _meta field we could align with?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So in the [PR](https://github.com/elastic/elasticsearch/pull/94529) adding it in it's described as
The _meta field stores an arbitrary key-value map. Keys are strings. Values are arbitrary objects (possibly also maps).

I don't believe schema let's you specify a key type without knowing what the key is. Happy to add it in if I'm wrong about that.

Copy link
Contributor

@walterra walterra Apr 11, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The TS spec now defines it as an optional record like _meta: undefined | Record<string, any>; (in other places _meta: undefined | Record<string, unknown>;) but this one just as an optional any, maybe it can be updated to also be like the Record?

@walterra - yep, did some digging and there is an option with an 'unknown' - added in in 7ee455c

@alvarezmelissa87
Copy link
Contributor Author

This has been updated and is ready for another look when you get a chance 🙏 cc @peteharverson, @darnautov, @walterra

@alvarezmelissa87
Copy link
Contributor Author

@elasticmachine merge upstream

onChange={onQueryEntitiesChange}
isClearable={true}
data-test-subj="mlJobCustomUrlQueryEntitiesInput"
entityOptions.length > 0 ? (
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a need to switch to this ternary version? Should be fine to keep the && variant.

Copy link
Contributor Author

@alvarezmelissa87 alvarezmelissa87 Apr 11, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just based on something @darnautov brought up before about unexpected things happening because of the nature of && and I thought we all agreed it was better to explicitly return null. Not married to either - happy to stick with whatever we decide is best practice. Just want to be consistent.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed in 3d93dc5


export function isAnomalyDetectionJob(arg: unknown): arg is Job {
return (
isPopulatedObject(arg) && typeof arg.job_id === 'string' && arg.analysis_config !== undefined
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: You could move part of the check to isPopulatedObject here like this:

isPopulatedObject(arg, ['job_id', 'analysis_config']) && typeof arg.job_id === 'string'

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated in 7ee455c


export function isKibanaUrlConfigWithTimeRange(arg: unknown): arg is KibanaUrlConfigWithTimeRange {
return (
isPopulatedObject(arg) &&
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: You could move part of the check to isPopulatedObject here like this:

isPopulatedObject(arg, ['url_name', 'url_value', 'time_range']) && typeof arg.time_range === 'string'

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated in 7ee455c


export function isDataFrameAnalyticsConfigs(arg: unknown): arg is DataFrameAnalyticsConfig {
return (
isPopulatedObject(arg) &&
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: You could move part of the check to isPopulatedObject here like this:

isPopulatedObject(arg, ['dest', 'analysis', 'id']) && typeof arg.id === 'string'

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated in 7ee455c

@@ -61,33 +61,6 @@ exports[`CustomUrlList renders a list of custom URLs 1`] = `
/>
</EuiFormRow>
</EuiFlexItem>
<EuiFlexItem
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd expect these snapshots not to change what do you think? Maybe it's worth updating the configs in the tests so they render the same.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep - it wasn't recognizing the job as an anomaly detection job so was removing the time range selector. I just added in the properties so it would be recognized and updated the result 👍 in 7ee455c

@@ -10,6 +10,7 @@ import { runtimeMappingsSchema } from './runtime_mappings_schema';

export const dataAnalyticsJobConfigSchema = schema.object({
description: schema.maybe(schema.string()),
_meta: schema.maybe(schema.any()),
Copy link
Contributor

@walterra walterra Apr 11, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The TS spec now defines it as an optional record like _meta: undefined | Record<string, any>; (in other places _meta: undefined | Record<string, unknown>;) but this one just as an optional any, maybe it can be updated to also be like the Record?

@walterra - yep, did some digging and there is an option with an 'unknown' - added in in 7ee455c

@alvarezmelissa87
Copy link
Contributor Author

@elasticmachine merge upstream

@alvarezmelissa87
Copy link
Contributor Author

Updated with all suggestions 🙏 cc @walterra, @peteharverson

Copy link
Contributor

@walterra walterra left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Latest changes LGTM

Copy link
Contributor

@peteharverson peteharverson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tested latest changes and looks good.

Would it be possible to add some functional test coverage for this, as we have for anomaly detection jobs?

@@ -87,6 +87,7 @@ export interface State {
maxNumThreads: undefined | number;
maxOptimizationRoundsPerHyperparameter: undefined | number;
maxTrees: undefined | number;
_meta: undefined | Record<string, any>;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
_meta: undefined | Record<string, any>;
_meta: undefined | Record<string, unknown>;

@@ -56,16 +57,26 @@ export interface ClassificationAnalysis {
}

export type AnalysisConfig = estypes.MlDataframeAnalysisContainer;
interface DataFrameAnalyticsMeta {
custom_urls: any[];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we have a type for custom_urls

@@ -56,16 +57,26 @@ export interface ClassificationAnalysis {
}

export type AnalysisConfig = estypes.MlDataframeAnalysisContainer;
interface DataFrameAnalyticsMeta {
custom_urls: any[];
[key: string]: any;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
[key: string]: any;
[key: string]: unknown;

defaultMessage="Interval"
/>
}
className="url-time-range"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this css class doesn't exist anymore

Suggested change
className="url-time-range"

@@ -179,22 +255,22 @@ async function buildDashboardUrlFromSettings(settings) {
});

// Temp workaround
const state = location.state;
const state: any = location?.state;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we have a better type definition for the state?

@@ -328,7 +401,7 @@ export async function getTestUrl(job, customUrl) {
// attempt load the non-combined job and datafeed so they can be used in the datafeed preview
const [{ jobs }, { datafeeds }] = await Promise.all([
ml.getJobs({ jobId: job.job_id }),
ml.getDatafeeds({ datafeedId: job.datafeed_config.datafeed_id }),
ml.getDatafeeds({ datafeedId: job.datafeed_config?.datafeed_id ?? '' }),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah sorry, ❓ shall we pass undefined instead of empty string here?

@@ -54,12 +58,20 @@ export const EditActionFlyout: FC<Required<EditAction>> = ({ closeFlyout, item }
);
const [mmlValidationError, setMmlValidationError] = useState<string | undefined>();
const [maxNumThreads, setMaxNumThreads] = useState<number | undefined>(config.max_num_threads);
const [activeTabId, setActiveTabId] = useState<string>('job-details');
const [customUrls, setCustomUrls] = useState<UrlConfig[]>([]);
const [analyticsJob, setAnalyticsJob] = useState<any>();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could you please set an appropriate type for the list of DFA jobs here?

Copy link
Contributor

@peteharverson peteharverson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense to add functional tests once the other items for custom URLs for DFA jobs are in. I added it as an item to #152009.
LGTM.

@kibana-ci
Copy link
Collaborator

💚 Build Succeeded

Metrics [docs]

Module Count

Fewer modules leads to a faster build time

id before after diff
ml 1721 1726 +5

Async chunks

Total size of all lazy-loaded chunks that will be downloaded as the user navigates the app

id before after diff
ml 3.4MB 3.4MB +5.9KB
Unknown metric groups

ESLint disabled line counts

id before after diff
securitySolution 433 436 +3

References to deprecated APIs

id before after diff
ml 160 161 +1

Total ESLint disabled count

id before after diff
securitySolution 513 516 +3

History

To update your PR or re-run it, just comment with:
@elasticmachine merge upstream

cc @alvarezmelissa87

@alvarezmelissa87 alvarezmelissa87 merged commit c7c5a21 into elastic:main Apr 13, 2023
@kibanamachine kibanamachine added the backport:skip This commit does not require backporting label Apr 13, 2023
@alvarezmelissa87 alvarezmelissa87 deleted the ml-dfa-column-drilldown branch April 13, 2023 14:47
@peteharverson peteharverson added release_note:feature Makes this part of the condensed release notes and removed release_note:enhancement labels Apr 21, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backport:skip This commit does not require backporting Feature:Data Frame Analytics ML data frame analytics features :ml release_note:feature Makes this part of the condensed release notes v8.8.0
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants