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

Add Enterprise Search API endpoints for 1 Click ELSER ML Model Deployment #155213

Merged
merged 62 commits into from
Apr 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
62 commits
Select commit Hold shift + click to select a range
3d5face
redo baseline framework for ent-search 4295
markjhoy Apr 18, 2023
d39b828
[CI] Auto-commit changed files from 'node scripts/precommit_hook.js -…
kibanamachine Apr 18, 2023
222c20d
create background task to watch model download
markjhoy Apr 19, 2023
334ec15
Merge branch 'main' into markjhoy/4295_add_ELSER_ent_search_endpoints
markjhoy Apr 19, 2023
83c8ed9
Merge branch 'markjhoy/4295_add_ELSER_ent_search_endpoints' of github…
markjhoy Apr 19, 2023
cae7922
Merge branch 'main' into markjhoy/4295_add_ELSER_ent_search_endpoints
markjhoy Apr 19, 2023
cd62a17
Merge branch 'main' into markjhoy/4295_add_ELSER_ent_search_endpoints
markjhoy Apr 20, 2023
1360b4f
add tests for GET deployment status
markjhoy Apr 20, 2023
f0f90d4
Merge branch 'main' into markjhoy/4295_add_ELSER_ent_search_endpoints
markjhoy Apr 20, 2023
3df8f7d
start of start deployment tests
markjhoy Apr 20, 2023
38ed14c
[CI] Auto-commit changed files from 'node scripts/precommit_hook.js -…
kibanamachine Apr 20, 2023
ba85079
fix some tests
markjhoy Apr 20, 2023
9a89783
Merge branch 'markjhoy/4295_add_ELSER_ent_search_endpoints' of github…
markjhoy Apr 20, 2023
dbccb77
Merge branch 'main' into markjhoy/4295_add_ELSER_ent_search_endpoints
markjhoy Apr 20, 2023
8ce3e1c
fix some tests
markjhoy Apr 20, 2023
a3e51c4
Merge branch 'main' into markjhoy/4295_add_ELSER_ent_search_endpoints
markjhoy Apr 20, 2023
d235d5d
remove setTimeout polling; update start tests
markjhoy Apr 20, 2023
562fc9c
add route test for POST / deploy
markjhoy Apr 20, 2023
d9ea8d8
add get status route test
markjhoy Apr 21, 2023
4e858d7
fix broken startMlModelDeployment test
markjhoy Apr 21, 2023
c437867
Merge branch 'main' into markjhoy/4295_add_ELSER_ent_search_endpoints
markjhoy Apr 21, 2023
bafe1a4
Merge branch 'main' into markjhoy/4295_add_ELSER_ent_search_endpoints
markjhoy Apr 24, 2023
4993ff1
cleanups around download status
markjhoy Apr 24, 2023
688aa2e
Merge branch 'main' into markjhoy/4295_add_ELSER_ent_search_endpoints
markjhoy Apr 24, 2023
22efac4
split deploy and download into two separate calls
markjhoy Apr 24, 2023
4b2b005
Merge branch 'main' into markjhoy/4295_add_ELSER_ent_search_endpoints
markjhoy Apr 24, 2023
d73dc53
update download index test
markjhoy Apr 24, 2023
9745d5a
[CI] Auto-commit changed files from 'node scripts/precommit_hook.js -…
kibanamachine Apr 24, 2023
b64a998
Merge branch 'main' into markjhoy/4295_add_ELSER_ent_search_endpoints
markjhoy Apr 24, 2023
d7ba709
remove check for !isNotFoundException
markjhoy Apr 24, 2023
c1f5526
[CI] Auto-commit changed files from 'node scripts/precommit_hook.js -…
kibanamachine Apr 24, 2023
c400b58
Merge branch 'main' into markjhoy/4295_add_ELSER_ent_search_endpoints
markjhoy Apr 24, 2023
33a51d0
modify endpoint for download and deploy
markjhoy Apr 24, 2023
2cc603c
Merge branch 'main' into markjhoy/4295_add_ELSER_ent_search_endpoints
markjhoy Apr 25, 2023
56575cf
fix lint
markjhoy Apr 25, 2023
db9d302
Merge branch 'main' into markjhoy/4295_add_ELSER_ent_search_endpoints
markjhoy Apr 25, 2023
264c950
workaround for missing types/remove sync
markjhoy Apr 25, 2023
87e584e
[CI] Auto-commit changed files from 'node scripts/precommit_hook.js -…
kibanamachine Apr 25, 2023
0e325b5
Merge branch 'main' into markjhoy/4295_add_ELSER_ent_search_endpoints
markjhoy Apr 25, 2023
6a8fff5
fix error / updated call for download
markjhoy Apr 25, 2023
19faf5c
Merge branch 'main' into markjhoy/4295_add_ELSER_ent_search_endpoints
markjhoy Apr 25, 2023
875f1d7
cleanups/re-add check for 404 status
markjhoy Apr 25, 2023
bc32cf0
Merge branch 'main' into markjhoy/4295_add_ELSER_ent_search_endpoints
markjhoy Apr 25, 2023
229433e
add ignore for inference_config attribute
markjhoy Apr 25, 2023
cc6feb3
Merge branch 'main' into markjhoy/4295_add_ELSER_ent_search_endpoints
markjhoy Apr 25, 2023
0e99e07
update not found error checking
markjhoy Apr 25, 2023
c6bd42b
[CI] Auto-commit changed files from 'node scripts/precommit_hook.js -…
kibanamachine Apr 25, 2023
c4cd7a8
Merge branch 'main' into markjhoy/4295_add_ELSER_ent_search_endpoints
markjhoy Apr 25, 2023
6d17c73
check deployment status undefined
markjhoy Apr 25, 2023
312abe3
Merge branch 'main' into markjhoy/4295_add_ELSER_ent_search_endpoints
kibanamachine Apr 25, 2023
25b1d4a
Merge branch 'main' into markjhoy/4295_add_ELSER_ent_search_endpoints
markjhoy Apr 25, 2023
86c8cf3
Merge branch 'main' into markjhoy/4295_add_ELSER_ent_search_endpoints
markjhoy Apr 25, 2023
88fd7d9
cleanup, common functions for checks
markjhoy Apr 25, 2023
8bba089
Merge branch 'main' into markjhoy/4295_add_ELSER_ent_search_endpoints
markjhoy Apr 25, 2023
93bf60f
completely fill in resource not found error
markjhoy Apr 25, 2023
d5ac2ef
Merge branch 'main' into markjhoy/4295_add_ELSER_ent_search_endpoints
markjhoy Apr 26, 2023
eb3ded5
remove getMlClient and use esClient.ml MlApi
markjhoy Apr 26, 2023
42b54c1
Merge branch 'main' into markjhoy/4295_add_ELSER_ent_search_endpoints
markjhoy Apr 26, 2023
da0d99a
Merge branch 'main' into markjhoy/4295_add_ELSER_ent_search_endpoints
markjhoy Apr 26, 2023
32d8029
use updated MlTrainedModels provider instead of ml
markjhoy Apr 26, 2023
4b9baf2
Merge branch 'main' into markjhoy/4295_add_ELSER_ent_search_endpoints
markjhoy Apr 26, 2023
932dc8e
fix broken types in test
markjhoy Apr 26, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions x-pack/plugins/enterprise_search/common/types/ml.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* 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 { MlTrainedModelConfig } from '@elastic/elasticsearch/lib/api/typesWithBodyKey';

