Get started with vector search
In this quickstart, you’ll set up a search that combines keyword-based and vector search approaches to find results based on both exact terms and meaning. This is called hybrid search, and in many cases it provides better results than using either approach alone.
What are keyword-based search, vector search, and hybrid search?
Keyword-based search matches exact terms in your data, while vector search understands the intent behind a query.
For example, if a document contains the phrase "annual leave policy", a keyword search for "annual leave" will return it because the terms match. However, a search for "vacation rules" may not return the same document, because those exact words are not present.
With vector search, a query like "vacation rules" can still return the "annual leave policy" document, because it matches based on meaning rather than exact terms.
With hybrid search, the same query can return both keyword and semantic matches, combining exact term matching with meaning-based retrieval to improve overall relevance.
First, you create an index and store your data in two forms: plain text and vector embeddings. Then you run a query that searches both representations and combines the results.
A running Elasticsearch cluster. Refer to Choosing your deployment type for an overview of how you can run Elasticsearch. For the fastest way to follow this quickstart, we recommend creating a serverless project (includes a free Serverless trial), or using a local development installation.
-
Create an index mapping
Define the index mapping. The mapping specifies the fields in your index and their data types, including both plain text fields and fields used to store vector embeddings for semantic search.
PUT semantic-embeddings{ "mappings": { "properties": { "semantic_text": { "type": "semantic_text" }, "content": { "type": "text", "copy_to": "semantic_text" } } } }- The
semantic_textfield with thesemantic_textfield type to create and store vector embeddings. Under the hood, it uses an inference endpoint to generate the embeddings. If you don’t specify theinference_idparameter (as in the example above), the default inference endpoint is used. - The
contentfield with thetextfield type to store plain text. This field is used for keyword search. - Values indexed into
contentare copied tosemantic_textand processed by the default inference endpoint.
Example response{ "acknowledged": true, "shards_acknowledged": true, "index": "semantic-embeddings" } - The
-
Index documents
Index sample documents with the bulk API. You only need to provide the content to the
contentfield. Thecopy_tofield populatessemantic_textand triggers embedding generation.POST _bulk{ "index": { "_index": "semantic-embeddings" } } { "content": "After running, cool down with light cardio for a few minutes to lower your heart rate and reduce muscle soreness." } { "index": { "_index": "semantic-embeddings" } } { "content": "Marathon plans stress weekly mileage; carb loading before a race does not replace recovery between hard sessions." } { "index": { "_index": "semantic-embeddings" } } { "content": "Tune cluster performance by monitoring thread pools and refresh interval." }Example response{ "errors": false, "took": 600, "items": [ { "index": { "_index": "semantic-embeddings", "_id": "akiYKZ0BGwHk8ONXXqmi", "_version": 1, "result": "created", "_shards": { "total": 1, "successful": 1, "failed": 0 }, "_seq_no": 0, "_primary_term": 1, "status": 201 } }, { "index": { "_index": "semantic-embeddings", "_id": "a0iYKZ0BGwHk8ONXXqmi", "_version": 1, "result": "created", "_shards": { "total": 1, "successful": 1, "failed": 0 }, "_seq_no": 0, "_primary_term": 1, "status": 201 } }, { "index": { "_index": "semantic-embeddings", "_id": "bEiYKZ0BGwHk8ONXXqmi", "_version": 1, "result": "created", "_shards": { "total": 1, "successful": 1, "failed": 0 }, "_seq_no": 1, "_primary_term": 1, "status": 201 } } ] }
Run a search using the Search API.
The JSON body defines a hybrid query, where an RRF retriever combines two standard retrievers running match queries on content and semantic_text fields.
An RRF retriever returns top documents based on the RRF formula, combining two or more child retrievers. This enables hybrid search by combining results from both keyword-based and semantic queries into a single ranked list.
GET semantic-embeddings/_search
{
"retriever": {
"rrf": {
"retrievers": [
{
"standard": {
"query": {
"match": {
"content": "muscle soreness after jogging"
}
}
}
},
{
"standard": {
"query": {
"match": {
"semantic_text": "muscle soreness after jogging"
}
}
}
}
]
}
}
}
- The match query is run against the
contentfield, which stores plain text for keyword matching. - The match query is run against the
semantic_textfield, which stores vector embeddings for meaning-based search.
Documents that score well on either side appear in the final merged list.
Example response
{
"took": 202,
"timed_out": false,
"_shards": {
"total": 6,
"successful": 6,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 2,
"relation": "eq"
},
"max_score": 0.032786883,
"hits": [
{
"_index": "semantic-embeddings",
"_id": "akiYKZ0BGwHk8ONXXqmi",
"_score": 0.032786883,
"_source": {
"content": "After running, cool down with light cardio for a few minutes to lower your heart rate and reduce muscle soreness."
}
},
{
"_index": "semantic-embeddings",
"_id": "a0iYKZ0BGwHk8ONXXqmi",
"_score": 0.016129032,
"_source": {
"content": "Marathon plans stress weekly mileage; carb loading before a race does not replace recovery between hard sessions."
}
}
]
}
}
- Semantic search - Compare different semantic search workflows and choose one for your scenario (for example
semantic_text, the inference API, or deploying models directly in Elasticsearch). - Vector search - Learn more about dense and sparse vectors, embeddings, and similarity search.
- Ranking and reranking - Learn more about multi-stage retrieval, rescoring, and reranking for better relevance.
- Build your search queries - Learn more about Query DSL, ES|QL, retrievers, and the Search API.