瀏覽代碼

[DOCS] Semantic search page (#97715)

Co-authored-by: István Zoltán Szabó <istvan.szabo@elastic.co>
Co-authored-by: David Roberts <dave.roberts@elastic.co>
Abdon Pijpelink 2 年之前
父節點
當前提交
40409bf8ca

二進制
docs/reference/images/search/vector-search-oversimplification.png


+ 1 - 1
docs/reference/search/search-your-data/knn-search.asciidoc

@@ -333,7 +333,7 @@ nearest documents. If the search also includes a `query`, then aggregations are
 calculated on the combined set of `knn` and `query` matches.
 
 [discrete]
-[[semantic-search]]
+[[knn-semantic-search]]
 ==== Perform semantic search
 
 kNN search enables you to perform semantic search by using a previously deployed

+ 1 - 1
docs/reference/search/search-your-data/search-your-data.asciidoc

@@ -531,4 +531,4 @@ include::search-shard-routing.asciidoc[]
 include::search-template.asciidoc[]
 include::sort-search-results.asciidoc[]
 include::knn-search.asciidoc[]
-include::semantic-search-elser.asciidoc[]
+include::semantic-search.asciidoc[]

+ 9 - 9
docs/reference/search/search-your-data/semantic-search-elser.asciidoc

@@ -1,5 +1,5 @@
 [[semantic-search-elser]]
-== Tutorial: semantic search with ELSER
+=== Tutorial: semantic search with ELSER
 ++++
 <titleabbrev>Semantic search with ELSER</titleabbrev>
 ++++
@@ -21,7 +21,7 @@ information.
 
 [discrete]
 [[requirements]]
-=== Requirements
+==== Requirements
 
 To perform semantic search by using ELSER, you must have the NLP model deployed 
 in your cluster. Refer to the 
@@ -40,7 +40,7 @@ you must provide suitably sized nodes yourself.
 
 [discrete]
 [[elser-mappings]]
-=== Create the index mapping
+==== Create the index mapping
 
 First, the mapping of the destination index - the index that contains the tokens 
 that the model created based on your text - must be created.  The destination 
@@ -82,7 +82,7 @@ To learn how to optimize space, refer to the <<save-space>> section.
 
 [discrete]
 [[inference-ingest-pipeline]]
-=== Create an ingest pipeline with an inference processor
+==== Create an ingest pipeline with an inference processor
 
 Create an <<ingest,ingest pipeline>> with an 
 <<inference-processor,{infer} processor>> to use ELSER to infer against the data 
@@ -120,7 +120,7 @@ processor.
 
 [discrete]
 [[load-data]]
-=== Load data
+==== Load data
 
 In this step, you load the data that you later use in the {infer} ingest 
 pipeline to extract tokens from it.
@@ -140,7 +140,7 @@ can see an index named `test-data` with 182469 documents.
 
 [discrete]
 [[reindexing-data-elser]]
-=== Ingest the data through the {infer} ingest pipeline
+==== Ingest the data through the {infer} ingest pipeline
 
 Create the tokens from the text by reindexing the data throught the {infer} 
 pipeline that uses ELSER as the inference model.
@@ -178,7 +178,7 @@ follow the progress. It may take a couple of minutes to complete the process.
 
 [discrete]
 [[text-expansion-query]]
-=== Semantic search by using the `text_expansion` query
+==== Semantic search by using the `text_expansion` query
 
 To perform semantic search, use the `text_expansion` query, and provide the 
 query text and the ELSER model ID. The example below uses the query text "How to 
@@ -251,7 +251,7 @@ To learn about optimizing your `text_expansion` query, refer to
 
 [discrete]
 [[text-expansion-compound-query]]
-=== Combining semantic search with other queries
+==== Combining semantic search with other queries
 
 You can combine `text_expansion` with other queries in a 
 <<compound-queries,compound query>>. For example using a filter clause in a 
@@ -356,7 +356,7 @@ PUT my-index
 
 [discrete]
 [[further-reading]]
-=== Further reading
+==== Further reading
 
 * {ml-docs}/ml-nlp-elser.html[How to download and deploy ELSER]
 * {ml-docs}/ml-nlp-limitations.html#ml-nlp-elser-v1-limit-512[ELSER v1 limitation]

+ 135 - 0
docs/reference/search/search-your-data/semantic-search.asciidoc

@@ -0,0 +1,135 @@
+[[semantic-search]]
+== Semantic search
+
+Semantic search is a search method that helps you find data based on the intent
+and contextual meaning of a search query, instead of a match on query terms
+(lexical search).
+
+{es} provides semantic search capabilities using {ml-docs}/ml-nlp.html[natural
+language processing (NLP)] and vector search. Deploying an NLP model to {es}
+enables it to extract text embeddings out of text. Embeddings are vectors that
+provide a numeric representation of a text. Pieces of content with similar
+meaning have similar representations. 
+
+[[semantic-search-diagram]]
+.A simplified representation of encoding textual concepts as vectors
+image::images/search/vector-search-oversimplification.png[A simplified representation of encoding textual concepts as vectors,align="center"]
+
+At query time, {es} can use the same NLP model to convert a query into
+embeddings, enabling you to find documents with similar text embeddings.
+
+This guide shows you how to implement semantic search with {es}, from selecting
+an NLP model, to writing queries.
+
+[discrete]
+[[semantic-search-select-nlp-model]]
+=== Select an NLP model
+
+{es} offers the usage of a 
+{ml-docs}/ml-nlp-model-ref.html#ml-nlp-model-ref-text-embedding[wide range of NLP models], 
+including both dense and sparse vector models. Your choice of the language model 
+is critical for implementing semantic search successfully.
+
+While it is possible to bring your own text embedding model, achieving good 
+search results through model tuning is challenging. Selecting an appropriate 
+model from our third-party model list is the first step. 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.
+
+To address this issue, Elastic provides a pre-trained representational model 
+called {ml-docs}/ml-nlp-elser.html[Elastic Learned Sparse EncodeR (ELSER)]. 
+ELSER, currently available only for English, is an out-of-domain sparse vector 
+model that does not require fine-tuning. This adaptability makes it suitable for 
+various NLP use cases out of the box. Unless you have a team of ML specialists, 
+it is highly recommended to use the ELSER model.
+
+In the case of sparse vector representation, the vectors mostly consist of zero 
+values, with only a small subset containing non-zero values. This representation 
+is commonly used for textual data. In the case of ELSER, each document in an 
+index and the query text itself are represented by high-dimensional sparse 
+vectors. Each non-zero element of the vector corresponds to a term in the model 
+vocabulary. The ELSER vocabulary contains around 30000 terms, so the sparse 
+vectors created by ELSER contain about 30000 values, the majority of which are 
+zero. Effectively the ELSER model is replacing the terms in the original query 
+with other terms that have been learnt to exist in the documents that best match 
+the original search terms in a training dataset, and weights to control how 
+important each is.
+
+
+[discrete]
+[[semantic-search-deploy-nlp-model]]
+=== Deploy the model
+
+After you decide which model you want to use for implementing semantic search, 
+you need to deploy the model in {es}.
+
+include::{es-repo-dir}/tab-widgets/semantic-search/deploy-nlp-model-widget.asciidoc[]
+
+[discrete]
+[[semantic-search-field-mappings]]
+=== Map a field for the text embeddings
+
+Before you start using the deployed model to generate embeddings based on your 
+input text, you need to prepare your index mapping first. The mapping of the 
+index depends on the type of model.
+
+include::{es-repo-dir}/tab-widgets/semantic-search/field-mappings-widget.asciidoc[]
+
+[discrete]
+[[semantic-search-generate-embeddings]]
+=== Generate text embeddings
+
+Once you have created the mappings for the index, you can generate text 
+embeddings from your input text. This can be done by using an 
+<<ingest,ingest pipeline>> with an <<inference-processor,inference processor>>. 
+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.
+
+include::{es-repo-dir}/tab-widgets/semantic-search/generate-embeddings-widget.asciidoc[]
+
+Now it is time to perform semantic search!
+
+[discrete]
+[[semantic-search-search]]
+=== Search the data
+
+Depending on the type of model you have deployed, you can query rank features 
+with a text expansion query, or dense vectors with a kNN search.
+
+include::{es-repo-dir}/tab-widgets/semantic-search/search-widget.asciidoc[]
+
+[discrete]
+[[semantic-search-hybrid-search]]
+=== 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
+<<rrf,reciprocal rank fusion>> provides the best of both worlds. Not only that,
+but hybrid search using reciprocal rank fusion {blog-ref}improving-information-retrieval-elastic-stack-hybrid[has been shown to perform better
+in general].
+
+include::{es-repo-dir}/tab-widgets/semantic-search/hybrid-search-widget.asciidoc[]
+
+[discrete]
+[[semantic-search-read-more]]
+=== Read more
+
+* Tutorials:
+** <<semantic-search-elser,Semantic search with ELSER>>
+** {ml-docs}/ml-nlp-text-emb-vector-search-example.html[Semantic search with the msmarco-MiniLM-L-12-v3 sentence-transformer model]
+* Blogs:
+** {blog-ref}may-2023-launch-sparse-encoder-ai-model[Introducing Elastic Learned Sparse Encoder: Elastic's AI model for semantic search]
+** {blog-ref}lexical-ai-powered-search-elastic-vector-database[How to get the best of lexical and AI-powered search with Elastic's vector database]
+** Information retrieval blog series:
+*** {blog-ref}improving-information-retrieval-elastic-stack-search-relevance[Part 1: Steps to improve search relevance]
+*** {blog-ref}improving-information-retrieval-elastic-stack-benchmarking-passage-retrieval[Part 2: Benchmarking passage retrieval]
+*** {blog-ref}may-2023-launch-information-retrieval-elasticsearch-ai-model[Part 3: Introducing Elastic Learned Sparse Encoder, our new retrieval model]
+*** {blog-ref}improving-information-retrieval-elastic-stack-hybrid[Part 4: Hybrid retrieval]
+
+include::semantic-search-elser.asciidoc[]

+ 1 - 1
docs/reference/search/search.asciidoc

@@ -515,7 +515,7 @@ include::{es-repo-dir}/rest-api/common-parms.asciidoc[tag=knn-query-vector]
 (Optional, object)
 A configuration object indicating how to build a query_vector before executing
 the request. You must provide a `query_vector_builder` or `query_vector`, but
-not both. Refer to <<semantic-search>> to learn more.
+not both. Refer to <<knn-semantic-search>> to learn more.
 
 `similarity`::
 (Optional, float)

+ 39 - 0
docs/reference/tab-widgets/semantic-search/deploy-nlp-model-widget.asciidoc

@@ -0,0 +1,39 @@
+++++
+<div class="tabs" data-tab-group="model">
+  <div role="tablist" aria-label="model">
+    <button role="tab"
+            aria-selected="true"
+            aria-controls="elser-tab-deploy-nlp-model"
+            id="elser-deploy-nlp-model">
+      ELSER
+    </button>
+    <button role="tab"
+            aria-selected="false"
+            aria-controls="dense-vector-tab-deploy-nlp-model"
+            id="dense-vector-deploy-nlp-model">
+      Dense vector models
+    </button>
+  </div>
+  <div tabindex="0"
+       role="tabpanel"
+       id="elser-tab-deploy-nlp-model"
+       aria-labelledby="elser-deploy-nlp-model">
+++++
+
+include::deploy-nlp-model.asciidoc[tag=elser]
+
+++++
+  </div>
+  <div tabindex="0"
+       role="tabpanel"
+       id="dense-vector-tab-deploy-nlp-model"
+       aria-labelledby="dense-vector-deploy-nlp-model"
+       hidden="">
+++++
+
+include::deploy-nlp-model.asciidoc[tag=dense-vector]
+
+++++
+  </div>
+</div>
+++++

+ 14 - 0
docs/reference/tab-widgets/semantic-search/deploy-nlp-model.asciidoc

@@ -0,0 +1,14 @@
+// tag::elser[]
+
+To deploy ELSER, refer to 
+{ml-docs}/ml-nlp-elser.html#download-deploy-elser[Download and deploy ELSER].
+
+// end::elser[]
+
+
+// tag::dense-vector[]
+
+To deploy a third-party text embedding model, refer to 
+{ml-docs}/ml-nlp-text-emb-vector-search-example.html#ex-te-vs-deploy[Deploy a text embedding model].
+
+// end::dense-vector[]

+ 39 - 0
docs/reference/tab-widgets/semantic-search/field-mappings-widget.asciidoc

@@ -0,0 +1,39 @@
+++++
+<div class="tabs" data-tab-group="model">
+  <div role="tablist" aria-label="model">
+    <button role="tab"
+            aria-selected="true"
+            aria-controls="elser-tab-field-mappings"
+            id="elser-field-mappings">
+      ELSER
+    </button>
+    <button role="tab"
+            aria-selected="false"
+            aria-controls="dense-vector-tab-field-mappings"
+            id="dense-vector-field-mappings">
+      Dense vector models
+    </button>
+  </div>
+  <div tabindex="0"
+       role="tabpanel"
+       id="elser-tab-field-mappings"
+       aria-labelledby="elser-field-mappings">
+++++
+
+include::field-mappings.asciidoc[tag=elser]
+
+++++
+  </div>
+  <div tabindex="0"
+       role="tabpanel"
+       id="dense-vector-tab-field-mappings"
+       aria-labelledby="dense-vector-field-mappings"
+       hidden="">
+++++
+
+include::field-mappings.asciidoc[tag=dense-vector]
+
+++++
+  </div>
+</div>
+++++

+ 89 - 0
docs/reference/tab-widgets/semantic-search/field-mappings.asciidoc

@@ -0,0 +1,89 @@
+// tag::elser[]
+
+ELSER produces token-weight pairs as output from the input text and the query. 
+The {es} <<rank-features,`rank_features`>> field type can store these 
+token-weight pairs as numeric feature vectors. The index must have a field with 
+the `rank_features` field type to index the tokens that ELSER generates.
+
+To create a mapping for your ELSER index, refer to the 
+<<elser-mappings,Create the index mapping section>> of the tutorial. The example 
+shows how to create an index mapping for `my-index` that defines the 
+`my_embeddings.tokens` field - which will contain the ELSER output - as a 
+`rank_features` field.
+
+[source,console]
+----
+PUT my-index
+{
+  "mappings": {
+    "properties": {
+      "my_embeddings.tokens": { <1>
+        "type": "rank_features" <2>
+      },
+      "my_text_field": { <3>
+        "type": "text" <4>
+      }
+    }
+  }
+}
+----
+<1> The name of the field that will contain the tokens generated by ELSER.
+<2> The field that contains the tokens must be a `rank_features` field.
+<3> The name of the field from which to create the sparse vector representation. 
+In this example, the name of the field is `my_text_field`.
+<4> The field type is `text` in this example.
+
+// end::elser[]
+
+
+// tag::dense-vector[]
+
+The models compatible with {es} NLP generate dense vectors as output. The 
+<<dense-vector,`dense_vector`>> field type is suitable for storing dense vectors 
+of numeric values. The index must have a field with the `dense_vector` field 
+type to index the embeddings that the supported third-party model that 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 
+{ml-docs}/ml-nlp-text-emb-vector-search-example.html#ex-text-emb-ingest[Add the text embedding model to an ingest inference pipeline] 
+section of the 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.
+
+[source,console]
+----
+PUT my-index
+{
+  "mappings": {
+    "properties": {
+      "my_embeddings.predicted_value": { <1>
+        "type": "dense_vector", <2>
+        "dims": 384,<3>
+        "index": true,
+        "similarity": "cosine"
+      },
+      "my_text_field": { <4>
+        "type": "text" <5>
+      }
+    }
+  }
+}
+----
+<1> The name of the field that will contain the embeddings generated by the 
+model.
+<2> The field that contains the embeddings must be a `dense_vector` field.
+<3> The model produces embeddings with a certain number of dimensions. The 
+`dense_vector` field must be configured with the same number of dimensions by 
+the `dims` option. Refer to the respective model documentation to get 
+information about the number of dimensions of the embeddings.
+<4> The name of the field from which to create the dense vector representation. 
+In this example, the name of the field is `my_text_field`.
+<5> The field type is `text` in this example.
+
+
+// end::dense-vector[]

+ 39 - 0
docs/reference/tab-widgets/semantic-search/generate-embeddings-widget.asciidoc

@@ -0,0 +1,39 @@
+++++
+<div class="tabs" data-tab-group="model">
+  <div role="tablist" aria-label="model">
+    <button role="tab"
+            aria-selected="true"
+            aria-controls="elser-tab-generate-embeddings"
+            id="elser-generate-embeddings">
+      ELSER
+    </button>
+    <button role="tab"
+            aria-selected="false"
+            aria-controls="dense-vector-tab-generate-embeddings"
+            id="dense-vector-generate-embeddings">
+      Dense vector models
+    </button>
+  </div>
+  <div tabindex="0"
+       role="tabpanel"
+       id="elser-tab-generate-embeddings"
+       aria-labelledby="elser-generate-embeddings">
+++++
+
+include::generate-embeddings.asciidoc[tag=elser]
+
+++++
+  </div>
+  <div tabindex="0"
+       role="tabpanel"
+       id="dense-vector-tab-generate-embeddings"
+       aria-labelledby="dense-vector-generate-embeddings"
+       hidden="">
+++++
+
+include::generate-embeddings.asciidoc[tag=dense-vector]
+
+++++
+  </div>
+</div>
+++++

+ 88 - 0
docs/reference/tab-widgets/semantic-search/generate-embeddings.asciidoc

@@ -0,0 +1,88 @@
+////
+
+[source,console]
+----
+DELETE _ingest/pipeline/my-text-embeddings-pipeline
+----
+// TEST
+// TEARDOWN
+
+////
+
+// tag::elser[]
+
+This is how an ingest pipeline that uses the ELSER model is created:
+
+[source,console]
+----
+PUT _ingest/pipeline/my-text-embeddings-pipeline
+{
+  "description": "Text embedding pipeline",
+  "processors": [
+    {
+      "inference": {
+        "model_id": ".elser_model_1",
+        "target_field": "my_embeddings",
+        "field_map": { <1>
+          "my_text_field": "text_field"
+        },
+        "inference_config": {
+          "text_expansion": { <2>
+            "results_field": "tokens"
+          }
+        }
+      }
+    }
+  ]
+}
+----
+<1> The `field_map` object maps the input document field name (which is
+`my_text_field` in this example) to the name of the field that the model expects
+(which is always `text_field`).
+<2> The `text_expansion` inference type needs to be used in the inference ingest 
+processor.
+
+To ingest data through the pipeline to generate tokens with ELSER, refer to the 
+<<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.
+
+// end::elser[]
+
+
+// tag::dense-vector[]
+
+This is how an ingest pipeline that uses a text embedding model is created:
+
+[source,console]
+----
+PUT _ingest/pipeline/my-text-embeddings-pipeline
+{
+  "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"
+        }
+      }
+    }
+  ]
+}
+----
+<1> The model ID of the text embedding model you want to use.
+<2> The `field_map` object maps the input document field name (which is 
+`my_text_field` in this example) to the name of the field that the model expects 
+(which is always `text_field`).
+
+To ingest data through the pipeline to generate text embeddings with your chosen 
+model, refer to the 
+{ml-docs}/ml-nlp-text-emb-vector-search-example.html#ex-text-emb-ingest[Add the text embedding model to an inference ingest pipeline] 
+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.
+
+// end::dense-vector[]

+ 39 - 0
docs/reference/tab-widgets/semantic-search/hybrid-search-widget.asciidoc

@@ -0,0 +1,39 @@
+++++
+<div class="tabs" data-tab-group="model">
+  <div role="tablist" aria-label="model">
+    <button role="tab"
+            aria-selected="true"
+            aria-controls="elser-tab-hybrid-search"
+            id="elser-hybrid-search">
+      ELSER
+    </button>
+    <button role="tab"
+            aria-selected="false"
+            aria-controls="dense-vector-tab-hybrid-search"
+            id="dense-vector-hybrid-search">
+      Dense vector models
+    </button>
+  </div>
+  <div tabindex="0"
+       role="tabpanel"
+       id="elser-tab-hybrid-search"
+       aria-labelledby="elser-hybrid-search">
+++++
+
+include::hybrid-search.asciidoc[tag=elser]
+
+++++
+  </div>
+  <div tabindex="0"
+       role="tabpanel"
+       id="dense-vector-tab-hybrid-search"
+       aria-labelledby="dense-vector-hybrid-search"
+       hidden="">
+++++
+
+include::hybrid-search.asciidoc[tag=dense-vector]
+
+++++
+  </div>
+</div>
+++++

+ 78 - 0
docs/reference/tab-widgets/semantic-search/hybrid-search.asciidoc

@@ -0,0 +1,78 @@
+// tag::elser[]
+
+Hybrid search between a semantic and lexical query can be achieved by using a
+`sub_searches` clause in your search request. In the `sub_searches` clause,
+provide a `text_expansion` query and a full-text query. Next to the
+`sub_searches` clause, also provide a <<request-body-rank,`rank`>> clause with
+the `rrf` parameter to rank documents using reciprocal rank fusion.
+
+[source,console]
+----
+GET my-index/_search
+{
+  "sub_searches": [
+    {
+      "query": {
+        "match": {
+          "my_text_field": "the query string"
+        }
+      }
+    },
+    {
+      "query": {
+        "text_expansion": {
+          "my_embeddings.tokens": {
+            "model_id": ".elser_model_1",
+            "model_text": "the query string"
+          }
+        }
+      }
+    }
+  ],
+  "rank": {
+    "rrf": {}
+  }
+}
+----
+// TEST[skip:TBD]
+
+// end::elser[]
+
+
+// tag::dense-vector[]
+
+Hybrid search between a semantic and lexical query can be achieved by providing:
+
+* a `query` clause for the full-text query;
+* a `knn` clause with the kNN search that queries the dense vector field;
+* and a `rank` clause with the `rrf` parameter to rank documents using 
+reciprocal rank fusion.
+
+[source,console]
+----
+GET my-index/_search
+{
+  "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"
+      }
+    }
+  },
+  "rank": {
+    "rrf": {}
+  }
+}
+----
+// TEST[skip:TBD]
+
+// end::dense-vector[]

+ 39 - 0
docs/reference/tab-widgets/semantic-search/search-widget.asciidoc

@@ -0,0 +1,39 @@
+++++
+<div class="tabs" data-tab-group="model">
+  <div role="tablist" aria-label="model">
+    <button role="tab"
+            aria-selected="true"
+            aria-controls="elser-tab-search"
+            id="elser-search">
+      ELSER
+    </button>
+    <button role="tab"
+            aria-selected="false"
+            aria-controls="dense-vector-tab-search"
+            id="dense-vector-search">
+      Dense vector models
+    </button>
+  </div>
+  <div tabindex="0"
+       role="tabpanel"
+       id="elser-tab-search"
+       aria-labelledby="elser-search">
+++++
+
+include::search.asciidoc[tag=elser]
+
+++++
+  </div>
+  <div tabindex="0"
+       role="tabpanel"
+       id="dense-vector-tab-search"
+       aria-labelledby="dense-vector-search"
+       hidden="">
+++++
+
+include::search.asciidoc[tag=dense-vector]
+
+++++
+  </div>
+</div>
+++++

+ 54 - 0
docs/reference/tab-widgets/semantic-search/search.asciidoc

@@ -0,0 +1,54 @@
+// tag::elser[]
+
+ELSER text embeddings can be queried using a 
+<<query-dsl-text-expansion-query,text expansion query>>. The text expansion 
+query enables you to query a rank features field, by providing the model ID of 
+the NLP model, and the query text:
+
+[source,console]
+----
+GET my-index/_search
+{
+   "query":{
+      "text_expansion":{
+         "my_embeddings.tokens":{ <1>
+            "model_id":".elser_model_1",
+            "model_text":"the query string"
+         }
+      }
+   }
+}
+----
+// TEST[skip:TBD]
+<1> The field of type `rank_features`.
+
+// end::elser[]
+
+
+// tag::dense-vector[]
+
+Text embeddings produced by dense vector models can be queried using a 
+<<knn-semantic-search,kNN 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.
+
+[source,console]
+----
+GET my-index/_search
+{
+  "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" 
+      }
+    }
+  }
+}
+----
+// TEST[skip:TBD]
+
+// end::dense-vector[]