export enum MlModelDeploymentState {
NotDeployed = '',
Downloading = 'downloading',
Downloaded = 'fully_downloaded',
Starting = 'starting',
Started = 'started',
FullyAllocated = 'fully_allocated',
}

export interface MlModelDeploymentStatus {
deploymentState: MlModelDeploymentState;
modelId: string;
nodeAllocationCount: number;
startTime: number;
targetAllocationCount: number;
}

// TODO - we can remove this extension once the new types are available
// in kibana that includes this field
export interface MlTrainedModelConfigWithDefined extends MlTrainedModelConfig {
fully_defined?: boolean;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,272 @@
/*
* 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 { MlTrainedModels } from '@kbn/ml-plugin/server';

import { MlModelDeploymentState } from '../../../common/types/ml';
import { ElasticsearchResponseError } from '../../utils/identify_exceptions';

import { getMlModelDeploymentStatus } from './get_ml_model_deployment_status';

describe('getMlModelDeploymentStatus', () => {
const mockTrainedModelsProvider = {
getTrainedModels: jest.fn(),
getTrainedModelsStats: jest.fn(),
};

beforeEach(() => {
jest.clearAllMocks();
});

it('should error when there is no trained model provider', () => {
expect(() => getMlModelDeploymentStatus('mockModelName', undefined)).rejects.toThrowError(
'Machine Learning is not enabled'
);
});

it('should return not deployed status if no model is found', async () => {
const mockGetReturn = {
count: 0,
trained_model_configs: [],
};

mockTrainedModelsProvider.getTrainedModels.mockImplementation(() =>
Promise.resolve(mockGetReturn)
);

const deployedStatus = await getMlModelDeploymentStatus(
'mockModelName',
mockTrainedModelsProvider as unknown as MlTrainedModels
);

expect(deployedStatus.deploymentState).toEqual(MlModelDeploymentState.NotDeployed);
expect(deployedStatus.modelId).toEqual('mockModelName');
});

it('should return not deployed status if no model is found when getTrainedModels has a 404', async () => {
const mockErrorRejection: ElasticsearchResponseError = {
meta: {
body: {
error: {
type: 'resource_not_found_exception',
},
},
statusCode: 404,
},
name: 'ResponseError',
};

mockTrainedModelsProvider.getTrainedModels.mockImplementation(() =>
Promise.reject(mockErrorRejection)
);

const deployedStatus = await getMlModelDeploymentStatus(
'mockModelName',
mockTrainedModelsProvider as unknown as MlTrainedModels
);

expect(deployedStatus.deploymentState).toEqual(MlModelDeploymentState.NotDeployed);
expect(deployedStatus.modelId).toEqual('mockModelName');
});

it('should return downloading if the model is downloading', async () => {
const mockGetReturn = {
count: 1,
trained_model_configs: [
{
fully_defined: false,
model_id: 'mockModelName',
},
],
};

mockTrainedModelsProvider.getTrainedModels.mockImplementation(() =>
Promise.resolve(mockGetReturn)
);

const deployedStatus = await getMlModelDeploymentStatus(
'mockModelName',
mockTrainedModelsProvider as unknown as MlTrainedModels
);

expect(deployedStatus.deploymentState).toEqual(MlModelDeploymentState.Downloading);
expect(deployedStatus.modelId).toEqual('mockModelName');
});

it('should return downloaded if the model is downloaded but not deployed', async () => {
const mockGetReturn = {
count: 1,
trained_model_configs: [
{
fully_defined: true,
model_id: 'mockModelName',
},
],
};

const mockStatsReturn = {
count: 0,
trained_model_stats: [],
};

mockTrainedModelsProvider.getTrainedModels.mockImplementation(() =>
Promise.resolve(mockGetReturn)
);
mockTrainedModelsProvider.getTrainedModelsStats.mockImplementation(() =>
Promise.resolve(mockStatsReturn)
);

const deployedStatus = await getMlModelDeploymentStatus(
'mockModelName',
mockTrainedModelsProvider as unknown as MlTrainedModels
);

expect(deployedStatus.deploymentState).toEqual(MlModelDeploymentState.Downloaded);
expect(deployedStatus.modelId).toEqual('mockModelName');
});

it('should return starting if the model is starting deployment', async () => {
const mockGetReturn = {
count: 1,
trained_model_configs: [
{
fully_defined: true,
model_id: 'mockModelName',
},
],
};

const mockStatsReturn = {
count: 1,
trained_model_stats: [
{
deployment_stats: {
allocation_status: {
allocation_count: 0,
state: 'starting',
target_allocation_count: 3,
},
start_time: 123456,
},
model_id: 'mockModelName',
},
],
};

mockTrainedModelsProvider.getTrainedModels.mockImplementation(() =>
Promise.resolve(mockGetReturn)
);
mockTrainedModelsProvider.getTrainedModelsStats.mockImplementation(() =>
Promise.resolve(mockStatsReturn)
);

const deployedStatus = await getMlModelDeploymentStatus(
'mockModelName',
mockTrainedModelsProvider as unknown as MlTrainedModels
);

expect(deployedStatus.deploymentState).toEqual(MlModelDeploymentState.Starting);
expect(deployedStatus.modelId).toEqual('mockModelName');
expect(deployedStatus.nodeAllocationCount).toEqual(0);
expect(deployedStatus.startTime).toEqual(123456);
expect(deployedStatus.targetAllocationCount).toEqual(3);
});

it('should return started if the model has been started', async () => {
const mockGetReturn = {
count: 1,
trained_model_configs: [
{
fully_defined: true,
model_id: 'mockModelName',
},
],
};

const mockStatsReturn = {
count: 1,
trained_model_stats: [
{
deployment_stats: {
allocation_status: {
allocation_count: 1,
state: 'started',
target_allocation_count: 3,
},
start_time: 123456,
},
model_id: 'mockModelName',
},
],
};

mockTrainedModelsProvider.getTrainedModels.mockImplementation(() =>
Promise.resolve(mockGetReturn)
);
mockTrainedModelsProvider.getTrainedModelsStats.mockImplementation(() =>
Promise.resolve(mockStatsReturn)
);

const deployedStatus = await getMlModelDeploymentStatus(
'mockModelName',
mockTrainedModelsProvider as unknown as MlTrainedModels
);

expect(deployedStatus.deploymentState).toEqual(MlModelDeploymentState.Started);
expect(deployedStatus.modelId).toEqual('mockModelName');
expect(deployedStatus.nodeAllocationCount).toEqual(1);
expect(deployedStatus.startTime).toEqual(123456);
expect(deployedStatus.targetAllocationCount).toEqual(3);
});

it('should return fully allocated if the model is fully allocated', async () => {
const mockGetReturn = {
count: 1,
trained_model_configs: [
{
fully_defined: true,
model_id: 'mockModelName',
},
],
};

const mockStatsReturn = {
count: 1,
trained_model_stats: [
{
deployment_stats: {
allocation_status: {
allocation_count: 3,
state: 'fully_allocated',
target_allocation_count: 3,
},
start_time: 123456,
},
model_id: 'mockModelName',
},
],
};

mockTrainedModelsProvider.getTrainedModels.mockImplementation(() =>
Promise.resolve(mockGetReturn)
);
mockTrainedModelsProvider.getTrainedModelsStats.mockImplementation(() =>
Promise.resolve(mockStatsReturn)
);

const deployedStatus = await getMlModelDeploymentStatus(
'mockModelName',
mockTrainedModelsProvider as unknown as MlTrainedModels
);

expect(deployedStatus.deploymentState).toEqual(MlModelDeploymentState.FullyAllocated);
expect(deployedStatus.modelId).toEqual('mockModelName');
expect(deployedStatus.nodeAllocationCount).toEqual(3);
expect(deployedStatus.startTime).toEqual(123456);
expect(deployedStatus.targetAllocationCount).toEqual(3);
});
});
Loading