Building Elastic Cloud Serverless From Code
This article covers deploying the Elastic Cloud Serverless project and subsequent interaction with that project via the Elastic JavaScript client. It also demonstrates a simple semantic search scenario.
This entire demo is done via application-level code (JavaScript). - Serverless REST API is leveraged to create and delete a serverless project, from scratch - Elastic JavaScript client is instantiated and used to index and search a sample dataset
Architecture
This demo places minimal load on the client device. The entire architecture is cloud-based, split between Elastic and Azure OpenAI. The demo application (demo.js) makes a series of Elastic serverless REST API and JavaScript client calls.
High Level
Application Level
Functions
Below is a step-by-step explanation of an end-to-end build of Elastic Serverless deployment using JavaScript code only.
Create an Elastic Serverless Project
The function below will initiate the build of a serverless project via REST API. In this case, I’ve requested a project optimized for vector operations.
async function createProject(name, url, key) {
const parms = {
name: name,
region_id:"aws-us-east-1",
optimized_for:"vector"
};
let resp = await axios.post(url, parms, {
headers: {
'Authorization': `ApiKey ${key}`,
'Content-Type': 'application/json'
}
});
if (resp.status === 201) {
console.log(resp.data);
return resp.data;
}
else {
throw new Error(resp.error);
}
}
Result
{
alias: 'demo-project-fb17e0',
cloud_id: 'demo-project:dXMtZWFzdC0xLmF3cy5lbGFzdGljLmNsb3VkJGZiMTdlMDI2NmVhNjQ2NzFiZDdmYmMxOWQ4ZDg1N2M1LmVzJGZiMTdlMDI2NmVhNjQ2NzFiZDdmYmMxOWQ4ZDg1N2M1Lmti',
id: 'fb17e0266ea64671bd7fbc19d8d857c5',
metadata: {
created_at: '2025-06-08T13:51:30.889055864Z',
created_by: '3109974691',
organization_id: '2698784787'
},
name: 'demo-project',
region_id: 'aws-us-east-1',
endpoints: {
elasticsearch: 'https://demo-project-fb17e0.es.us-east-1.aws.elastic.cloud',
kibana: 'https://demo-project-fb17e0.kb.us-east-1.aws.elastic.cloud'
},
optimized_for: 'vector',
search_lake: { boost_window: 7, search_power: 100 },
type: 'elasticsearch',
credentials: { password: 'REDACTED', username: 'admin' }
}
Wait For Build Completion
The function below awaits the completion of the cloud build kicked off from the above step. The REST API is used for this function.
async function projectReady(id, url, key) {
const sleep = (ms = 0) => new Promise((resolve) => setTimeout(resolve,ms));
const getProjectStatus = async () => {
const resp = await axios.get(`${url}/${id}/status`, {
headers: {
'Authorization': `ApiKey ${key}`,
'Content-Type': 'application/json'
}
});
if (resp.status === 200) {
return resp.data.phase;
}
else {
throw new Error(resp.error);
}
}
let status = '';
do {
await sleep(5000);
status = await getProjectStatus(id, url, key);
} while (status !== 'initialized');
console.log(status);
}
Result
initialized
Create an Azure OpenAI Inference Endpoint
This function creates an inference endpoint for a pre-provisioned Azure OpenAI embedding resource. This will automatically generate embeddings during data ingestion and query time. The Elastic JavaScript client is used for this provisioning.
Recommended by LinkedIn
async function createInferenceEP(client, inferenceId) {
const response = await client.inference.put({
task_type: "text_embedding",
inference_id: inferenceId,
inference_config: {
service: "azureopenai",
service_settings: {
api_key: process.env.AZURE_OPENAI_API_KEY,
resource_name: process.env.AZURE_OPENAI_RESOURCE_NAME,
deployment_id: process.env.AZURE_OPENAI_DEPLOYMENT_ID,
api_version: process.env.AZURE_OPENAI_API_VERSION,
},
},
});
console.log(response);
}
Result
{
inference_id: 'azure_openai_embeddings',
task_type: 'text_embedding',
service: 'azureopenai',
service_settings: {
resource_name: 'joey-openai',
deployment_id: 'text-embedding-ada-002',
api_version: '2023-05-15',
dimensions: 1536,
similarity: 'dot_product',
rate_limit: { requests_per_minute: 1440 }
},
chunking_settings: { strategy: 'sentence', max_chunk_size: 250, sentence_overlap: 1 }
}
Create the Elasticsearch Index Mapping
Using the JavaScript client, I built an index mapping (schema) for the sample dataset included in this repo. It’s a series of documents with metadata on news articles. It’s important to note that I’m using multi-fields to create semantic_text fields that will automate the embedding generation using the Azure OpenAI inference endpoint I created in the step above.
async function createIndexMapping(client, indexName, inferenceId) {
const resp = await client.indices.create({
index: indexName,
mappings: {
properties: {
link: { type: 'text' },
headline: {
type: 'text',
fields: {
semantic: {
type: 'semantic_text',
inference_id: inferenceId
}
}
},
category: {
type: 'text',
fields: { keyword: { type: 'keyword' } }
},
short_description: {
type: 'text',
fields: {
semantic: {
type: 'semantic_text',
inference_id: inferenceId
}
}
},
authors: { type: 'text' },
date: { type: 'date' }
}
}
});
console.log(resp);
}
Result
{ acknowledged: true, shards_acknowledged: true, index: 'articles' }
Data Load
With the index mapping defined, I now perform a bulk load of the JSON documents in the assets/articles.json file via the JavaScript client.
async function loadData(client, filePath, indexName) {
const result = await client.helpers.bulk({
datasource: fs.createReadStream(filePath).pipe(split2()),
onDocument: () => {
return {
index: {_index: indexName}
};
},
refreshOnCompletion: true
});
console.log(`${result.successful} documents indexed`);
}
Result
1000 documents indexed
Semantic Search
Next, perform a semantic search on the indexed “articles” dataset. Note that the query embedding step is handled automatically.
async function semanticSearch(client, indexName, text) {
const res = await client.search({
index: indexName,
size: 1,
query: {
semantic: {
field: 'short_description.semantic',
query: text
}
}
});
console.log(res.hits.hits);
}
Result
[
{
_index: 'articles',
_id: 'TUrRT5cBIGXfXs4VHrNy',
_score: 0.9098367,
_source: {
link: 'https://www.huffpost.com/entry/punk-band-responds-oath-keeper-shirt_n_62ce22e1e4b0aa392d4598dd',
headline: 'Punk Band Responds After Former Oath Keeper Wears Its Shirt At Jan. 6 Hearing',
category: 'U.S. NEWS',
short_description: 'The shirt featured "Milo," a cartoon on a number of album covers for the influential punk rock band The Descendents.',
authors: 'Ben Blanchet',
date: '2022-07-13'
}
}
]
Project Deletion
Finally, I use the serverless REST API to delete this project.
async function deleteProject(id) {
let resp = await axios.delete(`${process.env.ELASTIC_API_URL}/${id}`, {
headers: {
'Authorization': `ApiKey ${process.env.ELASTIC_API_KEY}`,
'Content-Type': 'application/json'
}
});
if (resp.status === 200) {
console.log(resp.data);
}
else {
throw new Error(resp.error);
}
}
Result
Project deletion successful