diff --git a/x-pack/solutions/search/plugins/search_indices/public/code_examples/ingest_data.ts b/x-pack/solutions/search/plugins/search_indices/public/code_examples/ingest_data.ts index 31bd93ea2545a..1abe1c6eec966 100644 --- a/x-pack/solutions/search/plugins/search_indices/public/code_examples/ingest_data.ts +++ b/x-pack/solutions/search/plugins/search_indices/public/code_examples/ingest_data.ts @@ -8,9 +8,9 @@ import { i18n } from '@kbn/i18n'; import { IngestDataCodeExamples } from '../types'; -import { JSIngestDataExample } from './javascript'; -import { PythonIngestDataExample } from './python'; -import { ConsoleIngestDataExample } from './sense'; +import { JSIngestDataExample, JSSemanticIngestDataExample } from './javascript'; +import { PythonIngestDataExample, PythonSemanticIngestDataExample } from './python'; +import { ConsoleIngestDataExample, ConsoleSemanticIngestDataExample } from './sense'; import { CurlIngestDataExample } from './curl'; import { INSTALL_INSTRUCTIONS_TITLE, INSTALL_INSTRUCTIONS_DESCRIPTION } from './constants'; @@ -76,8 +76,8 @@ export const SemanticIngestDataCodeExamples: IngestDataCodeExamples = { defaultMapping: { text: { type: 'semantic_text' }, }, - sense: ConsoleIngestDataExample, + sense: ConsoleSemanticIngestDataExample, curl: CurlIngestDataExample, - python: PythonIngestDataExample, - javascript: JSIngestDataExample, + python: PythonSemanticIngestDataExample, + javascript: JSSemanticIngestDataExample, }; diff --git a/x-pack/solutions/search/plugins/search_indices/public/code_examples/javascript.ts b/x-pack/solutions/search/plugins/search_indices/public/code_examples/javascript.ts index 2f0608262b99f..8d9847ec017a8 100644 --- a/x-pack/solutions/search/plugins/search_indices/public/code_examples/javascript.ts +++ b/x-pack/solutions/search/plugins/search_indices/public/code_examples/javascript.ts @@ -9,9 +9,11 @@ import { i18n } from '@kbn/i18n'; import { API_KEY_PLACEHOLDER, INDEX_PLACEHOLDER } from '../constants'; import { CodeLanguage, + CodeSnippetParameters, IngestDataCodeDefinition, SearchCodeDefinition, SearchCodeSnippetFunction, + SearchCodeSnippetParameters, } from '../types'; import { CreateIndexLanguageExamples } from './types'; @@ -25,178 +27,146 @@ export const JAVASCRIPT_INFO: CodeLanguage = { }; const INSTALL_CMD = `npm install @elastic/elasticsearch`; +const CLIENT_SERVERLESS_OPTION = `\n serverMode: 'serverless',`; + +const createClientSnippet = ({ + apiKey, + elasticsearchURL, + isServerless, +}: CodeSnippetParameters): string => `const client = new Client({ + node: '${elasticsearchURL}', + auth: { + apiKey: '${apiKey ?? API_KEY_PLACEHOLDER}' + },${isServerless ? CLIENT_SERVERLESS_OPTION : ''} +});`; export const JavascriptCreateIndexExamples: CreateIndexLanguageExamples = { default: { installCommand: INSTALL_CMD, - createIndex: ({ - elasticsearchURL, - apiKey, - indexName, - }) => `import { Client } from "@elastic/elasticsearch" + createIndex: (args) => `const { Client } = require('@elastic/elasticsearch'); -const client = new Client({ - node: '${elasticsearchURL}', - auth: { - apiKey: "${apiKey ?? API_KEY_PLACEHOLDER}" - } -}); +${createClientSnippet(args)} -async function run() { - await client.indices.create({ - index: "${indexName ?? INDEX_PLACEHOLDER}", - mappings: { - properties: { - text: { type: "text"} - }, +const createResponse = await client.indices.create({ + index: '${args.indexName ?? INDEX_PLACEHOLDER}', + mappings: { + properties: { + text: { type: 'text'} }, }); } -run().catch(console.log);`, +console.log(createResponse);`, }, dense_vector: { installCommand: INSTALL_CMD, - createIndex: ({ - elasticsearchURL, - apiKey, - indexName, - }) => `import { Client } from "@elastic/elasticsearch" + createIndex: (args) => `const { Client } = require('@elastic/elasticsearch'); -const client = new Client({ - node: '${elasticsearchURL}', - auth: { - apiKey: "${apiKey ?? API_KEY_PLACEHOLDER}" - } -}); +${createClientSnippet(args)} -async function run() { - await client.indices.create({ - index: "${indexName ?? INDEX_PLACEHOLDER}", - mappings: { - properties: { - vector: { type: "dense_vector", dims: 3 }, - text: { type: "text"} - }, +const createResponse = await client.indices.create({ + index: '${args.indexName ?? INDEX_PLACEHOLDER}', + mappings: { + properties: { + vector: { type: 'dense_vector', dims: 3 }, + text: { type: 'text'} }, }); } -run().catch(console.log);`, +console.log(createResponse);`, }, semantic: { installCommand: INSTALL_CMD, - createIndex: ({ - elasticsearchURL, - apiKey, - indexName, - }) => `import { Client } from "@elastic/elasticsearch" + createIndex: (args) => `const { Client } = require('@elastic/elasticsearch'); -const client = new Client({ - node: '${elasticsearchURL}', - auth: { - apiKey: "${apiKey ?? API_KEY_PLACEHOLDER}" - } -}); +${createClientSnippet(args)} -async function run() { - await client.indices.create({ - index: "${indexName ?? INDEX_PLACEHOLDER}", - mappings: { - properties: { - text: { type: "semantic_text"} - }, +const createResponse = client.indices.create({ + index: '${args.indexName ?? INDEX_PLACEHOLDER}', + mappings: { + properties: { + text: { type: 'semantic_text'} }, }); } -run().catch(console.log);`, +console.log(createResponse);`, }, }; export const JSIngestDataExample: IngestDataCodeDefinition = { installCommand: INSTALL_CMD, - ingestCommand: ({ - apiKey, - elasticsearchURL, - sampleDocuments, - indexName, - }) => `import { Client } from "@elastic/elasticsearch"; - -const client = new Client({ - node: '${elasticsearchURL}', - auth: { - apiKey: "${apiKey ?? API_KEY_PLACEHOLDER}" - }, -}); + ingestCommand: (args) => `const { Client } = require('@elastic/elasticsearch'); -const index = "${indexName}"; -const docs = ${JSON.stringify(sampleDocuments, null, 2)}; - -async function run() {} - const bulkIngestResponse = await client.helpers.bulk({ - index, - datasource: docs, - onDocument() { - return { - index: {}, - }; - } - }); - console.log(bulkIngestResponse); -} -run().catch(console.log);`, - updateMappingsCommand: ({ - apiKey, - elasticsearchURL, - indexName, - mappingProperties, - }) => `import { Client } from "@elastic/elasticsearch"; - -const client = new Client({ -node: '${elasticsearchURL}', -auth: { - apiKey: "${apiKey ?? API_KEY_PLACEHOLDER}" -} +${createClientSnippet(args)} + +const index = '${args.indexName}'; +const docs = ${JSON.stringify(args.sampleDocuments, null, 2)}; + +const bulkIngestResponse = await client.helpers.bulk({ + index, + datasource: docs, + onDocument() { + return { + index: {}, + }; + } }); +console.log(bulkIngestResponse);`, + updateMappingsCommand: (args) => `const { Client } = require('@elastic/elasticsearch'); -async function run() { - const index = "${indexName}"; - const mapping = ${JSON.stringify(mappingProperties, null, 2)}; +${createClientSnippet(args)} - const updateMappingResponse = await client.indices.putMapping({ - index, - properties: mapping, - }); - console.log(updateMappingResponse); -} -run().catch(console.log);`, +const index = '${args.indexName}'; +const mapping = ${JSON.stringify(args.mappingProperties, null, 2)}; + +const updateMappingResponse = await client.indices.putMapping({ + index, + properties: mapping, +}); +console.log(updateMappingResponse);`, }; -const searchCommand: SearchCodeSnippetFunction = ({ - elasticsearchURL, - apiKey, - indexName, - queryObject, -}) => `import { Client } from "@elastic/elasticsearch"; +const searchCommand: SearchCodeSnippetFunction = ( + args: SearchCodeSnippetParameters +) => `import { Client } from '@elastic/elasticsearch'; -const client = new Client({ - node: '${elasticsearchURL}', - auth: { - apiKey: "${apiKey ?? API_KEY_PLACEHOLDER}" - } -}); +${createClientSnippet(args)} -const index = "${indexName}"; -const query = ${JSON.stringify(queryObject, null, 2)}; +const index = '${args.indexName}'; +const query = ${JSON.stringify(args.queryObject, null, 2)}; -async function run() { - const result = await client.search({ - index, - query, - }); +const result = await client.search({ + index, + query, +}); - console.log(result.hits.hits); -} -run().catch(console.log);`; +console.log(result.hits.hits);`; export const JavascriptSearchExample: SearchCodeDefinition = { searchCommand, }; + +export const JSSemanticIngestDataExample: IngestDataCodeDefinition = { + ...JSIngestDataExample, + ingestCommand: (args) => `const { Client } = require('@elastic/elasticsearch'); + +${createClientSnippet(args)} + +// Timeout to allow machine learning model loading and semantic ingestion to complete +const timeout = '5m'; + +const index = '${args.indexName}'; +const docs = ${JSON.stringify(args.sampleDocuments, null, 2)}; + +const bulkIngestResponse = await client.helpers.bulk({ + index, + datasource: docs, + timeout, + onDocument() { + return { + index: {}, + }; + } +}); + +console.log(bulkIngestResponse);`, +}; diff --git a/x-pack/solutions/search/plugins/search_indices/public/code_examples/python.ts b/x-pack/solutions/search/plugins/search_indices/public/code_examples/python.ts index 37f8a4ff9c4b7..74272b6c1429a 100644 --- a/x-pack/solutions/search/plugins/search_indices/public/code_examples/python.ts +++ b/x-pack/solutions/search/plugins/search_indices/public/code_examples/python.ts @@ -135,6 +135,32 @@ mapping_response = client.indices.put_mapping(index=index_name, body=mappings) print(mapping_response) `; +const semanticIngestCommand: IngestCodeSnippetFunction = ({ + elasticsearchURL, + apiKey, + indexName, + sampleDocuments, +}) => `from elasticsearch import Elasticsearch, helpers + +client = Elasticsearch( + "${elasticsearchURL}", + api_key="${apiKey ?? API_KEY_PLACEHOLDER}", +) + +index_name = "${indexName}" + +docs = ${JSON.stringify(sampleDocuments, null, 4)} + +# Timeout to allow machine learning model loading and semantic ingestion to complete +ingestion_timeout=300 + +bulk_response = helpers.bulk( + client.options(request_timeout=ingestion_timeout), + docs, + index=index_name +) +print(bulk_response)`; + export const PythonIngestDataExample: IngestDataCodeDefinition = { installCommand: PYTHON_INSTALL_CMD, ingestCommand: ingestionCommand, @@ -165,3 +191,8 @@ print(search_response['hits']['hits']) export const PythonSearchExample: SearchCodeDefinition = { searchCommand, }; + +export const PythonSemanticIngestDataExample: IngestDataCodeDefinition = { + ...PythonIngestDataExample, + ingestCommand: semanticIngestCommand, +}; diff --git a/x-pack/solutions/search/plugins/search_indices/public/code_examples/sense.ts b/x-pack/solutions/search/plugins/search_indices/public/code_examples/sense.ts index 6a236a22a7b3d..3c0a3af2a5ad6 100644 --- a/x-pack/solutions/search/plugins/search_indices/public/code_examples/sense.ts +++ b/x-pack/solutions/search/plugins/search_indices/public/code_examples/sense.ts @@ -70,6 +70,21 @@ ${JSON.stringify(document)}\n`; ${JSON.stringify({ properties: mappingProperties }, null, 2)}`, }; +export const ConsoleSemanticIngestDataExample: IngestDataCodeDefinition = { + ...ConsoleIngestDataExample, + ingestCommand: ({ indexName, sampleDocuments }) => { + let result = `# The initial bulk ingestion request could take longer than the default request timeout. +# If this request times out, you should retry the request after allowing time for the machine learning model loading to complete (typically 1-5 minutes). +POST /_bulk?pretty\n`; + sampleDocuments.forEach((document) => { + result += `{ "index": { "_index": "${indexName}" } } +${JSON.stringify(document)}\n`; + }); + result += '\n'; + return result; + }, +}; + const searchCommand: SearchCodeSnippetFunction = ({ indexName, queryObject, diff --git a/x-pack/solutions/search/plugins/search_indices/public/components/index_documents/add_documents_code_example.tsx b/x-pack/solutions/search/plugins/search_indices/public/components/index_documents/add_documents_code_example.tsx index 266c6bc04c393..72eb3fb3cb886 100644 --- a/x-pack/solutions/search/plugins/search_indices/public/components/index_documents/add_documents_code_example.tsx +++ b/x-pack/solutions/search/plugins/search_indices/public/components/index_documents/add_documents_code_example.tsx @@ -41,7 +41,7 @@ export const AddDocumentsCodeExample = ({ indexName, mappingProperties, }: AddDocumentsCodeExampleProps) => { - const { application, share, console: consolePlugin } = useKibana().services; + const { application, share, console: consolePlugin, cloud } = useKibana().services; const elasticsearchUrl = useElasticsearchUrl(); const usageTracker = useUsageTracker(); const indexHasMappings = Object.keys(mappingProperties).length > 0; @@ -73,8 +73,17 @@ export const AddDocumentsCodeExample = ({ indexHasMappings, mappingProperties: codeSampleMappings, apiKey: apiKey || undefined, + isServerless: cloud?.isServerlessEnabled ?? undefined, }; - }, [indexName, elasticsearchUrl, sampleDocuments, codeSampleMappings, indexHasMappings, apiKey]); + }, [ + indexName, + elasticsearchUrl, + sampleDocuments, + codeSampleMappings, + indexHasMappings, + apiKey, + cloud, + ]); return ( { - const { application, share, console: consolePlugin } = useKibana().services; + const { application, share, cloud, console: consolePlugin } = useKibana().services; const usageTracker = useUsageTracker(); const elasticsearchUrl = useElasticsearchUrl(); const { apiKey } = useSearchApiKey(); - const codeParams = useMemo(() => { + const codeParams: CodeSnippetParameters = useMemo(() => { return { indexName: indexName || undefined, elasticsearchURL: elasticsearchUrl, apiKey: apiKey || undefined, + isServerless: cloud?.isServerlessEnabled ?? undefined, }; - }, [indexName, elasticsearchUrl, apiKey]); + }, [indexName, elasticsearchUrl, apiKey, cloud]); const selectedCodeExample = useMemo(() => { return selectedCodeExamples[selectedLanguage]; }, [selectedLanguage, selectedCodeExamples]); diff --git a/x-pack/solutions/search/plugins/search_indices/public/hooks/use_search_code_examples.ts b/x-pack/solutions/search/plugins/search_indices/public/hooks/use_search_code_examples.ts index 10c97195ba41f..9c97f585e24c2 100644 --- a/x-pack/solutions/search/plugins/search_indices/public/hooks/use_search_code_examples.ts +++ b/x-pack/solutions/search/plugins/search_indices/public/hooks/use_search_code_examples.ts @@ -14,6 +14,7 @@ import { } from '@kbn/search-queries'; import { Mappings, SearchCodeSnippetParameters } from '../types'; import { useElasticsearchUrl } from './use_elasticsearch_url'; +import { useKibana } from './use_kibana'; import { AvailableLanguages, Languages } from '../code_examples'; import { SearchCodeExample } from '../code_examples/search'; @@ -33,6 +34,7 @@ const DEFAULT_QUERY_OBJECT = { export const useSearchCodeExamples = (indexName: string, mappings?: Mappings) => { const elasticsearchURL = useElasticsearchUrl(); const { apiKey } = useSearchApiKey(); + const { cloud } = useKibana().services; return useMemo(() => { let queryObject: ReturnType = DEFAULT_QUERY_OBJECT; @@ -52,6 +54,7 @@ export const useSearchCodeExamples = (indexName: string, mappings?: Mappings) => apiKey: apiKey ?? undefined, indexName, queryObject, + isServerless: cloud?.isServerlessEnabled ?? false, }; const options = Object.entries(Languages).map(([key, language]) => ({ @@ -62,5 +65,5 @@ export const useSearchCodeExamples = (indexName: string, mappings?: Mappings) => options, console: SearchCodeExample.sense.searchCommand(codeParams), }; - }, [indexName, mappings, elasticsearchURL, apiKey]); + }, [indexName, mappings, elasticsearchURL, apiKey, cloud?.isServerlessEnabled]); }; diff --git a/x-pack/solutions/search/plugins/search_indices/public/types.ts b/x-pack/solutions/search/plugins/search_indices/public/types.ts index 2c6a94ecdb1b9..e47b9a3b04703 100644 --- a/x-pack/solutions/search/plugins/search_indices/public/types.ts +++ b/x-pack/solutions/search/plugins/search_indices/public/types.ts @@ -80,6 +80,7 @@ export interface CodeSnippetParameters { indexName?: string; apiKey?: string; elasticsearchURL: string; + isServerless?: boolean; } export type CodeSnippetFunction = (params: CodeSnippetParameters) => string;