mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 17:59:23 -04:00
[ML] ELSER v2 download in the Trained Models UI (#167407)
## Summary
Adds support for ELSER v2 download from the Trained Models UI.
- Marks an appropriate model version for the current cluster
configuration with the recommended flag.
- Updates the state column with better human-readable labels and colour
indicators.
- Adds a callout promoting a new version of ELSER
<img width="1686" alt="image"
src="0deea53a
-6d37-4af6-97bc-9f46e36f113b">
#### Notes for reviews
- We need to wait for
https://github.com/elastic/elasticsearch/pull/99584 to get the start
deployment validation functionality. At the moment you can successfully
start deployment of the wrong model version.
### Checklist
- [x] Any text added follows [EUI's writing
guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses
sentence case text and includes [i18n
support](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md)
- [ ]
[Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html)
was added for features that require explanation or tutorials
- [x] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios
- [x] Any UI touched in this PR is usable by keyboard only (learn more
about [keyboard accessibility](https://webaim.org/techniques/keyboard/))
- [x] Any UI touched in this PR does not create any new axe failures
(run axe in browser:
[FF](https://addons.mozilla.org/en-US/firefox/addon/axe-devtools/),
[Chrome](https://chrome.google.com/webstore/detail/axe-web-accessibility-tes/lhdoppojpmngadmnindnejefpokejbdd?hl=
- [x] This renders correctly on smaller devices using a responsive
layout. (You can test this [in your
browser](https://www.browserstack.com/guide/responsive-testing-on-local-server))
- [x] This was checked for [cross-browser
compatibility](https://www.elastic.co/support/matrix#matrix_browsers)
This commit is contained in:
parent
105935ace5
commit
0c6dfbf209
10 changed files with 375 additions and 77 deletions
|
@ -43,6 +43,89 @@ describe('modelsProvider', () => {
|
|||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
describe('getModelDownloads', () => {
|
||||
test('provides a list of models with recommended and default flag', async () => {
|
||||
const result = await modelService.getModelDownloads();
|
||||
expect(result).toEqual([
|
||||
{
|
||||
config: { input: { field_names: ['text_field'] } },
|
||||
description: 'Elastic Learned Sparse EncodeR v1 (Tech Preview)',
|
||||
hidden: true,
|
||||
name: '.elser_model_1',
|
||||
version: 1,
|
||||
},
|
||||
{
|
||||
config: { input: { field_names: ['text_field'] } },
|
||||
default: true,
|
||||
description: 'Elastic Learned Sparse EncodeR v2 (Tech Preview)',
|
||||
name: '.elser_model_2_SNAPSHOT',
|
||||
version: 2,
|
||||
},
|
||||
{
|
||||
arch: 'amd64',
|
||||
config: { input: { field_names: ['text_field'] } },
|
||||
description:
|
||||
'Elastic Learned Sparse EncodeR v2, optimized for linux-x86_64 (Tech Preview)',
|
||||
name: '.elser_model_2_linux-x86_64_SNAPSHOT',
|
||||
os: 'Linux',
|
||||
recommended: true,
|
||||
version: 2,
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
test('provides a list of models with default model as recommended', async () => {
|
||||
mockCloud.cloudId = undefined;
|
||||
(mockClient.asInternalUser.transport.request as jest.Mock).mockResolvedValueOnce({
|
||||
_nodes: {
|
||||
total: 1,
|
||||
successful: 1,
|
||||
failed: 0,
|
||||
},
|
||||
cluster_name: 'default',
|
||||
nodes: {
|
||||
yYmqBqjpQG2rXsmMSPb9pQ: {
|
||||
name: 'node-0',
|
||||
roles: ['ml'],
|
||||
attributes: {},
|
||||
os: {
|
||||
name: 'Mac OS X',
|
||||
arch: 'aarch64',
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const result = await modelService.getModelDownloads();
|
||||
|
||||
expect(result).toEqual([
|
||||
{
|
||||
config: { input: { field_names: ['text_field'] } },
|
||||
description: 'Elastic Learned Sparse EncodeR v1 (Tech Preview)',
|
||||
hidden: true,
|
||||
name: '.elser_model_1',
|
||||
version: 1,
|
||||
},
|
||||
{
|
||||
config: { input: { field_names: ['text_field'] } },
|
||||
recommended: true,
|
||||
description: 'Elastic Learned Sparse EncodeR v2 (Tech Preview)',
|
||||
name: '.elser_model_2_SNAPSHOT',
|
||||
version: 2,
|
||||
},
|
||||
{
|
||||
arch: 'amd64',
|
||||
config: { input: { field_names: ['text_field'] } },
|
||||
description:
|
||||
'Elastic Learned Sparse EncodeR v2, optimized for linux-x86_64 (Tech Preview)',
|
||||
name: '.elser_model_2_linux-x86_64_SNAPSHOT',
|
||||
os: 'Linux',
|
||||
version: 2,
|
||||
},
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getELSER', () => {
|
||||
test('provides a recommended definition by default', async () => {
|
||||
const result = await modelService.getELSER();
|
||||
|
|
|
@ -25,6 +25,7 @@ import type { CloudSetup } from '@kbn/cloud-plugin/server';
|
|||
import type { PipelineDefinition } from '../../../common/types/trained_models';
|
||||
|
||||
export type ModelService = ReturnType<typeof modelsProvider>;
|
||||
|
||||
export const modelsProvider = (client: IScopedClusterClient, cloud?: CloudSetup) =>
|
||||
new ModelsProvider(client, cloud);
|
||||
|
||||
|
@ -83,6 +84,7 @@ export class ModelsProvider {
|
|||
return { [index]: null };
|
||||
}
|
||||
}
|
||||
|
||||
private getNodeId(
|
||||
elementOriginalId: string,
|
||||
nodeType: typeof JOB_MAP_NODE_TYPES[keyof typeof JOB_MAP_NODE_TYPES]
|
||||
|
@ -446,18 +448,39 @@ export class ModelsProvider {
|
|||
}
|
||||
}
|
||||
|
||||
const result = Object.entries(ELASTIC_MODEL_DEFINITIONS).map(([name, def]) => {
|
||||
const modelDefinitionMap = new Map<string, ModelDefinitionResponse[]>();
|
||||
|
||||
for (const [name, def] of Object.entries(ELASTIC_MODEL_DEFINITIONS)) {
|
||||
const recommended =
|
||||
(isCloud && def.os === 'Linux' && def.arch === 'amd64') ||
|
||||
(sameArch && !!def?.os && def?.os === osName && def?.arch === arch);
|
||||
return {
|
||||
...def,
|
||||
name,
|
||||
...(recommended ? { recommended } : {}),
|
||||
};
|
||||
});
|
||||
|
||||
return result;
|
||||
const { modelName, ...rest } = def;
|
||||
|
||||
const modelDefinitionResponse = {
|
||||
...rest,
|
||||
...(recommended ? { recommended } : {}),
|
||||
name,
|
||||
};
|
||||
|
||||
if (modelDefinitionMap.has(modelName)) {
|
||||
modelDefinitionMap.get(modelName)!.push(modelDefinitionResponse);
|
||||
} else {
|
||||
modelDefinitionMap.set(modelName, [modelDefinitionResponse]);
|
||||
}
|
||||
}
|
||||
|
||||
// check if there is no recommended, so we mark default as recommended
|
||||
for (const arr of modelDefinitionMap.values()) {
|
||||
const defaultModel = arr.find((a) => a.default);
|
||||
const recommendedModel = arr.find((a) => a.recommended);
|
||||
if (defaultModel && !recommendedModel) {
|
||||
delete defaultModel.default;
|
||||
defaultModel.recommended = true;
|
||||
}
|
||||
}
|
||||
|
||||
return [...modelDefinitionMap.values()].flat();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue