Skip to content

Commit bac6d90

Browse files
[8.18] [Obs AI Assistant] Add KB re-indexing when encountering semantic_text bug (elastic#210386) (elastic#211497)
# Backport This will backport the following commits from `main` to `8.18`: - [[Obs AI Assistant] Add KB re-indexing when encountering `semantic_text` bug (elastic#210386)](elastic#210386) <!--- Backport version: 9.6.5 --> ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sorenlouv/backport) <!--BACKPORT [{"author":{"name":"Søren Louv-Jansen","email":"[email protected]"},"sourceCommit":{"committedDate":"2025-02-17T17:20:50Z","message":"[Obs AI Assistant] Add KB re-indexing when encountering `semantic_text` bug (elastic#210386)\n\nCloses https://github.com/elastic/kibana/issues/210204\n\nThis will automatically re-index the knowledge base if upon adding a KB\nentry there is this error:\n\n> The [sparse_vector] field type is not supported on indices created on\nversions 8.0 to 8.10\n\nThat error means that semantic_text is not supported in the given index,\nand it should therefore be re-indexed.\n\n**How to test this PR:**\n\n**8.10**\n- `git checkout -B 8.10 origin/8.10`\n- Start Kibana:\n - `nvm use && yarn kbn bootstrap && yarn start`\n- Start ES\n- `nvm use && yarn es snapshot --license trial --E\npath.data=\"/Users/sorenlouv/elastic/kbn_es_data/upgrade_testing\"`\n\n**8.19**\n- `git checkout -B 8.19 origin/8.x`\n- Start Kibana:\n - `nvm use && yarn kbn bootstrap && yarn start`\n- Start ES\n- `nvm use && yarn es snapshot --license trial --E\npath.data=\"/Users/sorenlouv/elastic/kbn_es_data/upgrade_testing\"`\n- Install Knowledge base\n- Try adding an item to KB (it should fail ❌️)\n\n**9.1.0**\n- `gh pr checkout 210386`\n- Start Kibana:\n - `nvm use && yarn kbn bootstrap && yarn start`\n- Start ES\n- `nvm use && yarn es snapshot --license trial --E\npath.data=\"/Users/sorenlouv/elastic/kbn_es_data/upgrade_testing\"`\n- Try adding an item to KB (it should succeed ✅️)\n\n**TODO:**\n\n- Add an upgrade test that covers this flow\n\n---------\n\nCo-authored-by: Viduni Wickramarachchi <[email protected]>","sha":"df67a09afab22521dfa9ff3ec3a4f624a039c462","branchLabelMapping":{"^v9.1.0$":"main","^v8.19.0$":"8.x","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:fix","backport:prev-major","Team:Obs AI Assistant","v9.1.0"],"title":"[Obs AI Assistant] Add KB re-indexing when encountering `semantic_text` bug","number":210386,"url":"https://github.com/elastic/kibana/pull/210386","mergeCommit":{"message":"[Obs AI Assistant] Add KB re-indexing when encountering `semantic_text` bug (elastic#210386)\n\nCloses https://github.com/elastic/kibana/issues/210204\n\nThis will automatically re-index the knowledge base if upon adding a KB\nentry there is this error:\n\n> The [sparse_vector] field type is not supported on indices created on\nversions 8.0 to 8.10\n\nThat error means that semantic_text is not supported in the given index,\nand it should therefore be re-indexed.\n\n**How to test this PR:**\n\n**8.10**\n- `git checkout -B 8.10 origin/8.10`\n- Start Kibana:\n - `nvm use && yarn kbn bootstrap && yarn start`\n- Start ES\n- `nvm use && yarn es snapshot --license trial --E\npath.data=\"/Users/sorenlouv/elastic/kbn_es_data/upgrade_testing\"`\n\n**8.19**\n- `git checkout -B 8.19 origin/8.x`\n- Start Kibana:\n - `nvm use && yarn kbn bootstrap && yarn start`\n- Start ES\n- `nvm use && yarn es snapshot --license trial --E\npath.data=\"/Users/sorenlouv/elastic/kbn_es_data/upgrade_testing\"`\n- Install Knowledge base\n- Try adding an item to KB (it should fail ❌️)\n\n**9.1.0**\n- `gh pr checkout 210386`\n- Start Kibana:\n - `nvm use && yarn kbn bootstrap && yarn start`\n- Start ES\n- `nvm use && yarn es snapshot --license trial --E\npath.data=\"/Users/sorenlouv/elastic/kbn_es_data/upgrade_testing\"`\n- Try adding an item to KB (it should succeed ✅️)\n\n**TODO:**\n\n- Add an upgrade test that covers this flow\n\n---------\n\nCo-authored-by: Viduni Wickramarachchi <[email protected]>","sha":"df67a09afab22521dfa9ff3ec3a4f624a039c462"}},"sourceBranch":"main","suggestedTargetBranches":[],"targetPullRequestStates":[{"branch":"main","label":"v9.1.0","branchLabelMappingKey":"^v9.1.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/210386","number":210386,"mergeCommit":{"message":"[Obs AI Assistant] Add KB re-indexing when encountering `semantic_text` bug (elastic#210386)\n\nCloses https://github.com/elastic/kibana/issues/210204\n\nThis will automatically re-index the knowledge base if upon adding a KB\nentry there is this error:\n\n> The [sparse_vector] field type is not supported on indices created on\nversions 8.0 to 8.10\n\nThat error means that semantic_text is not supported in the given index,\nand it should therefore be re-indexed.\n\n**How to test this PR:**\n\n**8.10**\n- `git checkout -B 8.10 origin/8.10`\n- Start Kibana:\n - `nvm use && yarn kbn bootstrap && yarn start`\n- Start ES\n- `nvm use && yarn es snapshot --license trial --E\npath.data=\"/Users/sorenlouv/elastic/kbn_es_data/upgrade_testing\"`\n\n**8.19**\n- `git checkout -B 8.19 origin/8.x`\n- Start Kibana:\n - `nvm use && yarn kbn bootstrap && yarn start`\n- Start ES\n- `nvm use && yarn es snapshot --license trial --E\npath.data=\"/Users/sorenlouv/elastic/kbn_es_data/upgrade_testing\"`\n- Install Knowledge base\n- Try adding an item to KB (it should fail ❌️)\n\n**9.1.0**\n- `gh pr checkout 210386`\n- Start Kibana:\n - `nvm use && yarn kbn bootstrap && yarn start`\n- Start ES\n- `nvm use && yarn es snapshot --license trial --E\npath.data=\"/Users/sorenlouv/elastic/kbn_es_data/upgrade_testing\"`\n- Try adding an item to KB (it should succeed ✅️)\n\n**TODO:**\n\n- Add an upgrade test that covers this flow\n\n---------\n\nCo-authored-by: Viduni Wickramarachchi <[email protected]>","sha":"df67a09afab22521dfa9ff3ec3a4f624a039c462"}}]}] BACKPORT--> Co-authored-by: Søren Louv-Jansen <[email protected]>
1 parent b408e8c commit bac6d90

File tree

19 files changed

+667
-228
lines changed

19 files changed

+667
-228
lines changed

x-pack/platform/plugins/shared/observability_ai_assistant/server/config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ export const config = schema.object({
1111
enabled: schema.boolean({ defaultValue: true }),
1212
scope: schema.maybe(schema.oneOf([schema.literal('observability'), schema.literal('search')])),
1313
enableKnowledgeBase: schema.boolean({ defaultValue: true }),
14+
disableKbSemanticTextMigration: schema.boolean({ defaultValue: false }),
1415
});
1516

1617
export type ObservabilityAIAssistantConfig = TypeOf<typeof config>;

x-pack/platform/plugins/shared/observability_ai_assistant/server/plugin.ts

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@ import { registerFunctions } from './functions';
3030
import { recallRankingEvent } from './analytics/recall_ranking';
3131
import { initLangtrace } from './service/client/instrumentation/init_langtrace';
3232
import { aiAssistantCapabilities } from '../common/capabilities';
33-
import { registerMigrateKnowledgeBaseEntriesTask } from './service/task_manager_definitions/register_migrate_knowledge_base_entries_task';
33+
import { registerAndScheduleKbSemanticTextMigrationTask } from './service/task_manager_definitions/register_kb_semantic_text_migration_task';
34+
import { updateExistingIndexAssets } from './service/create_or_update_index_assets';
3435

3536
export class ObservabilityAIAssistantPlugin
3637
implements
@@ -123,14 +124,22 @@ export class ObservabilityAIAssistantPlugin
123124
config: this.config,
124125
}));
125126

