[8.x] Remove hardcoded preconfigured ELSER endpoint (#201300) (#201811)

# Backport

This will backport the following commits from `main` to `8.x`:
- [Remove hardcoded preconfigured ELSER endpoint
(#201300)](https://github.com/elastic/kibana/pull/201300)

<!--- Backport version: 8.9.8 -->

### Questions ?
Please refer to the [Backport tool
documentation](https://github.com/sqren/backport)

<!--BACKPORT [{"author":{"name":"Samiul
Monir","email":"150824886+Samiul-TheSoccerFan@users.noreply.github.com"},"sourceCommit":{"committedDate":"2024-11-26T14:42:20Z","message":"Remove
hardcoded preconfigured ELSER endpoint (#201300)\n\n##
Summary\r\n\r\nThe Index mapping will have access to default elser
inference endpoint\r\nso we do not need to hardcode endpoint names in
the Kibana.\r\n\r\nThis needs to go
after\r\n#https://github.com/elastic/elasticsearch/pull/117294 merges in
`8.17`\r\nand
further.\r\n\r\n\r\nhttps://github.com/user-attachments/assets/4a786fde-e250-440d-a9d7-2256dacc8edd\r\n\r\n---------\r\n\r\nCo-authored-by:
Elastic Machine
<elasticmachine@users.noreply.github.com>","sha":"b3d638b7cf3022fbe1e0fb019462ad9df6d52f25","branchLabelMapping":{"^v9.0.0$":"main","^v8.18.0$":"8.x","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:skip","v9.0.0","Team:Search","backport:version","v8.17.0","v8.18.0"],"number":201300,"url":"https://github.com/elastic/kibana/pull/201300","mergeCommit":{"message":"Remove
hardcoded preconfigured ELSER endpoint (#201300)\n\n##
Summary\r\n\r\nThe Index mapping will have access to default elser
inference endpoint\r\nso we do not need to hardcode endpoint names in
the Kibana.\r\n\r\nThis needs to go
after\r\n#https://github.com/elastic/elasticsearch/pull/117294 merges in
`8.17`\r\nand
further.\r\n\r\n\r\nhttps://github.com/user-attachments/assets/4a786fde-e250-440d-a9d7-2256dacc8edd\r\n\r\n---------\r\n\r\nCo-authored-by:
Elastic Machine
<elasticmachine@users.noreply.github.com>","sha":"b3d638b7cf3022fbe1e0fb019462ad9df6d52f25"}},"sourceBranch":"main","suggestedTargetBranches":["8.17","8.x"],"targetPullRequestStates":[{"branch":"main","label":"v9.0.0","labelRegex":"^v9.0.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/201300","number":201300,"mergeCommit":{"message":"Remove
hardcoded preconfigured ELSER endpoint (#201300)\n\n##
Summary\r\n\r\nThe Index mapping will have access to default elser
inference endpoint\r\nso we do not need to hardcode endpoint names in
the Kibana.\r\n\r\nThis needs to go
after\r\n#https://github.com/elastic/elasticsearch/pull/117294 merges in
`8.17`\r\nand
further.\r\n\r\n\r\nhttps://github.com/user-attachments/assets/4a786fde-e250-440d-a9d7-2256dacc8edd\r\n\r\n---------\r\n\r\nCo-authored-by:
Elastic Machine
<elasticmachine@users.noreply.github.com>","sha":"b3d638b7cf3022fbe1e0fb019462ad9df6d52f25"}},{"branch":"8.17","label":"v8.17.0","labelRegex":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"},{"branch":"8.x","label":"v8.18.0","labelRegex":"^v8.18.0$","isSourceBranch":false,"state":"NOT_CREATED"}]}]
BACKPORT-->
This commit is contained in:
Samiul Monir 2024-11-26 12:01:57 -05:00 committed by GitHub
parent e006f0dbbf
commit aeb5d06647
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 59 additions and 96 deletions

View file

@ -31,15 +31,10 @@ export interface IndexErrorProps {
}
interface SemanticTextProperty extends MappingPropertyBase {
inference_id?: string;
inference_id: string;
type: 'semantic_text';
}
/*
This will be repalce once we add default elser inference_id
with the index mapping response.
*/
const ELSER_PRECONFIGURED_ENDPOINTS = '.elser-2-elasticsearch';
const isInferencePreconfigured = (inferenceId: string) => inferenceId.startsWith('.');
const parseMapping = (mappings: MappingTypeMapping) => {
@ -56,11 +51,6 @@ const getSemanticTextFields = (
): Array<{ path: string; source: SemanticTextProperty }> => {
return Object.entries(fields).flatMap(([key, value]) => {
const currentPath: string = path ? `${path}.${key}` : key;
if (value.type === 'semantic_text') {
value = value.inference_id
? value
: { ...value, inference_id: ELSER_PRECONFIGURED_ENDPOINTS };
}
const currentField: Array<{ path: string; source: SemanticTextProperty }> =
value.type === 'semantic_text' ? [{ path: currentPath, source: value }] : [];
if (hasProperties(value)) {

View file

@ -9,7 +9,7 @@ import {
Form,
useForm,
} from '../../../public/application/components/mappings_editor/shared_imports';
import { registerTestBed } from '@kbn/test-jest-helpers';
import { findTestSubject, registerTestBed } from '@kbn/test-jest-helpers';
import { act } from 'react-dom/test-utils';
import {
SelectInferenceId,
@ -152,4 +152,34 @@ describe('SelectInferenceId', () => {
expect(find('data-inference-endpoint-list').contains('endpoint-2')).toBe(true);
expect(find('data-inference-endpoint-list').contains('endpoint-3')).toBe(false);
});
it('select the first endpoint by default', () => {
find('inferenceIdButton').simulate('click');
const defaultElser = findTestSubject(
find('data-inference-endpoint-list'),
'custom-inference_.preconfigured-elser'
);
expect(defaultElser.prop('aria-checked')).toEqual(true);
});
it('does not select the other endpoints by default', () => {
find('inferenceIdButton').simulate('click');
const defaultE5 = findTestSubject(
find('data-inference-endpoint-list'),
'custom-inference_.preconfigured-e5'
);
expect(defaultE5.prop('aria-checked')).toEqual(false);
const endpoint1 = findTestSubject(
find('data-inference-endpoint-list'),
'custom-inference_endpoint-1'
);
expect(endpoint1.prop('aria-checked')).toEqual(false);
const endpoint2 = findTestSubject(
find('data-inference-endpoint-list'),
'custom-inference_endpoint-2'
);
expect(endpoint2.prop('aria-checked')).toEqual(false);
});
});

View file

@ -132,6 +132,14 @@ const SelectInferenceIdContent: React.FC<SelectInferenceIdContentProps> = ({
'data-test-subj': `custom-inference_${endpoint.inference_id}`,
checked: value === endpoint.inference_id ? 'on' : undefined,
}));
/**
* Adding this check to ensure we have the preconfigured elser endpoint selected by default.
*/
const hasInferenceSelected = newOptions.some((option) => option.checked === 'on');
if (!hasInferenceSelected && newOptions.length > 0) {
newOptions[0].checked = 'on';
}
if (value && !newOptions.find((option) => option.label === value)) {
// Sometimes we create a new endpoint but the backend is slow in updating so we need to optimistically update
const newOption: EuiSelectableOption = {
@ -273,6 +281,7 @@ const SelectInferenceIdContent: React.FC<SelectInferenceIdContentProps> = ({
searchable
isLoading={isLoading}
singleSelection="always"
defaultChecked
searchProps={{
compressed: true,
placeholder: i18n.translate(

View file

@ -13,16 +13,16 @@ import { act } from 'react-dom/test-utils';
jest.mock('../../../../../../../../hooks/use_details_page_mappings_model_management', () => ({
useDetailsPageMappingsModelManagement: () => ({
fetchInferenceToModelIdMap: () => ({
e5: {
isDeployed: false,
isDeployable: true,
trainedModelId: '.multilingual-e5-small',
},
elser_model_2: {
'.preconfigured_elser': {
isDeployed: false,
isDeployable: true,
trainedModelId: '.elser_model_2',
},
'.preconfigured_e5': {
isDeployed: false,
isDeployable: true,
trainedModelId: '.multilingual-e5-small',
},
openai: {
isDeployed: false,
isDeployable: false,
@ -49,13 +49,13 @@ const mockField: Record<string, SemanticTextField> = {
elser_model_2: {
name: 'name',
type: 'semantic_text',
inference_id: 'elser_model_2',
inference_id: '.preconfigured_elser',
reference_field: 'title',
},
e5: {
name: 'name',
type: 'semantic_text',
inference_id: 'e5',
inference_id: '.preconfigured_e5',
reference_field: 'title',
},
openai: {
@ -100,16 +100,16 @@ const mockDispatch = jest.fn();
jest.mock('../../../../../mappings_state_context', () => ({
useMappingsState: jest.fn().mockReturnValue({
inferenceToModelIdMap: {
e5: {
isDeployed: false,
isDeployable: true,
trainedModelId: '.multilingual-e5-small',
},
elser_model_2: {
'.preconfigured_elser': {
isDeployed: false,
isDeployable: true,
trainedModelId: '.elser_model_2',
},
'.preconfigured_e5': {
isDeployed: false,
isDeployable: true,
trainedModelId: '.multilingual-e5-small',
},
openai: {
isDeployed: false,
isDeployable: false,
@ -142,7 +142,7 @@ jest.mock('../../../../../../../services/api', () => ({
getInferenceEndpoints: jest.fn().mockResolvedValue({
data: [
{
inference_id: 'e5',
inference_id: '.preconfigured_e5',
task_type: 'text_embedding',
service: 'elasticsearch',
service_settings: {
@ -212,28 +212,6 @@ describe('useSemanticText', () => {
mockConfig.openai.modelConfig
);
});
it('should handle semantic text with inference endpoint created from flyout correctly', async () => {
const { result } = renderHook(() =>
useSemanticText({
form: mockForm.elasticModelEndpointCreatedfromFlyout,
setErrorsInTrainedModelDeployment: jest.fn(),
ml: mlMock,
})
);
await act(async () => {
result.current.handleSemanticText(mockField.my_elser_endpoint, mockConfig.elser);
});
expect(mockDispatch).toHaveBeenCalledWith({
type: 'field.add',
value: mockField.my_elser_endpoint,
});
expect(mlMock.mlApi.inferenceModels.createInferenceEndpoint).toHaveBeenCalledWith(
'my_elser_endpoint',
'sparse_embedding',
mockConfig.elser.modelConfig
);
});
it('should handle semantic text correctly', async () => {
const { result } = renderHook(() =>
@ -252,20 +230,6 @@ describe('useSemanticText', () => {
type: 'field.add',
value: mockField.elser_model_2,
});
expect(mlMock.mlApi.inferenceModels.createInferenceEndpoint).toHaveBeenCalledWith(
'elser_model_2',
'sparse_embedding',
{
service: 'elser',
service_settings: {
adaptive_allocations: {
enabled: true,
},
num_threads: 1,
model_id: '.elser_model_2',
},
}
);
});
it('does not call create inference endpoint api, if default endpoint already exists', async () => {
const { result } = renderHook(() =>

View file

@ -19,7 +19,6 @@ import { useMLModelNotificationToasts } from '../../../../../../../../hooks/use_
import { getInferenceEndpoints } from '../../../../../../../services/api';
import { getFieldByPathName } from '../../../../../lib/utils';
import { ELSER_PRECONFIGURED_ENDPOINTS } from '../../../../../constants';
interface UseSemanticTextProps {
form: FormHook<Field, Field>;
@ -63,9 +62,6 @@ export function useSemanticText(props: UseSemanticTextProps) {
if (!form.getFormData().reference_field) {
form.setFieldValue('reference_field', referenceField);
}
if (!form.getFormData().inference_id) {
form.setFieldValue('inference_id', ELSER_PRECONFIGURED_ENDPOINTS);
}
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [fieldTypeValue]);

View file

@ -19,11 +19,7 @@ import { i18n } from '@kbn/i18n';
import { NormalizedField, NormalizedFields, State } from '../../../types';
import { getTypeLabelFromField } from '../../../lib';
import {
CHILD_FIELD_INDENT_SIZE,
ELSER_PRECONFIGURED_ENDPOINTS,
LEFT_PADDING_SIZE_FIELD_ITEM_WRAPPER,
} from '../../../constants';
import { CHILD_FIELD_INDENT_SIZE, LEFT_PADDING_SIZE_FIELD_ITEM_WRAPPER } from '../../../constants';
import { FieldsList } from './fields_list';
import { CreateField } from './create_field';
@ -109,7 +105,6 @@ function FieldListItemComponent(
const indent = treeDepth * CHILD_FIELD_INDENT_SIZE - substractIndentAmount;
const isSemanticText = source.type === 'semantic_text';
const inferenceId: string = (source.inference_id as string) ?? ELSER_PRECONFIGURED_ENDPOINTS;
const indentCreateField =
(treeDepth + 1) * CHILD_FIELD_INDENT_SIZE +
@ -298,7 +293,7 @@ function FieldListItemComponent(
{isSemanticText && (
<EuiFlexItem grow={false}>
<EuiBadge color="hollow">{inferenceId}</EuiBadge>
<EuiBadge color="hollow">{source.inference_id as string}</EuiBadge>
</EuiFlexItem>
)}

View file

@ -13,9 +13,3 @@
export const INDEX_DEFAULT = 'index_default';
export const STANDARD = 'standard';
/*
This will be repalce once we add default elser inference_id
with the index mapping response.
*/
export const ELSER_PRECONFIGURED_ENDPOINTS = '.elser-2-elasticsearch';

View file

@ -1126,22 +1126,10 @@ export const PARAMETERS_DEFINITION: { [key in ParameterName]: ParameterDefinitio
},
inference_id: {
fieldConfig: {
defaultValue: 'elser_model_2',
defaultValue: '',
label: i18n.translate('xpack.idxMgmt.mappingsEditor.parameters.inferenceIdLabel', {
defaultMessage: 'Select an inference endpoint:',
}),
validations: [
{
validator: emptyField(
i18n.translate(
'xpack.idxMgmt.mappingsEditor.parameters.validations.inferenceIdIsRequiredErrorMessage',
{
defaultMessage: 'Inference ID is required.',
}
)
),
},
],
},
schema: t.string,
},

View file

@ -23331,7 +23331,6 @@
"xpack.idxMgmt.mappingsEditor.parameters.validations.fieldDataFrequency.numberGreaterThanOneErrorMessage": "La valeur doit être supérieure à un.",
"xpack.idxMgmt.mappingsEditor.parameters.validations.greaterThanZeroErrorMessage": "Le facteur de montée en charge doit être supérieur à 0.",
"xpack.idxMgmt.mappingsEditor.parameters.validations.ignoreAboveIsRequiredErrorMessage": "Limite de longueur de caractère obligatoire.",
"xpack.idxMgmt.mappingsEditor.parameters.validations.inferenceIdIsRequiredErrorMessage": "LID dinférence est requis.",
"xpack.idxMgmt.mappingsEditor.parameters.validations.localeFieldRequiredErrorMessage": "Spécifiez un paramètre régional.",
"xpack.idxMgmt.mappingsEditor.parameters.validations.maxInputLengthFieldRequiredErrorMessage": "Spécifiez une longueur d'entrée maximale.",
"xpack.idxMgmt.mappingsEditor.parameters.validations.nameIsRequiredErrorMessage": "Donnez un nom au champ.",

View file

@ -23303,7 +23303,6 @@
"xpack.idxMgmt.mappingsEditor.parameters.validations.fieldDataFrequency.numberGreaterThanOneErrorMessage": "値は1よりも大きい値でなければなりません。",
"xpack.idxMgmt.mappingsEditor.parameters.validations.greaterThanZeroErrorMessage": "スケーリングファクターは0よりも大きくなくてはなりません。",
"xpack.idxMgmt.mappingsEditor.parameters.validations.ignoreAboveIsRequiredErrorMessage": "文字数制限が必要です。",
"xpack.idxMgmt.mappingsEditor.parameters.validations.inferenceIdIsRequiredErrorMessage": "推論IDは必須です。",
"xpack.idxMgmt.mappingsEditor.parameters.validations.localeFieldRequiredErrorMessage": "ロケールを指定します。",
"xpack.idxMgmt.mappingsEditor.parameters.validations.maxInputLengthFieldRequiredErrorMessage": "最大入力長さを指定します。",
"xpack.idxMgmt.mappingsEditor.parameters.validations.nameIsRequiredErrorMessage": "フィールドに名前を付けます。",

View file

@ -23355,7 +23355,6 @@
"xpack.idxMgmt.mappingsEditor.parameters.validations.fieldDataFrequency.numberGreaterThanOneErrorMessage": "值必须大于 1。",
"xpack.idxMgmt.mappingsEditor.parameters.validations.greaterThanZeroErrorMessage": "缩放因数必须大于 0。",
"xpack.idxMgmt.mappingsEditor.parameters.validations.ignoreAboveIsRequiredErrorMessage": "字符长度限制必填。",
"xpack.idxMgmt.mappingsEditor.parameters.validations.inferenceIdIsRequiredErrorMessage": "“推理 ID”必填。",
"xpack.idxMgmt.mappingsEditor.parameters.validations.localeFieldRequiredErrorMessage": "指定区域设置。",
"xpack.idxMgmt.mappingsEditor.parameters.validations.maxInputLengthFieldRequiredErrorMessage": "指定最大输入长度。",
"xpack.idxMgmt.mappingsEditor.parameters.validations.nameIsRequiredErrorMessage": "为字段提供名称。",