﻿---
title: Tutorial: Dense and sparse workflows using ingest pipelines
description: This guide shows how to implement semantic search in Elasticsearch with deployed NLP models: from selecting a model, to configuring ingest pipelines,...
url: https://docs-v3-preview.elastic.dev/elastic/docs-content/pull/6727/solutions/search/vector/dense-versus-sparse-ingest-pipelines
products:
  - Elasticsearch
applies_to:
  - Elastic Cloud Serverless: Generally available
  - Elastic Stack: Generally available
---

# Tutorial: Dense and sparse workflows using ingest pipelines
<important>
  - For the easiest way to perform semantic search in the Elastic Stack, refer to the [`semantic_text`](https://docs-v3-preview.elastic.dev/elastic/docs-content/pull/6727/solutions/search/semantic-search/semantic-search-semantic-text) end-to-end tutorial.
  - This tutorial predates the [inference endpoint](https://www.elastic.co/docs/api/doc/elasticsearch/group/endpoint-inference) and the [`semantic_text` field type](https://docs-v3-preview.elastic.dev/elastic/elasticsearch/tree/main/reference/elasticsearch/mapping-reference/semantic-text). Today there are simpler, higher-level options for semantic search than the ones outlined in this tutorial. The semantic text workflow is the recommended way to perform semantic search for most use cases.
</important>

This guide shows how to implement semantic search in Elasticsearch with deployed NLP models: from selecting a model, to configuring ingest pipelines, to running queries.

## Select an NLP model

Elasticsearch supports a [wide range of NLP models](/elastic/docs-content/pull/6727/explore-analyze/machine-learning/nlp/ml-nlp-model-ref#ml-nlp-model-ref-text-embedding), including **dense** and **sparse** vector models. Choosing the right model is critical for good relevance.
While bringing your own text embedding model is possible, achieving strong results typically requires tuning and evaluation. Selecting a well-performing third-party model from our list is a good start. Training the model on your own data is essential to ensure better search results than using only BM25. However, the model training process requires a team of data scientists and ML experts, making it expensive and time-consuming.
<dropdown title="When to use dense or sparse embeddings?">
  Dense and sparse embeddings represent text differently, and each approach fits different search goals. The following examples illustrate typical choices.

  #### Sparse embeddingsUse sparse embeddings when you want semantic expansion on top of keyword-style search. Sparse models such as [ELSER](https://docs-v3-preview.elastic.dev/elastic/docs-content/pull/6727/explore-analyze/machine-learning/nlp/ml-nlp-elser) expand queries and documents into weighted terms, which helps when users search with short phrases, acronyms, or domain vocabulary. Sparse vectors are high-dimensional vectors where most values are zero and only a small set of token weights are non-zero.
  Common use cases include:
  - Workplace and IT search: Find runbooks, tickets, and internal wikis when users search for error codes, service names, or team-specific jargon.
  - Security and observability: Surface related alerts, playbooks, and detection rules from analyst queries that mix technical terms and natural language.
  - Support and self-service: Match customer questions to help articles when the query uses product terminology that does not appear verbatim in the document.
  Sparse embeddings are a practical default when you need explainable results, strong relevance for English text without training a custom model, or semantic search at scale without a dedicated machine learning team.For more detail, refer to [Sparse vector search in Elasticsearch](https://docs-v3-preview.elastic.dev/elastic/docs-content/pull/6727/solutions/search/vector/sparse-vector).

  #### Dense embeddingsUse dense embeddings when you want to match content by overall meaning in vector space, not by overlapping keywords. Dense models map text (and other content types) to fixed-length vectors so that conceptually similar items sit close together. Dense vectors are compact arrays of floating-point values from an embedding model.
  Common use cases include:
  - [Retrieval augmented generation (RAG)](https://docs-v3-preview.elastic.dev/elastic/docs-content/pull/6727/solutions/search/rag): Retrieve document passages that answer a user's question, even when the question and the source text use different words.
  - [Natural language Q&A](https://docs-v3-preview.elastic.dev/elastic/docs-content/pull/6727/explore-analyze/machine-learning/nlp/ml-nlp-text-emb-vector-search-example): Match questions like "How do I reset my password?" to FAQ entries, product documentation, or policy pages.
  - [Recommendations and similarity](https://docs-v3-preview.elastic.dev/elastic/docs-content/pull/6727/solutions/search/vector/knn): Find related articles, products, or media. For example, you can surface articles like the current one or visually similar product images.
  Dense embeddings are a good choice when you need multilingual retrieval or a specific third-party embedding model you have already evaluated on your data.For more detail, refer to [Dense vector search in Elasticsearch](https://docs-v3-preview.elastic.dev/elastic/docs-content/pull/6727/solutions/search/vector/dense-vector).
</dropdown>


## Deploy the model in Elasticsearch

After you choose a model, deploy it in Elasticsearch.
<tab-set>
  <tab-item title="ELSER">
    To deploy ELSER, refer to [Download and deploy ELSER](/elastic/docs-content/pull/6727/explore-analyze/machine-learning/nlp/ml-nlp-elser#download-deploy-elser).
  </tab-item>

  <tab-item title="Dense vector models">
    To deploy a third-party text embedding model, refer to [Deploy a text embedding model](/elastic/docs-content/pull/6727/explore-analyze/machine-learning/nlp/ml-nlp-text-emb-vector-search-example#ex-te-vs-deploy).
  </tab-item>
</tab-set>


## Map a field for the text embeddings

Before generating embeddings, prepare your **index mapping**. The mapping depends on whether you use a **sparse** (ELSER) or **dense** model.
<tab-set>
  <tab-item title="ELSER">
    ELSER outputs token-weight pairs. Use the [`sparse_vector`](https://docs-v3-preview.elastic.dev/elastic/elasticsearch/tree/main/reference/elasticsearch/mapping-reference/sparse-vector) field to store them.To create a mapping for your ELSER index, refer to the [Create the index mapping section](/elastic/docs-content/pull/6727/solutions/search/semantic-search/semantic-search-elser-ingest-pipelines#elser-mappings) of the tutorial.
    Create a mapping with a `sparse_vector` field for the tokens and a `text` field for the source content. For example:
    ```json

    {
      "mappings": {
        "properties": {
          "my_tokens": { <1>
            "type": "sparse_vector" <2>
          },
          "my_text_field": { <3>
            "type": "text" <4>
          }
        }
      }
    }
    ```
  </tab-item>

  <tab-item title="Dense vector models">
    Dense vector models output numeric embeddings. Use the [`dense_vector`](https://docs-v3-preview.elastic.dev/elastic/elasticsearch/tree/main/reference/elasticsearch/mapping-reference/dense-vector) field type for storing dense vectors that the supported third-party model you selected generates. Keep in mind that the model produces embeddings with a certain number of dimensions. The `dense_vector` field must be configured with the same number of dimensions using the `dims` option. Refer to the respective model documentation to get information about the number of dimensions of the embeddings.To review a mapping of an index for an NLP model, refer to the mapping code snippet in the [Add the text embedding model to an ingest inference pipeline](/elastic/docs-content/pull/6727/explore-analyze/machine-learning/nlp/ml-nlp-text-emb-vector-search-example#ex-text-emb-ingest) section of the related tutorial. The example shows how to create an index mapping that defines the `my_embeddings.predicted_value` field - which will contain the model output - as a `dense_vector` field.
    ```json

    {
      "mappings": {
        "properties": {
          "my_embeddings.predicted_value": { <1>
            "type": "dense_vector", <2>
            "dims": 384 <3>
          },
          "my_text_field": { <4>
            "type": "text" <5>
          }
        }
      }
    }
    ```
  </tab-item>
</tab-set>


## Generate text embeddings

Use an [ingest pipeline](https://docs-v3-preview.elastic.dev/elastic/docs-content/pull/6727/manage-data/ingest/transform-enrich/ingest-pipelines) with an [inference processor](https://docs-v3-preview.elastic.dev/elastic/elasticsearch/tree/main/reference/enrich-processor/inference-processor) to generate embeddings at ingest time. The ingest pipeline processes the input data and indexes it into the destination index. At index time, the inference ingest processor uses the trained model to infer against the data ingested through the pipeline. After you created the ingest pipeline with the inference processor, you can ingest your data through it to generate the model output.
<tab-set>
  <tab-item title="ELSER">
    This is how an ingest pipeline that uses the ELSER model is created:
    ```json

    {
      "description": "Text embedding pipeline",
      "processors": [
        {
          "inference": {
            "model_id": ".elser_model_2",
            "input_output": [ <1>
              {
                "input_field": "my_text_field",
                "output_field": "my_tokens"
              }
            ]
          }
        }
      ]
    }
    ```
    To ingest data through the pipeline to generate tokens with ELSER, refer to the [Ingest the data through the inference ingest pipeline](/elastic/docs-content/pull/6727/solutions/search/semantic-search/semantic-search-elser-ingest-pipelines#reindexing-data-elser) section of the tutorial. After you successfully ingested documents by using the pipeline, your index will contain the tokens generated by ELSER. Tokens are learned associations capturing relevance, they are not synonyms. To learn more about what tokens are, refer to [this page](/elastic/docs-content/pull/6727/explore-analyze/machine-learning/nlp/ml-nlp-elser#elser-tokens).
  </tab-item>

  <tab-item title="Dense vector models">
    Example ingest pipeline using a text embedding model:
    ```json

    {
      "description": "Text embedding pipeline",
      "processors": [
        {
          "inference": {
            "model_id": "sentence-transformers__msmarco-minilm-l-12-v3", <1>
            "target_field": "my_embeddings",
            "field_map": { <2>
              "my_text_field": "text_field"
            }
          }
        }
      ]
    }
    ```
    To ingest data through the pipeline to generate text embeddings with your chosen model, refer to the [Add the text embedding model to an inference ingest pipeline](/elastic/docs-content/pull/6727/explore-analyze/machine-learning/nlp/ml-nlp-text-emb-vector-search-example#ex-text-emb-ingest) section. The example shows how to create the pipeline with the inference processor and reindex your data through the pipeline. After you successfully ingested documents by using the pipeline, your index will contain the text embeddings generated by the model.
  </tab-item>
</tab-set>

Now it is time to perform semantic search!

## Search the data with vector search

Depending on the type of model you have deployed, you can query rank features with a [sparse vector](https://docs-v3-preview.elastic.dev/elastic/elasticsearch/tree/main/reference/query-languages/query-dsl/query-dsl-sparse-vector-query) query, or dense vectors with a kNN search.
<tab-set>
  <tab-item title="ELSER">
    ELSER text embeddings can be queried using a [sparse vector query](https://docs-v3-preview.elastic.dev/elastic/elasticsearch/tree/main/reference/query-languages/query-dsl/query-dsl-sparse-vector-query). The sparse vector query enables you to query a [sparse vector](https://docs-v3-preview.elastic.dev/elastic/elasticsearch/tree/main/reference/elasticsearch/mapping-reference/sparse-vector) field, by providing the inference ID associated with the NLP model you want to use, and the query text:
    ```json

    {
       "query":{
        "sparse_vector": {
            "field": "my_tokens",
            "inference_id": "my-elser-endpoint",
            "query": "the query string"
          }
       }
    }
    ```
  </tab-item>

  <tab-item title="Dense vector models">
    Text embeddings produced by dense vector models can be queried using a [kNN search](/elastic/docs-content/pull/6727/solutions/search/vector/knn#knn-semantic-search). In the `knn` clause, provide the name of the dense vector field, and a `query_vector_builder` clause with the model ID and the query text.
    ```json

    {
      "knn": {
        "field": "my_embeddings.predicted_value",
        "k": 10,
        "num_candidates": 100,
        "query_vector_builder": {
          "text_embedding": {
            "model_id": "sentence-transformers__msmarco-minilm-l-12-v3",
            "model_text": "the query string"
          }
        }
      }
    }
    ```
  </tab-item>
</tab-set>


## Beyond semantic search with hybrid search

In some situations, lexical search may perform better than semantic search. For example, when searching for single words or IDs, like product numbers.
Combining semantic and lexical search into one hybrid search request using [reciprocal rank fusion](https://docs-v3-preview.elastic.dev/elastic/elasticsearch/tree/main/reference/elasticsearch/rest-apis/reciprocal-rank-fusion) provides the best of both worlds. Not only that, but hybrid search using reciprocal rank fusion [has been shown to perform better in general](https://www.elastic.co/blog/improving-information-retrieval-elastic-stack-hybrid).
<tab-set>
  <tab-item title="ELSER">
    Hybrid search between a semantic and lexical query can be achieved by using an [`rrf` retriever](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-search#operation-search-body-application-json-retriever) as part of your search request. Provide a `sparse_vector` query and a full-text query as [`standard` retrievers](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-search#operation-search-body-application-json-retriever) for the `rrf` retriever. The `rrf` retriever uses [reciprocal rank fusion](https://docs-v3-preview.elastic.dev/elastic/elasticsearch/tree/main/reference/elasticsearch/rest-apis/reciprocal-rank-fusion) to rank the top documents.
    ```json

    {
      "retriever": {
        "rrf": {
          "retrievers": [
            {
              "standard": {
                "query": {
                  "match": {
                    "my_text_field": "the query string"
                  }
                }
              }
            },
            {
              "standard": {
                "query": {
                 "sparse_vector": {
                    "field": "my_tokens",
                    "inference_id": "my-elser-endpoint",
                    "query": "the query string"
                  }
                }
              }
            }
          ]
        }
      }
    }
    ```
  </tab-item>

  <tab-item title="Dense vector models">
    Hybrid search between a semantic and lexical query can be achieved by providing:
    - an `rrf` retriever to rank top documents using [reciprocal rank fusion](https://docs-v3-preview.elastic.dev/elastic/elasticsearch/tree/main/reference/elasticsearch/rest-apis/reciprocal-rank-fusion)
    - a `standard` retriever as a child retriever with `query` clause for the full-text query
    - a `knn` retriever as a child retriever with the kNN search that queries the dense vector field

    ```json

    {
      "retriever": {
        "rrf": {
          "retrievers": [
            {
              "standard": {
                "query": {
                  "match": {
                    "my_text_field": "the query string"
                  }
                }
              }
            },
            {
              "knn": {
                "field": "text_embedding.predicted_value",
                "k": 10,
                "num_candidates": 100,
                "query_vector_builder": {
                  "text_embedding": {
                    "model_id": "sentence-transformers__msmarco-minilm-l-12-v3",
                    "model_text": "the query string"
                  }
                }
              }
            }
          ]
        }
      }
    }
    ```
  </tab-item>
</tab-set>