126-
registerMigrateKnowledgeBaseEntriesTask({
127+
// Update existing index assets (mappings, templates, etc). This will not create assets if they do not exist.
128+
updateExistingIndexAssets({ logger: this.logger.get('index_assets'), core }).catch((e) =>
129+
this.logger.error(`Index assets could not be updated: ${e.message}`)
130+
);
131+
132+
// register task to migrate knowledge base entries to include semantic_text field
133+
registerAndScheduleKbSemanticTextMigrationTask({
127134
core,
128135
taskManager: plugins.taskManager,
129-
logger: this.logger,
136+
logger: this.logger.get('kb_semantic_text_migration_task'),
130137
config: this.config,
131-
}).catch((e) => {
132-
this.logger.error(`Knowledge base migration was not successfully: ${e.message}`);
133-
});
138+
}).catch((e) =>
139+
this.logger.error(
140+
`Knowledge base semantic_text migration task could not be registered: ${e.message}`
141+
)
142+
);
134143

135144
service.register(registerFunctions);
136145

x-pack/platform/plugins/shared/observability_ai_assistant/server/routes/get_global_observability_ai_assistant_route_repository.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,11 @@ import { connectorRoutes } from './connectors/route';
1010
import { conversationRoutes } from './conversations/route';
1111
import { functionRoutes } from './functions/route';
1212
import { knowledgeBaseRoutes } from './knowledge_base/route';
13+
import { topLevelRoutes } from './top_level/route';
1314

1415
export function getGlobalObservabilityAIAssistantServerRouteRepository() {
1516
return {
17+
...topLevelRoutes,
1618
...chatRoutes,
1719
...conversationRoutes,
1820
...connectorRoutes,

x-pack/platform/plugins/shared/observability_ai_assistant/server/routes/knowledge_base/route.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ const resetKnowledgeBase = createObservabilityAIAssistantServerRoute({
101101
});
102102

103103
const semanticTextMigrationKnowledgeBase = createObservabilityAIAssistantServerRoute({
104-
endpoint: 'POST /internal/observability_ai_assistant/kb/semantic_text_migration',
104+
endpoint: 'POST /internal/observability_ai_assistant/kb/migrations/kb_semantic_text',
105105
security: {
106106
authz: {
107107
requiredPrivileges: ['ai_assistant'],
@@ -114,7 +114,7 @@ const semanticTextMigrationKnowledgeBase = createObservabilityAIAssistantServerR
114114
throw notImplemented();
115115
}
116116

117-
return client.migrateKnowledgeBaseToSemanticText();
117+
return client.reIndexKnowledgeBaseAndPopulateSemanticTextField();
118118
},
119119
});
120120

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License
4+
* 2.0; you may not use this file except in compliance with the Elastic License
5+
* 2.0.
6+
*/
7+
8+
import { createOrUpdateIndexAssets } from '../../service/create_or_update_index_assets';
9+
import { createObservabilityAIAssistantServerRoute } from '../create_observability_ai_assistant_server_route';
10+
11+
const createOrUpdateIndexAssetsRoute = createObservabilityAIAssistantServerRoute({
12+
endpoint: 'POST /internal/observability_ai_assistant/index_assets',
13+
security: {
14+
authz: {
15+
requiredPrivileges: ['ai_assistant'],
16+
},
17+
},
18+
handler: async (resources): Promise<void> => {
19+
return createOrUpdateIndexAssets({
20+
logger: resources.logger,
21+
core: resources.plugins.core.setup,
22+
});
23+
},
24+
});
25+
26+
export const topLevelRoutes = {
27+
...createOrUpdateIndexAssetsRoute,
28+
};

x-pack/platform/plugins/shared/observability_ai_assistant/server/service/client/index.ts

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -75,9 +75,9 @@ import { extractTokenCount } from './operators/extract_token_count';
7575
import { getGeneratedTitle } from './operators/get_generated_title';
7676
import { instrumentAndCountTokens } from './operators/instrument_and_count_tokens';
7777
import {
78-
runSemanticTextKnowledgeBaseMigration,
79-
scheduleSemanticTextMigration,
80-
} from '../task_manager_definitions/register_migrate_knowledge_base_entries_task';
78+
reIndexKnowledgeBaseAndPopulateSemanticTextField,
79+
scheduleKbSemanticTextMigrationTask,
80+
} from '../task_manager_definitions/register_kb_semantic_text_migration_task';
8181
import { ObservabilityAIAssistantPluginStartDependencies } from '../../types';
8282
import { ObservabilityAIAssistantConfig } from '../../config';
8383
import { getElserModelId } from '../knowledge_base_service/get_elser_model_id';
@@ -688,12 +688,11 @@ export class ObservabilityAIAssistantClient {
688688

689689
core
690690
.getStartServices()
691-
.then(([_, pluginsStart]) => {
692-
logger.debug('Schedule semantic text migration task');
693-
return scheduleSemanticTextMigration(pluginsStart);
694-
})
691+
.then(([_, pluginsStart]) =>
692+
scheduleKbSemanticTextMigrationTask({ taskManager: pluginsStart.taskManager, logger })
693+
)
695694
.catch((error) => {
696-
logger.error(`Failed to run semantic text migration task: ${error}`);
695+
logger.error(`Failed to schedule semantic text migration task: ${error}`);
697696
});
698697

699698
return res;
@@ -704,8 +703,8 @@ export class ObservabilityAIAssistantClient {
704703
return this.dependencies.knowledgeBaseService.reset(esClient);
705704
};
706705

707-
migrateKnowledgeBaseToSemanticText = () => {
708-
return runSemanticTextKnowledgeBaseMigration({
706+
reIndexKnowledgeBaseAndPopulateSemanticTextField = () => {
707+
return reIndexKnowledgeBaseAndPopulateSemanticTextField({
709708
esClient: this.dependencies.esClient,
710709
logger: this.dependencies.logger,
711710
config: this.dependencies.config,

x-pack/platform/plugins/shared/observability_ai_assistant/server/service/setup_conversation_and_kb_index_assets.ts renamed to x-pack/platform/plugins/shared/observability_ai_assistant/server/service/create_or_update_index_assets.ts

Lines changed: 55 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,39 @@
66
*/
77

88
import { createConcreteWriteIndex, getDataStreamAdapter } from '@kbn/alerting-plugin/server';
9-
import type { CoreSetup, Logger } from '@kbn/core/server';
9+
import type { CoreSetup, ElasticsearchClient, Logger } from '@kbn/core/server';
1010
import type { ObservabilityAIAssistantPluginStartDependencies } from '../types';
1111
import { conversationComponentTemplate } from './conversation_component_template';
1212
import { kbComponentTemplate } from './kb_component_template';
1313
import { resourceNames } from '.';
1414

15-
export async function setupConversationAndKbIndexAssets({
15+
export async function updateExistingIndexAssets({
16+
logger,
17+
core,
18+
}: {
19+
logger: Logger;
20+
core: CoreSetup<ObservabilityAIAssistantPluginStartDependencies>;
21+
}) {
22+
const [coreStart] = await core.getStartServices();
23+
const { asInternalUser } = coreStart.elasticsearch.client;
24+
25+
const hasKbIndex = await asInternalUser.indices.exists({
26+
index: resourceNames.aliases.kb,
27+
});
28+
29+
const hasConversationIndex = await asInternalUser.indices.exists({
30+
index: resourceNames.aliases.conversations,
31+
});
32+
33+
if (!hasKbIndex && !hasConversationIndex) {
34+
logger.debug('Index assets do not exist. Aborting updating index assets');
35+
return;
36+
}
37+
38+
await createOrUpdateIndexAssets({ logger, core });
39+
}
40+
41+
export async function createOrUpdateIndexAssets({
1642
logger,
1743
core,
1844
}: {
@@ -56,7 +82,7 @@ export async function setupConversationAndKbIndexAssets({
5682
alias: conversationAliasName,
5783
pattern: `${conversationAliasName}*`,
5884
basePattern: `${conversationAliasName}*`,
59-
name: `${conversationAliasName}-000001`,
85+
name: resourceNames.concreteIndexName.conversations,
6086
template: resourceNames.indexTemplate.conversations,
6187
},
6288
dataStreamAdapter: getDataStreamAdapter({ useDataStreamForAlerts: false }),
@@ -86,24 +112,36 @@ export async function setupConversationAndKbIndexAssets({
86112
});
87113

88114
// Knowledge base: write index
89-
const kbAliasName = resourceNames.aliases.kb;
90-
await createConcreteWriteIndex({
91-
esClient: asInternalUser,
92-
logger,
93-
totalFieldsLimit: 10000,
94-
indexPatterns: {
95-
alias: kbAliasName,
96-
pattern: `${kbAliasName}*`,
97-
basePattern: `${kbAliasName}*`,
98-
name: `${kbAliasName}-000001`,
99-
template: resourceNames.indexTemplate.kb,
100-
},
101-
dataStreamAdapter: getDataStreamAdapter({ useDataStreamForAlerts: false }),
102-
});
115+
await createKbConcreteIndex({ logger, esClient: coreStart.elasticsearch.client });
103116

104117
logger.info('Successfully set up index assets');
105118
} catch (error) {
106119
logger.error(`Failed setting up index assets: ${error.message}`);
107120
logger.debug(error);
108121
}
109122
}
123+
124+
export async function createKbConcreteIndex({
125+
logger,
126+
esClient,
127+
}: {
128+
logger: Logger;
129+
esClient: {
130+
asInternalUser: ElasticsearchClient;
131+
};
132+
}) {
133+
const kbAliasName = resourceNames.aliases.kb;
134+
return createConcreteWriteIndex({
135+
esClient: esClient.asInternalUser,
136+
logger,
137+
totalFieldsLimit: 10000,
138+
indexPatterns: {
139+
alias: kbAliasName,
140+
pattern: `${kbAliasName}*`,
141+
basePattern: `${kbAliasName}*`,
142+
name: resourceNames.concreteIndexName.kb,
143+
template: resourceNames.indexTemplate.kb,
144+
},
145+
dataStreamAdapter: getDataStreamAdapter({ useDataStreamForAlerts: false }),
146+
});
147+
}

x-pack/platform/plugins/shared/observability_ai_assistant/server/service/index.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import { ObservabilityAIAssistantClient } from './client';
1717
import { KnowledgeBaseService } from './knowledge_base_service';
1818
import type { RegistrationCallback, RespondFunctionResources } from './types';
1919
import { ObservabilityAIAssistantConfig } from '../config';
20-
import { setupConversationAndKbIndexAssets } from './setup_conversation_and_kb_index_assets';
20+
import { createOrUpdateIndexAssets } from './create_or_update_index_assets';
2121

2222
function getResourceName(resource: string) {
2323
return `.kibana-observability-ai-assistant-${resource}`;
@@ -40,11 +40,15 @@ export const resourceNames = {
4040
conversations: getResourceName('index-template-conversations'),
4141
kb: getResourceName('index-template-kb'),
4242
},
43+
concreteIndexName: {
44+
conversations: getResourceName('conversations-000001'),
45+
kb: getResourceName('kb-000001'),
46+
},
4347
};
4448

4549
const createIndexAssetsOnce = once(
4650
(logger: Logger, core: CoreSetup<ObservabilityAIAssistantPluginStartDependencies>) =>
47-
pRetry(() => setupConversationAndKbIndexAssets({ logger, core }))
51+
pRetry(() => createOrUpdateIndexAssets({ logger, core }))
4852
);
4953

5054
export class ObservabilityAIAssistantService {

x-pack/platform/plugins/shared/observability_ai_assistant/server/service/knowledge_base_service/index.ts

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,11 @@ import {
2828
import { recallFromSearchConnectors } from './recall_from_search_connectors';
2929
import { ObservabilityAIAssistantPluginStartDependencies } from '../../types';
3030
import { ObservabilityAIAssistantConfig } from '../../config';
31+
import {
32+
isKnowledgeBaseIndexWriteBlocked,
33+
isSemanticTextUnsupportedError,
34+
} from './reindex_knowledge_base';
35+
import { scheduleKbSemanticTextMigrationTask } from '../task_manager_definitions/register_kb_semantic_text_migration_task';
3136

3237
interface Dependencies {
3338
core: CoreSetup<ObservabilityAIAssistantPluginStartDependencies>;
@@ -406,7 +411,9 @@ export class KnowledgeBaseService {
406411
}
407412

408413
try {
409-
await this.dependencies.esClient.asInternalUser.index({
414+
await this.dependencies.esClient.asInternalUser.index<
415+
Omit<KnowledgeBaseEntry, 'id'> & { namespace: string }
416+
>({
410417
index: resourceNames.aliases.kb,
411418
id,
412419
document: {
@@ -418,10 +425,40 @@ export class KnowledgeBaseService {
418425
},
419426
refresh: 'wait_for',
420427
});
428+
this.dependencies.logger.debug(`Entry added to knowledge base`);
421429
} catch (error) {
430+
this.dependencies.logger.debug(`Failed to add entry to knowledge base ${error}`);
422431
if (isInferenceEndpointMissingOrUnavailable(error)) {
423432
throwKnowledgeBaseNotReady(error.body);
424433
}
434+
435+
if (isSemanticTextUnsupportedError(error)) {
436+
this.dependencies.core
437+
.getStartServices()
438+
.then(([_, pluginsStart]) => {
439+
return scheduleKbSemanticTextMigrationTask({
440+
taskManager: pluginsStart.taskManager,
441+
logger: this.dependencies.logger,
442+
runSoon: true,
443+
});
444+
})
445+
.catch((e) => {
446+
this.dependencies.logger.error(
447+
`Failed to schedule knowledge base semantic text migration task: ${e}`
448+
);
449+
});
450+
451+
throw serverUnavailable(
452+
'The knowledge base is currently being re-indexed. Please try again later'
453+
);
454+
}
455+
456+
if (isKnowledgeBaseIndexWriteBlocked(error)) {
457+
throw new Error(
458+
`Writes to the knowledge base are currently blocked due to an Elasticsearch write index block. This is most likely due to an ongoing re-indexing operation. Please try again later. Error: ${error.message}`
459+
);
460+
}
461+
425462
throw error;
426463
}
427464
};

0 commit comments

Comments
 (0)