From 4745d2c975d2a99bb1d7ef549201441d526fa555 Mon Sep 17 00:00:00 2001 From: Gary Gray <137797428+ggray-cb@users.noreply.github.com> Date: Tue, 1 Oct 2024 16:20:44 -0400 Subject: [PATCH 01/41] Adding initial rough draft --- .../pages/use-vector-indexes.adoc | 113 ++++++++++++++++++ modules/vector-index/partials/nav.adoc | 1 + 2 files changed, 114 insertions(+) create mode 100644 modules/vector-index/pages/use-vector-indexes.adoc create mode 100644 modules/vector-index/partials/nav.adoc diff --git a/modules/vector-index/pages/use-vector-indexes.adoc b/modules/vector-index/pages/use-vector-indexes.adoc new file mode 100644 index 000000000..273e411bb --- /dev/null +++ b/modules/vector-index/pages/use-vector-indexes.adoc @@ -0,0 +1,113 @@ += Use Vector Indexes for AI Applications +:page-topic-type: concept +:page-ui-name: {ui-name} +:page-product-name: {product-name} +:description: Use Couchbase {page-product-name}'s Vector Index features to find documents based on content similarity or semantic meaning. + +{description} + +Vector Indexing lets you add vectors to Couchbase {product-name} indexes. +You store index values as attributes in your documents, and then index those attributes. +You can then find relevant data by executing queries on the vector attributes, which use the index to find similar vectors. + +== About Vectors + +Vectors are a numerical representation of complex data such as text, images, or audio. +They distill this complex data into an array of floating-point values called dimensions. +These dimensions capture features of the data in a way that makes the data easy to compare. +Similar data, such as text about the same topic or images of a similar subject, have similar vectors. +These vectors are close together the multi-dimensional space formed by all of the vectors in the dataset. +Vectors for dissimilar data (for example, articles discussing two different topics) have vectors that are further apart in this multi-dimensional space. + +By comparing two vectors, you can find the similarity between two pieces of data. +This similarity goes beyond just finding parts of the data that's identical (for example, finding many of the same words in two pieces of text). +The vectors represent features such as the semantic meaning of text rather than just superficial similarities. + +In Couchbase {product-name}, you can use vectors to find documents that are similar to an existing document or query values. +By searching your database for similar vectors, you can identify data that's semantically similar to your query value. + +=== Embedding Vectors + +Embedding is the process of generating vectors that represent a piece of complex data. +You use a model that's specific to the data's type to generate its vector. +For example, to generate vectors from text, you can use a use models such as https://en.wikipedia.org/wiki/Word2vec[Word2Vec^] or https://en.wikipedia.org/wiki/GloVe[Global Vectors for Word Representation (GloVe)^]. +The models take into account the context around each potion of the text when generating a vector. +This context is what captures the semantic meaning of the text and embeds it in the vector's dimensions. + +You can only compare the similarity of vectors when the same model generated them. +For example, you cannot find the similarity of two pieces of text if the vector for one was generated by Word2Vec and the other was generated by GloVe. + +Couchbase {product-name} does not implement any embedding models. +To store vectors into your database, you must use external embedding models to generate vectors for your data. +A common method of embedding vectors in your database is to call the https://openai.com/index/introducing-text-and-code-embeddings/[OpenAI Embedding API^] to generate vectors for your data. + +=== Comparing Vectors + +Once complex data embedded in your database as a vector, you can find data has a similar meaning by locating similar vectors. +A vector database such as Couchbase {product-name} can help with this task by indexing vectors in a way that makes finding similar vectors faster. + +Several algorithms exist that you can use to compare vectors. +For example, +When choosing an algorithm, you often have to balance accuracy for speed. +Couchbase {product-name} supports several different comparison algorithms, such as + +=== Reducing Vector Complexity + +The number of dimensions in a vector can vary. +A vector that represents highly complex data such as images can contain several thousand dimensions. +Simpler data, such as text, can still have hundreds of dimensions. +When you execute a query to find similar vectors, this large number of dimensions can make the query computationally expensive. +A search for similar raw vectors in an index would require comparing hundreds or thousands of values for each index entry. + +You can use several techniques to reduce the overhead of searching for similar vectors. + +* Partitioning groups vectors together based on similarity. +When searching for vectors that are similar to a value, you only need to search the relevant groups. + +* Quantization reduces the space taken by a vector by lowering its precision. +It maps each vector to the closest centroid which is vector contained in a compiled list of representative vectors called a codebook. +Instead of storing the full original vector, this technique stores just the index of the centroid in the codebook. +It reduces the storage size without altering the dimensionality of the vector. +This storage reduction makes vector comparisons faster, because searches only compare the codebook index values instead of the full vectors. + +For large amounts of complex data, you often use multiple techniques. + +Some types of Couchbase {product-name} indexes can perform quantization and partitioning on your vectors. + +== Vectors in Couchbase {product-name} Indexes + +To use vectors in Couchbase {product-name} queries, you store them in attributes in your documents and then add those attributes to an index. +Couchbase {product-name} supports vectors in the following index types: + +* Vector Indexes are specifically designed for vector searches. +They can index billions of documents. +Most of the Vector Index is stored in a highly optimized format on disk. +Use this type of index when you want to query multiple vector values with a low memory footprint. +This index offers high accuracy even for vectors with a large number of dimensions. + +* Global Secondary Indexes (GSI) can be extended with a single vector column. +Adding a vector to a GSI index is useful when your queries combine a single vector value with standard scalar attributes. +The scalar attributes in a query reduce the number of vectors the Couchbase {product-name} has to compare to find similar vectors. +Use GSI indexes with a vector column when you want to perform hybrid searches of documents using both scalars and a vector. +They consume a moderate amount of memory and can index billions of documents. +When querying, the scalar attributes in the query limit the number of vectors that the query has to compare. + +* A Search index used for Full-Text Search can have an added vector attribute, +These indexes can index millions of documents. +The search results combine the scores of full text search and the semantic meanings of the vector search to give you hybrid results. +Use Search indexes with a vector attribute when you want to query based on keywords, geospacial data, and a vector value. + +== Uses for Vectors in Couchbase {product-name} Indexes + +Here's some ways you can use vector indexes in your applications: + +* Improve your application's search ability by querying not just for values data, but also based on similar content. +For example, suppose your application is a product catalog. +Using a GSI index extended with a vector column, it could find similar products based not just on attributes (such as color or size) but also the similarity of the product's description and customer reviews. + +* Create a customized chatbot based on your own data by implementing a Retrieval-Augmented Generation (RAG) workflow. +When a user enters a question, convert it to a vector using the same embedding model you used to embed vectors into your index. +Perform a query using the vector index to find relevant documents in your database. +Then pass the user's question and the relevant documents to a Large Language Model to generate a final response for the user. + + diff --git a/modules/vector-index/partials/nav.adoc b/modules/vector-index/partials/nav.adoc new file mode 100644 index 000000000..b55ee4b61 --- /dev/null +++ b/modules/vector-index/partials/nav.adoc @@ -0,0 +1 @@ +* xref:7.7@server:vector-index:use-vector-indexes.adoc[] From 7201ce699143e485c4246963b7e16452c75e0958 Mon Sep 17 00:00:00 2001 From: Gary Gray <137797428+ggray-cb@users.noreply.github.com> Date: Tue, 8 Oct 2024 16:52:47 -0400 Subject: [PATCH 02/41] Interim checkin. Lots of work on the overview. Added a diagram. Added start of the GSI topic. --- .../vector-index/pages/gsi-with-vector.adoc | 45 ++++++++ .../pages/use-vector-indexes.adoc | 102 ++++++++++++------ .../partials/ai-app-workflow.puml | 96 +++++++++++++++++ modules/vector-index/partials/nav.adoc | 1 + 4 files changed, 210 insertions(+), 34 deletions(-) create mode 100644 modules/vector-index/pages/gsi-with-vector.adoc create mode 100644 modules/vector-index/partials/ai-app-workflow.puml diff --git a/modules/vector-index/pages/gsi-with-vector.adoc b/modules/vector-index/pages/gsi-with-vector.adoc new file mode 100644 index 000000000..c06a75a70 --- /dev/null +++ b/modules/vector-index/pages/gsi-with-vector.adoc @@ -0,0 +1,45 @@ += Use GSI with a Vector Column +:page-topic-type: guide +:page-ui-name: {ui-name} +:page-product-name: {product-name} +:description: You can extend a Couchbase {product-name}'s Global Secondary Index (GSI) with a single vector column to enable queries to find semantically-related content. + +{description} + +The added vector column lets your application perform a hybrid query using both the index's scalar. array, and object index entries plus a vector value. +See xref:learn:services-and-indexes/indexes/indexes.adoc[] for an overview of GSI and other indexes. + +== How the GSI's Column Works + +You can add a single vector column to a GSI to enable semantic and similarity searches within your {sqlpp} queries. +When creating the index, you set the type of the attribute containing the embedded vector to `VECTOR`. +In the process of creating the index, the Index Service quantizes the data in the attribute to make it easier to scan and process. +For more information about quantization, see xref:use-vector-indexes.adoc#quantize[Reducing Vector Complexity]. + +When your query uses a GSI containing a vector column, the Query Service uses any non-vector predicates in the query to filter index entries before it performs an IndexScan for relevant vectors. +This behavior reduces the number of vector similarity comparisons the Query Service must do to find similar vectors. + + +== Prerequisites + +* You must have the Index Service enabled on a node in your database. +For more information about how to deploy a new node and Services on your database, see xref:manage:manage-nodes/node-management-overview.adoc[]. + +* You must have a bucket with scopes and collections in your database. +For more information about how to create a bucket, see xref:manage:manage-buckets/create-bucket.adoc[]. + +* You have documents in a keyspace inside your bucket that contain a vector embedding. +Embeddings can be an array of floats or a base64 encoded string. + +* Your account has the xref:learn:security:roles.adoc#query-manage-index[Query Manage Index] role. + +== Planning a GSI Extended with a Vector Column + +Before you create a GSI with a vector column, you must make several decisions: + +* The type of quantization to use when storing the vector in you your index. +GSI always uses Inverted File (IVF) indexing with a form of quantization for its vector column. +It supports two types of quantization: +** *IVF Scalar Quantization (SQ)* reduces each dimension of the vector independently. +It reduces the size of the vector stored in the index at the cost of some precision. +** *IVF Product Quantization (PQ)* \ No newline at end of file diff --git a/modules/vector-index/pages/use-vector-indexes.adoc b/modules/vector-index/pages/use-vector-indexes.adoc index 273e411bb..5fe3f8d26 100644 --- a/modules/vector-index/pages/use-vector-indexes.adoc +++ b/modules/vector-index/pages/use-vector-indexes.adoc @@ -35,79 +35,113 @@ The models take into account the context around each potion of the text when gen This context is what captures the semantic meaning of the text and embeds it in the vector's dimensions. You can only compare the similarity of vectors when the same model generated them. -For example, you cannot find the similarity of two pieces of text if the vector for one was generated by Word2Vec and the other was generated by GloVe. +For example, you cannot find the similarity of two pieces of text if you generated one text's vector using Word2Vec and you used GloVe for the other. Couchbase {product-name} does not implement any embedding models. -To store vectors into your database, you must use external embedding models to generate vectors for your data. +You must use external embedding models to generate them. A common method of embedding vectors in your database is to call the https://openai.com/index/introducing-text-and-code-embeddings/[OpenAI Embedding API^] to generate vectors for your data. +You then store the vector as an attribute in your database. -=== Comparing Vectors +=== Vector Similarity -Once complex data embedded in your database as a vector, you can find data has a similar meaning by locating similar vectors. -A vector database such as Couchbase {product-name} can help with this task by indexing vectors in a way that makes finding similar vectors faster. +Once you have embedded complex data as a vector in your database, you find data with a similar meaning by locating similar vectors. +Several algorithms exist that you can use to find similar vectors. +They're also called distance functions, as they determine the distance between vectors in the vector space. +These algorithms are broken into two categories: -Several algorithms exist that you can use to compare vectors. -For example, -When choosing an algorithm, you often have to balance accuracy for speed. -Couchbase {product-name} supports several different comparison algorithms, such as +* *K-Nearest Neighbor (KNN)* methods use precise algorithms to determine the distance between two vectors. +This precision comes at a higher computational cost. +They are best used with smaller vector datasets and when precision is more important than computational resource use. +* *Approximate Nearest Neighbor (ANN)* uses methods that approximate the distance between two vectors. +They use less computational power, but at the cost of less precise results. +These methods are not guaranteed to return the closest matches to a particular vector. +Use one of these methods when limiting computing resource use is more important than precise results, especially with a large dataset. + +[#quantize] === Reducing Vector Complexity The number of dimensions in a vector can vary. A vector that represents highly complex data such as images can contain several thousand dimensions. -Simpler data, such as text, can still have hundreds of dimensions. +Less complex data, such as text, can still have hundreds to over a thousand dimensions. When you execute a query to find similar vectors, this large number of dimensions can make the query computationally expensive. -A search for similar raw vectors in an index would require comparing hundreds or thousands of values for each index entry. - -You can use several techniques to reduce the overhead of searching for similar vectors. +A search for similar raw vectors in an index requires comparing hundreds or thousands of values for each index entry. -* Partitioning groups vectors together based on similarity. -When searching for vectors that are similar to a value, you only need to search the relevant groups. +Several techniques (collectively known as quantization) can reduce the size of vectors, making them faster to process. +This reduction in space comes at the cost of lower precision. -* Quantization reduces the space taken by a vector by lowering its precision. -It maps each vector to the closest centroid which is vector contained in a compiled list of representative vectors called a codebook. -Instead of storing the full original vector, this technique stores just the index of the centroid in the codebook. +A technique called Product Quantization (PQ) reduces the size of the vectors by finding representative sub-vectors (portions of the full vector), called centroids, in the dataset's vector space. +It saves the centroids in a list called a codebook. +It then breaks each vector in the dataset into sub-vectors and maps these portions to the closest centroid in the codebook. +Instead of storing the full original vector, this technique stores just the indexes of these centroids in the codebook instead of the full vector value. It reduces the storage size without altering the dimensionality of the vector. -This storage reduction makes vector comparisons faster, because searches only compare the codebook index values instead of the full vectors. -For large amounts of complex data, you often use multiple techniques. +Another technique, Scalar Quantization reduces the size of a vector by mapping its floating point dimensions to a smaller data type, such as an integer. +In doing so, it does lose accuracy. +However, it makes the vector computationally easier to process. +And the process of quantization is faster than PQ, because it does not need to build a codebook. -Some types of Couchbase {product-name} indexes can perform quantization and partitioning on your vectors. +Some types of Couchbase {product-name} indexes perform quantization on your vectors to improve performance and reduce storage requirements. == Vectors in Couchbase {product-name} Indexes -To use vectors in Couchbase {product-name} queries, you store them in attributes in your documents and then add those attributes to an index. +To use vectors in Couchbase {product-name} queries and searches, you store them in attributes in your documents and then add those attributes to an index. Couchbase {product-name} supports vectors in the following index types: * Vector Indexes are specifically designed for vector searches. They can index billions of documents. -Most of the Vector Index is stored in a highly optimized format on disk. -Use this type of index when you want to query multiple vector values with a low memory footprint. +Most of the Vector Index resides in a highly optimized format on disk. +Use this type of index when you want to primarily query vector values with a low memory footprint. +They excel at traditional vector similarity and semantic searches. This index offers high accuracy even for vectors with a large number of dimensions. * Global Secondary Indexes (GSI) can be extended with a single vector column. -Adding a vector to a GSI index is useful when your queries combine a single vector value with standard scalar attributes. -The scalar attributes in a query reduce the number of vectors the Couchbase {product-name} has to compare to find similar vectors. +Adding a vector to a GSI is useful when your queries combine a single vector value with standard scalar attributes. +The scalar attributes in a query reduce the number of vectors the Couchbase {product-name} has to scan to find similar vectors. Use GSI indexes with a vector column when you want to perform hybrid searches of documents using both scalars and a vector. +They work well for cases where your queries are highly selective---returning a small number of results from a large dataset. They consume a moderate amount of memory and can index billions of documents. -When querying, the scalar attributes in the query limit the number of vectors that the query has to compare. * A Search index used for Full-Text Search can have an added vector attribute, -These indexes can index millions of documents. -The search results combine the scores of full text search and the semantic meanings of the vector search to give you hybrid results. +The search results combine keyword matching of Full-Text Search with the semantic meaning matching of vectors to give you hybrid results. Use Search indexes with a vector attribute when you want to query based on keywords, geospacial data, and a vector value. +These indexes can index millions of documents. + == Uses for Vectors in Couchbase {product-name} Indexes Here's some ways you can use vector indexes in your applications: -* Improve your application's search ability by querying not just for values data, but also based on similar content. +* Improve your application's search ability by querying not just for discrete values, but also based on similar content. For example, suppose your application is a product catalog. Using a GSI index extended with a vector column, it could find similar products based not just on attributes (such as color or size) but also the similarity of the product's description and customer reviews. -* Create a customized chatbot based on your own data by implementing a Retrieval-Augmented Generation (RAG) workflow. -When a user enters a question, convert it to a vector using the same embedding model you used to embed vectors into your index. -Perform a query using the vector index to find relevant documents in your database. -Then pass the user's question and the relevant documents to a Large Language Model to generate a final response for the user. +* Create a customized chatbot based on your own data by implementing a Retrieval-Augmented Generation (RAG) workflow using a Vector Index. +When a user enters a question, convert it to a vector using the same embedding model you used to embed vectors into your database. +Perform a query using a Vector Index to find relevant documents in your database. +Then pass the user's question and the relevant documents to a Large Language Model (LLM) to generate a final response for the user. + +== Application Workflow with Vector Indexes + +No matter which type of Couchbase {product-name} index you use, the workflow for your application to use them is similar, as shown in the following diagram. + +[plantuml,ai-app-workflow,svg] +.... +include::vector-index:partial$ai-app-workflow.puml[] +.... + +. Your application often needs to load or update data that contains one or more attributes that have embedded vectors in Couchbase {product-name}. +Before it can load the data, your application calls an embedding model to create vectors for these attributes. + +. The application then sends the data including the embedded vector to Couchbase {product-name} for storage. +The Data Service handles creating or updating a document in a bucket. + +. The addition or update of data in an indexed collection causes the Index Service to update the index. + +. When your application needs to perform a query or search that includes a vector, it uses the embedding model to generate a vector for the search value. +It then passes this vector as part of the search request or query. + +. Depending if the application is performing a search or a query, the Search Service or Query Service processes the request using the appropriate index +. The Search or Query Service returns any results to your application. diff --git a/modules/vector-index/partials/ai-app-workflow.puml b/modules/vector-index/partials/ai-app-workflow.puml new file mode 100644 index 000000000..3d8d54dae --- /dev/null +++ b/modules/vector-index/partials/ai-app-workflow.puml @@ -0,0 +1,96 @@ +@startuml ai-app-workflow + +!pragma layout smetana +!include +!include +!include +!include +!include +!include +!include +!include +!include +sprite Couchbase + + + +'title: Application Workflow with Vector Indexes + +skinparam defaultTextAlignment center + +skinparam linetype ortho + +top to bottom direction + + + frame "Your Application" as APP { + card DL [ + Data + Loading + ] + card EM [ + Embedding + Models + ] + card SE [ + Search & Query Logic + ] + + DL --> EM : <$ma_numeric_1_box{scale=0.4}>Complex\nData + EM --> DL : Vectors + SE --> EM : <$ma_numeric_4_box{scale=0.4}>Complex\nData + EM --> SE : Vectors + + } + + frame "<$Couchbase{scale=0.15}> Couchbase Cluster" as CC { + database DS [ + <$Couchbase{scale=0.15,color=red}> + .. + Data + .. + Service + .. + ] + rectangle " <$Couchbase{scale=0.15}> Index Service" as IS { + card GSI [ + GSI with + Vector + Column + ] + card VI [ + Vector + Index + ] + } + rectangle " <$Couchbase{scale=0.15}> Search Service" as SSERV { + card SI [ + Search + Index + w/ Vector + ] + } + + rectangle "<$Couchbase{scale=0.15}> Query Service" as QS { + + } + + } + + +DL ----> DS : <$ma_numeric_2_box{scale=0.4}> Data &\nVectors +DS --> GSI : Data &\nVectors +DS --> VI : Data &\nVectors +DS --> SI : <$ma_numeric_3_box{scale=0.4}>Data &\nVectors + +QS <--> IS :Index\nScans + + +SE ----> QS : <$ma_numeric_5_box{scale=0.4}>Queries +SE --------> SSERV : <$ma_numeric_5_box{scale=0.4}>Searches + +QS ----> SE :<$ma_numeric_6_box{scale=0.4}> Results +SSERV ---------> SE :<$ma_numeric_6_box{scale=0.4}> Results + +@enduml diff --git a/modules/vector-index/partials/nav.adoc b/modules/vector-index/partials/nav.adoc index b55ee4b61..bd38107c9 100644 --- a/modules/vector-index/partials/nav.adoc +++ b/modules/vector-index/partials/nav.adoc @@ -1 +1,2 @@ * xref:7.7@server:vector-index:use-vector-indexes.adoc[] +** xref:7.7@server:vector-index:gsi-with-vector.adoc[] From 4d84c144ab5fe5b9b642d8bac1c57ebbb8f5e524 Mon Sep 17 00:00:00 2001 From: Gary Gray <137797428+ggray-cb@users.noreply.github.com> Date: Thu, 10 Oct 2024 16:56:53 -0400 Subject: [PATCH 03/41] In-progress checkin. * Edits to the overview. * More work on the GSI topic * Changed link in the download partial because the old one only pointed to the SDK. --- .../vector-index/pages/gsi-with-vector.adoc | 171 ++++++++++++++++-- .../pages/use-vector-indexes.adoc | 66 ++++--- .../partials/download-sample-partial.adoc | 3 +- 3 files changed, 202 insertions(+), 38 deletions(-) diff --git a/modules/vector-index/pages/gsi-with-vector.adoc b/modules/vector-index/pages/gsi-with-vector.adoc index c06a75a70..139a00647 100644 --- a/modules/vector-index/pages/gsi-with-vector.adoc +++ b/modules/vector-index/pages/gsi-with-vector.adoc @@ -9,14 +9,15 @@ The added vector column lets your application perform a hybrid query using both the index's scalar. array, and object index entries plus a vector value. See xref:learn:services-and-indexes/indexes/indexes.adoc[] for an overview of GSI and other indexes. -== How the GSI's Column Works +== How the GSI's Vector Column Works You can add a single vector column to a GSI to enable semantic and similarity searches within your {sqlpp} queries. -When creating the index, you set the type of the attribute containing the embedded vector to `VECTOR`. +When creating the index, you use a `VECTOR` key attribute to designate the attribute that contains the embedded vectors. In the process of creating the index, the Index Service quantizes the data in the attribute to make it easier to scan and process. For more information about quantization, see xref:use-vector-indexes.adoc#quantize[Reducing Vector Complexity]. -When your query uses a GSI containing a vector column, the Query Service uses any non-vector predicates in the query to filter index entries before it performs an IndexScan for relevant vectors. +When your query contains a embedded vector, the Query Service uses any non-vector predicates in the query to filter index entries. +Then it performs an index scan on the remaining index entries, using the similarity function you specify in the query to locate similar vectors. This behavior reduces the number of vector similarity comparisons the Query Service must do to find similar vectors. @@ -28,18 +29,162 @@ For more information about how to deploy a new node and Services on your databas * You must have a bucket with scopes and collections in your database. For more information about how to create a bucket, see xref:manage:manage-buckets/create-bucket.adoc[]. -* You have documents in a keyspace inside your bucket that contain a vector embedding. +* Your account must have the xref:learn:security:roles.adoc#query-manage-index[Query Manage Index] role to be able to create an index. + +* You have documents in a collection that contain one or more vector embeddings. +You can add a single vector to a GSI index. +If your documents contain multiple embedded vectors, you can create multiple indexes---one for each vector attribute. ++ Embeddings can be an array of floats or a base64 encoded string. +Couchbase {product-name} does not embed vectors itself. +You must use an external embedding model to embed vectors into your data and add them to your documents. ++ +[TIP] +-- +include::vector-search:partial$download-sample-partial.adoc[] +-- + +* You must know the number of dimensions the vector contains. +The embedding model you use to embed the vectors determines this value for you. +For example, OpenAI API's `text-embedding-ada-002` embedding model that was used for the sample data creates vectors that have 1536 dimensions. + +You also have several options to choose before you create a GSI that has a vector column: + + +* The type of quantization you want to use when storing the vector in you your index. +GSI vector columns support two types of quantization: Scalar Quantization (SQ) and Product Quantization (PQ). +See xref:vector-index:use-vector-indexes.adoc#quantize[Reducing Vector Size] for more information about quantization. ++ +In addition to the quantization type, you can also supply a value that affects the quantization: ++ +** For SQ, the value sets the data type and number of bits that represent a dimension. For example, `SQ8` uses 8 bits to represent a dimension. `SQfp16` uses a 16-bit floating point value to represent a dimension. +** For PQ, the value sets the number of subquantizers and the number of bits each quantizers uses. For example `PQ8x8` uses 8 subquantizer each of which uses 8 bits. `PQ32x8` uses thirty two quantizers with 8 bits per quantizer. +* Optionally, choose the number of centroids to use if the quantization uses centroids. + +* The proximity function to use when generating the index. +For the best results, use the same proximity function used to embed the + +== Create a GSI with a Vector Column + +Creating a GSI with a vector column is similar to creating a non-vector GSI index. +In the `CREATE INDEX` statement to create the GSI, add the `VECTOR` lead key attribute after the vector's to declare that the attribute contains an embedded vector. + +You must also use the `WITH` clause to specify some additional information for the vector column: + +* `dimension` in an integer value that sets the number of dimensions in the vector. +* `similarity` is a string that sets the distance function to use when comparing vectors during index creation. +For the highest accuracy, use the distance function you plan to use when querying or searching vector data. +* `description` is a string that sets the number of centroids and the quantization to use when creating the index. +The format for this string is: ++ +[source,sqlpp] +---- +'IVF,[PQ|SQ]' +---- + +// Note: I originally thought that the similarity function had to match the function used to embed the vectors, but +// embedding doesn't require a distance function? But there was a reference to keeping the function here and in the queries +// the same, so will mention that later. + +[#examples] +=== Examples + +The following examples show you how to create two Global Secondary Indexes with a vector column using the sample data. +They both use the data from the `color_data_2vectors.zip` file mentioned previously. +The data in `rgb.json` file looks like this: + +[source,json] +---- +[ + { + "id": "#FFEFD5", + "color": "papaya whip", + "brightness": 240.82, + "colorvect_l2": [ + 255, + 239, + 213 + ], + "wheel_pos": "other", + "verbs": [ + "soften", + "mellow", + "lighten" + ], + "description": "Papaya whip is a soft and mellow color that can be described as a light shade of peach or coral. It has a calming and soothing effect, similar to the tropical fruit it is named after. This color is perfect for creating a warm and inviting atmosphere, and it pairs well with other pastel shades or neutral tones. Papaya whip is a versatile color that can be used in both fashion and interior design, adding a touch of elegance and sophistication to any space.", + "embedding_model": "text-embedding-ada-002-v2", + "embedding_vector_dot": [ + -0.014644118957221508, + 0.017003899440169334, + -0.013450744561851025, + 0.0021356006618589163, + 0.006283756345510483, + 0.01162360142916441, + . . . + ] + } + . . . +] +---- + +==== Index the RGB Values + +The `rgb.json` file's `colorvect_l2` attribute defines an array containing the RGB values for the entry's color. +While this technically is not an embedded vector, you can still create a vector index column for this array. +The following example creates a GSI for this attribute as an embedded vector as well as the color's name and brightness. + +[source,sqlpp] +---- +CREATE INDEX `color_vectors_idx` ON `vector-sample`.`colors`.`rgb` + (`colorvect_l2` VECTOR, color, brightness) + WITH { "dimension":3 , "similarity":"L2", "description":"IVF,SQ8"}; +---- + +In this example: + +* The number of dimensions is 3, because there are three values in the array containing the RGB value. +* The similarity function is `L2`. +This is a slower, but more accurate function that other options. +* The description sets the index column to use SQ quantization, reducing dimension values to an 8-bit value. + +The result of running example is: + +[source,json] +---- +[ + { + "id": "f572fa0b1c7358ee", + "name": "color_vectors_idx", + "state": "online" + } +] +---- + +==== Create a GSI Using the Embedded Vectors + +The `embedding_vector_dot` attribute contains the embedded vectors for the text in the `description` attribute. +The data sample shown in <<#examples>> truncated this attribute to several values. +The embedded vector contains 1536 dimensions. + +The following example creates a GSI that indexes the embedded vectors in the `embedding_vector_dot` as well as indexing the scalar `color` that contains the color's name and `brightness.` -* Your account has the xref:learn:security:roles.adoc#query-manage-index[Query Manage Index] role. +[source,sqlpp] +---- +CREATE INDEX `color_desc_idx` ON `vector-sample`.`colors`.`rgb` + (`embedding_vector_dot` VECTOR, color, brightness) + WITH { "dimension":1536, "similarity":"l2", "description":" IVF16,SQ8" } +---- -== Planning a GSI Extended with a Vector Column +The response: -Before you create a GSI with a vector column, you must make several decisions: +[source, json] +---- +[ + { + "id": "c965205718c3e4c2", + "name": "color_desc_idx", + "state": "online" + } +] +---- -* The type of quantization to use when storing the vector in you your index. -GSI always uses Inverted File (IVF) indexing with a form of quantization for its vector column. -It supports two types of quantization: -** *IVF Scalar Quantization (SQ)* reduces each dimension of the vector independently. -It reduces the size of the vector stored in the index at the cost of some precision. -** *IVF Product Quantization (PQ)* \ No newline at end of file diff --git a/modules/vector-index/pages/use-vector-indexes.adoc b/modules/vector-index/pages/use-vector-indexes.adoc index 5fe3f8d26..d4a2c107a 100644 --- a/modules/vector-index/pages/use-vector-indexes.adoc +++ b/modules/vector-index/pages/use-vector-indexes.adoc @@ -14,9 +14,9 @@ You can then find relevant data by executing queries on the vector attributes, w Vectors are a numerical representation of complex data such as text, images, or audio. They distill this complex data into an array of floating-point values called dimensions. -These dimensions capture features of the data in a way that makes the data easy to compare. +These dimensions capture features of the data in a way that makes them easy to compare mathematically. Similar data, such as text about the same topic or images of a similar subject, have similar vectors. -These vectors are close together the multi-dimensional space formed by all of the vectors in the dataset. +Similar vectors are close together the multi-dimensional space formed by all of the vectors in the dataset. Vectors for dissimilar data (for example, articles discussing two different topics) have vectors that are further apart in this multi-dimensional space. By comparing two vectors, you can find the similarity between two pieces of data. @@ -24,7 +24,7 @@ This similarity goes beyond just finding parts of the data that's identical (for The vectors represent features such as the semantic meaning of text rather than just superficial similarities. In Couchbase {product-name}, you can use vectors to find documents that are similar to an existing document or query values. -By searching your database for similar vectors, you can identify data that's semantically similar to your query value. +By searching your database for similar vectors, you can identify data that's semantically similar to a value. === Embedding Vectors @@ -34,7 +34,7 @@ For example, to generate vectors from text, you can use a use models such as htt The models take into account the context around each potion of the text when generating a vector. This context is what captures the semantic meaning of the text and embeds it in the vector's dimensions. -You can only compare the similarity of vectors when the same model generated them. +You can only compare the similarity of vectors generated by the same model. For example, you cannot find the similarity of two pieces of text if you generated one text's vector using Word2Vec and you used GloVe for the other. Couchbase {product-name} does not implement any embedding models. @@ -44,14 +44,14 @@ You then store the vector as an attribute in your database. === Vector Similarity -Once you have embedded complex data as a vector in your database, you find data with a similar meaning by locating similar vectors. +Once you have embedded a vector in your database, you find data with a similar meaning by locating similar vectors. Several algorithms exist that you can use to find similar vectors. They're also called distance functions, as they determine the distance between vectors in the vector space. These algorithms are broken into two categories: * *K-Nearest Neighbor (KNN)* methods use precise algorithms to determine the distance between two vectors. This precision comes at a higher computational cost. -They are best used with smaller vector datasets and when precision is more important than computational resource use. +They're best used with smaller vector datasets and when precision is more important than computational resource use. * *Approximate Nearest Neighbor (ANN)* uses methods that approximate the distance between two vectors. They use less computational power, but at the cost of less precise results. @@ -59,29 +59,47 @@ These methods are not guaranteed to return the closest matches to a particular v Use one of these methods when limiting computing resource use is more important than precise results, especially with a large dataset. [#quantize] -=== Reducing Vector Complexity +=== Reducing Vector Size The number of dimensions in a vector can vary. A vector that represents highly complex data such as images can contain several thousand dimensions. -Less complex data, such as text, can still have hundreds to over a thousand dimensions. +Less complex data, such as text, can still have hundreds to thousands of dimensions. When you execute a query to find similar vectors, this large number of dimensions can make the query computationally expensive. A search for similar raw vectors in an index requires comparing hundreds or thousands of values for each index entry. -Several techniques (collectively known as quantization) can reduce the size of vectors, making them faster to process. -This reduction in space comes at the cost of lower precision. - -A technique called Product Quantization (PQ) reduces the size of the vectors by finding representative sub-vectors (portions of the full vector), called centroids, in the dataset's vector space. -It saves the centroids in a list called a codebook. -It then breaks each vector in the dataset into sub-vectors and maps these portions to the closest centroid in the codebook. -Instead of storing the full original vector, this technique stores just the indexes of these centroids in the codebook instead of the full vector value. +Several techniques, known as quantization, can reduce the size of vectors, making them faster to process. +This reduction in space can come at the cost of lower precision. +Couchbase {product-name} can use the following two forms of quantization for some indexes: + +Product Quantization (PQ):: +PQ reduces the size of the vectors by: ++ +-- +. Grouping their dimensions into sub-vectors. +. Sampling the vector dataset to find representative values called centroids. +. Saving the centroids in a list called a codebook. +. Mapping each vector's sub-vectors to the closest centroid in the codebook. +-- ++ +Instead of storing the full original vector, PQ stores just the codebook's index value of the centroid. ++ It reduces the storage size without altering the dimensionality of the vector. - -Another technique, Scalar Quantization reduces the size of a vector by mapping its floating point dimensions to a smaller data type, such as an integer. -In doing so, it does lose accuracy. +With less data to compare, finding similar vectors is less computationally expensive. +However, it retains the accuracy of the original vector values. +This method is best suited for large datasets where you want accurate semantic and similarity results. ++ +One issue with PQ is that as you add new vectors to the dataset, the initially chosen centroids may no longer be representative. +This skew can mean that new vectors are poorly fitted to centroids which can result in less accurate quantization. +The loss of quantization accuracy can result in less accurate similarity comparisons and semantic searches. + +Scalar Quantization (SQ):: +SQ reduces the size of a vector by mapping its floating point dimensions to a smaller data type, such as an integer. +This mapping loses some accuracy. However, it makes the vector computationally easier to process. -And the process of quantization is faster than PQ, because it does not need to build a codebook. +This process of quantization is faster than PQ, because it does not need to build a codebook. +Also, because it does not rely on a sampling od data, it does not have the same potential loss of accuracy as PQ. -Some types of Couchbase {product-name} indexes perform quantization on your vectors to improve performance and reduce storage requirements. +Some types of Couchbase {product-name} indexes use one of these forms of quantization on your vectors to improve performance and reduce storage requirements. == Vectors in Couchbase {product-name} Indexes @@ -123,18 +141,18 @@ Then pass the user's question and the relevant documents to a Large Language Mod == Application Workflow with Vector Indexes -No matter which type of Couchbase {product-name} index you use, the workflow for your application to use them is similar, as shown in the following diagram. +No matter which type of Couchbase {product-name} index you add vectors to, the workflow for your application to use them is similar. The following diagram shows a typical workflow. [plantuml,ai-app-workflow,svg] .... include::vector-index:partial$ai-app-workflow.puml[] .... -. Your application often needs to load or update data that contains one or more attributes that have embedded vectors in Couchbase {product-name}. -Before it can load the data, your application calls an embedding model to create vectors for these attributes. +. Your application may need to load or update data that contains one or more attributes that have embedded vectors in Couchbase {product-name}. +Before it can load the data into a Couchbase collection, it calls an embedding model to create vectors for these attributes. . The application then sends the data including the embedded vector to Couchbase {product-name} for storage. -The Data Service handles creating or updating a document in a bucket. +The Data Service handles creating or updating a document in a collection. . The addition or update of data in an indexed collection causes the Index Service to update the index. diff --git a/modules/vector-search/partials/download-sample-partial.adoc b/modules/vector-search/partials/download-sample-partial.adoc index 1d5692ec9..e258c4d35 100644 --- a/modules/vector-search/partials/download-sample-partial.adoc +++ b/modules/vector-search/partials/download-sample-partial.adoc @@ -3,7 +3,8 @@ You can download a sample dataset to use with the procedure or examples on this https://cbc-remote-execution-examples-prod.s3.amazonaws.com/color_data_2vectors.zip[Download color_data_2vectors.zip] -To get the best results with using the sample data with the examples in this documentation, xref:guides:import.adoc[import the sample files] from the dataset into your database with the following settings: +To get the best results with using the sample data with the examples in this documentation, +xref:guides:load.adoc[import the sample files] from the dataset into your database with the following settings: * Use a bucket called `vector-sample`. * Use a scope called `color`. From fb75cd326608a72d3462fcf7ee873a17a0bdadc3 Mon Sep 17 00:00:00 2001 From: Gary Gray <137797428+ggray-cb@users.noreply.github.com> Date: Fri, 11 Oct 2024 17:13:47 -0400 Subject: [PATCH 04/41] Working on examples. Moved some to their own example file. --- .../examples/gsi-vector-idx-examples.sqlpp | 1573 +++++++++++++++++ .../vector-index/pages/gsi-with-vector.adoc | 31 +- 2 files changed, 1600 insertions(+), 4 deletions(-) create mode 100644 modules/vector-index/examples/gsi-vector-idx-examples.sqlpp diff --git a/modules/vector-index/examples/gsi-vector-idx-examples.sqlpp b/modules/vector-index/examples/gsi-vector-idx-examples.sqlpp new file mode 100644 index 000000000..6937e8cd6 --- /dev/null +++ b/modules/vector-index/examples/gsi-vector-idx-examples.sqlpp @@ -0,0 +1,1573 @@ +/* tag::create-rgb-idx[] */ +CREATE INDEX `color_vectors_idx` ON `vector-sample`.`colors`.`rgb` + (`colorvect_l2` VECTOR, color, brightness) + WITH { "dimension":3 , "similarity":"L2", "description":"IVF,SQ8"}; +/* end::create-rgb-idx[] */ + +/* tag::create-vectors-idx[] */ +CREATE INDEX `color_vectors_idx` ON `vector-sample`.`colors`.`rgb` + (`colorvect_l2` VECTOR, color, brightness) + WITH { "dimension":3, "similarity":"DOT", "description":" IVF16,SQ8" } +/* end::create-rgb-idx[] */ + +/* tag::query-rgb-idx[] */ +SELECT b.color, b.colorvect_l2, b.brightness from `rgb` AS b +WHERE b.brightness > 128 +ORDER BY APPROX_VECTOR_DISTANCE(b.colorvect_l2,[128,128,128],"L2") +LIMIT 5; +/* end::query-rgb-idx[] */ + +/* tag::query-vectors-idx-subquery[] */ +WITH question_vec AS ( + SELECT RAW couchbase_search_query.knn[0].vector + from `vector-sample`.`colors`.`rgb-questions` + WHERE meta().id = "#FFEFD5") +SELECT b.color, b.description from `rgb` AS b +order by VECTOR_DISTANCE(b.embedding_vector_dot, +question_vec[0], "DOT") LIMIT 3; +/* end::query-vectors-idx-subquery[] */ + +/* tag::query-vectors-idx-whole[] */ +SELECT b.color, b.description from `rgb` AS b +order by VECTOR_DISTANCE(b.embedding_vector_dot, +[ + 0.005115953739732504, + 0.004331615287810564, + 0.014279481954872608, + 0.000619320897385478, +/* end::query-vectors-idx-full-list[] */ + 0.006700769532471895, + 0.018410978838801384, + -0.010367471724748611, + -0.019805356860160828, + 0.013059400022029877, + -0.011271236464381218, + -0.011251870542764664, + -0.004915834404528141, + -0.0031744735315442085, + 0.00843728892505169, + -0.01706824265420437, + 0.013362806290388107, + 0.04694411903619766, + 0.011258325539529324, + 0.01298193447291851, + -0.01080644316971302, + -0.01744265854358673, + 0.0044155362993478775, + -0.00742378132417798, + 0.014214927330613136, + -0.01248486340045929, + 0.0009481459856033325, + 0.027293693274259567, + -0.029204510152339935, + 0.006355402525514364, + 0.016254853457212448, + 0.02933361940085888, + -0.017352283000946045, + 0.007236572913825512, + -0.017094064503908157, + 0.002293302910402417, + -0.018139848485589027, + 0.007811109069734812, + 0.015028315596282482, + -0.008785883896052837, + -0.013453182764351368, + -8.422360406257212e-05, + 0.010896819643676281, + 0.002246500924229622, + -0.010586957447230816, + -0.0011482653208076954, + -0.003537593176588416, + 0.02017977461218834, + -0.013491915538907051, + -0.00977356918156147, + 0.01215563528239727, + 0.032122381031513214, + 0.02827492356300354, + 0.002995334332808852, + -0.027396980673074722, + 0.004583378322422504, + 0.0007577098440378904, + 0.00016683334251865745, + 0.025731472298502922, + 0.006158510688692331, + -0.008288813754916191, + 0.00016885067452676594, + 0.01956005021929741, + -0.01309813279658556, + 0.009934956207871437, + -0.007920851930975914, + 0.008721329271793365, + -0.032354775816202164, + -0.0031050771940499544, + -0.0049997554160654545, + 0.029178688302636147, + 0.0075980788096785545, + 0.024995548650622368, + 0.018165670335292816, + -0.008463110774755478, + 0.025292500853538513, + -0.0031518794130533934, + -0.01706824265420437, + -0.00925713311880827, + -0.013375717215240002, + 0.0066749476827681065, + 0.015144513919949532, + -0.0011805426329374313, + -0.037312570959329605, + 0.015092870220541954, + 0.01786871999502182, + 0.015002493746578693, + -0.020631656050682068, + 0.0021415995433926582, + -0.004912606440484524, + -0.004880329128354788, + -0.012523596175014973, + 0.024246715009212494, + 0.02413051761686802, + 0.0008162125013768673, + -0.02077367715537548, + 0.005419360473752022, + 0.008508299477398396, + 0.010470759123563766, + 0.0004575308703351766, + -0.01443441305309534, + -0.00852766539901495, + 0.017326461151242256, + -0.03674449026584625, + -0.009579905308783054, + -0.018643373623490334, + -0.0009473390528000891, + 0.00832109060138464, + -0.0016057961620390415, + 0.023614080622792244, + -0.024272536858916283, + -0.042502760887145996, + 0.03207073733210564, + 0.009534717537462711, + -0.041082561016082764, + -0.010651512071490288, + -0.01997319981455803, + 0.016306497156620026, + 0.015648040920495987, + -0.00894081499427557, + -0.03473038598895073, + -0.00884398352354765, + 0.018010739237070084, + 0.019004879519343376, + -0.015970813110470772, + 0.01914690062403679, + 0.0008166159386746585, + -0.006232748739421368, + -0.033568404614925385, + -0.03416230529546738, + -0.02494390495121479, + 0.02163870818912983, + 0.01701659895479679, + -0.004396169912070036, + 0.003786128479987383, + -0.008372734300792217, + 0.014563522301614285, + -0.01029646210372448, + 0.005622707307338715, + 0.010270640254020691, + 0.0004607586015481502, + 0.032096557319164276, + 0.021096449345350266, + -0.00034355162642896175, + -0.007966040633618832, + -0.004928745329380035, + 0.02806834876537323, + 0.010528858751058578, + 0.013349895365536213, + -0.006629759445786476, + -0.01913398876786232, + 0.02205185778439045, + -0.015480197966098785, + 0.02580893784761429, + 0.013362806290388107, + 0.010244818404316902, + 0.024246715009212494, + -0.0043122489005327225, + 0.0009594430448487401, + -0.02948855049908161, + 0.005044943653047085, + -0.004499457310885191, + -0.010373927652835846, + 0.0007040488417260349, + 0.012032981030642986, + 0.02039925940334797, + 0.02788759581744671, + 0.01807529479265213, + 0.008695507422089577, + 0.0015170335536822677, + 0.02059292420744896, + -0.012291199527680874, + 0.02706129662692547, + -0.009663826785981655, + 0.01101301796734333, + -0.013336984440684319, + 0.025705650448799133, + 0.006765324156731367, + 0.007197840139269829, + 0.024156339466571808, + -0.012975478544831276, + -0.03098621778190136, + -0.004870646167546511, + -0.000659667537547648, + -0.01186513900756836, + -0.007849842309951782, + -0.005797004792839289, + 0.022310076281428337, + -0.02099316194653511, + 0.0013346667401492596, + -0.011600465513765812, + -0.002236817730590701, + 0.020825320854783058, + 0.0010651513002812862, + -0.022826513275504112, + -0.6420344114303589, + 8.150020585162565e-05, + -0.014214927330613136, + -0.015841703861951828, + 0.02079949900507927, + 0.020205596461892128, + 0.037544965744018555, + 0.012265377677977085, + 0.0005870435852557421, + -0.01665509305894375, + 0.005919658578932285, + 0.013349895365536213, + 0.016577627509832382, + -0.01664218120276928, + 0.0006382837891578674, + -0.013969619758427143, + -0.017326461151242256, + -0.00033669269760139287, + -0.013027122244238853, + 0.00042283275979571044, + -0.00431870436295867, + 0.02161288633942604, + -0.007572256959974766, + 0.007262394763529301, + 0.019469672814011574, + 0.01372431218624115, + 0.001147458446212113, + -0.013479004614055157, + 0.014279481954872608, + 0.043587278574705124, + -0.027138762176036835, + 0.015118692070245743, + 8.61400694702752e-05, + 0.00968319270759821, + 0.04738309234380722, + 0.01579006016254425, + -0.026544859632849693, + 0.03506607189774513, + -0.022348809987306595, + 0.05510382354259491, + -0.01931474171578884, + 0.011671475134789944, + 0.02081240899860859, + -0.03098621778190136, + 0.0003318511007819325, + 0.021574154496192932, + 0.024272536858916283, + -0.015854615718126297, + 0.028378210961818695, + -0.015467287041246891, + 0.019689159467816353, + 0.005471004173159599, + 0.014718453399837017, + 0.0048641907051205635, + 0.00894081499427557, + 0.010845175944268703, + 0.030056631192564964, + -0.016538893803954124, + 0.012317021377384663, + 0.009366875514388084, + -0.003025997895747423, + 0.0029791956767439842, + -0.01434403657913208, + -0.019185632467269897, + -0.014976671896874905, + 0.03465292230248451, + -0.013788866810500622, + -0.013091676868498325, + -0.0024353230837732553, + -0.028791360557079315, + -0.005522647872567177, + -0.008630952797830105, + -0.02286524698138237, + 0.009418519213795662, + 0.00011145758617203683, + -0.0103932935744524, + 0.012342843227088451, + 0.017584679648280144, + -0.008288813754916191, + 0.009754203259944916, + 0.0016525982646271586, + -0.00712683005258441, + -0.005467776209115982, + 0.0034956326708197594, + 0.0353759340941906, + 0.013324073515832424, + -0.03535011038184166, + -0.04258022829890251, + 0.01322078611701727, + 0.011193770915269852, + 0.023756099864840508, + 0.030934574082493782, + 0.0018236680189147592, + -0.0009667054400779307, + -0.012588150799274445, + 0.003983020316809416, + -0.02369154617190361, + -0.015234890393912792, + -0.026299552991986275, + -0.007107463665306568, + 0.00779174268245697, + -0.015389821492135525, + -0.012310566380620003, + 0.008262991905212402, + 0.02664814703166485, + -0.0017284499481320381, + -0.0297467689961195, + 0.022607028484344482, + 0.023575346916913986, + -0.017326461151242256, + 0.020115219056606293, + -0.026751434430480003, + 0.0026580365374684334, + 0.003090552520006895, + 0.03596983477473259, + -0.02451784536242485, + 0.02471150830388069, + -0.003347157035022974, + -0.007533524185419083, + -0.02556362934410572, + 0.02933361940085888, + -0.013298251666128635, + -0.014279481954872608, + 0.007507702335715294, + 0.017571767792105675, + 0.00280489819124341, + -0.008424378000199795, + -0.0010514333844184875, + -0.0030469780322164297, + -0.0012862507719546556, + 0.021161004900932312, + -0.0022755505051463842, + -0.0011644039768725634, + 0.0031744735315442085, + -0.00047205566079355776, + -0.014576433226466179, + 0.004460724536329508, + -0.010031787678599358, + 0.008256535977125168, + -0.04513658955693245, + -0.019288919866085052, + -0.013233697041869164, + 0.00965091586112976, + 0.0026709474623203278, + -0.021884016692638397, + -0.03516935929656029, + -0.03281956911087036, + 0.008663230575621128, + -0.038784414529800415, + -0.010322283953428268, + -0.016474340111017227, + -0.013788866810500622, + -0.022568294778466225, + 0.03183833882212639, + 0.025834759697318077, + -0.0028807499911636114, + -0.02100607380270958, + -0.02249082922935486, + -0.01434403657913208, + -0.007365682162344456, + 0.01994737796485424, + 0.02972094714641571, + -0.008837527595460415, + -0.009457251988351345, + -0.013595202937722206, + -0.04121166840195656, + -0.009605727158486843, + 0.013111043721437454, + -0.010877453722059727, + -0.023368772119283676, + 0.012420308776199818, + -0.012820547446608543, + -0.006842789705842733, + 0.012523596175014973, + -0.005935797467827797, + 0.013646846637129784, + -0.006868611555546522, + -0.021264292299747467, + -0.002252956386655569, + -0.007681999821215868, + 0.00020627219055313617, + 0.009089291095733643, + -0.005713083781301975, + -0.005212785676121712, + 0.03496278449892998, + 0.001072413637302816, + 0.022090591490268707, + 0.07266268134117126, + -0.02431127056479454, + 0.032974500209093094, + -0.0030485920142382383, + 0.009289409965276718, + -0.01660344935953617, + 0.001254780450835824, + -0.01340153906494379, + 0.01103238482028246, + 0.010199629701673985, + -0.0026919275987893343, + -0.012142724357545376, + -0.005038488190621138, + 0.031709231436252594, + 0.023562436923384666, + 0.011781218461692333, + -0.003963653929531574, + 0.016164477914571762, + -0.02034761570394039, + 0.016745468601584435, + 0.0006649125716648996, + 0.008069328032433987, + 0.022168057039380074, + -0.0036215141881257296, + -0.03199326992034912, + -0.008366279304027557, + -0.014576433226466179, + 0.006668492220342159, + 0.0007762692985124886, + 0.00029594259103760123, + 0.010864542797207832, + -0.0174555703997612, + 0.013349895365536213, + 0.017984917387366295, + 0.010993652045726776, + 0.01976662501692772, + -0.013956708833575249, + -0.00499007198959589, + 0.007546435110270977, + 0.014498967677354813, + -0.0032164340373128653, + -0.01974080316722393, + -0.03395573049783707, + -0.013853421434760094, + -0.0065393829718232155, + -0.005961619317531586, + 0.0028016704600304365, + -0.005122409202158451, + 0.005061082076281309, + 0.01603536866605282, + -0.024595310911536217, + 0.03449799120426178, + 0.008217803202569485, + 0.01891450397670269, + 0.031683407723903656, + 0.005170824937522411, + 0.006481283809989691, + 0.04433611407876015, + -0.02637701854109764, + 0.0172231737524271, + 0.005474231671541929, + 0.0028710667975246906, + 0.0050417156890034676, + -0.026351196691393852, + -0.007681999821215868, + -0.04808028042316437, + 0.009780025109648705, + 0.011619831435382366, + -0.013982530683279037, + 0.014576433226466179, + -0.0004478476766962558, + 0.020864052698016167, + 0.017545945942401886, + 0.02428544871509075, + -0.019043613225221634, + 0.009986599907279015, + -0.01952131651341915, + 0.00379258394241333, + 0.008004773408174515, + 0.004909378942102194, + 0.003116374369710684, + -0.018785394728183746, + -0.008095149882137775, + 0.008701963350176811, + -0.0237173680216074, + 0.009082835167646408, + -0.02453075535595417, + -0.0049674781039357185, + 0.0127753596752882, + -0.003941059578210115, + -0.018165670335292816, + -0.00499007198959589, + 0.00441230833530426, + -0.010193174704909325, + -0.032328955829143524, + 0.004309020936489105, + 0.0170553307980299, + -0.005080448463559151, + -0.018630463629961014, + -0.00671368045732379, + 0.030237384140491486, + -0.026958009228110313, + 0.0016606675926595926, + 0.024375824257731438, + 0.033800799399614334, + 0.022619938477873802, + -0.0027839180547744036, + -0.0024272536393254995, + -0.02493099495768547, + 0.017829986289143562, + 0.004564011935144663, + 0.010690244846045971, + -0.00247244187630713, + 0.006426412612199783, + -0.006271481513977051, + -0.024220893159508705, + 0.008295268751680851, + 0.02227134443819523, + 0.017300639301538467, + 0.002096411306411028, + -0.00018418239778839052, + 0.00420250603929162, + -0.019430940970778465, + -0.010774166323244572, + -0.011903871782124043, + 0.0039023268036544323, + -0.00925713311880827, + 0.009276499040424824, + 0.015118692070245743, + -0.016383962705731392, + -0.018359335139393806, + 0.042270366102457047, + -0.013582292012870312, + 0.0026806306559592485, + -0.011206681840121746, + -0.014821740798652172, + 0.007075186353176832, + 0.05422588065266609, + -0.006026173941791058, + -0.010412660427391529, + 0.0015331722097471356, + 0.019676247611641884, + 0.012058802880346775, + -0.021303024142980576, + -0.02076076529920101, + 0.00893435999751091, + 0.004357437137514353, + -0.0068105123937129974, + 0.003177701262757182, + -0.014770097099244595, + 0.008469566702842712, + 0.0034052561968564987, + 0.001760727260261774, + -0.0002231169055448845, + -0.02892046980559826, + -0.006868611555546522, + -0.028326567262411118, + -0.014369858428835869, + 0.014395680278539658, + -0.005064310040324926, + 0.015467287041246891, + -0.010787077248096466, + 0.010832265019416809, + 0.038242157548666, + 0.018785394728183746, + 0.006449006497859955, + -0.020463814958930016, + 0.014679720625281334, + 0.0031486516818404198, + -0.007694910746067762, + 0.001307231024838984, + -0.030237384140491486, + -0.003976564854383469, + -0.020902786403894424, + -0.005809915717691183, + -0.01404708530753851, + -0.003650563769042492, + -0.003025997895747423, + 0.015660950914025307, + -0.014176194556057453, + -0.0116262873634696, + 0.01331116259098053, + -0.010535313747823238, + -0.014085818082094193, + 0.003834544448181987, + -0.013956708833575249, + 0.01422783825546503, + 0.007656177971512079, + -0.0012346070725470781, + -0.0008440516539849341, + -0.006145599763840437, + 0.0010465917875990272, + 0.0094766179099679, + -0.023188019171357155, + -0.0028339477721601725, + 0.01321433112025261, + -0.019689159467816353, + -0.0012321863323450089, + -0.022335898131132126, + 0.0003241852391511202, + 0.008256535977125168, + -0.011613376438617706, + -0.04136659950017929, + 0.005361261311918497, + -0.038242157548666, + -0.01059341337531805, + -0.014576433226466179, + -0.005667895544320345, + -0.027319515123963356, + -0.012704349122941494, + 0.01828186959028244, + 0.02349788136780262, + 0.02330421842634678, + 0.007236572913825512, + 0.00861804187297821, + 0.01975371316075325, + 0.01621612161397934, + -0.0014678107108920813, + -0.009424974210560322, + -0.006681403145194054, + -0.018772482872009277, + -0.0005394345498643816, + -0.0009868787601590157, + 0.0320449136197567, + -0.015635129064321518, + -0.01580297201871872, + 0.010122164152562618, + 0.016177387908101082, + -0.013259518891572952, + 0.03413648530840874, + -0.021057717502117157, + -0.00473508145660162, + 0.018152760341763496, + 0.011000107042491436, + 0.015919169411063194, + -0.004273516125977039, + -0.027758486568927765, + 0.008914993144571781, + -0.026983831077814102, + -0.0003104673814959824, + -0.02206476964056492, + 0.012168546207249165, + -0.00358600914478302, + -0.009308775886893272, + 0.0029097995720803738, + -0.018979057669639587, + -0.007385048549622297, + 0.010464304126799107, + -0.005532330833375454, + 0.004405852872878313, + 0.023562436923384666, + -0.006629759445786476, + 0.007101008202880621, + -0.023536615073680878, + 0.030857108533382416, + -0.00613914430141449, + -0.028817182406783104, + 0.012213733978569508, + -0.05587847903370857, + 0.0013596817152574658, + -0.0006209347629919648, + -0.022168057039380074, + 0.0028807499911636114, + 0.006303758826106787, + -0.00539999408647418, + 0.00671368045732379, + -0.0013120726216584444, + 0.002383679384365678, + 0.013149776495993137, + -0.007772376295179129, + -0.022568294778466225, + -0.04898404702544212, + -0.004215416964143515, + 0.011019473895430565, + 0.016345230862498283, + -0.004915834404528141, + -0.020463814958930016, + -0.01891450397670269, + 0.03300032392144203, + -0.015209068544209003, + -0.02121264860033989, + -0.03568579629063606, + -0.030624711886048317, + 0.033129431307315826, + 0.0057485890574753284, + -0.009941411204636097, + 0.02680307812988758, + -0.026364106684923172, + -0.00288559147156775, + -0.013995441608130932, + 0.014369858428835869, + -7.84742078394629e-05, + -0.014447323977947235, + -0.03196744993329048, + -0.017804164439439774, + 0.018385156989097595, + -0.005532330833375454, + 0.01112921629101038, + 0.015480197966098785, + 0.032742105424404144, + 0.011000107042491436, + -0.017197351902723312, + -0.010212540626525879, + -0.015441465191543102, + 0.002488580532371998, + -0.01600954681634903, + 0.012859280221164227, + 0.02429835870862007, + 0.014692631550133228, + 0.00968319270759821, + 0.00819843728095293, + 0.03116697072982788, + 0.022297166287899017, + 0.008689052425324917, + -0.01892741397023201, + -0.008863349445164204, + -0.02413051761686802, + -0.014653898775577545, + 0.005671123508363962, + -0.009625094011425972, + -0.00072664296021685, + 0.02493099495768547, + 0.009786480106413364, + 0.0253828763961792, + 0.017106974497437477, + -0.009689648635685444, + 0.004954567179083824, + 0.029798412695527077, + 0.010244818404316902, + 0.024569489061832428, + -0.005290251225233078, + 0.01206525880843401, + -0.03989475592970848, + -0.032948680222034454, + 0.0032067508436739445, + -0.024827707558870316, + -0.007230117451399565, + 0.0014653898542746902, + 0.009005369618535042, + 0.011961971409618855, + -0.0028016704600304365, + 0.011903871782124043, + 0.022374631837010384, + 0.014279481954872608, + 0.002787145785987377, + 0.008256535977125168, + -0.007920851930975914, + -0.0590287446975708, + -0.008179070428013802, + -0.04596288874745369, + -0.04172810539603233, + 0.0019027474336326122, + 0.006784690544009209, + -0.038552019745111465, + 0.026570681482553482, + 0.010012421756982803, + -0.002772620879113674, + -0.008153248578310013, + -0.0035827814135700464, + 0.00415731780230999, + -0.020334705710411072, + 0.0441037155687809, + -0.004292882513254881, + -0.00043211248703300953, + -0.009115112945437431, + 0.001920499955303967, + -0.016074100509285927, + -0.011755396611988544, + 0.03496278449892998, + 0.019418029114603996, + -0.001509771216660738, + -0.020864052698016167, + 0.022710315883159637, + 0.005758272018283606, + -0.015015404671430588, + -0.009192578494548798, + 0.004983616527169943, + 0.040230438113212585, + 0.0032842163927853107, + -0.039817288517951965, + 0.030185740441083908, + -0.02413051761686802, + 0.03341347351670265, + 0.0032083645928651094, + -0.018036561086773872, + 0.016732558608055115, + -0.02183237299323082, + 0.0003052223182749003, + 0.022723225876688957, + -0.017106974497437477, + 0.022568294778466225, + -0.00087632896611467, + 0.014176194556057453, + -0.01289155799895525, + 0.008753607049584389, + -0.022193878889083862, + -0.004238010849803686, + -0.0060584512539207935, + 0.0023304217029362917, + 0.01770087704062462, + 0.003155107144266367, + 0.011581098660826683, + 0.014628076925873756, + 0.0070170871913433075, + 0.01621612161397934, + 0.011774762533605099, + 0.027810130268335342, + -0.010141531005501747, + 0.014318214729428291, + -0.013737223111093044, + 0.0001642108109081164, + 0.0021545104682445526, + -0.0005850262241438031, + 0.0009626707760617137, + -0.0011571416398510337, + -0.0033891175407916307, + -0.015919169411063194, + 0.03881023824214935, + -0.00852766539901495, + -0.0292819757014513, + 0.01413746178150177, + 0.001689717173576355, + 0.009986599907279015, + -0.030908752232789993, + -0.017326461151242256, + 0.02330421842634678, + 0.0007924079545773566, + -0.03119279257953167, + -0.020257240161299706, + 3.0058245101827197e-05, + 0.018578819930553436, + 0.001744588604196906, + -0.012471952475607395, + -0.005761499982327223, + -0.0022077681496739388, + -0.020915696397423744, + 0.03488531708717346, + -0.007688455283641815, + 0.010548224672675133, + -0.009818757884204388, + 0.012323477305471897, + -0.0036150587256997824, + -0.04596288874745369, + 0.026983831077814102, + -0.01952131651341915, + -0.035453397780656815, + -0.011807040311396122, + 0.01847553253173828, + 0.014240749180316925, + -0.009547628462314606, + -0.0049707056023180485, + 0.0062262932769954205, + 0.006449006497859955, + -0.006158510688692331, + 0.0026919275987893343, + -0.016913311555981636, + 0.012736626900732517, + -0.008146793581545353, + -0.01372431218624115, + 0.015518930740654469, + -0.006048767827451229, + -0.005877698305994272, + -0.031915806233882904, + -0.005909975618124008, + -0.007139740977436304, + -0.031244436278939247, + -0.003595692338421941, + -0.0068105123937129974, + 0.036873601377010345, + -0.007165562827140093, + -0.014150372706353664, + -0.015183246694505215, + 0.0006019718130119145, + -0.01622903160750866, + 0.01874666102230549, + 0.012020070105791092, + -0.01619029976427555, + -0.017403926700353622, + 0.029462728649377823, + 0.022180967032909393, + 0.0210189837962389, + -0.007572256959974766, + -0.01644851826131344, + -0.01825604774057865, + -0.018385156989097595, + -0.01466680970042944, + -0.00905055832117796, + -0.0055839745327830315, + 0.027371158823370934, + 0.02597677893936634, + -0.04059194400906563, + -0.030857108533382416, + 0.023781921714544296, + -0.023420415818691254, + -0.025834759697318077, + 0.016371052712202072, + 0.004722170531749725, + -0.0015210682759061456, + 0.01724899560213089, + -0.004993299953639507, + 0.018991969525814056, + 0.004809319041669369, + -0.01748139224946499, + -0.019237276166677475, + 0.0008916606893762946, + 0.012743081897497177, + -0.030934574082493782, + 0.03842290863394737, + -0.025615273043513298, + -0.03036649338901043, + -0.005680806469172239, + 0.01932765357196331, + -0.0033923452720046043, + 0.0026725612115114927, + 0.004583378322422504, + 0.010361016727983952, + 0.019882822409272194, + -0.004883557092398405, + 0.033129431307315826, + -0.0001690524077275768, + 0.003650563769042492, + 0.009011825546622276, + -0.020063575357198715, + -0.02286524698138237, + -0.02081240899860859, + 0.03661538287997246, + -0.036073122173547745, + 0.013750134035944939, + 0.023162197321653366, + 0.012846369296312332, + -0.026958009228110313, + -0.019392207264900208, + -0.006219837814569473, + 0.006013263016939163, + -0.019043613225221634, + -0.001880153315141797, + 0.003411711659282446, + -0.014305303804576397, + -0.008359823375940323, + -0.011897416785359383, + -0.015867525711655617, + -0.006100411526858807, + -0.025499075651168823, + -0.013995441608130932, + -0.0001231581118190661, + 0.021483777090907097, + -0.0021464412566274405, + -0.0072236619889736176, + -0.016525983810424805, + 0.016061190515756607, + -0.01829477958381176, + -0.018578819930553436, + -0.02680307812988758, + -0.02726787142455578, + -0.01600954681634903, + 0.028972113505005836, + 0.016371052712202072, + -0.014382769353687763, + 0.007843386381864548, + -0.014692631550133228, + -0.007055819965898991, + 0.0005442761466838419, + -0.0042799715884029865, + 0.005874470341950655, + -0.04758966714143753, + 0.010361016727983952, + 0.009818757884204388, + -0.02969512529671192, + -0.003356840228661895, + -0.003760306630283594, + 0.007772376295179129, + 0.01788162998855114, + 0.03176087513566017, + 0.22434021532535553, + 0.022206788882613182, + -0.0009489529184065759, + 0.039171744138002396, + 0.0189532358199358, + 0.022387541830539703, + 0.02620917558670044, + 0.022168057039380074, + -0.0061326888389885426, + 0.026570681482553482, + 0.0018317373469471931, + 0.016990777105093002, + 0.0008521209820173681, + 0.00717201828956604, + 0.008237170055508614, + -0.007778831757605076, + -0.04635021835565567, + -0.00758516788482666, + -0.02014104090631008, + 0.0025369965005666018, + 0.005935797467827797, + -0.024453289806842804, + -0.021767817437648773, + -0.008986003696918488, + 0.0469699427485466, + 0.013530648313462734, + -0.004231555387377739, + 0.011878049932420254, + 0.004512368235737085, + -0.006113322451710701, + -0.002269095042720437, + 0.006681403145194054, + 0.00701063172891736, + -0.0016316180117428303, + -0.02034761570394039, + -0.0013120726216584444, + -0.012181457132101059, + -0.031657587736845016, + 0.02450493350625038, + 0.022916890680789948, + -0.025938047096133232, + 0.006946077104657888, + -0.018436800688505173, + 0.0010780622251331806, + -0.02056710235774517, + 0.01331116259098053, + -0.025912225246429443, + -0.018139848485589027, + 0.030082453042268753, + 0.006636214908212423, + -0.018862860277295113, + -0.0018220541533082724, + 0.032922856509685516, + 0.027164584025740623, + 0.0049674781039357185, + 0.004890012554824352, + 0.013375717215240002, + 0.001705855829641223, + -0.0007004176150076091, + 0.022826513275504112, + -0.016525983810424805, + 0.019172722473740578, + -0.014602255076169968, + 0.027371158823370934, + -0.010109253227710724, + -0.009250677190721035, + -0.027319515123963356, + -0.0037570788990706205, + 0.015699684619903564, + -0.006100411526858807, + -9.284770203521475e-05, + -0.006997720804065466, + 0.0019172722240909934, + 0.02329130657017231, + -0.00461565563455224, + -0.013685579411685467, + 0.005170824937522411, + -0.0017203806200996041, + 0.011639198288321495, + 0.016964955255389214, + -0.008856894448399544, + -0.013788866810500622, + -0.022206788882613182, + 0.013027122244238853, + -0.008327546529471874, + -0.012026526033878326, + 0.00020344792574178427, + 0.00208027265034616, + 0.001817212556488812, + -0.00914738979190588, + 0.002096411306411028, + 0.024801885709166527, + -0.006571660283952951, + -0.006784690544009209, + 0.014279481954872608, + 0.014150372706353664, + 0.0026709474623203278, + 0.008559943176805973, + -0.009076380170881748, + 0.01402126345783472, + -0.0292819757014513, + -0.004083079751580954, + 0.020283062011003494, + 0.012194368056952953, + -0.01624194346368313, + 0.008689052425324917, + -0.011761851608753204, + 0.003563415026292205, + 0.04289009049534798, + -0.0017591133946552873, + -0.009747747331857681, + 0.00556138064712286, + 0.018656285479664803, + -0.014382769353687763, + -0.0028823637403547764, + -0.005170824937522411, + -0.0009061854798346758, + -0.016138656064867973, + 0.003221275517717004, + -0.00014050716708879918, + -0.007094552740454674, + -0.022180967032909393, + -0.03075382113456726, + 0.01372431218624115, + -0.017403926700353622, + -0.007966040633618832, + -0.03653791546821594, + 0.013052944093942642, + 0.020115219056606293, + -0.03119279257953167, + 0.00556138064712286, + -0.0019156583584845066, + 0.02409178391098976, + -0.03305196762084961, + -0.01537691056728363, + 0.016500161960721016, + 0.015854615718126297, + -0.014008352532982826, + 0.014537700451910496, + -0.018036561086773872, + -0.01507995929569006, + -0.03488531708717346, + 0.02494390495121479, + -0.013763044960796833, + 0.005593657959252596, + -0.030289027839899063, + -0.024788973852992058, + 0.003569870488718152, + -0.015893347561359406, + -0.031115327030420303, + 0.007966040633618832, + -0.0341106615960598, + -0.009812301956117153, + -0.014524789527058601, + 0.016461428254842758, + -0.0013120726216584444, + -0.003531137714162469, + 0.004305793438106775, + 0.023988496512174606, + 0.014886295422911644, + -0.023846477270126343, + 0.0060584512539207935, + 0.027319515123963356, + 0.008185526356101036, + -0.01665509305894375, + -0.011871594935655594, + -0.16247107088565826, + 0.04035954922437668, + 0.017003687098622322, + -0.0315801203250885, + 0.0046995761804282665, + 0.011096939444541931, + -0.007197840139269829, + 0.012000704184174538, + -0.010193174704909325, + 0.016099922358989716, + 0.016500161960721016, + 0.004973933566361666, + -0.01971498131752014, + -0.029798412695527077, + -0.01080644316971302, + -0.0011305127991363406, + -0.032509706914424896, + 0.009599272161722183, + 0.03225148841738701, + 0.0255507193505764, + 0.003721573855727911, + -0.015454376116394997, + 0.022929800674319267, + 0.0010328739881515503, + 4.037815870105987e-06, + 0.005090131890028715, + -0.01528653409332037, + -0.004086307715624571, + 0.016964955255389214, + -0.014718453399837017, + -0.011671475134789944, + 0.005903520155698061, + 0.016706736758351326, + 0.01484756264835596, + 0.001228151610121131, + 0.0060294014401733875, + 0.009754203259944916, + 0.005745361093431711, + -0.0023772239219397306, + 0.02664814703166485, + -0.0033051965292543173, + 0.0022109958808869123, + 0.003171245800331235, + 0.02409178391098976, + -0.016745468601584435, + 0.02391103096306324, + 0.020502546802163124, + -0.01203943695873022, + -0.01030291710048914, + -0.018824126571416855, + 0.006219837814569473, + -0.01620320975780487, + 0.008772972971200943, + -0.004564011935144663, + 0.004709259606897831, + 0.015131602995097637, + 0.03558250889182091, + 0.00420250603929162, + 0.005432271398603916, + -0.014176194556057453, + -0.007094552740454674, + -0.007417325861752033, + 0.018772482872009277, + 0.0015840090345591307, + 0.017158618196845055, + -0.015196157619357109, + 0.0010005966760218143, + -0.0034407612401992083, + -0.022710315883159637, + 0.024840617552399635, + -0.025899313390254974, + -0.025279588997364044, + 0.003889415878802538, + -0.01059986837208271, + 0.0070493645034730434, + 0.009786480106413364, + 0.0005386276170611382, + -0.005629162769764662, + -0.017765432596206665, + -0.006481283809989691, + -0.04260604828596115, + 0.0211868267506361, + -0.015699684619903564, + 0.02015395276248455, + 0.005109498277306557, + 0.010193174704909325, + -0.015325266867876053, + 0.00905055832117796, + -0.017003687098622322, + -0.018630463629961014, + 0.032303132116794586, + -0.036279696971178055, + 0.01810111664235592, + -0.03912010043859482, + 0.025060104206204414, + 0.021741995587944984, + -0.0008488932508043945, + 0.01870792917907238, + -0.006171421613544226, + -0.0001905370008898899, + 0.017726698890328407, + -0.013763044960796833, + 0.0060907285660505295, + -0.0021157776936888695, + 0.030108274891972542, + 0.015712594613432884, + -0.012491319328546524, + 0.026067156344652176, + 0.03757078945636749, + 0.004628566559404135, + -0.027990883216261864, + 0.005409677047282457, + 0.036692846566438675, + 0.027500268071889877, + -0.02289106883108616, + 0.008275902830064297, + 0.013801777735352516, + -0.018036561086773872, + 0.01994737796485424, + 0.003921693190932274, + 0.05012020841240883, + -0.028972113505005836, + -0.011878049932420254, + 0.009670281782746315, + -0.0016542121302336454, + -0.004651160445064306, + -0.09636713564395905, + 0.013298251666128635, + 0.02558945119380951, + -0.008656774647533894, + 0.0031841567251831293, + 0.026880543678998947, + 0.010722522623836994, + 0.014731364324688911, + 0.011167949065566063, + 0.014989582821726799, + 0.00011952691420447081, + -0.015118692070245743, + -0.015351088717579842, + -0.014615166001021862, + -0.004676982294768095, + 0.007178473751991987, + -0.01321433112025261, + -0.0021851740311831236, + -0.034394703805446625, + 0.0041766841895878315, + -0.0012846369063481688, + -0.02619626559317112, + -0.016900399699807167, + -0.011309969238936901, + -0.01496376097202301, + -0.0008892398909665644, + -0.024698598310351372, + 0.011548821814358234, + 0.006468372885137796, + 0.02830074541270733, + -0.0017558856634423137, + -0.025873491540551186, + -0.007081641815602779, + -0.012032981030642986, + -0.026751434430480003, + -0.028145814314484596, + -0.0124590415507555, + 0.007075186353176832, + -0.0004353402182459831, + -0.020670389756560326, + 0.004770586267113686, + -0.014860473573207855, + 0.017829986289143562, + -0.013905065134167671, + 0.024982638657093048, + -0.020954430103302002, + -0.016125744208693504, + 0.018837038427591324, + 0.02428544871509075, + -0.003297127317637205, + -0.01994737796485424, + 0.006875067017972469, + -0.003363295691087842, + -0.0033277906477451324, + 0.030314849689602852, + -0.02930779755115509, + 0.012284744530916214, + 0.007184929214417934, + -0.014731364324688911, + -0.0052805677987635136, + -0.01622903160750866, + 0.027706842869520187, + -0.007468969561159611, + 0.018875770270824432, + -0.0013758203713223338, + 0.0021916294936090708, + -0.005780866369605064, + 0.008889171294867992, + 0.020915696397423744, + -0.022193878889083862, + -0.04263187199831009, + 0.005548469722270966, + -0.019004879519343376, + 0.0062262932769954205, + -0.032561350613832474, + 0.0063715409487485886, + -0.034807853400707245, + 0.009734836407005787, + -0.003019542433321476, + 0.0006003579474054277, + -0.014524789527058601, + -0.011251870542764664, + -0.014331125654280186, + -0.005874470341950655, + 0.0014960533007979393, + 0.043561458587646484, + 0.010348105803132057, + -0.006694314070045948, + -0.0012450972571969032, + -0.03240641951560974, + -0.01913398876786232, + 0.018152760341763496, + 0.0034536721650511026, + 0.0028178091160953045, + -0.00041839462937787175, + 0.014899206347763538, + 0.0057485890574753284, + 0.01018026378005743, + 0.03811304643750191, + -0.012452586553990841, + -0.011600465513765812, + -0.007972495630383492, + -0.06326352804899216, + 0.016977865248918533, + 0.01873375102877617, + -0.010858086869120598, + 0.02577020414173603, + 0.013775955885648727, + 0.027112940326333046, + 0.013479004614055157, + -0.009851034730672836, + -0.0170553307980299, + -0.008250080980360508, + 0.032535530626773834, + -0.0118586840108037, + -0.02180655114352703, + -0.025266679003834724, + 0.008049961179494858, + 0.024195071309804916, + 0.017972007393836975, + 0.011309969238936901, + 0.010832265019416809, + -0.021341757848858833, + 0.021135183051228523, + 0.02948855049908161, + 0.013905065134167671, + -0.023975586518645287, + -0.0034924049396067858, + -0.0065361554734408855, + -0.009063469246029854, + -0.025899313390254974, + 0.005367716774344444, + 0.02161288633942604, + -0.02096734009683132, + -0.0019414802081882954, + 0.04691829904913902, + -0.027371158823370934, + -0.008914993144571781, + 0.010380382649600506, + 0.019017791375517845, + 0.007972495630383492, + -0.020902786403894424, + -0.008166159503161907, + -0.025434520095586777, + -0.0012886716285720468, + -0.022206788882613182, + -0.015234890393912792, + 0.00441230833530426, + -0.009205489419400692, + 0.00014434009790420532, + 0.04059194400906563, + -0.008133882656693459, + 0.025666916742920876, + 0.018372245132923126, + -0.005380627699196339, + -0.004631794057786465, + 0.014214927330613136, + -0.026467394083738327, + 0.02014104090631008, + 0.004031436052173376, + 0.017145708203315735, + -0.008798794820904732, + 0.026092978194355965, + 0.0026644919998943806, + 0.021470867097377777, + 0.0034859494771808386, + 0.009224855341017246, + -0.00832109060138464, + -0.020205596461892128, + -0.01195551548153162, + 0.02597677893936634, + -0.011290603317320347, + -0.008805250748991966, + 0.00395074300467968, + 0.008953725919127464, + 0.007191384676843882, + 0.028145814314484596, + -0.020838230848312378, + 0.006842789705842733, + 0.003640880575403571, + -0.010612779296934605, + 0.03465292230248451, + 0.0011087256716564298, + 0.004305793438106775, + -0.05572354793548584, + 0.0075980788096785545, + 0.017933273687958717, + 0.006468372885137796, + -0.009760658256709576, + 0.0006330387550406158, + 0.004483318421989679, + 0.01786871999502182, + 0.02407887391746044, + -0.011084028519690037, + -0.04472343996167183, + 0.004089535214006901, + -0.008140337653458118, + -0.02079949900507927, + -0.006823423318564892, + -0.015854615718126297, + -0.001550117856822908, + 0.044413577765226364, + 0.019495494663715363, + 0.012730170972645283, + 0.017765432596206665, + -0.019637515768408775, + -0.016267765313386917, + 0.006419957149773836, + -0.013943797908723354, + -0.020437993109226227, + -0.008585765026509762, + 0.004725398030132055, + 0.004215416964143515, + -0.015196157619357109, + -0.0038506831042468548, + 0.012175001204013824, + -0.020231418311595917, + 0.012142724357545376, + -0.030056631192564964, + -0.021909838542342186, + 0.003108304925262928, + 0.02263285033404827, + -0.0094766179099679, + 0.00822425913065672, + 0.013020667247474194, + 0.005596885457634926, + 0.004270288161933422, + 0.006771779619157314, + 0.02207767963409424, + 0.0013701717834919691, + 0.03057306818664074, + 0.005603340920060873, + 0.021664530038833618, + -0.025421610102057457, + -0.0067459577694535255, + -0.017533035948872566, + 0.0064038182608783245, + -0.006187560502439737, + 0.040023863315582275, + 0.004673754330724478, + 0.0036118309944868088, + 0.050404246896505356, + 0.008488932624459267, + -0.031037861481308937, + -0.002519244095310569, + -0.008508299477398396, + 0.015944991260766983, + 0.017804164439439774, + 0.010845175944268703, + -0.02598969079554081, + -0.0043832589872181416, + 0.006277936976402998, + 0.010703155770897865, + 0.023446237668395042, + -0.005651757121086121, + -0.044207002967596054, + 0.011374523863196373, + -0.03535011038184166, + 0.007488335948437452, + -0.0061940159648656845, + -5.169412816030672e-06, + -0.0012289586011320353, + 0.0037635343614965677, + 0.01103238482028246, + 0.002398204058408737, + -0.015105781145393848, + -0.01289801299571991, + -0.015480197966098785, + -0.015944991260766983, + -0.02496972680091858, + -0.018824126571416855, + 0.013672668486833572, + -0.003145423950627446, + -0.04782206192612648, + -0.010154441930353642, + 0.008863349445164204, + -0.003411711659282446, + -0.005028804764151573, + 0.004906150978058577, + 0.005093359388411045, + 0.03612476587295532, + -0.018126938492059708, + 0.017403926700353622, + -0.03473038598895073, + -0.02283942513167858, + -0.0028016704600304365, + -0.004421991761773825, + -0.005022349301725626, + 0.002007648814469576, +/* tag::query-vectors-full-list[] */ + -0.03757078945636749 + ], "DOT") LIMIT 3; +/* end::query-vectors-idx-whole[] */ diff --git a/modules/vector-index/pages/gsi-with-vector.adoc b/modules/vector-index/pages/gsi-with-vector.adoc index 139a00647..85cba0039 100644 --- a/modules/vector-index/pages/gsi-with-vector.adoc +++ b/modules/vector-index/pages/gsi-with-vector.adoc @@ -135,9 +135,7 @@ The following example creates a GSI for this attribute as an embedded vector as [source,sqlpp] ---- -CREATE INDEX `color_vectors_idx` ON `vector-sample`.`colors`.`rgb` - (`colorvect_l2` VECTOR, color, brightness) - WITH { "dimension":3 , "similarity":"L2", "description":"IVF,SQ8"}; +include::vector-index:example$gsi-vector-idx-examples.sqlpp[tag=create-rgb-idx] ---- In this example: @@ -175,7 +173,7 @@ CREATE INDEX `color_desc_idx` ON `vector-sample`.`colors`.`rgb` WITH { "dimension":1536, "similarity":"l2", "description":" IVF16,SQ8" } ---- -The response: +If successful, Couchbase {product-name} responds with: [source, json] ---- @@ -188,3 +186,28 @@ The response: ] ---- +== Query with a GSI Vector Column + +Something + +=== Query GSI RGB Values + +Something + +=== Query the Embedded Vectors + +[source,sqlpp] +---- +include::vector-index:example$gsi-vector-idx-examples.sqlpp[tag=query-vectors-idx-whole;!query-vectors-idx-full-list] +---- + + + +.Show full example +[%collapsible] +==== +[source,sqlpp] +---- +include::vector-index:example$gsi-vector-idx-examples.sqlpp[tag=query-vectors-idx-whole] +---- +==== From 1cbc68744a24a0e9e31dbdf295f6b52b12aef59b Mon Sep 17 00:00:00 2001 From: Gary Gray <137797428+ggray-cb@users.noreply.github.com> Date: Mon, 14 Oct 2024 14:04:16 -0400 Subject: [PATCH 05/41] Checkin current state of docs before vacation. --- .../examples/gsi-vector-idx-examples.sqlpp | 29 ++- .../vector-index/pages/gsi-with-vector.adoc | 242 +++++++++++++++++- 2 files changed, 254 insertions(+), 17 deletions(-) diff --git a/modules/vector-index/examples/gsi-vector-idx-examples.sqlpp b/modules/vector-index/examples/gsi-vector-idx-examples.sqlpp index 6937e8cd6..f3ace2ae8 100644 --- a/modules/vector-index/examples/gsi-vector-idx-examples.sqlpp +++ b/modules/vector-index/examples/gsi-vector-idx-examples.sqlpp @@ -5,9 +5,9 @@ CREATE INDEX `color_vectors_idx` ON `vector-sample`.`colors`.`rgb` /* end::create-rgb-idx[] */ /* tag::create-vectors-idx[] */ -CREATE INDEX `color_vectors_idx` ON `vector-sample`.`colors`.`rgb` - (`colorvect_l2` VECTOR, color, brightness) - WITH { "dimension":3, "similarity":"DOT", "description":" IVF16,SQ8" } +CREATE INDEX `color_desc_idx` ON `vector-sample`.`colors`.`rgb` + (`embedding_vector_dot` VECTOR, color, brightness) + WITH { "dimension":1536, "similarity":"DOT", "description":" IVF,SQ8" } /* end::create-rgb-idx[] */ /* tag::query-rgb-idx[] */ @@ -17,6 +17,13 @@ ORDER BY APPROX_VECTOR_DISTANCE(b.colorvect_l2,[128,128,128],"L2") LIMIT 5; /* end::query-rgb-idx[] */ +/* tag::query-rgb-idx-w-predicate[] */ +SELECT b.color, b.colorvect_l2, b.brightness from `rgb` AS b +WHERE b.brightness > 128 +ORDER BY APPROX_VECTOR_DISTANCE(b.colorvect_l2,[128,128,128],"L2") +LIMIT 5; +/* end::query-rgb-idx-w-predicate[] */ + /* tag::query-vectors-idx-subquery[] */ WITH question_vec AS ( SELECT RAW couchbase_search_query.knn[0].vector @@ -27,6 +34,20 @@ order by VECTOR_DISTANCE(b.embedding_vector_dot, question_vec[0], "DOT") LIMIT 3; /* end::query-vectors-idx-subquery[] */ +/* tag::query-vectors-idx-truncated[] */ +SELECT b.color, b.description from `rgb` AS b +order by VECTOR_DISTANCE(b.embedding_vector_dot, +[ + 0.005115953739732504, + 0.004331615287810564, + 0.014279481954872608, + /* long list of vector values omitted */ + -0.005022349301725626, + 0.002007648814469576, + -0.03757078945636749 + ], "DOT") LIMIT 3; +/* end::query-vectors-idx-truncated[] */ + /* tag::query-vectors-idx-whole[] */ SELECT b.color, b.description from `rgb` AS b order by VECTOR_DISTANCE(b.embedding_vector_dot, @@ -35,7 +56,6 @@ order by VECTOR_DISTANCE(b.embedding_vector_dot, 0.004331615287810564, 0.014279481954872608, 0.000619320897385478, -/* end::query-vectors-idx-full-list[] */ 0.006700769532471895, 0.018410978838801384, -0.010367471724748611, @@ -1567,7 +1587,6 @@ order by VECTOR_DISTANCE(b.embedding_vector_dot, -0.004421991761773825, -0.005022349301725626, 0.002007648814469576, -/* tag::query-vectors-full-list[] */ -0.03757078945636749 ], "DOT") LIMIT 3; /* end::query-vectors-idx-whole[] */ diff --git a/modules/vector-index/pages/gsi-with-vector.adoc b/modules/vector-index/pages/gsi-with-vector.adoc index 85cba0039..ad4be33bd 100644 --- a/modules/vector-index/pages/gsi-with-vector.adoc +++ b/modules/vector-index/pages/gsi-with-vector.adoc @@ -111,7 +111,11 @@ The data in `rgb.json` file looks like this: "mellow", "lighten" ], - "description": "Papaya whip is a soft and mellow color that can be described as a light shade of peach or coral. It has a calming and soothing effect, similar to the tropical fruit it is named after. This color is perfect for creating a warm and inviting atmosphere, and it pairs well with other pastel shades or neutral tones. Papaya whip is a versatile color that can be used in both fashion and interior design, adding a touch of elegance and sophistication to any space.", + "description": "Papaya whip is a soft and mellow color that can be described as a light shade of + peach or coral. It has a calming and soothing effect, similar to the tropical fruit it is named + after. This color is perfect for creating a warm and inviting atmosphere, and it pairs well with + other pastel shades or neutral tones. Papaya whip is a versatile color that can be used in both + fashion and interior design, adding a touch of elegance and sophistication to any space.", "embedding_model": "text-embedding-ada-002-v2", "embedding_vector_dot": [ -0.014644118957221508, @@ -120,10 +124,10 @@ The data in `rgb.json` file looks like this: 0.0021356006618589163, 0.006283756345510483, 0.01162360142916441, - . . . + // . . . ] - } - . . . + }, + // . . . ] ---- @@ -168,9 +172,7 @@ The following example creates a GSI that indexes the embedded vectors in the `em [source,sqlpp] ---- -CREATE INDEX `color_desc_idx` ON `vector-sample`.`colors`.`rgb` - (`embedding_vector_dot` VECTOR, color, brightness) - WITH { "dimension":1536, "similarity":"l2", "description":" IVF16,SQ8" } +include::vector-index:example$gsi-vector-idx-examples.sqlpp[tag=create-vectors-idx] ---- If successful, Couchbase {product-name} responds with: @@ -188,20 +190,197 @@ If successful, Couchbase {product-name} responds with: == Query with a GSI Vector Column -Something +You query embedded vector attributes that you have indexed in a GSI to find similar vectors and therefore similar semantic content. +To find the most similar vectors, you use a `GROUP BY` clause in your query to return the most relevant vectors first. +In this clause, you call one of two functions that actually performs the vector comparisons: `APPROX_VECTOR_DISTANCE` or `VECTOR_DISTANCE`. +The first of these functions is faster, but less precise. +The second is more precise, but slower. +Which you choose depends on your use case. -=== Query GSI RGB Values +=== Query RGB Values -Something +Querying the RGB values in `rgb.colorvect_l2` requires a vector with only three values. +You can easily specify the vector by hand. +The following example finds colors that are similar to grey, which has an RGB value of 128, 128, 128: + +[source, sqlpp] +---- +include::vector-index:example$gsi-vector-idx-examples.sqlpp[tag=query-rgb-idx] +---- + +The query uses the `APPROX_VECTOR_DISTANCE` function to sort the results. +You pass it the vector column to search, the vector to search for (in this case, the array `128, 128, 128`) and the distance function. +For the best accuracy, use the same distance function you specified when creating the GSI (in this case, `L2`). +The `LIMIT` clause is pushed down into the index scan, so once it finds the 5 entries that satify the query, it exits. + +The top result is the entry for grey. The other results are all shades of grey: + +[source,json] +---- +[{ + "color": "grey", + "colorvect_l2": [ + 128, + 128, + 128 + ], + "brightness": 128 + }, + { + "color": "slate gray", + "colorvect_l2": [ + 112, + 128, + 144 + ], + "brightness": 125.04 + }, + { + "color": "light slate gray", + "colorvect_l2": [ + 119, + 136, + 153 + ], + "brightness": 132.855 + }, + { + "color": "light gray", + "colorvect_l2": [ + 144, + 144, + 144 + ], + "brightness": 144 + }, + { + "color": "dim gray", + "colorvect_l2": [ + 105, + 105, + 105 + ], + "brightness": 105 + } +] +---- + +You can also add other predicates to help reduce the workload of searching for similar vectors by excluding vectors. +The following example searches for colors similar to grey, which has an RGB value of 128, 128, 128 and have a brightness greater than 128: + +[source, sqlpp] +---- +include::vector-index:example$gsi-vector-idx-examples.sqlpp[tag=query-rgb-idx-w-predicate[] +---- + +The result of running this query are: + +[source, json] +---- +[{ + "color": "light slate gray", + "colorvect_l2": [ + 119, + 136, + 153 + ], + "brightness": 132.855 + }, + { + "color": "light gray", + "colorvect_l2": [ + 144, + 144, + 144 + ], + "brightness": 144 + }, + { + "color": "cadet blue", + "colorvect_l2": [ + 95, + 158, + 160 + ], + "brightness": 139.391 + }, + { + "color": "rosy brown", + "colorvect_l2": [ + 188, + 143, + 143 + ], + "brightness": 156.455 + }, + { + "color": "dark sea green", + "colorvect_l2": [ + 143, + 188, + 143 + ], + "brightness": 169.415 + } +] +---- === Query the Embedded Vectors -[source,sqlpp] +To query the `color_desc_idx` GSI containing the embedded vector for the description attribute, you must supply a vector. +In a production environment, your application will call the same embedding model it called to generate the embedded vectors in your documents to generate a vector for the query value. + +For this example, you can use embedded vectors in the `rgb_questions.json` file that's in the `color_data_2vectors.zip` file. +This file contains a `question` attribute containing a search prompt for a particular color. +The `couchbase_search_query.knn.vector` attribute contains the embedded vector for the `question` attribute: + +[source,json] ---- -include::vector-index:example$gsi-vector-idx-examples.sqlpp[tag=query-vectors-idx-whole;!query-vectors-idx-full-list] +[ + { + "id": "#FFEFD5", + "question": "What is the name of the color that is reminiscent of a tropical fruit and has a calming + effect, often used in fashion and interior design?", + "wanted_similar_color_from_search": "papaya whip", + "embedding_model": "text-embedding-ada-002-v2", + "couchbase_search_query": { + "fields": [ + "*" + ], + "knn": [ + { + "field": "embedding_vector_dot", + "k": 3, + "vector": [ + 0.005115953739732504, + 0.004331615287810564, + 0.014279481954872608, + // .... + ] + } + ], + "query": { + "match_none": {} + }, + "sort": [ + "-_score" + ] + } + }, + // ... +] ---- +This example uses the more accurate `VECTOR_DISTANCE` function to order the results of querying the `embedding_vector_dot` column. +It appears here with most of the 1536 vectors omitted: + +[source,sqlpp] +---- +include::vector-index:example$gsi-vector-idx-examples.sqlpp[tag=query-vectors-idx-truncated] +---- + +You can expand the following dropdown to see and copy the entire query with all the vectors: .Show full example [%collapsible] @@ -211,3 +390,42 @@ include::vector-index:example$gsi-vector-idx-examples.sqlpp[tag=query-vectors-id include::vector-index:example$gsi-vector-idx-examples.sqlpp[tag=query-vectors-idx-whole] ---- ==== + +Another option is to import the `rgb_questions.json` file into another collection in the `vector-sample` bucket's `colors` scope named `rgb-questions`. +Then you can use a subquery to get the vectors for the question and use it in your query of the `rgb` collection's `embedding_vector_dot` attribute: + +[source,sqlpp] +---- +include::vector-index:example$gsi-vector-idx-examples.sqlpp[tag=query-vectors-idx-subquery] +---- + +In either case, the results of the query are the same: + +[source,json] +---- +[ + { + "color": "cantalope", + "description": "The color cantaloupe is a soft and soothing shade that evokes feelings of calmness + and relaxation. It is a refreshing hue that brings to mind the juicy and sweet fruit it is named + after. This delicate color is a pale orange with hints of pink, giving it a subtle and gentle + appearance. It is a perfect color for creating a peaceful and tranquil atmosphere." + }, + { + "color": "papaya whip", + "description": "Papaya whip is a soft and mellow color that can be described as a light shade of + peach or coral. It has a calming and soothing effect, similar to the tropical fruit it is named + after. This color is perfect for creating a warm and inviting atmosphere, and it pairs well with + other pastel shades or neutral tones. Papaya whip is a versatile color that can be used in both + fashion and interior design, adding a touch of elegance and sophistication to any space." + }, + { + "color": "apricot", + "description": "Apricot is a warm and inviting color, reminiscent of the soft glow of a sunset. It + has the ability to soften the harshness of other colors and enliven any space it is used in. It is a + delicate and soothing hue, perfect for creating a cozy and welcoming atmosphere." + } +] +---- + +The second result, the color "papaya whip," matches the `rgb_questions`'s `wanted_similar_color_from_search` attribute. \ No newline at end of file From d9656c5099d069476e67a84522134b7a5f44cd3f Mon Sep 17 00:00:00 2001 From: Gary Gray <137797428+ggray-cb@users.noreply.github.com> Date: Mon, 14 Oct 2024 14:55:57 -0400 Subject: [PATCH 06/41] Misc fixes --- modules/vector-index/examples/gsi-vector-idx-examples.sqlpp | 3 +-- modules/vector-index/pages/gsi-with-vector.adoc | 6 +++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/modules/vector-index/examples/gsi-vector-idx-examples.sqlpp b/modules/vector-index/examples/gsi-vector-idx-examples.sqlpp index f3ace2ae8..f33da6751 100644 --- a/modules/vector-index/examples/gsi-vector-idx-examples.sqlpp +++ b/modules/vector-index/examples/gsi-vector-idx-examples.sqlpp @@ -8,11 +8,10 @@ CREATE INDEX `color_vectors_idx` ON `vector-sample`.`colors`.`rgb` CREATE INDEX `color_desc_idx` ON `vector-sample`.`colors`.`rgb` (`embedding_vector_dot` VECTOR, color, brightness) WITH { "dimension":1536, "similarity":"DOT", "description":" IVF,SQ8" } -/* end::create-rgb-idx[] */ +/* end::create-vectors-idx[] */ /* tag::query-rgb-idx[] */ SELECT b.color, b.colorvect_l2, b.brightness from `rgb` AS b -WHERE b.brightness > 128 ORDER BY APPROX_VECTOR_DISTANCE(b.colorvect_l2,[128,128,128],"L2") LIMIT 5; /* end::query-rgb-idx[] */ diff --git a/modules/vector-index/pages/gsi-with-vector.adoc b/modules/vector-index/pages/gsi-with-vector.adoc index ad4be33bd..1bce8eb60 100644 --- a/modules/vector-index/pages/gsi-with-vector.adoc +++ b/modules/vector-index/pages/gsi-with-vector.adoc @@ -169,7 +169,7 @@ The data sample shown in <<#examples>> truncated this attribute to several value The embedded vector contains 1536 dimensions. The following example creates a GSI that indexes the embedded vectors in the `embedding_vector_dot` as well as indexing the scalar `color` that contains the color's name and `brightness.` - + [source,sqlpp] ---- include::vector-index:example$gsi-vector-idx-examples.sqlpp[tag=create-vectors-idx] @@ -270,7 +270,7 @@ The following example searches for colors similar to grey, which has an RGB valu [source, sqlpp] ---- -include::vector-index:example$gsi-vector-idx-examples.sqlpp[tag=query-rgb-idx-w-predicate[] +include::vector-index:example$gsi-vector-idx-examples.sqlpp[tag=query-rgb-idx-w-predicate] ---- The result of running this query are: @@ -428,4 +428,4 @@ In either case, the results of the query are the same: ] ---- -The second result, the color "papaya whip," matches the `rgb_questions`'s `wanted_similar_color_from_search` attribute. \ No newline at end of file +The second result, the color "papaya whip," matches the `rgb_questions` collection's `wanted_similar_color_from_search` attribute. \ No newline at end of file From 0ea9113ce342182424f3638272f6e118e3d7bf82 Mon Sep 17 00:00:00 2001 From: Gary Gray <137797428+ggray-cb@users.noreply.github.com> Date: Mon, 13 Jan 2025 11:07:48 -0500 Subject: [PATCH 07/41] In progress checkin: * Added diagram illustrating vector space. * More detail on vector similarity functions. --- .../images/draw-vector-space-diagram.py | 41 + .../assets/images/vector-space-example.svg | 1411 +++++++++++++++++ .../pages/use-vector-indexes.adoc | 65 +- 3 files changed, 1501 insertions(+), 16 deletions(-) create mode 100644 modules/vector-index/assets/images/draw-vector-space-diagram.py create mode 100644 modules/vector-index/assets/images/vector-space-example.svg diff --git a/modules/vector-index/assets/images/draw-vector-space-diagram.py b/modules/vector-index/assets/images/draw-vector-space-diagram.py new file mode 100644 index 000000000..f53a75586 --- /dev/null +++ b/modules/vector-index/assets/images/draw-vector-space-diagram.py @@ -0,0 +1,41 @@ +# Script to generate the 3D vector diagram in +# This mainly came about because ChatGPT lied to me about Kroki supporting +# Matplotlib. It does not. Instead of throwing away the work to generate this +# diagram, I'll just check in the source code and include the SVG file in the document. +# +# If You need to update this diagram, you will need to install Python 3, numpy and +# matplotlib. On MacOS, this can be done via the brew command. + +import numpy as np +import matplotlib.pyplot as plt +from mpl_toolkits.mplot3d import Axes3D + +# Define the AI embedded vectors for feral cats, domestic cats, and Linux command line cat tool +feral_cats_vector = np.array([0.13, 0.21, 0.34]) +domestic_cats_vector = np.array([0.1, 0.27, 0.30]) +linux_cat_vector = np.array([0.4, 0.4, 0.3]) + +# Create a figure and a 3D axis +fig = plt.figure() +ax = fig.add_subplot(111, projection='3d') + +# Plot the vectors +ax.quiver(0, 0, 0.1, feral_cats_vector[0], feral_cats_vector[1], feral_cats_vector[2], color='indianred', label='Feral Cats') +ax.quiver(0, 0.1, 0, domestic_cats_vector[0], domestic_cats_vector[1], domestic_cats_vector[2], color='darkred', label='Domestic Cats') +ax.quiver(0.4, 0.3, 0.1, linux_cat_vector[0], linux_cat_vector[1], linux_cat_vector[2], color='green', label='Linux Cat Command') + +# Set the plot labels +ax.set_xlabel('X') +ax.set_ylabel('Y') +ax.set_zlabel('Z') + +# Set the plot limits +ax.set_xlim([0.0, 0.8]) +ax.set_ylim([0.0, 0.8]) +ax.set_zlim([0.0, 0.8]) + +# Add a legend +ax.legend() + +plt.savefig('vector-space-example.svg') # Save as an image +plt.close() diff --git a/modules/vector-index/assets/images/vector-space-example.svg b/modules/vector-index/assets/images/vector-space-example.svg new file mode 100644 index 000000000..ff0601e3d --- /dev/null +++ b/modules/vector-index/assets/images/vector-space-example.svg @@ -0,0 +1,1411 @@ + + + + + + + + 2025-01-07T16:59:55.771382 + image/svg+xml + + + Matplotlib v3.10.0, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/modules/vector-index/pages/use-vector-indexes.adoc b/modules/vector-index/pages/use-vector-indexes.adoc index d4a2c107a..e32639b6d 100644 --- a/modules/vector-index/pages/use-vector-indexes.adoc +++ b/modules/vector-index/pages/use-vector-indexes.adoc @@ -20,10 +20,17 @@ Similar vectors are close together the multi-dimensional space formed by all of Vectors for dissimilar data (for example, articles discussing two different topics) have vectors that are further apart in this multi-dimensional space. By comparing two vectors, you can find the similarity between two pieces of data. -This similarity goes beyond just finding parts of the data that's identical (for example, finding many of the same words in two pieces of text). +This similarity goes beyond just finding parts of the data that's identical (for example, finding similar words in two pieces of text). The vectors represent features such as the semantic meaning of text rather than just superficial similarities. -In Couchbase {product-name}, you can use vectors to find documents that are similar to an existing document or query values. +For example, suppose you have three text articles. +The first is about feral cats, the second about domestic cats, and the third is about the UNIX/Linux `cat` command. +Because their subject matter is similar, vectors representing the first two articles are close to each other and have other similarities. +The third article, despite sharing the word "cat" in its title with the two other articles, is further away and is dissimilar in other ways. + +image::vector-space-example.svg["Three-dimensional plot showing two vectors that are close by and parallel. A third vector that's away and points in another direction"] + +In Couchbase {product-name}, you can use vectors to find documents that are similar to an existing document or query value. By searching your database for similar vectors, you can identify data that's semantically similar to a value. === Embedding Vectors @@ -32,7 +39,7 @@ Embedding is the process of generating vectors that represent a piece of complex You use a model that's specific to the data's type to generate its vector. For example, to generate vectors from text, you can use a use models such as https://en.wikipedia.org/wiki/Word2vec[Word2Vec^] or https://en.wikipedia.org/wiki/GloVe[Global Vectors for Word Representation (GloVe)^]. The models take into account the context around each potion of the text when generating a vector. -This context is what captures the semantic meaning of the text and embeds it in the vector's dimensions. +This context is what captures the semantic meaning of the text and embeds it in the vector's dimensions. To generate vectors from images, you use different embedding models such as https://en.wikipedia.org/wiki/Residual_neural_network[Residual Neural Networks (ResNet)^]. You can only compare the similarity of vectors generated by the same model. For example, you cannot find the similarity of two pieces of text if you generated one text's vector using Word2Vec and you used GloVe for the other. @@ -44,19 +51,45 @@ You then store the vector as an attribute in your database. === Vector Similarity -Once you have embedded a vector in your database, you find data with a similar meaning by locating similar vectors. -Several algorithms exist that you can use to find similar vectors. -They're also called distance functions, as they determine the distance between vectors in the vector space. -These algorithms are broken into two categories: - -* *K-Nearest Neighbor (KNN)* methods use precise algorithms to determine the distance between two vectors. -This precision comes at a higher computational cost. -They're best used with smaller vector datasets and when precision is more important than computational resource use. - -* *Approximate Nearest Neighbor (ANN)* uses methods that approximate the distance between two vectors. -They use less computational power, but at the cost of less precise results. -These methods are not guaranteed to return the closest matches to a particular vector. -Use one of these methods when limiting computing resource use is more important than precise results, especially with a large dataset. +Once you have embedded vectors in your database, you find documents with a similar meaning by locating similar vectors. +Several algorithms exist that you can use to find similar vectors. +Couchbase {product-name} supports three similarity methods: + +Euclidean Distance:: +Calculates the geometric distance between two vectors by finding the distance between the individual elements in the vectors. +This method is most sensitive to the distance between the vectors in space, rather than their alignment. +It's sensitive to the scale of the vectors, where the length of one vector verses the other is important in the results. +Use this method when the proximity of the vectors matters, such as image similarity searches. + +Dot Product:: +Compares the magnitude and alignment of the vectors. +In this method, the proximity of the vectors in space is less important than whether they point in the same direction and have the same size. +Vectors that point in similar directions (have a low angle between them) and have similar length are strongly associated with each other. +It uses the similarity of the vectors magnitudes to rank how related they are. +Use this method for tasks such as recommendation engines where ranking results from most to least related is important. + +Cosine Similarity:: +This method is similar to the dot product. +However, it normalizes the vectors during comparison so their magnitudes are not taken into account, just their alignment. +This normalization makes this method better for comparing textual data. +By normalizing the vectors, this method is less sensitive to the length of the data than its semantic meaning when performing comparisons. +Therefore, Cosine Similarity can find the correlation between a short question and a long article that's relevant to answering it. +Use this method when you're performing similarity searches on text or similar data. + +== Vector Indexes + +As with other data types in Couchbase {product-name}, indexes make searching for similar vectors much faster. +You can include vectors in three types of indexes: + +* Vector indexes support vectors natively. +They provide the best performance when querying vector values. +This vector type can + +* Global Secondary Indexes (GSI) can include a single vector field. +Using a GSI with a vector value lets you query both scalar and vector at once. +In this case, the scalar data helps limit the scope that Couchbase + +When you add a vector to an index, you specify a vector similarity [#quantize] === Reducing Vector Size From 643badc8e414ab36dc76869ae5e277d8be3a57cc Mon Sep 17 00:00:00 2001 From: Gary Gray <137797428+ggray-cb@users.noreply.github.com> Date: Thu, 16 Jan 2025 06:43:44 -0500 Subject: [PATCH 08/41] Interim checkin. More edits. More diagrams --- .../assets/images/draw-cosine-diagram.py | 134 ++ .../assets/images/draw-dot-product-diagram.py | 124 ++ .../images/draw-euclidean-distance-diagram.py | 67 + .../images/euclidean-distance-example.svg | 1185 +++++++++++++++++ .../assets/images/euclidean-example.svg | 779 +++++++++++ .../assets/images/vector-space-example.svg | 22 +- .../pages/use-vector-indexes.adoc | 83 +- 7 files changed, 2357 insertions(+), 37 deletions(-) create mode 100644 modules/vector-index/assets/images/draw-cosine-diagram.py create mode 100644 modules/vector-index/assets/images/draw-dot-product-diagram.py create mode 100644 modules/vector-index/assets/images/draw-euclidean-distance-diagram.py create mode 100644 modules/vector-index/assets/images/euclidean-distance-example.svg create mode 100644 modules/vector-index/assets/images/euclidean-example.svg diff --git a/modules/vector-index/assets/images/draw-cosine-diagram.py b/modules/vector-index/assets/images/draw-cosine-diagram.py new file mode 100644 index 000000000..80f174d9e --- /dev/null +++ b/modules/vector-index/assets/images/draw-cosine-diagram.py @@ -0,0 +1,134 @@ +import matplotlib.pyplot as plt +import numpy as np + + +def calculate_midpoint(origin, vector): + """ + Calculate the midpoint of a vector given an origin. + + Parameters: + origin (array-like): The coordinates of the origin (x, y, z). + vector (array-like): The components of the vector (vx, vy, vz). + + Returns: + numpy array: The coordinates of the midpoint. + """ + origin = np.array(origin) + vector = np.array(vector) + endpoint = origin + vector + midpoint = (origin + endpoint) / 2 + return midpoint + + +def calculate_endpoint(origin, vector): + """ + Calculate the midpoint of a vector given an origin. + + Parameters: + origin (array-like): The coordinates of the origin (x, y, z). + vector (array-like): The components of the vector (vx, vy, vz). + + Returns: + numpy array: The coordinates of the midpoint. + """ + origin = np.array(origin) + vector = np.array(vector) + endpoint = origin + vector + return endpoint + +def vector_magnitude(origin, vector): + # Convert origin and vector to numpy arrays + origin = np.array(origin) + vector = np.array(vector) + + # Calculate the difference between the origin and vector + diff = vector - origin + + # Calculate the magnitude (Euclidean distance) + magnitude = np.linalg.norm(diff) + + return magnitude + +def normalize(vector, origin=None): + if origin is not None: + # Subtract origin from the vector + vector = np.array(vector) - np.array(origin) + # Calculate the magnitude of the vector + magnitude = np.linalg.norm(vector) + # Normalize the vector + return vector / magnitude + +# Define two vectors in 3D space +v1 = np.array([2, 3, 5]) +v2 = np.array([6, 4, 6]) + +v1_origin = np.array([0, 0, 0]) +v2_origin = np.array([1, 0, 0]) + +v1_norm = normalize(v1, v1_origin) +v2_norm = normalize(v2, v2_origin) + +# Define two points in 3D space +#point1 = np.array([2, 3, 5]) +#point2 = np.array([6, 7, 2]) +point1 = calculate_endpoint(v1_origin, v1) +point2 = calculate_endpoint(v2_origin, v2) + +midpoint1 = calculate_midpoint(v1_origin, v1) +midpoint2 = calculate_midpoint(v2_origin, v2) + + +# Compute a vector from point1 to point2 +vector = point2 - point1 +midpoint = (point1 + point2) / 2 + +# Find a perpendicular vector (normal to the line connecting the two points) +arbitrary_vector = np.array([1, 0, 0]) if vector[0] == 0 else np.array([0, 1, 0]) +normal_vector = np.cross(vector, arbitrary_vector).astype(float) # Convert to float +normal_vector /= np.linalg.norm(normal_vector) # Normalize the normal vector + +# Control the "height" of the arc (smaller values for a shallower arc) +arc_height = 1 + +# Generate points on the arc +t = np.linspace(0, 1, 100) +arc_points = (1 - t)[:, None] * point1 + t[:, None] * point2 + arc_height * np.sin(np.pi * t)[:, None] * normal_vector + +# Set up the plot +fig = plt.figure() +ax = fig.add_subplot(111, projection='3d') + +# Plot the vectors +ax.quiver(0, 0, 0, v1[0], v1[1], v1[2], color='b', linewidth=2) +ax.quiver(1, 0, 0, v2[0], v2[1], v2[2], color='r', linewidth=2) + +# Plot the original points +ax.scatter(*point1, color='b', s=100) +ax.scatter(*point2, color='r', s=100) + +# Plot the arc +ax.plot3D(arc_points[:, 0], arc_points[:, 1], arc_points[:, 2], 'g', linestyle='dotted', linewidth=2) + +# Label the arc +ax.text(*midpoint, r'$\theta$', color='k', fontsize=14) + +# Move the lables showing the vector magnitude a bit. +text_offset = np.array([-1.3, 0, 2]) + +# Add vector magnitudes +ax.text(*(point1 + text_offset), r'$\left| \mathbf{v_1} \right| = $' + "{:.2f}".format(vector_magnitude(v1_origin, v1)), color='b', fontsize=14) + + +ax.text(*(point2 + text_offset), r'$\left| \mathbf{v_2} \right| = $' + "{:.2f}".format(vector_magnitude(v2_origin, v2)), color='r', fontsize=14) + +# Set axis limits and labels +ax.set_xlim(0, 8) +ax.set_ylim(0, 8) +ax.set_zlim(0, 8) +ax.set_xlabel('X-axis') +ax.set_ylabel('Y-axis') +ax.set_zlabel('Z-axis') +ax.set_title('Dot Product') + +# Show plot +plt.show() diff --git a/modules/vector-index/assets/images/draw-dot-product-diagram.py b/modules/vector-index/assets/images/draw-dot-product-diagram.py new file mode 100644 index 000000000..e3107414c --- /dev/null +++ b/modules/vector-index/assets/images/draw-dot-product-diagram.py @@ -0,0 +1,124 @@ +import matplotlib.pyplot as plt +import numpy as np + + +def calculate_midpoint(origin, vector): + """ + Calculate the midpoint of a vector given an origin. + + Parameters: + origin (array-like): The coordinates of the origin (x, y, z). + vector (array-like): The components of the vector (vx, vy, vz). + + Returns: + numpy array: The coordinates of the midpoint. + """ + origin = np.array(origin) + vector = np.array(vector) + endpoint = origin + vector + midpoint = (origin + endpoint) / 2 + return midpoint + + +def calculate_endpoint(origin, vector): + """ + Calculate the midpoint of a vector given an origin. + + Parameters: + origin (array-like): The coordinates of the origin (x, y, z). + vector (array-like): The components of the vector (vx, vy, vz). + + Returns: + numpy array: The coordinates of the midpoint. + """ + origin = np.array(origin) + vector = np.array(vector) + endpoint = origin + vector + return endpoint + +def vector_magnitude(origin, vector): + # Convert origin and vector to numpy arrays + origin = np.array(origin) + vector = np.array(vector) + + # Calculate the difference between the origin and vector + diff = vector - origin + + # Calculate the magnitude (Euclidean distance) + magnitude = np.linalg.norm(diff) + + return magnitude + +# Define two vectors in 3D space +v1 = np.array([2, 3, 5]) +v2 = np.array([6, 4, 6]) + +v1_origin = np.array([0, 0, 0]) +v2_origin = np.array([1, 0, 0]) + + + +# Define two points in 3D space +#point1 = np.array([2, 3, 5]) +#point2 = np.array([6, 7, 2]) +point1 = calculate_endpoint(v1_origin, v1) +point2 = calculate_endpoint(v2_origin, v2) + +midpoint1 = calculate_midpoint(v1_origin, v1) +midpoint2 = calculate_midpoint(v2_origin, v2) + + +# Compute a vector from point1 to point2 +vector = point2 - point1 +midpoint = (point1 + point2) / 2 + +# Find a perpendicular vector (normal to the line connecting the two points) +arbitrary_vector = np.array([1, 0, 0]) if vector[0] == 0 else np.array([0, 1, 0]) +normal_vector = np.cross(vector, arbitrary_vector).astype(float) # Convert to float +normal_vector /= np.linalg.norm(normal_vector) # Normalize the normal vector + +# Control the "height" of the arc (smaller values for a shallower arc) +arc_height = 1 + +# Generate points on the arc +t = np.linspace(0, 1, 100) +arc_points = (1 - t)[:, None] * point1 + t[:, None] * point2 + arc_height * np.sin(np.pi * t)[:, None] * normal_vector + +# Set up the plot +fig = plt.figure() +ax = fig.add_subplot(111, projection='3d') + +# Plot the vectors +ax.quiver(0, 0, 0, v1[0], v1[1], v1[2], color='b', linewidth=2) +ax.quiver(1, 0, 0, v2[0], v2[1], v2[2], color='r', linewidth=2) + +# Plot the original points +ax.scatter(*point1, color='b', s=100) +ax.scatter(*point2, color='r', s=100) + +# Plot the arc +ax.plot3D(arc_points[:, 0], arc_points[:, 1], arc_points[:, 2], 'g', linestyle='dotted', linewidth=2) + +# Label the arc +ax.text(*midpoint, r'$\theta$', color='k', fontsize=14) + +# Move the lables showing the vector magnitude a bit. +text_offset = np.array([-1.3, 0, 2]) + +# Add vector magnitudes +ax.text(*(point1 + text_offset), r'$\left| \mathbf{v_1} \right| = $' + "{:.2f}".format(vector_magnitude(v1_origin, v1)), color='b', fontsize=14) + + +ax.text(*(point2 + text_offset), r'$\left| \mathbf{v_2} \right| = $' + "{:.2f}".format(vector_magnitude(v2_origin, v2)), color='r', fontsize=14) + +# Set axis limits and labels +ax.set_xlim(0, 8) +ax.set_ylim(0, 8) +ax.set_zlim(0, 8) +ax.set_xlabel('X-axis') +ax.set_ylabel('Y-axis') +ax.set_zlabel('Z-axis') +ax.set_title('Dot Product') + +# Show plot +plt.show() diff --git a/modules/vector-index/assets/images/draw-euclidean-distance-diagram.py b/modules/vector-index/assets/images/draw-euclidean-distance-diagram.py new file mode 100644 index 000000000..3f2dbdda4 --- /dev/null +++ b/modules/vector-index/assets/images/draw-euclidean-distance-diagram.py @@ -0,0 +1,67 @@ +# Illustrates how euclidean distance works +import matplotlib.pyplot as plt +from mpl_toolkits.mplot3d import Axes3D +import numpy as np + +# Define two vectors in 3D space +v1 = np.array([2, 3, 5]) +v2 = np.array([6, 4, 6]) + +v1_one_third = (1/3) * v1 +v2_one_third = (1/3) * v2 + +v1_two_third = (2/3) * v1 +v2_two_third = (2/3) * v2 + + + +# Set up the 3D plot +fig = plt.figure(figsize=(10, 7)) +ax = fig.add_subplot(111, projection='3d') + +# Plot the vectors +ax.quiver(0, 0, 0, v1[0], v1[1], v1[2], color='b', linewidth=2) +ax.quiver(1, 1, 1, v2[0], v2[1], v2[2], color='r', linewidth=2) + +# Plot points +ax.scatter(0,0,0, color='r', s=100) +ax.scatter(1,1,1, color='r', s=100) + +ax.scatter(v1_one_third[0],v1_one_third[1],v1_one_third[2], color='r', s=100) +ax.scatter(v2_one_third[0]+1,v2_one_third[1]+1,v2_one_third[2]+1, color='r', s=100) + +ax.scatter(v1_two_third[0],v1_two_third[1],v1_two_third[2], color='r', s=100) +ax.scatter(v2_two_third[0]+1,v2_two_third[1]+1,v2_two_third[2]+1, color='r', s=100) + +# Draw dotted lines connecting corresponding points on the two vectors + +ax.plot([0,1], [0,1], [0,1], linestyle='dotted', color='k') + +ax.plot([v1_one_third[0], v2_one_third[0]+1], [v1_one_third[1], v2_one_third[1]+1], [v1_one_third[2], v2_one_third[2]+1], linestyle='dotted', color='k') + +ax.plot([v1_two_third[0], v2_two_third[0]+1], [v1_two_third[1], v2_two_third[1]+1], [v1_two_third[2], v2_two_third[2]+1], linestyle='dotted', color='k') + + + +#ax.plot([v1[0], v2[0]], [v1[1], v1[1]], [v1[2], v1[2]], linestyle='dotted', color='k') # X-axis difference +#ax.plot([v2[0], v2[0]], [v1[1], v2[1]], [v1[2], v1[2]], linestyle='dotted', color='k') # Y-axis difference +#ax.plot([v2[0], v2[0]], [v2[1], v2[1]], [v1[2], v2[2]], linestyle='dotted', color='k') # Z-axis difference + +# Highlight the Euclidean distance with a line between the vector endpoints +ax.plot([v1[0], v2[0]+1], [v1[1], v2[1]+1], [v1[2], v2[2]+1], color='k', linestyle='dotted') + +# Set axis limits for better visibility +ax.set_xlim(0, 7) +ax.set_ylim(0, 7) +ax.set_zlim(0, 7) + +# Labels and title +ax.set_xlabel('X-axis') +ax.set_ylabel('Y-axis') +ax.set_zlabel('Z-axis') +ax.set_title('Euclidean Distance') +ax.legend() + +# Show plot +#plt.show() +plt.savefig('euclidean-distance-example.svg') # Save as an image \ No newline at end of file diff --git a/modules/vector-index/assets/images/euclidean-distance-example.svg b/modules/vector-index/assets/images/euclidean-distance-example.svg new file mode 100644 index 000000000..2727227de --- /dev/null +++ b/modules/vector-index/assets/images/euclidean-distance-example.svg @@ -0,0 +1,1185 @@ + + + + + + + + 2025-01-15T15:53:22.729761 + image/svg+xml + + + Matplotlib v3.10.0, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/modules/vector-index/assets/images/euclidean-example.svg b/modules/vector-index/assets/images/euclidean-example.svg new file mode 100644 index 000000000..a797a01a0 --- /dev/null +++ b/modules/vector-index/assets/images/euclidean-example.svg @@ -0,0 +1,779 @@ + + + + + + + + 2025-01-15T13:58:48.604022 + image/svg+xml + + + Matplotlib v3.10.0, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/modules/vector-index/assets/images/vector-space-example.svg b/modules/vector-index/assets/images/vector-space-example.svg index ff0601e3d..cdf4d3bd5 100644 --- a/modules/vector-index/assets/images/vector-space-example.svg +++ b/modules/vector-index/assets/images/vector-space-example.svg @@ -6,7 +6,7 @@ - 2025-01-07T16:59:55.771382 + 2025-01-15T13:56:45.816393 image/svg+xml @@ -916,35 +916,35 @@ z +" clip-path="url(#p7b5799f38a)" style="fill: none; stroke: #8b0000; stroke-width: 1.5"/> +" clip-path="url(#p7b5799f38a)" style="fill: none; stroke: #8b0000; stroke-width: 1.5"/> +" clip-path="url(#p7b5799f38a)" style="fill: none; stroke: #8b0000; stroke-width: 1.5"/> +" clip-path="url(#p7b5799f38a)" style="fill: none; stroke: #008000; stroke-width: 1.5"/> +" clip-path="url(#p7b5799f38a)" style="fill: none; stroke: #008000; stroke-width: 1.5"/> +" clip-path="url(#p7b5799f38a)" style="fill: none; stroke: #008000; stroke-width: 1.5"/> +" clip-path="url(#p7b5799f38a)" style="fill: none; stroke: #cd5c5c; stroke-width: 1.5"/> +" clip-path="url(#p7b5799f38a)" style="fill: none; stroke: #cd5c5c; stroke-width: 1.5"/> +" clip-path="url(#p7b5799f38a)" style="fill: none; stroke: #cd5c5c; stroke-width: 1.5"/> @@ -1404,7 +1404,7 @@ z - + diff --git a/modules/vector-index/pages/use-vector-indexes.adoc b/modules/vector-index/pages/use-vector-indexes.adoc index e32639b6d..8710e311e 100644 --- a/modules/vector-index/pages/use-vector-indexes.adoc +++ b/modules/vector-index/pages/use-vector-indexes.adoc @@ -12,42 +12,68 @@ You can then find relevant data by executing queries on the vector attributes, w == About Vectors -Vectors are a numerical representation of complex data such as text, images, or audio. -They distill this complex data into an array of floating-point values called dimensions. -These dimensions capture features of the data in a way that makes them easy to compare mathematically. +Vectors are a numerical representation of complex unstructured data such as text, images, or audio. +They distill this complex data into an array of floating-point values called dimensions. +The dimensions in vectors capture features of the data in a way that makes them easy to compare mathematically. Similar data, such as text about the same topic or images of a similar subject, have similar vectors. Similar vectors are close together the multi-dimensional space formed by all of the vectors in the dataset. Vectors for dissimilar data (for example, articles discussing two different topics) have vectors that are further apart in this multi-dimensional space. By comparing two vectors, you can find the similarity between two pieces of data. -This similarity goes beyond just finding parts of the data that's identical (for example, finding similar words in two pieces of text). -The vectors represent features such as the semantic meaning of text rather than just superficial similarities. +This similarity goes beyond just finding parts of the data that's identical (finding similar words in two pieces of text, for example). +The vectors represent features such as the meaning of text rather than just superficial similarities. For example, suppose you have three text articles. The first is about feral cats, the second about domestic cats, and the third is about the UNIX/Linux `cat` command. -Because their subject matter is similar, vectors representing the first two articles are close to each other and have other similarities. -The third article, despite sharing the word "cat" in its title with the two other articles, is further away and is dissimilar in other ways. +A text search for the term "cat" could return all three articles at the top of its search results due to their frequent use of the search term. +However, that does not mean that the articles are semantically related (about the same topic). -image::vector-space-example.svg["Three-dimensional plot showing two vectors that are close by and parallel. A third vector that's away and points in another direction"] +By generating vectors for the articles and comparing them, you can determine any semantic relationship between them. + +Vectors can be similar in a variety of ways: + +* Their vectors may point in similar directions. +* They may be close to each other in the vector space made up of all the dimensions in the vectors. +* They may have a similar magnitude (length). + +Because the first two articles are about cats, they point in a similar direction and are in a similar location in space. +The third article, despite using the word "cat" as frequently as the two other articles, has a vector that differs significantly from the other two. + +image::vector-space-example.svg["Three-dimensional plot showing two vectors that are close by and parallel and a third vector that's away and points in another direction"] + +Vectors also make it possible to search for similarity in data that's hard to search using traditional techniques. +Image data, for example, is just a string of raw binary values. +Matching portions of this data within two images does not mean they're of the same subject, or even have any resemblance. +Also, comparing megabytes of raw image data is computationally expensive. +Generating vectors of the images distills features of the image into a smaller, more manageable amount of data. +It also emphasizes features of the images that viewers find important, such as shapes and textures. +Comparing the vectors is more manageable, and actually results in finding similar images. In Couchbase {product-name}, you can use vectors to find documents that are similar to an existing document or query value. By searching your database for similar vectors, you can identify data that's semantically similar to a value. === Embedding Vectors -Embedding is the process of generating vectors that represent a piece of complex data. +Embedding is the process of generating vectors that represent a piece of complex unstructured data. You use a model that's specific to the data's type to generate its vector. + For example, to generate vectors from text, you can use a use models such as https://en.wikipedia.org/wiki/Word2vec[Word2Vec^] or https://en.wikipedia.org/wiki/GloVe[Global Vectors for Word Representation (GloVe)^]. The models take into account the context around each potion of the text when generating a vector. -This context is what captures the semantic meaning of the text and embeds it in the vector's dimensions. To generate vectors from images, you use different embedding models such as https://en.wikipedia.org/wiki/Residual_neural_network[Residual Neural Networks (ResNet)^]. +This context is what captures the semantic meaning of the text and embeds it in the vector's dimensions. + +To generate vectors from images, you use different embedding models such as a https://en.wikipedia.org/wiki/Residual_neural_network[Residual Neural Network (ResNet)^]. + +Behind the scenes, embedding models use neural networks that mimic how the brain recognizes patterns to distill complex data into an array of floating point values. +Beyond choosing an embedding model that's appropriate for your data, you generally do not worry about the details of how the model transforms data into a vector. -You can only compare the similarity of vectors generated by the same model. -For example, you cannot find the similarity of two pieces of text if you generated one text's vector using Word2Vec and you used GloVe for the other. +You can only compare the similarity of vectors generated by the same embedding model. +For example, you cannot find the similarity of a vector generated by Word2Vec and one generated by GloVe. +You also cannot compare a vector for a piece of text generated by Word2Vec with the vector for an image generated by ResNet. Couchbase {product-name} does not implement any embedding models. -You must use external embedding models to generate them. -A common method of embedding vectors in your database is to call the https://openai.com/index/introducing-text-and-code-embeddings/[OpenAI Embedding API^] to generate vectors for your data. -You then store the vector as an attribute in your database. +You must use external embedding models to generate them and then store the resulting vectors in your documents. +A common method of embedding vectors in your database is to call an https://openai.com/index/introducing-text-and-code-embeddings/[OpenAI Embedding API^] to generate vectors for your data. +You then store the vector as an attribute in your document. === Vector Similarity @@ -58,36 +84,41 @@ Couchbase {product-name} supports three similarity methods: Euclidean Distance:: Calculates the geometric distance between two vectors by finding the distance between the individual elements in the vectors. This method is most sensitive to the distance between the vectors in space, rather than their alignment. -It's sensitive to the scale of the vectors, where the length of one vector verses the other is important in the results. +It's sensitive to the scale of the vectors, where the length of one vector verses the other is important in the results. Use this method when the proximity of the vectors matters, such as image similarity searches. ++ +image::euclidean-distance-example.svg["Three-dimensional plot showing two vectors with points along each vector joined by dotted lines, indicating the summing of corresponding points."] Dot Product:: Compares the magnitude and alignment of the vectors. -In this method, the proximity of the vectors in space is less important than whether they point in the same direction and have the same size. -Vectors that point in similar directions (have a low angle between them) and have similar length are strongly associated with each other. -It uses the similarity of the vectors magnitudes to rank how related they are. -Use this method for tasks such as recommendation engines where ranking results from most to least related is important. +In this method, the proximity of the vectors in space is less important than whether they point in the same direction and have the same magnitude. +Vectors that point in similar directions (have a low angle between them) and have similar magnitude are strongly associated with each other. +This method uses the similarity of the vectors' magnitudes to rank their relation. +Use this method for tasks such as recommendation engines where you want to rank results from most to least related. Cosine Similarity:: This method is similar to the dot product. However, it normalizes the vectors during comparison so their magnitudes are not taken into account, just their alignment. -This normalization makes this method better for comparing textual data. -By normalizing the vectors, this method is less sensitive to the length of the data than its semantic meaning when performing comparisons. +This normalization makes this method better for comparing textual data because it's less sensitive to the length of the data. +The magnitude of a vector generated by some textual data embedding models depend on the length of the source text. +Normalizing the vector magnitude emphasizes the semantic meaning when performing comparisons. Therefore, Cosine Similarity can find the correlation between a short question and a long article that's relevant to answering it. -Use this method when you're performing similarity searches on text or similar data. +Use this method when you're performing similarity searches on text. == Vector Indexes As with other data types in Couchbase {product-name}, indexes make searching for similar vectors much faster. +Using indexes for vector searches is especially important due to the size of the vector data. You can include vectors in three types of indexes: -* Vector indexes support vectors natively. +* Vector Indexes support vectors natively. They provide the best performance when querying vector values. -This vector type can * Global Secondary Indexes (GSI) can include a single vector field. Using a GSI with a vector value lets you query both scalar and vector at once. -In this case, the scalar data helps limit the scope that Couchbase +In this case, the scalar data can reduce the number vectors that Couchbase {product-name} has to compare. + +* When you add a vector to an index, you specify a vector similarity From 5dc170420f51dc96fc332f4b232dfde8d710cf82 Mon Sep 17 00:00:00 2001 From: Gary Gray <137797428+ggray-cb@users.noreply.github.com> Date: Wed, 22 Jan 2025 16:12:04 -0500 Subject: [PATCH 09/41] Adding code for several diagrams and a few diagrams hand-drawn in Inkscape. --- .../images/cosine-similarity-example.svg | 1097 + .../assets/images/dot-product-example.svg | 1462 + .../images/draw-centroid-ivf-diagram.py | 86 + .../assets/images/draw-centroid-pq-diagram.py | 86 + .../assets/images/draw-cosine-diagram.py | 53 +- .../assets/images/draw-dot-product-diagram.py | 3 +- .../assets/images/ivf-centroid-diagram.png | Bin 0 -> 465084 bytes .../assets/images/ivf-centroid-diagram.svg | 174743 +++++++++++++++ .../images/ivf-diagram-with-vectors.svg | 775 + .../assets/images/pq-centroid-diagram.png | Bin 0 -> 439296 bytes .../assets/images/pq-centroid-diagram.svg | 174443 ++++++++++++++ .../vector-index/assets/images/pq-diagram.svg | 1432 + .../vector-index/assets/images/sq-diagram.svg | 1432 + .../pages/use-vector-indexes.adoc | 190 +- 14 files changed, 355713 insertions(+), 89 deletions(-) create mode 100644 modules/vector-index/assets/images/cosine-similarity-example.svg create mode 100644 modules/vector-index/assets/images/dot-product-example.svg create mode 100644 modules/vector-index/assets/images/draw-centroid-ivf-diagram.py create mode 100644 modules/vector-index/assets/images/draw-centroid-pq-diagram.py create mode 100644 modules/vector-index/assets/images/ivf-centroid-diagram.png create mode 100644 modules/vector-index/assets/images/ivf-centroid-diagram.svg create mode 100644 modules/vector-index/assets/images/ivf-diagram-with-vectors.svg create mode 100644 modules/vector-index/assets/images/pq-centroid-diagram.png create mode 100644 modules/vector-index/assets/images/pq-centroid-diagram.svg create mode 100644 modules/vector-index/assets/images/pq-diagram.svg create mode 100644 modules/vector-index/assets/images/sq-diagram.svg diff --git a/modules/vector-index/assets/images/cosine-similarity-example.svg b/modules/vector-index/assets/images/cosine-similarity-example.svg new file mode 100644 index 000000000..3c88ede3c --- /dev/null +++ b/modules/vector-index/assets/images/cosine-similarity-example.svg @@ -0,0 +1,1097 @@ + + + + + + + + 2025-01-16T14:23:50.569388 + image/svg+xml + + + Matplotlib v3.10.0, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/modules/vector-index/assets/images/dot-product-example.svg b/modules/vector-index/assets/images/dot-product-example.svg new file mode 100644 index 000000000..e43e36c59 --- /dev/null +++ b/modules/vector-index/assets/images/dot-product-example.svg @@ -0,0 +1,1462 @@ + + + + + + + + 2025-01-16T11:01:53.235124 + image/svg+xml + + + Matplotlib v3.10.0, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/modules/vector-index/assets/images/draw-centroid-ivf-diagram.py b/modules/vector-index/assets/images/draw-centroid-ivf-diagram.py new file mode 100644 index 000000000..0e80e3de0 --- /dev/null +++ b/modules/vector-index/assets/images/draw-centroid-ivf-diagram.py @@ -0,0 +1,86 @@ +# Illustrates how euclidean distance works +import matplotlib.pyplot as plt +from mpl_toolkits.mplot3d import Axes3D +from matplotlib.patches import FancyArrowPatch +from mpl_toolkits.mplot3d.proj3d import proj_transform +import numpy as np +import random + + +# Draws a cluster of random points around a point in space, labels the center with a star, and draws a +# sphere around the area. +def draw_cluster(x, y, z, color, dist=0.4, numpoints=10): + point_list = '' + # Draw some random points around the area + my_xs = [] + my_ys = [] + my_zs = [] + for point in range(numpoints): + my_x = random.uniform(x-dist, x+dist) + my_y = random.uniform(y-dist, y+dist) + my_z = random.uniform(z-dist, z+dist) + ax.scatter(my_x, my_y, my_z, color=color, s=20, alpha=0.8, edgecolors='black') + point_list += f' {point}: [{my_x:.4f}, {my_y:.4f}, {my_z:.4f}]\n' + my_xs.append(my_x) + my_ys.append(my_y) + my_zs.append(my_z) + + # Find center of all random points getting average of points + cx = np.mean(my_xs) + cy = np.mean(my_ys) + cz = np.mean(my_zs) + + # Plot centroid as a star + ax.scatter(cx, cy, cz, color=color, marker='*', s=100, edgecolors='black') + + # Draw a sphere to highlight the area + radius = dist + 0.1 + u = np.linspace(0, 2 * np.pi, 100) + v = np.linspace(0, np.pi, 100) + sx = radius * np.outer(np.cos(u), np.sin(v)) + cx + sy = radius * np.outer(np.sin(u), np.sin(v)) + cy + sz = radius * np.outer(np.ones(np.size(u)), np.cos(v)) + cz + # Add the sphere as a transparent surface + ax.plot_surface(sx, sy, sz, color=color, alpha=0.2) + point_list = f'centroid [{cx:.4f}, {cy:.4f}, {cz:.4f}] ({color})\n' + point_list + return point_list + +# Set up the 3D plot +fig = plt.figure(figsize=(12, 6)) +ax = fig.add_subplot(111, projection='3d') + +# Move the 3D plot to the left +ax.set_position([0.05, 0.1, 0.5, 0.8]) # [left, bottom, width, height] + +# Adjust size of 3d plot +fig.subplots_adjust(left=0.0, right=0.5, top=0.9, bottom=0.1) + +point_list = 'All points:\n' + +# Call to create a bunch of regions +point_list += draw_cluster(0.8, 0.5, 0.7, 'red', 0.15, 20) +point_list += draw_cluster(0.1, 0.1, 0.5, 'blue', 0.1, 20) +point_list += draw_cluster(0.75, 0.2, 0.3, 'green', 0.2, 30) +point_list += draw_cluster(0.2, 0.8, 0.6, 'orange', 0.15, 20) +point_list += draw_cluster(0.1, 0.7, 0.15, 'purple', 0.1, 10) +point_list += draw_cluster(0.25, 0.3, 0.1, 'maroon', 0.1, 10) +point_list += draw_cluster(0.6, 0.9, 0.85, 'cyan', 0.1, 10) + +print(point_list) + +# Set axis limits for better visibility +ax.set_xlim(0, 1) +ax.set_ylim(0, 1) +ax.set_zlim(0, 1) + +# Suppress numeric labels +ax.set_xticklabels([]) +ax.set_yticklabels([]) +ax.set_zticklabels([]) + + +# Show plot + +plt.savefig('ivf-centroid-diagram.svg') # Save as an image +plt.savefig('ivf-centroid-diagram.png') # Save as an image +plt.show() \ No newline at end of file diff --git a/modules/vector-index/assets/images/draw-centroid-pq-diagram.py b/modules/vector-index/assets/images/draw-centroid-pq-diagram.py new file mode 100644 index 000000000..44c30455c --- /dev/null +++ b/modules/vector-index/assets/images/draw-centroid-pq-diagram.py @@ -0,0 +1,86 @@ +# Illustrates how euclidean distance works +import matplotlib.pyplot as plt +from mpl_toolkits.mplot3d import Axes3D +from matplotlib.patches import FancyArrowPatch +from mpl_toolkits.mplot3d.proj3d import proj_transform +import numpy as np +import random + + +# Draws a cluster of random points around a point in space, labels the center with a star, and draws a +# sphere around the area. +def draw_cluster(x, y, z, color, dist=0.4, numpoints=10): + point_list = '' + # Draw some random points around the area + my_xs = [] + my_ys = [] + my_zs = [] + for point in range(numpoints): + my_x = random.uniform(x-dist, x+dist) + my_y = random.uniform(y-dist, y+dist) + my_z = random.uniform(z-dist, z+dist) + ax.scatter(my_x, my_y, my_z, color=color, s=40, alpha=0.8) + point_list += f' {point}: [{my_x:.4f}, {my_y:.4f}, {my_z:.4f}]\n' + my_xs.append(my_x) + my_ys.append(my_y) + my_zs.append(my_z) + + # Find center of all random points getting average of points + cx = np.mean(my_xs) + cy = np.mean(my_ys) + cz = np.mean(my_zs) + + # Plot centroid as a star + ax.scatter(cx, cy, cz, color=color, marker='*', s=100, edgecolors='black') + + # Draw a sphere to highlight the area + radius = dist + 0.1 + u = np.linspace(0, 2 * np.pi, 100) + v = np.linspace(0, np.pi, 100) + sx = radius * np.outer(np.cos(u), np.sin(v)) + cx + sy = radius * np.outer(np.sin(u), np.sin(v)) + cy + sz = radius * np.outer(np.ones(np.size(u)), np.cos(v)) + cz + # Add the sphere as a transparent surface + ax.plot_surface(sx, sy, sz, color=color, alpha=0.2) + point_list = f'centroid [{cx:.4f}, {cy:.4f}, {cz:.4f}] ({color})\n' + point_list + return point_list + +# Set up the 3D plot +fig = plt.figure(figsize=(12, 6)) +ax = fig.add_subplot(111, projection='3d') + +# Move the 3D plot to the left +ax.set_position([0.05, 0.1, 0.5, 0.8]) # [left, bottom, width, height] + +# Adjust size of 3d plot +fig.subplots_adjust(left=0.0, right=0.5, top=0.9, bottom=0.1) + +point_list = 'All points:\n' + +# Call to create a bunch of regions +point_list += draw_cluster(0.8, 0.5, 0.7, 'red', 0.15, 10) +point_list += draw_cluster(0.1, 0.1, 0.5, 'blue', 0.1, 10) +point_list += draw_cluster(0.75, 0.2, 0.3, 'green', 0.2, 15) +point_list += draw_cluster(0.2, 0.8, 0.6, 'orange', 0.15, 10) +point_list += draw_cluster(0.1, 0.7, 0.15, 'purple', 0.1, 5) +point_list += draw_cluster(0.25, 0.3, 0.1, 'maroon', 0.1, 5) +point_list += draw_cluster(0.6, 0.9, 0.85, 'cyan', 0.1, 5) + +print(point_list) + +# Set axis limits for better visibility +ax.set_xlim(0, 1) +ax.set_ylim(0, 1) +ax.set_zlim(0, 1) + +# Suppress numeric labels +ax.set_xticklabels([]) +ax.set_yticklabels([]) +ax.set_zticklabels([]) + + +# Show plot + +plt.savefig('pq-centroid-diagram.svg') # Save as an image +plt.savefig('pq-centroid-diagram.png') # Save as an image +plt.show() \ No newline at end of file diff --git a/modules/vector-index/assets/images/draw-cosine-diagram.py b/modules/vector-index/assets/images/draw-cosine-diagram.py index 80f174d9e..9aa892bbc 100644 --- a/modules/vector-index/assets/images/draw-cosine-diagram.py +++ b/modules/vector-index/assets/images/draw-cosine-diagram.py @@ -71,11 +71,8 @@ def normalize(vector, origin=None): # Define two points in 3D space #point1 = np.array([2, 3, 5]) #point2 = np.array([6, 7, 2]) -point1 = calculate_endpoint(v1_origin, v1) -point2 = calculate_endpoint(v2_origin, v2) - -midpoint1 = calculate_midpoint(v1_origin, v1) -midpoint2 = calculate_midpoint(v2_origin, v2) +point1 = calculate_endpoint(v1_origin, v1_norm) +point2 = calculate_endpoint(v2_origin, v2_norm) # Compute a vector from point1 to point2 @@ -88,7 +85,7 @@ def normalize(vector, origin=None): normal_vector /= np.linalg.norm(normal_vector) # Normalize the normal vector # Control the "height" of the arc (smaller values for a shallower arc) -arc_height = 1 +arc_height = 0.5 # Generate points on the arc t = np.linspace(0, 1, 100) @@ -99,8 +96,8 @@ def normalize(vector, origin=None): ax = fig.add_subplot(111, projection='3d') # Plot the vectors -ax.quiver(0, 0, 0, v1[0], v1[1], v1[2], color='b', linewidth=2) -ax.quiver(1, 0, 0, v2[0], v2[1], v2[2], color='r', linewidth=2) +ax.quiver(0, 0, 0, v1_norm[0], v1_norm[1], v1_norm[2], color='b', linewidth=2) +ax.quiver(1, 0, 0, v2_norm[0], v2_norm[1], v2_norm[2], color='r', linewidth=2) # Plot the original points ax.scatter(*point1, color='b', s=100) @@ -113,22 +110,46 @@ def normalize(vector, origin=None): ax.text(*midpoint, r'$\theta$', color='k', fontsize=14) # Move the lables showing the vector magnitude a bit. -text_offset = np.array([-1.3, 0, 2]) +# text_offset = np.array([-1.3, 0, 2]) # Add vector magnitudes -ax.text(*(point1 + text_offset), r'$\left| \mathbf{v_1} \right| = $' + "{:.2f}".format(vector_magnitude(v1_origin, v1)), color='b', fontsize=14) +#ax.text(*(point1 + text_offset), r'$\left| \mathbf{v_1} \right| = $' + "{:.2f}".format(vector_magnitude(v1_origin, v1)), color='b', fontsize=14) + + +#ax.text(*(point2 + text_offset), r'$\left| \mathbf{v_2} \right| = $' + "{:.2f}".format(vector_magnitude(v2_origin, v2)), color='r', fontsize=14) + -ax.text(*(point2 + text_offset), r'$\left| \mathbf{v_2} \right| = $' + "{:.2f}".format(vector_magnitude(v2_origin, v2)), color='r', fontsize=14) # Set axis limits and labels -ax.set_xlim(0, 8) -ax.set_ylim(0, 8) -ax.set_zlim(0, 8) +ax.set_xlim(0, 2) +ax.set_ylim(0, 2) +ax.set_zlim(0, 2) + +# The values on the axes were too close together, so this will filter out +# half of them. + +# Get the current ticks +x_ticks = ax.get_xticks() +y_ticks = ax.get_yticks() +z_ticks = ax.get_zticks() + +# Filter the ticks to show every other tick +x_ticks_custom = x_ticks[::2] +y_ticks_custom = y_ticks[::2] +z_ticks_custom = z_ticks[::2] + +# Set the custom ticks +ax.set_xticks(x_ticks_custom) +ax.set_yticks(y_ticks_custom) +ax.set_zticks(z_ticks_custom) + + ax.set_xlabel('X-axis') ax.set_ylabel('Y-axis') ax.set_zlabel('Z-axis') -ax.set_title('Dot Product') +ax.set_title('Cosine Similarity') # Show plot -plt.show() +#plt.show() +plt.savefig('cosine-similarity-example.svg') # Save as an image diff --git a/modules/vector-index/assets/images/draw-dot-product-diagram.py b/modules/vector-index/assets/images/draw-dot-product-diagram.py index e3107414c..11a8f0df4 100644 --- a/modules/vector-index/assets/images/draw-dot-product-diagram.py +++ b/modules/vector-index/assets/images/draw-dot-product-diagram.py @@ -121,4 +121,5 @@ def vector_magnitude(origin, vector): ax.set_title('Dot Product') # Show plot -plt.show() +# plt.show() +plt.savefig('dot-product-example.svg') # Save as an image diff --git a/modules/vector-index/assets/images/ivf-centroid-diagram.png b/modules/vector-index/assets/images/ivf-centroid-diagram.png new file mode 100644 index 0000000000000000000000000000000000000000..d31cd36cf44b1f65c14b7b9fd3e768b526087955 GIT binary patch literal 465084 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¨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≥~cN8RoFmC6VYF=%asFWQL>uet2D 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

5nrdq|4?y@Hpsnu=`{*mkKJuuZ&M?QAx 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 literal 0 HcmV?d00001 diff --git a/modules/vector-index/assets/images/ivf-centroid-diagram.svg b/modules/vector-index/assets/images/ivf-centroid-diagram.svg new file mode 100644 index 000000000..b5fa25b68 --- /dev/null +++ b/modules/vector-index/assets/images/ivf-centroid-diagram.svg @@ -0,0 +1,174743 @@ + + + + + + + + 2025-01-21T11:22:36.926818 + image/svg+xml + + + Matplotlib v3.10.0, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/modules/vector-index/assets/images/ivf-diagram-with-vectors.svg b/modules/vector-index/assets/images/ivf-diagram-with-vectors.svg new file mode 100644 index 000000000..ec178ce88 --- /dev/null +++ b/modules/vector-index/assets/images/ivf-diagram-with-vectors.svg @@ -0,0 +1,775 @@ + + + +Inverted File[0.6112, 0.8848, 0.8647, ... ][0.7873, 0.5196, 0.7417, ... ][0.7582, 0.1887, 0.3127, ... ]Centroids[0.5310, 0.8713, 0.9366, ... ][0.6948, 0.8841, 0.9403, ... ][0.6086, 0.8479, 0.9275, ... ] ... [0.9351, 0.4427, 0.6946, ... ][0.9070, 0.3921, 0.8074, ... ][0.6943, 0.3971, 0.6288, ... ] ... [0.5971, 0.3632, 0.2923, ... ][0.9355, 0.3466, 0.3779, ... ][0.6862, 0.0993, 0.4445, ... ] ... Vectors diff --git a/modules/vector-index/assets/images/pq-centroid-diagram.png b/modules/vector-index/assets/images/pq-centroid-diagram.png new file mode 100644 index 0000000000000000000000000000000000000000..2b3761f653c7e8692af098ccf5dfc1e4c06edc79 GIT binary patch literal 439296 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

#J!zkWdv0e&dA*(% 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�*LczujrG6Z+86M`X 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%0AFi-d!mgKLp*IRjETiU_~sgQKdv znIiZVlG%lrV+=_^I}*bi*rf_t`x9v8A}R|LLR^m{8%`T55v~*}CT^$uMfds|T>5yJ zzc*{xMAn43KRfi4F{|eJVsPX=F7Jl)s-ir#ZAKL7=ExSpn5$Td>_Yr)%}&0K?^ru~ zTs%w19K@xR51QDNVoo@th;A^iUOh{FU> zVwzKttjQU})OY^`HuK@iw||c)($EXnnVIxXR4r#akexmkCGvB~ z-cz0LdE=tX%hUZO-Rb+$H>svi92sl(K_QALA!)Rj43H4fYcNeVZZ~̻|@FDFsT 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 z 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%0Dq@A_CB)L<%Dw;jsDdrxFvG~^}K8Rau% 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

?jrcBE-w<{CoVOvISI}Ht>b2bkE+@%NDDv9auUt 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

PS90PTzuf9VlFuY|wt8n^oud>U$F+64% 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 JowdW>|3B + + + + + + + 2025-01-21T14:44:37.531670 + image/svg+xml + + + Matplotlib v3.10.0, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/modules/vector-index/assets/images/pq-diagram.svg b/modules/vector-index/assets/images/pq-diagram.svg new file mode 100644 index 000000000..0d338e144 --- /dev/null +++ b/modules/vector-index/assets/images/pq-diagram.svg @@ -0,0 +1,1432 @@ + + + +1Subvector 1Subvector 2Subvector X. . .[0.2113, 0.3594, ..., 0.1787, 0.7915, 0.1175, ..., 0.2543, [0.6404, 0.3555, ..., 0.2011, 0.8088, 0.1800, ..., 0.2837,0.8855, 0.6129, ..., 0.1616][0.6502, 0.6809, ..., 0.8088, 0.5766, 0.2704, ..., 0.4346, 0.1050, 0.8578, ..., 0.6275]. . .0.9007, 0.0672, ..., 0.2275]. . .Subvector 1Subvector 2Subvector X. . .. . .134214. . .CentroidIndex[0.6212, 0.6790, ..., 0.8101 ]1[0.7873, 0.5196, 0.7417, ... ]2[0.7582, 0.1887, 0.3127, ... ]3Codebook[0.6212, 0.6790, ..., 0.8101 ][0.7873, 0.5196, 0.7417, ... ][0.7582, 0.1887, 0.3127, ... ]CentroidIndex123Codebook1485314. . .11162102. . .Product QuantizationRaw VectorsQuantized Vectors diff --git a/modules/vector-index/assets/images/sq-diagram.svg b/modules/vector-index/assets/images/sq-diagram.svg new file mode 100644 index 000000000..8271cd018 --- /dev/null +++ b/modules/vector-index/assets/images/sq-diagram.svg @@ -0,0 +1,1432 @@ + + + +1Subvector 1Subvector 2Subvector X. . .[0.2113, 0.3594, ..., 0.1787, 0.7915, 0.1175, ..., 0.2543, [0.6404, 0.3555, ..., 0.2011, 0.8088, 0.1800, ..., 0.2837,0.8855, 0.6129, ..., 0.1616][0.6502, 0.6809, ..., 0.8088, 0.5766, 0.2704, ..., 0.4346, 0.1050, 0.8578, ..., 0.6275]. . .0.9007, 0.0672, ..., 0.2275]. . .Subvector 1Subvector 2Subvector X. . .. . .134214. . .CentroidIndex[0.6212, 0.6790, ..., 0.8101 ]1[0.7873, 0.5196, 0.7417, ... ]2[0.7582, 0.1887, 0.3127, ... ]3Codebook[0.6212, 0.6790, ..., 0.8101 ][0.7873, 0.5196, 0.7417, ... ][0.7582, 0.1887, 0.3127, ... ]CentroidIndex123Codebook1485314. . .11162102. . .Product QuantizationRaw VectorsQuantized Vectors diff --git a/modules/vector-index/pages/use-vector-indexes.adoc b/modules/vector-index/pages/use-vector-indexes.adoc index 8710e311e..75955057e 100644 --- a/modules/vector-index/pages/use-vector-indexes.adoc +++ b/modules/vector-index/pages/use-vector-indexes.adoc @@ -3,6 +3,7 @@ :page-ui-name: {ui-name} :page-product-name: {product-name} :description: Use Couchbase {page-product-name}'s Vector Index features to find documents based on content similarity or semantic meaning. +:page-toclevels: 3 {description} @@ -29,21 +30,20 @@ A text search for the term "cat" could return all three articles at the top of i However, that does not mean that the articles are semantically related (about the same topic). By generating vectors for the articles and comparing them, you can determine any semantic relationship between them. - Vectors can be similar in a variety of ways: * Their vectors may point in similar directions. * They may be close to each other in the vector space made up of all the dimensions in the vectors. * They may have a similar magnitude (length). -Because the first two articles are about cats, they point in a similar direction and are in a similar location in space. -The third article, despite using the word "cat" as frequently as the two other articles, has a vector that differs significantly from the other two. +Because the first two articles are about cats, their vectors point in a similar direction and are in a similar location in space. +The third article, despite using the word "cat" as frequently as the two other articles, has a vector that has significant differences from the other two. image::vector-space-example.svg["Three-dimensional plot showing two vectors that are close by and parallel and a third vector that's away and points in another direction"] -Vectors also make it possible to search for similarity in data that's hard to search using traditional techniques. +Vectors also let you search for similarity in data that's hard to search using traditional techniques. Image data, for example, is just a string of raw binary values. -Matching portions of this data within two images does not mean they're of the same subject, or even have any resemblance. +Matching portions of this data within two image files does not mean they're of the same subject, or even have any resemblance. Also, comparing megabytes of raw image data is computationally expensive. Generating vectors of the images distills features of the image into a smaller, more manageable amount of data. It also emphasizes features of the images that viewers find important, such as shapes and textures. @@ -81,94 +81,47 @@ Once you have embedded vectors in your database, you find documents with a simil Several algorithms exist that you can use to find similar vectors. Couchbase {product-name} supports three similarity methods: -Euclidean Distance:: -Calculates the geometric distance between two vectors by finding the distance between the individual elements in the vectors. +Euclidean Distance (also known as L2):: +Calculates the geometric distance between two vectors by finding the distance between the individual dimensions in the vectors. This method is most sensitive to the distance between the vectors in space, rather than their alignment. -It's sensitive to the scale of the vectors, where the length of one vector verses the other is important in the results. -Use this method when the proximity of the vectors matters, such as image similarity searches. +It's also sensitive to the scale of the vectors, where the length of one vector verses the other affects the relationship between the vectors. +Use this method when the proximity of the vectors and their magnitudes are important. +A common use case is image similarity searches, as vectors for similar images form clusters within vector space. + image::euclidean-distance-example.svg["Three-dimensional plot showing two vectors with points along each vector joined by dotted lines, indicating the summing of corresponding points."] Dot Product:: -Compares the magnitude and alignment of the vectors. -In this method, the proximity of the vectors in space is less important than whether they point in the same direction and have the same magnitude. +Finds related vectors by comparing the magnitude and alignment of the vectors. +In this method, the proximity of the vectors in space is less important than whether they point in a similar direction and have the a similar magnitude. Vectors that point in similar directions (have a low angle between them) and have similar magnitude are strongly associated with each other. This method uses the similarity of the vectors' magnitudes to rank their relation. Use this method for tasks such as recommendation engines where you want to rank results from most to least related. ++ +image::dot-product-example.svg["Three-dimensional plot showing two vectors labeled with their magnitudes and the angle between them labeled with the theta symbol."] Cosine Similarity:: This method is similar to the dot product. However, it normalizes the vectors during comparison so their magnitudes are not taken into account, just their alignment. This normalization makes this method better for comparing textual data because it's less sensitive to the length of the data. The magnitude of a vector generated by some textual data embedding models depend on the length of the source text. -Normalizing the vector magnitude emphasizes the semantic meaning when performing comparisons. -Therefore, Cosine Similarity can find the correlation between a short question and a long article that's relevant to answering it. +Normalizing vector magnitudes emphasizes the semantic meaning when performing comparisons. +Therefore, Cosine Similarity can find the semantic relationship between a short question and a long article that's relevant to answering it. Use this method when you're performing similarity searches on text. ++ +image::cosine-similarity-example.svg["Three-dimensional plot showing two vectors that are of equal length, with the angle between them labeled as theta."] + +When you search for similar vectors in Couchbase {product-name}, you must specify which similarity method to use to compare vectors. == Vector Indexes As with other data types in Couchbase {product-name}, indexes make searching for similar vectors much faster. Using indexes for vector searches is especially important due to the size of the vector data. -You can include vectors in three types of indexes: - -* Vector Indexes support vectors natively. -They provide the best performance when querying vector values. - -* Global Secondary Indexes (GSI) can include a single vector field. -Using a GSI with a vector value lets you query both scalar and vector at once. -In this case, the scalar data can reduce the number vectors that Couchbase {product-name} has to compare. - -* - -When you add a vector to an index, you specify a vector similarity - -[#quantize] -=== Reducing Vector Size - -The number of dimensions in a vector can vary. -A vector that represents highly complex data such as images can contain several thousand dimensions. -Less complex data, such as text, can still have hundreds to thousands of dimensions. -When you execute a query to find similar vectors, this large number of dimensions can make the query computationally expensive. -A search for similar raw vectors in an index requires comparing hundreds or thousands of values for each index entry. - -Several techniques, known as quantization, can reduce the size of vectors, making them faster to process. -This reduction in space can come at the cost of lower precision. -Couchbase {product-name} can use the following two forms of quantization for some indexes: - -Product Quantization (PQ):: -PQ reduces the size of the vectors by: -+ --- -. Grouping their dimensions into sub-vectors. -. Sampling the vector dataset to find representative values called centroids. -. Saving the centroids in a list called a codebook. -. Mapping each vector's sub-vectors to the closest centroid in the codebook. --- -+ -Instead of storing the full original vector, PQ stores just the codebook's index value of the centroid. -+ -It reduces the storage size without altering the dimensionality of the vector. -With less data to compare, finding similar vectors is less computationally expensive. -However, it retains the accuracy of the original vector values. -This method is best suited for large datasets where you want accurate semantic and similarity results. -+ -One issue with PQ is that as you add new vectors to the dataset, the initially chosen centroids may no longer be representative. -This skew can mean that new vectors are poorly fitted to centroids which can result in less accurate quantization. -The loss of quantization accuracy can result in less accurate similarity comparisons and semantic searches. - -Scalar Quantization (SQ):: -SQ reduces the size of a vector by mapping its floating point dimensions to a smaller data type, such as an integer. -This mapping loses some accuracy. -However, it makes the vector computationally easier to process. -This process of quantization is faster than PQ, because it does not need to build a codebook. -Also, because it does not rely on a sampling od data, it does not have the same potential loss of accuracy as PQ. +Vectors can contain hundreds to even thousands of dimensions. +Using indexes helps limit the resources needed to perform vector searches. -Some types of Couchbase {product-name} indexes use one of these forms of quantization on your vectors to improve performance and reduce storage requirements. +=== Index Support for Vectors -== Vectors in Couchbase {product-name} Indexes - -To use vectors in Couchbase {product-name} queries and searches, you store them in attributes in your documents and then add those attributes to an index. -Couchbase {product-name} supports vectors in the following index types: +You can include vectors in three types of indexes: * Vector Indexes are specifically designed for vector searches. They can index billions of documents. @@ -177,7 +130,7 @@ Use this type of index when you want to primarily query vector values with a low They excel at traditional vector similarity and semantic searches. This index offers high accuracy even for vectors with a large number of dimensions. -* Global Secondary Indexes (GSI) can be extended with a single vector column. +* Global Secondary Indexes (GSI) can have a single vector column. Adding a vector to a GSI is useful when your queries combine a single vector value with standard scalar attributes. The scalar attributes in a query reduce the number of vectors the Couchbase {product-name} has to scan to find similar vectors. Use GSI indexes with a vector column when you want to perform hybrid searches of documents using both scalars and a vector. @@ -189,6 +142,99 @@ The search results combine keyword matching of Full-Text Search with the semanti Use Search indexes with a vector attribute when you want to query based on keywords, geospacial data, and a vector value. These indexes can index millions of documents. +=== Indexing Algorithms + +When you add a vector column to an index, you specify an algorithm for Couchbase {product-name} to process the vector values in the index. +These algorithms organize and consolidate vector data in the index to make it more efficient to search. + +Couchbase {product-name} supports the following methods: + +Flat Index:: +This algorithm just stores the full vector value in the index without performing any sort of optimization. +Searches using this index use a brute-force method to find similar vectors. +This method is simple. +Adding new vectors to a flat index is fast, and the index does not need training. +It also offers high precision, because search compares the full vector values. +However, it does not scale well. +You should only use it for small data sets or for testing. + +Inverted File (IVF):: +This method performs a training phase where it locates clusters of similar vectors in the dataset. +It then chooses representative vectors (called centroids) from these clusters. +Finally, it associates all vectors with their closest centroid in a structure called an inverted list. +During a vector search, Couchbase {product-name} locates the closest centroids for the vector you're searching for. +A search of an IVF index locates the centroids that are most relevant for the vector value you are searching for. +It just searches the vectors associated to those centroids in the inverted list. +This technique partitions the vector space to limit the number of vectors that the search must compare. +However, it does lose some precision because it maps vectors to representative centroids. +It provides a balance between precision and speed. ++ +image::ivf-diagram-with-vectors.svg["A plot showing clusters of points in a 3D graph being labvelled and assigned centroid vectors. The centroids them point to multiple vectors."] + + +Product Quantization (PQ):: +Product Quantization also has a training phase where it groups the vector's dimensions into chunks called subvectors. +For example, if the vectors contain 1024 dimensions, the PQ may break the vectors into 8 subvectors, each containing 128 dimensions. +It then finds groups of centroids in each subvector space and adds them to a data structure called a codebook. +The codebook assigns each centroid an index number. +PQ then quantizes the vectors by replacing each subvector's dimensions with a reference to the closest centroid in the codebook. +The quantized vectors reduce a vector that's 1024 64-bit floating point values to 128 8 bit or 16 bit integer values. +This reduction improves performance and reduces memory use. ++ +Once it quantizes the vectors, PQ finds centroids in a similar manner as IVF. +The index stores the centroids and their related vectors in quantized format. ++ +A search of the index performs the same steps on the vector you're searching for. +It breaks the search vector into subvectors and quantizes it using the codebook. +It then locates centroids that are related to the query vector. +Finally, it searches the vectors related to the matching centroids for vectors that relate to the search vector. ++ +PQ sacrifices some accuracy as it compares quantized vectors instead of their original raw values. +Also, the process of quantization in addition to finding centroids makes training the index to computationally expensive than the other methods. +However, PQ reduces the amount of memory and processing time necessary when searching for related vectors in a large dataset. +It's the best indexing method choose when: ++ +* Your vectors contain a large number of dimensions. +* You want to limit memory use. +* Your dataset is large (millions of documents). ++ +image::pq-diagram.svg["Three-dimensional plot showing two vectors that are of equal length, with the angle between them labeled as theta."] + +Scalar Quantization (SQ):: +Scalar Quantization partitions each dimension in the vector into equal segments (called bins) over the range of the dimension's values. +It assigns each bin an index value that's 8 or 16 bits. +SQ then quantizes the vectors by replacing their dimensional values with the index of the bin the value falls into. +This quantization reduces the dimensions from 32 or 64 bit floating point values to 8 or 16 bit integers. +It lowers a search's memory and computational overhead. +It also makes search faster because integer operations are computationally less expensive than floating point operations. ++ +Because this method quantizes the vectors, it loses precision. +It's less precise than the PQ method because it assumes that each dimension can be evenly divided. +Its accuracy suffers if your data has clusters. +However, the gain in performance is often worth the tradeoff. +It has a lower training overhead compared to the PQ and IVF methods because it does not search for clusters of vectors. +Its training just determines the range of values for each dimension. +It's better suited for data that's more evenly distributed and does not have high correlations. ++ +Use this method if you want to gain some of the memory efficiency offered by vector quantization, but you do not want the processing overhead of training a PQ index. + +=== The Importance of Index Training + +Three of the four indexing methods rely on training the index on existing data. +For example, both PQ and IVF locate centroids that represent clusters of vectors in vector space. +This training reflects the content of dataset at training time. +For this training to result in accurate search results, the data in your dataset must represent the full range of data you expect to search. +If it does not, the centroids the PQ or IVF indexing method selects may not accurately represent clusters of data in the dataset. +Having accurate centroids are key to these indexing methods returning accurate results. + +Over time, you may find the accuracy of your vector searches decreasing. +Searches for similar vectors may miss relevant results or may rank less-related vectors higher than more relevant results. +These inaccuracies can occur because the data in the dataset changes over time as you add and remove documents. +The centroids identified by PQ and IVF may no longer adequately reflect the data in your database. +New clusters of vectors may have developed, and old ones may have dissipated. + +To resolve these accuracy issues, retrain your indexes. +You can choose to retrain indexes periodically, or when == Uses for Vectors in Couchbase {product-name} Indexes From 92f6fe27425b263353cf21067eee65c409156efe Mon Sep 17 00:00:00 2001 From: Gary Gray <137797428+ggray-cb@users.noreply.github.com> Date: Thu, 23 Jan 2025 11:02:15 -0500 Subject: [PATCH 10/41] Added SQ diagram. --- .../vector-index/assets/images/sq-diagram.svg | 1233 +++++++---------- .../pages/use-vector-indexes.adoc | 41 +- 2 files changed, 566 insertions(+), 708 deletions(-) diff --git a/modules/vector-index/assets/images/sq-diagram.svg b/modules/vector-index/assets/images/sq-diagram.svg index 8271cd018..2cff84f4f 100644 --- a/modules/vector-index/assets/images/sq-diagram.svg +++ b/modules/vector-index/assets/images/sq-diagram.svg @@ -2,9 +2,9 @@ 11Subvector 1Subvector 2Subvector X. . .[0.2113, 0.3594, ..., 0.1787, 0.7915, 0.1175, ..., 0.2543, [0.6404, 0.3555, ..., 0.2011, 0.8088, 0.1800, ..., 0.2837,0.8855, 0.6129, ..., 0.1616][0.6502, 0.6809, ..., 0.8088, 0.5766, 0.2704, ..., 0.4346, 0.1050, 0.8578, ..., 0.6275]. . .0.9007, 0.0672, ..., 0.2275]. . .Subvector 1Subvector 2Subvector X. . .. . .134214. . .Centroid[0.0421, 0.1594, 0.1787, ...] Index[0.6212, 0.6790, ..., 0.8101 ]1[0.7873, 0.5196, 0.7417, ... ]2[0.7582, 0.1887, 0.3127, ... ]3[0.2404, 0.8555, 0.7011, ...]Codebook[0.6502, 0.2809, 0.2188, ...] . . .[0.6212, 0.6790, ..., 0.8101 ][162,[0.7873, 0.5196, 0.7417, ... ][60,[0.7582, 0.1887, 0.3127, ... ][10,Centroid57,Index241,119,227, ...]3217, ...]Codebook1485314. . .1116210211, ...]. . .. . .Product QuantizationScalar QuantizationRaw VectorsRaw VectorsQuantized Vectors + id="tspan40">Quantized Vectors0 0.0000 - 0.0040 1 0.0041 - 0.0080 Bin #DimensionValue Range. . .. . .162 0.6480 - 0.6520 163 0.6521 - 0.6560 0 0.1000 - 0.1031 1 0.1032 - 0.1063 Bin #DimensionValue Range. . .. . .57 0.2781 - 0.2812 58 0.2813 - 0.2844 diff --git a/modules/vector-index/pages/use-vector-indexes.adoc b/modules/vector-index/pages/use-vector-indexes.adoc index 75955057e..b6f1ba38d 100644 --- a/modules/vector-index/pages/use-vector-indexes.adoc +++ b/modules/vector-index/pages/use-vector-indexes.adoc @@ -159,44 +159,52 @@ However, it does not scale well. You should only use it for small data sets or for testing. Inverted File (IVF):: -This method performs a training phase where it locates clusters of similar vectors in the dataset. +This method partitions the vector space to limit the number of vectors that a search must compare. +When creating the index, you perform a training step where it locates clusters of similar vectors in the dataset. It then chooses representative vectors (called centroids) from these clusters. Finally, it associates all vectors with their closest centroid in a structure called an inverted list. -During a vector search, Couchbase {product-name} locates the closest centroids for the vector you're searching for. -A search of an IVF index locates the centroids that are most relevant for the vector value you are searching for. -It just searches the vectors associated to those centroids in the inverted list. -This technique partitions the vector space to limit the number of vectors that the search must compare. -However, it does lose some precision because it maps vectors to representative centroids. -It provides a balance between precision and speed. ++ +A search of an IVF index first locates the centroids that are most relevant to the vector value you're searching for. +It then searches just the vectors associated to those centroids in the inverted list. +By limiting the number of vector comparisons to just the vectors close to the relevant centroids, IVF makes vector search faster. ++ +A drawback of this method is the risk that some relevant vectors won't be searched if they are associated with a centroid that isn't relevant to the search vector. +This risk increases if you add and delete data after you train the index. +The centroids chosen during the initial training may no longer accurately represent clusters in current dataset. +See {{index-training}} for more information about index accuracy. ++ +Use this method if you want a balance between precision and search speed. + image::ivf-diagram-with-vectors.svg["A plot showing clusters of points in a 3D graph being labvelled and assigned centroid vectors. The centroids them point to multiple vectors."] Product Quantization (PQ):: -Product Quantization also has a training phase where it groups the vector's dimensions into chunks called subvectors. +Product Quantization is similar to IVF, but adds additionals step to its training. +First, it groups the vector's dimensions into chunks called subvectors. For example, if the vectors contain 1024 dimensions, the PQ may break the vectors into 8 subvectors, each containing 128 dimensions. It then finds groups of centroids in each subvector space and adds them to a data structure called a codebook. The codebook assigns each centroid an index number. -PQ then quantizes the vectors by replacing each subvector's dimensions with a reference to the closest centroid in the codebook. +PQ then quantizes the vectors by replacing each subvector's dimensions with the index of the closest centroid in the codebook. The quantized vectors reduce a vector that's 1024 64-bit floating point values to 128 8 bit or 16 bit integer values. -This reduction improves performance and reduces memory use. +This reduction improves performance because integer operations are less intensive than floating point operations. +It also reduces memory use. + -Once it quantizes the vectors, PQ finds centroids in a similar manner as IVF. +Once it quantizes the vectors, PQ finds centroids in the dataset the same way IVF does. The index stores the centroids and their related vectors in quantized format. + A search of the index performs the same steps on the vector you're searching for. It breaks the search vector into subvectors and quantizes it using the codebook. -It then locates centroids that are related to the query vector. +It then locates centroids that are related to the quantized query vector. Finally, it searches the vectors related to the matching centroids for vectors that relate to the search vector. + PQ sacrifices some accuracy as it compares quantized vectors instead of their original raw values. -Also, the process of quantization in addition to finding centroids makes training the index to computationally expensive than the other methods. +Also, the process of quantization in addition to finding centroids makes training the index more computationally expensive than the other methods. However, PQ reduces the amount of memory and processing time necessary when searching for related vectors in a large dataset. It's the best indexing method choose when: + * Your vectors contain a large number of dimensions. * You want to limit memory use. -* Your dataset is large (millions of documents). +* Your dataset is large (millions to billions of vectors). + image::pq-diagram.svg["Three-dimensional plot showing two vectors that are of equal length, with the angle between them labeled as theta."] @@ -215,9 +223,14 @@ However, the gain in performance is often worth the tradeoff. It has a lower training overhead compared to the PQ and IVF methods because it does not search for clusters of vectors. Its training just determines the range of values for each dimension. It's better suited for data that's more evenly distributed and does not have high correlations. +For example, SQ may be a good fit for an IoT sensor dataset where the measured values (such as temperature) are evenly distributed over the range of measurements. + Use this method if you want to gain some of the memory efficiency offered by vector quantization, but you do not want the processing overhead of training a PQ index. ++ +image::sq-diagram.svg["Diagram showing each floating point dimension of a vector being converted to an 8-bit integer by looking up which bucket it falls into."] + +{#index-training} === The Importance of Index Training Three of the four indexing methods rely on training the index on existing data. From 5a4b4d81389214eb8ab8361dc6816a498b079b53 Mon Sep 17 00:00:00 2001 From: Gary Gray <137797428+ggray-cb@users.noreply.github.com> Date: Thu, 23 Jan 2025 16:46:17 -0500 Subject: [PATCH 11/41] Added vector embedding diagram --- .../assets/images/embedding-vectors.svg | 443 ++++++++++++++++ .../images/ivf-diagram-with-vectors.svg | 492 +++++++++--------- .../pages/use-vector-indexes.adoc | 59 ++- 3 files changed, 724 insertions(+), 270 deletions(-) create mode 100644 modules/vector-index/assets/images/embedding-vectors.svg diff --git a/modules/vector-index/assets/images/embedding-vectors.svg b/modules/vector-index/assets/images/embedding-vectors.svg new file mode 100644 index 000000000..bdfc5c963 --- /dev/null +++ b/modules/vector-index/assets/images/embedding-vectors.svg @@ -0,0 +1,443 @@ + + + +’Twas brillig, and the slithy toves + Did gyre and gimble in the wabe: +All mimsy were the borogoves, + And the mome raths outgrabe. + +“Beware the Jabberwock, my son! + The jaws that bite, the claws that catch! +Beware the Jubjub bird, and shun + The frumious Bandersnatch!” DataEmbedding ModelsVectors +all-MiniLM-L6-v2Resnet50OpenL3[ -3.3394, -2.3334, -3.0436, -3.3161, -1.9979, ... ][ -0.34820265, 0.6125417 -0.13429512, 0.25497625, ... ][ 0.00599869 -0.0045266 -0.0341841 -0.04532388 -0.03882601, ... ]TextImageAudio diff --git a/modules/vector-index/assets/images/ivf-diagram-with-vectors.svg b/modules/vector-index/assets/images/ivf-diagram-with-vectors.svg index ec178ce88..2aab94227 100644 --- a/modules/vector-index/assets/images/ivf-diagram-with-vectors.svg +++ b/modules/vector-index/assets/images/ivf-diagram-with-vectors.svg @@ -25,8 +25,8 @@ inkscape:deskcolor="#d1d1d1" inkscape:document-units="mm" inkscape:zoom="1.0482005" - inkscape:cx="500.85839" - inkscape:cy="244.22809" + inkscape:cx="500.85838" + inkscape:cy="244.22808" inkscape:window-width="1920" inkscape:window-height="1027" inkscape:window-x="1024" @@ -515,261 +515,259 @@ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:24px;font-family:'Open Sans';-inkscape-font-specification:'Open Sans';text-align:center;writing-mode:lr-tb;direction:ltr;white-space:pre;shape-inside:url(#rect5);stroke:#000000">Inverted FileInverted File[0.6112, 0.8848, 0.8647, ... ][0.7873, 0.5196, 0.7417, ... ][0.7582, 0.1887, 0.3127, ... ]Centroids[0.6112, 0.8848, 0.8647, ... ][0.5310, 0.8713, 0.9366, ... ][0.7873, 0.5196, 0.7417, ... ][0.6948, 0.8841, 0.9403, ... ][0.7582, 0.1887, 0.3127, ... ]Centroids[0.5310, 0.8713, 0.9366, ... ][0.6948, 0.8841, 0.9403, ... ][0.6086, 0.8479, 0.9275, ... ] ... [0.9351, 0.4427, 0.6946, ... ][0.9070, 0.3921, 0.8074, ... ][0.6943, 0.3971, 0.6288, ... ] ... [0.5971, 0.3632, 0.2923, ... ][0.9355, 0.3466, 0.3779, ... ][0.6862, 0.0993, 0.4445, ... ] ... [0.6086, 0.8479, 0.9275, ... ]Vectors + transform="matrix(0.26458333,0,0,0.26458333,10.381842,4.91574)" + id="text4-4-7" + style="font-size:10.6667px;text-align:start;writing-mode:lr-tb;direction:ltr;white-space:pre;shape-inside:url(#rect4-5-48);display:inline;fill:#000000"> ... [0.9351, 0.4427, 0.6946, ... ][0.9070, 0.3921, 0.8074, ... ][0.6943, 0.3971, 0.6288, ... ] ... [0.5971, 0.3632, 0.2923, ... ][0.9355, 0.3466, 0.3779, ... ][0.6862, 0.0993, 0.4445, ... ] ... Vectors diff --git a/modules/vector-index/pages/use-vector-indexes.adoc b/modules/vector-index/pages/use-vector-indexes.adoc index b6f1ba38d..dd474de2a 100644 --- a/modules/vector-index/pages/use-vector-indexes.adoc +++ b/modules/vector-index/pages/use-vector-indexes.adoc @@ -57,11 +57,13 @@ By searching your database for similar vectors, you can identify data that's sem Embedding is the process of generating vectors that represent a piece of complex unstructured data. You use a model that's specific to the data's type to generate its vector. -For example, to generate vectors from text, you can use a use models such as https://en.wikipedia.org/wiki/Word2vec[Word2Vec^] or https://en.wikipedia.org/wiki/GloVe[Global Vectors for Word Representation (GloVe)^]. +For example, to generate vectors from text, you can use a use models such as https://en.wikipedia.org/wiki/Word2vec[Word2Vec^], https://en.wikipedia.org/wiki/GloVe[Global Vectors for Word Representation (GloVe)^], or https://huggingface.co/sentence-transformers/all-MiniLM-L6-v2[all-MiniLM-L6-v2^]. The models take into account the context around each potion of the text when generating a vector. This context is what captures the semantic meaning of the text and embeds it in the vector's dimensions. -To generate vectors from images, you use different embedding models such as a https://en.wikipedia.org/wiki/Residual_neural_network[Residual Neural Network (ResNet)^]. +To generate vectors from images, you use different embedding models such as a https://en.wikipedia.org/wiki/Residual_neural_network[Residual Neural Network (ResNet)^]. Audio can be embedded using a model such as OpenL3. + +image::embedding-vectors.svg["Diagram showing text, image, and audio data being transformed by embedding models into a string of floating point numbers that represent vectors."] Behind the scenes, embedding models use neural networks that mimic how the brain recognizes patterns to distill complex data into an array of floating point values. Beyond choosing an embedding model that's appropriate for your data, you generally do not worry about the details of how the model transforms data into a vector. @@ -88,7 +90,7 @@ It's also sensitive to the scale of the vectors, where the length of one vector Use this method when the proximity of the vectors and their magnitudes are important. A common use case is image similarity searches, as vectors for similar images form clusters within vector space. + -image::euclidean-distance-example.svg["Three-dimensional plot showing two vectors with points along each vector joined by dotted lines, indicating the summing of corresponding points."] +image::euclidean-distance-example.svg["Three-dimensional plot showing two vectors with points along each vector joined by dotted lines, indicating the summing of corresponding points."] Dot Product:: Finds related vectors by comparing the magnitude and alignment of the vectors. @@ -160,10 +162,12 @@ You should only use it for small data sets or for testing. Inverted File (IVF):: This method partitions the vector space to limit the number of vectors that a search must compare. -When creating the index, you perform a training step where it locates clusters of similar vectors in the dataset. +When creating the index, you train the locates clusters of similar vectors in the dataset. It then chooses representative vectors (called centroids) from these clusters. Finally, it associates all vectors with their closest centroid in a structure called an inverted list. + +image::ivf-diagram-with-vectors.svg["A plot showing clusters of points in a 3D graph being labvelled and assigned centroid vectors. The centroids them point to multiple vectors."] ++ A search of an IVF index first locates the centroids that are most relevant to the vector value you're searching for. It then searches just the vectors associated to those centroids in the inverted list. By limiting the number of vector comparisons to just the vectors close to the relevant centroids, IVF makes vector search faster. @@ -171,31 +175,39 @@ By limiting the number of vector comparisons to just the vectors close to the re A drawback of this method is the risk that some relevant vectors won't be searched if they are associated with a centroid that isn't relevant to the search vector. This risk increases if you add and delete data after you train the index. The centroids chosen during the initial training may no longer accurately represent clusters in current dataset. -See {{index-training}} for more information about index accuracy. +See <<#index-training>> for more information about index accuracy. + Use this method if you want a balance between precision and search speed. -+ -image::ivf-diagram-with-vectors.svg["A plot showing clusters of points in a 3D graph being labvelled and assigned centroid vectors. The centroids them point to multiple vectors."] + Product Quantization (PQ):: -Product Quantization is similar to IVF, but adds additionals step to its training. -First, it groups the vector's dimensions into chunks called subvectors. +Product Quantization is similar to IVF, but adds additional steps to its training: ++ +-- +1. It groups the vector's dimensions into chunks called subvectors. For example, if the vectors contain 1024 dimensions, the PQ may break the vectors into 8 subvectors, each containing 128 dimensions. -It then finds groups of centroids in each subvector space and adds them to a data structure called a codebook. +2. It finds groups of centroids in each subvector space and adds them to a data structure called a codebook. The codebook assigns each centroid an index number. -PQ then quantizes the vectors by replacing each subvector's dimensions with the index of the closest centroid in the codebook. +3. PQ then reduces the size of the vectors (called quantizing) by replacing each subvector's dimensions with the index of the closest centroid in the codebook. +-- ++ +image::pq-diagram.svg["Three-dimensional plot showing two vectors that are of equal length, with the angle between them labeled as theta."] ++ The quantized vectors reduce a vector that's 1024 64-bit floating point values to 128 8 bit or 16 bit integer values. This reduction improves performance because integer operations are less intensive than floating point operations. -It also reduces memory use. +It also reduces memory use because each vector requires less data to store (for example, from 64KB to 128 bytes). + Once it quantizes the vectors, PQ finds centroids in the dataset the same way IVF does. -The index stores the centroids and their related vectors in quantized format. +The index stores the centroids and their related vectors in the inverted list using the quantized format. + -A search of the index performs the same steps on the vector you're searching for. -It breaks the search vector into subvectors and quantizes it using the codebook. -It then locates centroids that are related to the quantized query vector. -Finally, it searches the vectors related to the matching centroids for vectors that relate to the search vector. +A search of the PQ index performs the same steps on the vector you're searching for: ++ +-- +1. It breaks the search vector into subvectors and quantizes it using the codebook. +2. It then locates closest centroids to the quantized query vector. +3. It searches the vectors related to the matching centroids for vectors that relate to the search vector. +-- + PQ sacrifices some accuracy as it compares quantized vectors instead of their original raw values. Also, the process of quantization in addition to finding centroids makes training the index more computationally expensive than the other methods. @@ -205,8 +217,8 @@ It's the best indexing method choose when: * Your vectors contain a large number of dimensions. * You want to limit memory use. * Your dataset is large (millions to billions of vectors). -+ -image::pq-diagram.svg["Three-dimensional plot showing two vectors that are of equal length, with the angle between them labeled as theta."] + + Scalar Quantization (SQ):: Scalar Quantization partitions each dimension in the vector into equal segments (called bins) over the range of the dimension's values. @@ -216,6 +228,8 @@ This quantization reduces the dimensions from 32 or 64 bit floating point values It lowers a search's memory and computational overhead. It also makes search faster because integer operations are computationally less expensive than floating point operations. + +image::sq-diagram.svg["Diagram showing each floating point dimension of a vector being converted to an 8-bit integer by looking up which bucket it falls into."] ++ Because this method quantizes the vectors, it loses precision. It's less precise than the PQ method because it assumes that each dimension can be evenly divided. Its accuracy suffers if your data has clusters. @@ -226,11 +240,10 @@ It's better suited for data that's more evenly distributed and does not have hig For example, SQ may be a good fit for an IoT sensor dataset where the measured values (such as temperature) are evenly distributed over the range of measurements. + Use this method if you want to gain some of the memory efficiency offered by vector quantization, but you do not want the processing overhead of training a PQ index. -+ -image::sq-diagram.svg["Diagram showing each floating point dimension of a vector being converted to an 8-bit integer by looking up which bucket it falls into."] -{#index-training} + +[#index-training] === The Importance of Index Training Three of the four indexing methods rely on training the index on existing data. @@ -247,7 +260,7 @@ The centroids identified by PQ and IVF may no longer adequately reflect the data New clusters of vectors may have developed, and old ones may have dissipated. To resolve these accuracy issues, retrain your indexes. -You can choose to retrain indexes periodically, or when +You can retrain indexes periodically, or after you have made significant changes to your dataset. == Uses for Vectors in Couchbase {product-name} Indexes From 91dc41feb640f9f0dcd17d46edcbcf7cbafc2b4e Mon Sep 17 00:00:00 2001 From: Gary Gray <137797428+ggray-cb@users.noreply.github.com> Date: Fri, 24 Jan 2025 09:11:59 -0500 Subject: [PATCH 12/41] Some last minute edits --- .../pages/use-vector-indexes.adoc | 108 +++++++++++------- 1 file changed, 66 insertions(+), 42 deletions(-) diff --git a/modules/vector-index/pages/use-vector-indexes.adoc b/modules/vector-index/pages/use-vector-indexes.adoc index dd474de2a..b32c48e57 100644 --- a/modules/vector-index/pages/use-vector-indexes.adoc +++ b/modules/vector-index/pages/use-vector-indexes.adoc @@ -20,6 +20,8 @@ Similar data, such as text about the same topic or images of a similar subject, Similar vectors are close together the multi-dimensional space formed by all of the vectors in the dataset. Vectors for dissimilar data (for example, articles discussing two different topics) have vectors that are further apart in this multi-dimensional space. + + By comparing two vectors, you can find the similarity between two pieces of data. This similarity goes beyond just finding parts of the data that's identical (finding similar words in two pieces of text, for example). The vectors represent features such as the meaning of text rather than just superficial similarities. @@ -41,6 +43,12 @@ The third article, despite using the word "cat" as frequently as the two other a image::vector-space-example.svg["Three-dimensional plot showing two vectors that are close by and parallel and a third vector that's away and points in another direction"] +NOTE: Many of the diagrams in this document (and in many other discussion available on the web) show vectors in three dimensions. +These diagrams are a simplification. +The vectors used in AI applications have hundreds to thousands of dimensions. +They are easy for computers to handle, but rather difficult for humans to visualize. +So, when viewing these diagrams, remember that they only scratch the surface of the data encoded in a vector. + Vectors also let you search for similarity in data that's hard to search using traditional techniques. Image data, for example, is just a string of raw binary values. Matching portions of this data within two image files does not mean they're of the same subject, or even have any resemblance. @@ -55,17 +63,19 @@ By searching your database for similar vectors, you can identify data that's sem === Embedding Vectors Embedding is the process of generating vectors that represent a piece of complex unstructured data. -You use a model that's specific to the data's type to generate its vector. +You use an embedding model that's specific to the data's type to generate a vector to represent it. For example, to generate vectors from text, you can use a use models such as https://en.wikipedia.org/wiki/Word2vec[Word2Vec^], https://en.wikipedia.org/wiki/GloVe[Global Vectors for Word Representation (GloVe)^], or https://huggingface.co/sentence-transformers/all-MiniLM-L6-v2[all-MiniLM-L6-v2^]. -The models take into account the context around each potion of the text when generating a vector. +These models take into account the context around each potion of the text when generating a vector. This context is what captures the semantic meaning of the text and embeds it in the vector's dimensions. -To generate vectors from images, you use different embedding models such as a https://en.wikipedia.org/wiki/Residual_neural_network[Residual Neural Network (ResNet)^]. Audio can be embedded using a model such as OpenL3. +To generate vectors from images, you use different embedding models such as a https://en.wikipedia.org/wiki/Residual_neural_network[Residual Neural Network (ResNet)^]. +You can embed audio using a model such as OpenL3. image::embedding-vectors.svg["Diagram showing text, image, and audio data being transformed by embedding models into a string of floating point numbers that represent vectors."] -Behind the scenes, embedding models use neural networks that mimic how the brain recognizes patterns to distill complex data into an array of floating point values. +Behind the scenes, embedding models use neural networks that mimic how the brain recognizes patterns. +The neural nets distill the complex data into an array of floating point values. Beyond choosing an embedding model that's appropriate for your data, you generally do not worry about the details of how the model transforms data into a vector. You can only compare the similarity of vectors generated by the same embedding model. @@ -79,8 +89,11 @@ You then store the vector as an attribute in your document. === Vector Similarity -Once you have embedded vectors in your database, you find documents with a similar meaning by locating similar vectors. +Once you have embedded vectors in your database, you find documents with a similar meaning by finding similar vectors. Several algorithms exist that you can use to find similar vectors. +When you search for similar vectors in Couchbase {product-name}, you must specify which similarity method to use to compare vectors. +Each algorithm is suited for different types of data. ++ Couchbase {product-name} supports three similarity methods: Euclidean Distance (also known as L2):: @@ -88,31 +101,33 @@ Calculates the geometric distance between two vectors by finding the distance be This method is most sensitive to the distance between the vectors in space, rather than their alignment. It's also sensitive to the scale of the vectors, where the length of one vector verses the other affects the relationship between the vectors. Use this method when the proximity of the vectors and their magnitudes are important. -A common use case is image similarity searches, as vectors for similar images form clusters within vector space. + -image::euclidean-distance-example.svg["Three-dimensional plot showing two vectors with points along each vector joined by dotted lines, indicating the summing of corresponding points."] +image::euclidean-distance-example.svg["Three-dimensional plot showing two vectors with points along each vector joined by dotted lines, indicating the summing of corresponding points."] ++ +Euclidean Distance is useful for tasks such as image similarity searches. Vectors for similar images form clusters within vector space. Dot Product:: Finds related vectors by comparing the magnitude and alignment of the vectors. In this method, the proximity of the vectors in space is less important than whether they point in a similar direction and have the a similar magnitude. Vectors that point in similar directions (have a low angle between them) and have similar magnitude are strongly associated with each other. This method uses the similarity of the vectors' magnitudes to rank their relation. -Use this method for tasks such as recommendation engines where you want to rank results from most to least related. + image::dot-product-example.svg["Three-dimensional plot showing two vectors labeled with their magnitudes and the angle between them labeled with the theta symbol."] ++ +Use this method for tasks such as recommendation engines where you want to rank results from most to least related. Cosine Similarity:: This method is similar to the dot product. -However, it normalizes the vectors during comparison so their magnitudes are not taken into account, just their alignment. +However, it normalizes the vectors (making them the same length) during comparison. +Normalization means their magnitudes are not taken into account, just their alignment. This normalization makes this method better for comparing textual data because it's less sensitive to the length of the data. The magnitude of a vector generated by some textual data embedding models depend on the length of the source text. Normalizing vector magnitudes emphasizes the semantic meaning when performing comparisons. Therefore, Cosine Similarity can find the semantic relationship between a short question and a long article that's relevant to answering it. -Use this method when you're performing similarity searches on text. + image::cosine-similarity-example.svg["Three-dimensional plot showing two vectors that are of equal length, with the angle between them labeled as theta."] - -When you search for similar vectors in Couchbase {product-name}, you must specify which similarity method to use to compare vectors. ++ +Use this method when you're performing similarity searches on text. == Vector Indexes @@ -146,7 +161,7 @@ These indexes can index millions of documents. === Indexing Algorithms -When you add a vector column to an index, you specify an algorithm for Couchbase {product-name} to process the vector values in the index. +When you add a vector column to an index, you specify an algorithm that Couchbase {product-name} uses to process the vector values in the index. These algorithms organize and consolidate vector data in the index to make it more efficient to search. Couchbase {product-name} supports the following methods: @@ -154,42 +169,44 @@ Couchbase {product-name} supports the following methods: Flat Index:: This algorithm just stores the full vector value in the index without performing any sort of optimization. Searches using this index use a brute-force method to find similar vectors. -This method is simple. Adding new vectors to a flat index is fast, and the index does not need training. It also offers high precision, because search compares the full vector values. However, it does not scale well. +However, searching a flat index is inefficient, because the search must compare every vector in the index to find matchers. You should only use it for small data sets or for testing. Inverted File (IVF):: This method partitions the vector space to limit the number of vectors that a search must compare. -When creating the index, you train the locates clusters of similar vectors in the dataset. +After creating the index, you must train it before using it. +This training locates clusters of similar vectors in the dataset. It then chooses representative vectors (called centroids) from these clusters. Finally, it associates all vectors with their closest centroid in a structure called an inverted list. + image::ivf-diagram-with-vectors.svg["A plot showing clusters of points in a 3D graph being labvelled and assigned centroid vectors. The centroids them point to multiple vectors."] + -A search of an IVF index first locates the centroids that are most relevant to the vector value you're searching for. +When you search an IVF index, it first locates the centroids that are most relevant to the vector value you're searching for. It then searches just the vectors associated to those centroids in the inverted list. By limiting the number of vector comparisons to just the vectors close to the relevant centroids, IVF makes vector search faster. + -A drawback of this method is the risk that some relevant vectors won't be searched if they are associated with a centroid that isn't relevant to the search vector. -This risk increases if you add and delete data after you train the index. +A drawback of this method is the risk that the search will miss some relevant vectors. +These vectors can be missed if they're associated with a centroid that is not relevant to the search vector. +This risk increases as you add and delete data after you train the index. The centroids chosen during the initial training may no longer accurately represent clusters in current dataset. See <<#index-training>> for more information about index accuracy. + Use this method if you want a balance between precision and search speed. - - Product Quantization (PQ):: Product Quantization is similar to IVF, but adds additional steps to its training: + -- -1. It groups the vector's dimensions into chunks called subvectors. -For example, if the vectors contain 1024 dimensions, the PQ may break the vectors into 8 subvectors, each containing 128 dimensions. -2. It finds groups of centroids in each subvector space and adds them to a data structure called a codebook. +. It groups the vector's dimensions into chunks called subvectors. +For example, suppose the vectors contain 1024 dimensions. +Then PQ may break the vectors into 8 subvectors, each containing 128 dimensions. +. It finds groups of centroids in each subvector space and adds them to a data structure called a codebook. The codebook assigns each centroid an index number. -3. PQ then reduces the size of the vectors (called quantizing) by replacing each subvector's dimensions with the index of the closest centroid in the codebook. +. PQ then reduces the size of the vectors in a process called quantizing. +Quantization replaces each subvector's dimensions with the index of the closest centroid in the codebook. -- + image::pq-diagram.svg["Three-dimensional plot showing two vectors that are of equal length, with the angle between them labeled as theta."] @@ -204,44 +221,43 @@ The index stores the centroids and their related vectors in the inverted list us A search of the PQ index performs the same steps on the vector you're searching for: + -- -1. It breaks the search vector into subvectors and quantizes it using the codebook. -2. It then locates closest centroids to the quantized query vector. -3. It searches the vectors related to the matching centroids for vectors that relate to the search vector. +. It breaks the search vector into subvectors and quantizes it using the codebook. +. It then locates closest centroids to the quantized query vector. +. It searches the vectors related to the matching centroids for vectors that relate to the search vector. -- + -PQ sacrifices some accuracy as it compares quantized vectors instead of their original raw values. -Also, the process of quantization in addition to finding centroids makes training the index more computationally expensive than the other methods. +PQ sacrifices some accuracy because it compares quantized vectors instead of their original raw values. +The process of quantization in addition to finding centroids makes training the index more computationally expensive than the other methods. However, PQ reduces the amount of memory and processing time necessary when searching for related vectors in a large dataset. It's the best indexing method choose when: + * Your vectors contain a large number of dimensions. -* You want to limit memory use. +* You are willing to trade higher processing requirements during training for lower memory use during searches. * Your dataset is large (millions to billions of vectors). - - Scalar Quantization (SQ):: Scalar Quantization partitions each dimension in the vector into equal segments (called bins) over the range of the dimension's values. +In the diagram, the first dimension's values range from 0 to 1, while the second dimension's range from 0.1 to 0.9. It assigns each bin an index value that's 8 or 16 bits. SQ then quantizes the vectors by replacing their dimensional values with the index of the bin the value falls into. -This quantization reduces the dimensions from 32 or 64 bit floating point values to 8 or 16 bit integers. -It lowers a search's memory and computational overhead. -It also makes search faster because integer operations are computationally less expensive than floating point operations. + image::sq-diagram.svg["Diagram showing each floating point dimension of a vector being converted to an 8-bit integer by looking up which bucket it falls into."] + +This quantization reduces the dimensions from 32 or 64 bit floating point values to 8 or 16 bit integers. +It lowers the memory needed to perform the search. +It also makes search faster because integer operations are computationally less expensive than floating point operations. ++ Because this method quantizes the vectors, it loses precision. -It's less precise than the PQ method because it assumes that each dimension can be evenly divided. +It's less precise than the PQ method (which also quantizes vectors) because it assumes that each dimension can be evenly divided. Its accuracy suffers if your data has clusters. However, the gain in performance is often worth the tradeoff. -It has a lower training overhead compared to the PQ and IVF methods because it does not search for clusters of vectors. ++ +SQ has a lower training overhead compared to the PQ and IVF methods because it does not search for clusters of vectors. Its training just determines the range of values for each dimension. -It's better suited for data that's more evenly distributed and does not have high correlations. +It's best suited for data that's more evenly distributed and does not have high correlations. For example, SQ may be a good fit for an IoT sensor dataset where the measured values (such as temperature) are evenly distributed over the range of measurements. + -Use this method if you want to gain some of the memory efficiency offered by vector quantization, but you do not want the processing overhead of training a PQ index. - - +Use this method if you want to gain some of the memory efficiency offered by vector quantization, but want the processing overhead of training a PQ index. [#index-training] === The Importance of Index Training @@ -249,7 +265,7 @@ Use this method if you want to gain some of the memory efficiency offered by vec Three of the four indexing methods rely on training the index on existing data. For example, both PQ and IVF locate centroids that represent clusters of vectors in vector space. This training reflects the content of dataset at training time. -For this training to result in accurate search results, the data in your dataset must represent the full range of data you expect to search. +For this training to give you accurate search results, the data in your dataset must represent the full range of data you expect to search. If it does not, the centroids the PQ or IVF indexing method selects may not accurately represent clusters of data in the dataset. Having accurate centroids are key to these indexing methods returning accurate results. @@ -259,9 +275,17 @@ These inaccuracies can occur because the data in the dataset changes over time a The centroids identified by PQ and IVF may no longer adequately reflect the data in your database. New clusters of vectors may have developed, and old ones may have dissipated. +Indexes using the SQ indexing algorithm can return inaccurate results if the range of values in the dimensions change. +If one or more dimensional values fall outside the range that SQ assign buckets to, they get assigned closest bucket. +These inaccuracies can build over time, skewing results,. + To resolve these accuracy issues, retrain your indexes. You can retrain indexes periodically, or after you have made significant changes to your dataset. +You should consider the need to retrain your indexes when choosing which index algorithm to use. +For example, the PQ index method requires more resources to train than the IVF or SQ method. +If your dataset evolves rapidly, you may want avoid using PQ because you will need to perform more frequent retraining. + == Uses for Vectors in Couchbase {product-name} Indexes Here's some ways you can use vector indexes in your applications: From dbe473de7cb42d1cd1a8529dc9a4aefb89a0132b Mon Sep 17 00:00:00 2001 From: Gary Gray <137797428+ggray-cb@users.noreply.github.com> Date: Fri, 24 Jan 2025 09:41:54 -0500 Subject: [PATCH 13/41] Remove stray plus. --- modules/vector-index/pages/use-vector-indexes.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/vector-index/pages/use-vector-indexes.adoc b/modules/vector-index/pages/use-vector-indexes.adoc index b32c48e57..a6e76d90f 100644 --- a/modules/vector-index/pages/use-vector-indexes.adoc +++ b/modules/vector-index/pages/use-vector-indexes.adoc @@ -93,7 +93,7 @@ Once you have embedded vectors in your database, you find documents with a simil Several algorithms exist that you can use to find similar vectors. When you search for similar vectors in Couchbase {product-name}, you must specify which similarity method to use to compare vectors. Each algorithm is suited for different types of data. -+ + Couchbase {product-name} supports three similarity methods: Euclidean Distance (also known as L2):: From 8d0a0bf52821608bd2d85506566468ccb893de7b Mon Sep 17 00:00:00 2001 From: Gary Gray <137797428+ggray-cb@users.noreply.github.com> Date: Fri, 24 Jan 2025 13:50:13 -0500 Subject: [PATCH 14/41] Updated that the distance function has to match the embedding. --- modules/vector-index/pages/use-vector-indexes.adoc | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/modules/vector-index/pages/use-vector-indexes.adoc b/modules/vector-index/pages/use-vector-indexes.adoc index a6e76d90f..20110d279 100644 --- a/modules/vector-index/pages/use-vector-indexes.adoc +++ b/modules/vector-index/pages/use-vector-indexes.adoc @@ -90,11 +90,12 @@ You then store the vector as an attribute in your document. === Vector Similarity Once you have embedded vectors in your database, you find documents with a similar meaning by finding similar vectors. -Several algorithms exist that you can use to find similar vectors. -When you search for similar vectors in Couchbase {product-name}, you must specify which similarity method to use to compare vectors. -Each algorithm is suited for different types of data. +Several algorithms exist that you can use to find similar vectors (often referred to as the distance function). +When you add vectors to a Couchbase {product-name} index, you must specify which distance function to use to compare vectors. +Each function is suited for different types of data. +This distance function must match the distance function the embedding model used when generating the vectors. -Couchbase {product-name} supports three similarity methods: +Couchbase {product-name} supports three distance function: Euclidean Distance (also known as L2):: Calculates the geometric distance between two vectors by finding the distance between the individual dimensions in the vectors. From 9ab48d4dd83f760866a1d9c66ea9b0a8de6aa004 Mon Sep 17 00:00:00 2001 From: Gary Gray <137797428+ggray-cb@users.noreply.github.com> Date: Mon, 27 Jan 2025 15:26:29 -0500 Subject: [PATCH 15/41] Adding some additional details based on the arguments we can pass into indexing. Added clarification to SQ diagram and description about subspace centroid storage. --- .../vector-index/assets/images/sq-diagram.svg | 577 +++++++++--------- .../pages/use-vector-indexes.adoc | 73 ++- 2 files changed, 336 insertions(+), 314 deletions(-) diff --git a/modules/vector-index/assets/images/sq-diagram.svg b/modules/vector-index/assets/images/sq-diagram.svg index 2cff84f4f..c4ef0deda 100644 --- a/modules/vector-index/assets/images/sq-diagram.svg +++ b/modules/vector-index/assets/images/sq-diagram.svg @@ -2,9 +2,9 @@ 11[0.0421, 0.1594, 0.1787, ...] [0.2404, 0.8555, 0.7011, ...][0.6502, 0.2809, 0.2188, ...] . . .. . .[162,[162,[60,[60,[10,[10,57,57,241,241,19,19,27, ...]...]217, ...]...]11, ...]...]. . .. . .Scalar QuantizationScalar QuantizationRaw VectorsRaw VectorsQuantized Vectors0 0.0000 - 0.0040 1 0.0041 - 0.0080 Bin #DimensionValue Range. . .. . .162 0.6480 - 0.6520 163 0.6521 - 0.6560 0 0.1000 - 0.1031 1 0.1032 - 0.1063 Bin #DimensionValue Range. . .. . .57 0.2781 - 0.2812 58 0.2813 - 0.2844 Quantized Vectors[0.0421, 0.1594, ...] [0.2404, 0.8555, ...][0.6502, 0.2809, ...] . . .. . .0 0.0021 0.0000 - 0.0040 1 0.0067 0.0041 - 0.0080 Bin #CentroidDimensionValue Range162 0.6507 0.6480 - 0.6520 163 0.6534 0.6521 - 0.6560 . . .. . .CentroidBin#DimensionValue Range0 0.1016 0.1000 - 0.1031 1 0.1049 0.1032 - 0.1063 57 0.2799 0.2781 - 0.2812 58 0.2831 0.2813 - 0.2844 + sodipodi:nodetypes="csssc" /> diff --git a/modules/vector-index/pages/use-vector-indexes.adoc b/modules/vector-index/pages/use-vector-indexes.adoc index 20110d279..686db7ef1 100644 --- a/modules/vector-index/pages/use-vector-indexes.adoc +++ b/modules/vector-index/pages/use-vector-indexes.adoc @@ -20,7 +20,7 @@ Similar data, such as text about the same topic or images of a similar subject, Similar vectors are close together the multi-dimensional space formed by all of the vectors in the dataset. Vectors for dissimilar data (for example, articles discussing two different topics) have vectors that are further apart in this multi-dimensional space. - +=== Finding Semantically Similar Text Data By comparing two vectors, you can find the similarity between two pieces of data. This similarity goes beyond just finding parts of the data that's identical (finding similar words in two pieces of text, for example). @@ -49,6 +49,8 @@ The vectors used in AI applications have hundreds to thousands of dimensions. They are easy for computers to handle, but rather difficult for humans to visualize. So, when viewing these diagrams, remember that they only scratch the surface of the data encoded in a vector. +=== Using Vectors to Find Similar Complex Data + Vectors also let you search for similarity in data that's hard to search using traditional techniques. Image data, for example, is just a string of raw binary values. Matching portions of this data within two image files does not mean they're of the same subject, or even have any resemblance. @@ -105,7 +107,8 @@ Use this method when the proximity of the vectors and their magnitudes are impor + image::euclidean-distance-example.svg["Three-dimensional plot showing two vectors with points along each vector joined by dotted lines, indicating the summing of corresponding points."] + -Euclidean Distance is useful for tasks such as image similarity searches. Vectors for similar images form clusters within vector space. +Euclidean Distance is useful for tasks such as image similarity searches. +Vectors for similar images tend to form clusters within vector space. Dot Product:: Finds related vectors by comparing the magnitude and alignment of the vectors. @@ -155,14 +158,14 @@ Use GSI indexes with a vector column when you want to perform hybrid searches of They work well for cases where your queries are highly selective---returning a small number of results from a large dataset. They consume a moderate amount of memory and can index billions of documents. -* A Search index used for Full-Text Search can have an added vector attribute, +* A Search index used for full-text and geospacial search can have an added vector attribute, The search results combine keyword matching of Full-Text Search with the semantic meaning matching of vectors to give you hybrid results. Use Search indexes with a vector attribute when you want to query based on keywords, geospacial data, and a vector value. These indexes can index millions of documents. === Indexing Algorithms -When you add a vector column to an index, you specify an algorithm that Couchbase {product-name} uses to process the vector values in the index. +When you add a vector column to an index, you specify one or more algorithms that Couchbase {product-name} uses to process the vector values. These algorithms organize and consolidate vector data in the index to make it more efficient to search. Couchbase {product-name} supports the following methods: @@ -172,25 +175,25 @@ This algorithm just stores the full vector value in the index without performing Searches using this index use a brute-force method to find similar vectors. Adding new vectors to a flat index is fast, and the index does not need training. It also offers high precision, because search compares the full vector values. -However, it does not scale well. However, searching a flat index is inefficient, because the search must compare every vector in the index to find matchers. You should only use it for small data sets or for testing. Inverted File (IVF):: -This method partitions the vector space to limit the number of vectors that a search must compare. -After creating the index, you must train it before using it. -This training locates clusters of similar vectors in the dataset. -It then chooses representative vectors (called centroids) from these clusters. -Finally, it associates all vectors with their closest centroid in a structure called an inverted list. +This algorithm partitions the vector space to limit the number of vectors that a search must compare. +An IVF index trains itself during creation using a set of parameters you pass to it: ++ +. It samples vectors in the dataset to locate clusters of similar vectors. +. For each cluster it finds, it chooses a representative vector (called a centroid). +. It creates a data structure called an inverted list that associates all vectors with their closest centroid. + -image::ivf-diagram-with-vectors.svg["A plot showing clusters of points in a 3D graph being labvelled and assigned centroid vectors. The centroids them point to multiple vectors."] +image::ivf-diagram-with-vectors.svg["A plot showing clusters of points in a 3D graph being labelled and assigned centroid vectors. The centroids them point to multiple vectors."] + When you search an IVF index, it first locates the centroids that are most relevant to the vector value you're searching for. It then searches just the vectors associated to those centroids in the inverted list. By limiting the number of vector comparisons to just the vectors close to the relevant centroids, IVF makes vector search faster. + -A drawback of this method is the risk that the search will miss some relevant vectors. -These vectors can be missed if they're associated with a centroid that is not relevant to the search vector. +A drawback of this method is the possibility that the search could miss some relevant vectors. +Vectors can be missed if they're associated with a centroid that's not relevant to the search vector. This risk increases as you add and delete data after you train the index. The centroids chosen during the initial training may no longer accurately represent clusters in current dataset. See <<#index-training>> for more information about index accuracy. @@ -198,26 +201,29 @@ See <<#index-training>> for more information about index accuracy. Use this method if you want a balance between precision and search speed. Product Quantization (PQ):: -Product Quantization is similar to IVF, but adds additional steps to its training: +Product Quantization simplifies vector data to reduce its storage and processing requirements. +Quantization is similar to using a lossy image compression format, such as JPEG, on an picture to reduce its data size. +It trades off some detail and accuracy for a smaller, more manageable data size. ++ +PQ processes vectors using the following steps: + -- . It groups the vector's dimensions into chunks called subvectors. For example, suppose the vectors contain 1024 dimensions. -Then PQ may break the vectors into 8 subvectors, each containing 128 dimensions. +Then PQ may break the vectors into 128 subvectors, each containing 8 dimensions. . It finds groups of centroids in each subvector space and adds them to a data structure called a codebook. The codebook assigns each centroid an index number. -. PQ then reduces the size of the vectors in a process called quantizing. -Quantization replaces each subvector's dimensions with the index of the closest centroid in the codebook. +. PQ then reduces the size of the vectors by replacing each subvector's dimensions with the index of the closest centroid in the codebook. -- + image::pq-diagram.svg["Three-dimensional plot showing two vectors that are of equal length, with the angle between them labeled as theta."] + -The quantized vectors reduce a vector that's 1024 64-bit floating point values to 128 8 bit or 16 bit integer values. -This reduction improves performance because integer operations are less intensive than floating point operations. +PQ could quantize the vector in the previous example from 1024 64-bit floating point values to 128 8 bit or 16 bit integer values. +This data size reduction improves performance because integer operations are less intensive than floating point operations. It also reduces memory use because each vector requires less data to store (for example, from 64KB to 128 bytes). + -Once it quantizes the vectors, PQ finds centroids in the dataset the same way IVF does. -The index stores the centroids and their related vectors in the inverted list using the quantized format. +You often use PQ in addition to IVF---after quantization, the training process finds centroids in the dataset. +It stores the centroids and their related vectors in the inverted list using the quantized format. + A search of the PQ index performs the same steps on the vector you're searching for: + @@ -228,26 +234,31 @@ A search of the PQ index performs the same steps on the vector you're searching -- + PQ sacrifices some accuracy because it compares quantized vectors instead of their original raw values. -The process of quantization in addition to finding centroids makes training the index more computationally expensive than the other methods. +The process of quantization adds additional processing requirements to training. +This overhead makes training a PQ index more computationally expensive than the other methods. However, PQ reduces the amount of memory and processing time necessary when searching for related vectors in a large dataset. -It's the best indexing method choose when: +Using this indexing algorithm when: + * Your vectors contain a large number of dimensions. -* You are willing to trade higher processing requirements during training for lower memory use during searches. +* You're willing to trade higher processing requirements during training for lower memory use during searches. * Your dataset is large (millions to billions of vectors). Scalar Quantization (SQ):: -Scalar Quantization partitions each dimension in the vector into equal segments (called bins) over the range of the dimension's values. -In the diagram, the first dimension's values range from 0 to 1, while the second dimension's range from 0.1 to 0.9. -It assigns each bin an index value that's 8 or 16 bits. +Scalar Quantization is a simpler form of quantization than PQ. +During training, SQ determines the maximum and minimum values for each dimension in the dataset. +It then partitions each dimension in the vector into equal segments (called bins) over the range of the dimension's values. +For example, in the diagram, the first dimension's values range from 0 to 1, while the second dimension's range from 0.1 to 0.9. +SQ assigns each bin an index value that's an 8 or 16 bit integer value. +It stores the centroid value associated with the bin in the index as a 16 or 32 bit floating point number. SQ then quantizes the vectors by replacing their dimensional values with the index of the bin the value falls into. + image::sq-diagram.svg["Diagram showing each floating point dimension of a vector being converted to an 8-bit integer by looking up which bucket it falls into."] + -This quantization reduces the dimensions from 32 or 64 bit floating point values to 8 or 16 bit integers. -It lowers the memory needed to perform the search. +This quantization reduces the dimensions from 32 or 64 bit floating point values to 8 or 16 bits, reducing the memory needed for search. It also makes search faster because integer operations are computationally less expensive than floating point operations. + +A search reassembles each vector to be compared by taking the integer bin number stored as the dimension's value and replacing it with the floating point centroid associated with the bin. ++ Because this method quantizes the vectors, it loses precision. It's less precise than the PQ method (which also quantizes vectors) because it assumes that each dimension can be evenly divided. Its accuracy suffers if your data has clusters. @@ -258,12 +269,12 @@ Its training just determines the range of values for each dimension. It's best suited for data that's more evenly distributed and does not have high correlations. For example, SQ may be a good fit for an IoT sensor dataset where the measured values (such as temperature) are evenly distributed over the range of measurements. + -Use this method if you want to gain some of the memory efficiency offered by vector quantization, but want the processing overhead of training a PQ index. +Use this method if you want to gain some of the memory efficiency offered by vector quantization, but do not want the processing overhead of training a PQ index. [#index-training] === The Importance of Index Training -Three of the four indexing methods rely on training the index on existing data. +Three of the four indexing algorithms rely on training the index on existing data. For example, both PQ and IVF locate centroids that represent clusters of vectors in vector space. This training reflects the content of dataset at training time. For this training to give you accurate search results, the data in your dataset must represent the full range of data you expect to search. From e4ea2418f01039a0a0e0c5a100bd4fb753dc02d8 Mon Sep 17 00:00:00 2001 From: Gary Gray <137797428+ggray-cb@users.noreply.github.com> Date: Tue, 28 Jan 2025 09:21:37 -0500 Subject: [PATCH 16/41] Few more clarifications and edits. --- .../pages/use-vector-indexes.adoc | 36 +++++++++++-------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/modules/vector-index/pages/use-vector-indexes.adoc b/modules/vector-index/pages/use-vector-indexes.adoc index 686db7ef1..8eeba94b9 100644 --- a/modules/vector-index/pages/use-vector-indexes.adoc +++ b/modules/vector-index/pages/use-vector-indexes.adoc @@ -32,26 +32,28 @@ A text search for the term "cat" could return all three articles at the top of i However, that does not mean that the articles are semantically related (about the same topic). By generating vectors for the articles and comparing them, you can determine any semantic relationship between them. -Vectors can be similar in a variety of ways: +Vectors can be similar in a variety of ways. They may: -* Their vectors may point in similar directions. -* They may be close to each other in the vector space made up of all the dimensions in the vectors. -* They may have a similar magnitude (length). +* Point in similar directions. +* Be close to each other in the vector space made up of all the dimensions in the vectors. +* Have a similar magnitude (length). Because the first two articles are about cats, their vectors point in a similar direction and are in a similar location in space. The third article, despite using the word "cat" as frequently as the two other articles, has a vector that has significant differences from the other two. image::vector-space-example.svg["Three-dimensional plot showing two vectors that are close by and parallel and a third vector that's away and points in another direction"] -NOTE: Many of the diagrams in this document (and in many other discussion available on the web) show vectors in three dimensions. +NOTE: Many diagrams in this document (and in other discussions available on the web) show vectors in three dimensions. These diagrams are a simplification. The vectors used in AI applications have hundreds to thousands of dimensions. -They are easy for computers to handle, but rather difficult for humans to visualize. -So, when viewing these diagrams, remember that they only scratch the surface of the data encoded in a vector. +They're easy for computers to handle, but rather difficult for humans to visualize. +Also, vector dimension values in the diagrams show only 4 decimal places to conserve space. +The floating point dimensional values of actual vectors often use 6 or 7 decimal places. +When viewing these diagrams, remember that they only scratch the surface of the data encoded in a vector. === Using Vectors to Find Similar Complex Data -Vectors also let you search for similarity in data that's hard to search using traditional techniques. +Vectors let you search for similarity in data that's hard to search using traditional techniques. Image data, for example, is just a string of raw binary values. Matching portions of this data within two image files does not mean they're of the same subject, or even have any resemblance. Also, comparing megabytes of raw image data is computationally expensive. @@ -59,10 +61,9 @@ Generating vectors of the images distills features of the image into a smaller, It also emphasizes features of the images that viewers find important, such as shapes and textures. Comparing the vectors is more manageable, and actually results in finding similar images. -In Couchbase {product-name}, you can use vectors to find documents that are similar to an existing document or query value. -By searching your database for similar vectors, you can identify data that's semantically similar to a value. -=== Embedding Vectors + +== Embedding Vectors Embedding is the process of generating vectors that represent a piece of complex unstructured data. You use an embedding model that's specific to the data's type to generate a vector to represent it. @@ -89,7 +90,7 @@ You must use external embedding models to generate them and then store the resul A common method of embedding vectors in your database is to call an https://openai.com/index/introducing-text-and-code-embeddings/[OpenAI Embedding API^] to generate vectors for your data. You then store the vector as an attribute in your document. -=== Vector Similarity +== Vector Similarity Once you have embedded vectors in your database, you find documents with a similar meaning by finding similar vectors. Several algorithms exist that you can use to find similar vectors (often referred to as the distance function). @@ -223,7 +224,7 @@ This data size reduction improves performance because integer operations are les It also reduces memory use because each vector requires less data to store (for example, from 64KB to 128 bytes). + You often use PQ in addition to IVF---after quantization, the training process finds centroids in the dataset. -It stores the centroids and their related vectors in the inverted list using the quantized format. +The index stores the centroids the their related vectors in the inverted list using the quantized format. + A search of the PQ index performs the same steps on the vector you're searching for: + @@ -254,10 +255,15 @@ SQ then quantizes the vectors by replacing their dimensional values with the ind + image::sq-diagram.svg["Diagram showing each floating point dimension of a vector being converted to an 8-bit integer by looking up which bucket it falls into."] + -This quantization reduces the dimensions from 32 or 64 bit floating point values to 8 or 16 bits, reducing the memory needed for search. +This quantization reduces the dimensions from 32 or 64 bit floating point values to 8 or 16 bit integers, reducing the memory needed for search. It also makes search faster because integer operations are computationally less expensive than floating point operations. + -A search reassembles each vector to be compared by taking the integer bin number stored as the dimension's value and replacing it with the floating point centroid associated with the bin. +A search on an SQ index reassembles vectors before comparing them. +For each of the vector's dimensions, the integer bin number is replaced with the floating point centroid associated with the bin. +This recreation results in an approximation of the original vector, which the search compares to the search vector. ++ +Like the PQ algorithm, you often combine SQ and IVF. +This combination limits the number of vectors that a search has to compare and reduces its memory and processing requirements. + Because this method quantizes the vectors, it loses precision. It's less precise than the PQ method (which also quantizes vectors) because it assumes that each dimension can be evenly divided. From bc985ce772478ccd843a9a25d2c0949ea1b8eb32 Mon Sep 17 00:00:00 2001 From: Gary Gray <137797428+ggray-cb@users.noreply.github.com> Date: Fri, 31 Jan 2025 15:57:05 -0500 Subject: [PATCH 17/41] Complete revised rough draft --- .../vector-index/assets/images/pq-diagram.svg | 182 +- .../examples/gsi-vector-idx-examples.sqlpp | 1583 ++++++++++++++++- .../vector-index/pages/gsi-with-vector.adoc | 285 ++- .../pages/use-vector-indexes.adoc | 66 +- 4 files changed, 1953 insertions(+), 163 deletions(-) diff --git a/modules/vector-index/assets/images/pq-diagram.svg b/modules/vector-index/assets/images/pq-diagram.svg index 0d338e144..dc9892172 100644 --- a/modules/vector-index/assets/images/pq-diagram.svg +++ b/modules/vector-index/assets/images/pq-diagram.svg @@ -24,15 +24,15 @@ inkscape:pagecheckerboard="0" inkscape:deskcolor="#d1d1d1" inkscape:document-units="mm" - inkscape:zoom="1.0482005" - inkscape:cx="328.6585" - inkscape:cy="285.25077" + inkscape:zoom="2.096401" + inkscape:cx="549.51319" + inkscape:cy="248.52116" inkscape:window-width="1920" inkscape:window-height="1027" inkscape:window-x="1024" inkscape:window-y="25" inkscape:window-maximized="0" - inkscape:current-layer="layer1" + inkscape:current-layer="g74" showguides="false" />11Subvector 1Subspace 1Subvector 2Subspace 2Subvector XSubspace X. . .. . .[0.2113, 0.3594, ..., 0.1787, 0.7915, 0.1175, ..., 0.2543, [0.2113, 0.3594, ..., 0.1787, 0.7915, 0.1175, ..., 0.2543, [0.6404, 0.3555, ..., 0.2011, 0.8088, 0.1800, ..., 0.2837,[0.6404, 0.3555, ..., 0.2011, 0.8088, 0.1800, ..., 0.2837,0.8855, 0.6129, ..., 0.1616]0.8855, 0.6129, ..., 0.1616][0.6502, 0.6809, ..., 0.8088, 0.5766, 0.2704, ..., 0.4346, [0.6502, 0.6809, ..., 0.8088, 0.5766, 0.2704, ..., 0.4346, 0.1050, 0.8578, ..., 0.6275]0.1050, 0.8578, ..., 0.6275]. . .. . .0.9007, 0.0672, ..., 0.2275]0.9007, 0.0672, ..., 0.2275]. . .. . .Subvector 1Subspace 1Subvector 2Subspace 2Subvector XSubspace X. . .. . .. . .. . .113434214214. . .. . .CentroidCentroidIndexIndex[0.6212, 0.6790, ..., 0.8101 ][0.6212, 0.6790, ..., 0.8101 ]11[0.7873, 0.5196, 0.7417, ... ][0.7873, 0.5196, 0.7417, ... ]22[0.7582, 0.1887, 0.3127, ... ][0.7582, 0.1887, 0.3127, ... ]33CodebookCodebook[0.6212, 0.6790, ..., 0.8101 ][0.6212, 0.6790, ..., 0.8101 ][0.7873, 0.5196, 0.7417, ... ][0.7873, 0.5196, 0.7417, ... ][0.7582, 0.1887, 0.3127, ... ][0.7582, 0.1887, 0.3127, ... ]CentroidCentroidIndexIndex112233CodebookCodebook14814853531414. . .. . .1111116262102102. . .. . .Product QuantizationProduct QuantizationRaw VectorsRaw VectorsQuantized Vectors + id="tspan87">Quantized Vectors diff --git a/modules/vector-index/examples/gsi-vector-idx-examples.sqlpp b/modules/vector-index/examples/gsi-vector-idx-examples.sqlpp index f33da6751..51b779770 100644 --- a/modules/vector-index/examples/gsi-vector-idx-examples.sqlpp +++ b/modules/vector-index/examples/gsi-vector-idx-examples.sqlpp @@ -1,11 +1,11 @@ /* tag::create-rgb-idx[] */ -CREATE INDEX `color_vectors_idx` ON `vector-sample`.`colors`.`rgb` +CREATE INDEX `color_vectors_idx` ON `vector-sample`.`color`.`rgb` (`colorvect_l2` VECTOR, color, brightness) WITH { "dimension":3 , "similarity":"L2", "description":"IVF,SQ8"}; /* end::create-rgb-idx[] */ /* tag::create-vectors-idx[] */ -CREATE INDEX `color_desc_idx` ON `vector-sample`.`colors`.`rgb` +CREATE INDEX `color_desc_idx` ON `vector-sample`.`color`.`rgb` (`embedding_vector_dot` VECTOR, color, brightness) WITH { "dimension":1536, "similarity":"DOT", "description":" IVF,SQ8" } /* end::create-vectors-idx[] */ @@ -26,16 +26,16 @@ LIMIT 5; /* tag::query-vectors-idx-subquery[] */ WITH question_vec AS ( SELECT RAW couchbase_search_query.knn[0].vector - from `vector-sample`.`colors`.`rgb-questions` + from `vector-sample`.`color`.`rgb-questions` WHERE meta().id = "#FFEFD5") SELECT b.color, b.description from `rgb` AS b -order by VECTOR_DISTANCE(b.embedding_vector_dot, +order by APPROX_VECTOR_DISTANCE(b.embedding_vector_dot, question_vec[0], "DOT") LIMIT 3; /* end::query-vectors-idx-subquery[] */ /* tag::query-vectors-idx-truncated[] */ SELECT b.color, b.description from `rgb` AS b -order by VECTOR_DISTANCE(b.embedding_vector_dot, +order by APPROX_VECTOR_DISTANCE(b.embedding_vector_dot, [ 0.005115953739732504, 0.004331615287810564, @@ -47,9 +47,20 @@ order by VECTOR_DISTANCE(b.embedding_vector_dot, ], "DOT") LIMIT 3; /* end::query-vectors-idx-truncated[] */ +/* tag::query-vectors-idx-subquery-filtered[] */ +WITH question_vec AS ( + SELECT RAW couchbase_search_query.knn[0].vector + from `vector-sample`.`color`.`rgb-questions` + WHERE meta().id = "#FFEFD5") +SELECT b.color, b.description, b.brightness from `rgb` AS b +WHERE b.brightness > 190.0 +order by APPROX_VECTOR_DISTANCE(b.embedding_vector_dot, +question_vec[0], "DOT") LIMIT 3; +/* end::query-vectors-idx-subquery-filtered[] */ + /* tag::query-vectors-idx-whole[] */ SELECT b.color, b.description from `rgb` AS b -order by VECTOR_DISTANCE(b.embedding_vector_dot, +order by APPROX_VECTOR_DISTANCE(b.embedding_vector_dot, [ 0.005115953739732504, 0.004331615287810564, @@ -1589,3 +1600,1563 @@ order by VECTOR_DISTANCE(b.embedding_vector_dot, -0.03757078945636749 ], "DOT") LIMIT 3; /* end::query-vectors-idx-whole[] */ + + +/* tag::query-vectors-idx-filtered-truncated[] */ +SELECT b.color, b.description from `rgb` AS b +WHERE brightness > 190.0 +ORDER BY APPROX_VECTOR_DISTANCE(b.embedding_vector_dot, +[ + 0.005115953739732504, + 0.004331615287810564, + 0.014279481954872608, + /* long list of vector values omitted */ + -0.005022349301725626, + 0.002007648814469576, + -0.03757078945636749 + ], "DOT") LIMIT 3; +/* end::query-vectors-idx-filtered-truncated[] */ + +/* tag::query-vectors-idx-filtered-whole[] */ +SELECT b.color, b.description from `rgb` AS b +WHERE brightness > 190.0 +ORDER BY APPROX_VECTOR_DISTANCE(b.embedding_vector_dot, +[ + 0.005115953739732504, + 0.004331615287810564, + 0.014279481954872608, + 0.000619320897385478, + 0.006700769532471895, + 0.018410978838801384, + -0.010367471724748611, + -0.019805356860160828, + 0.013059400022029877, + -0.011271236464381218, + -0.011251870542764664, + -0.004915834404528141, + -0.0031744735315442085, + 0.00843728892505169, + -0.01706824265420437, + 0.013362806290388107, + 0.04694411903619766, + 0.011258325539529324, + 0.01298193447291851, + -0.01080644316971302, + -0.01744265854358673, + 0.0044155362993478775, + -0.00742378132417798, + 0.014214927330613136, + -0.01248486340045929, + 0.0009481459856033325, + 0.027293693274259567, + -0.029204510152339935, + 0.006355402525514364, + 0.016254853457212448, + 0.02933361940085888, + -0.017352283000946045, + 0.007236572913825512, + -0.017094064503908157, + 0.002293302910402417, + -0.018139848485589027, + 0.007811109069734812, + 0.015028315596282482, + -0.008785883896052837, + -0.013453182764351368, + -8.422360406257212e-05, + 0.010896819643676281, + 0.002246500924229622, + -0.010586957447230816, + -0.0011482653208076954, + -0.003537593176588416, + 0.02017977461218834, + -0.013491915538907051, + -0.00977356918156147, + 0.01215563528239727, + 0.032122381031513214, + 0.02827492356300354, + 0.002995334332808852, + -0.027396980673074722, + 0.004583378322422504, + 0.0007577098440378904, + 0.00016683334251865745, + 0.025731472298502922, + 0.006158510688692331, + -0.008288813754916191, + 0.00016885067452676594, + 0.01956005021929741, + -0.01309813279658556, + 0.009934956207871437, + -0.007920851930975914, + 0.008721329271793365, + -0.032354775816202164, + -0.0031050771940499544, + -0.0049997554160654545, + 0.029178688302636147, + 0.0075980788096785545, + 0.024995548650622368, + 0.018165670335292816, + -0.008463110774755478, + 0.025292500853538513, + -0.0031518794130533934, + -0.01706824265420437, + -0.00925713311880827, + -0.013375717215240002, + 0.0066749476827681065, + 0.015144513919949532, + -0.0011805426329374313, + -0.037312570959329605, + 0.015092870220541954, + 0.01786871999502182, + 0.015002493746578693, + -0.020631656050682068, + 0.0021415995433926582, + -0.004912606440484524, + -0.004880329128354788, + -0.012523596175014973, + 0.024246715009212494, + 0.02413051761686802, + 0.0008162125013768673, + -0.02077367715537548, + 0.005419360473752022, + 0.008508299477398396, + 0.010470759123563766, + 0.0004575308703351766, + -0.01443441305309534, + -0.00852766539901495, + 0.017326461151242256, + -0.03674449026584625, + -0.009579905308783054, + -0.018643373623490334, + -0.0009473390528000891, + 0.00832109060138464, + -0.0016057961620390415, + 0.023614080622792244, + -0.024272536858916283, + -0.042502760887145996, + 0.03207073733210564, + 0.009534717537462711, + -0.041082561016082764, + -0.010651512071490288, + -0.01997319981455803, + 0.016306497156620026, + 0.015648040920495987, + -0.00894081499427557, + -0.03473038598895073, + -0.00884398352354765, + 0.018010739237070084, + 0.019004879519343376, + -0.015970813110470772, + 0.01914690062403679, + 0.0008166159386746585, + -0.006232748739421368, + -0.033568404614925385, + -0.03416230529546738, + -0.02494390495121479, + 0.02163870818912983, + 0.01701659895479679, + -0.004396169912070036, + 0.003786128479987383, + -0.008372734300792217, + 0.014563522301614285, + -0.01029646210372448, + 0.005622707307338715, + 0.010270640254020691, + 0.0004607586015481502, + 0.032096557319164276, + 0.021096449345350266, + -0.00034355162642896175, + -0.007966040633618832, + -0.004928745329380035, + 0.02806834876537323, + 0.010528858751058578, + 0.013349895365536213, + -0.006629759445786476, + -0.01913398876786232, + 0.02205185778439045, + -0.015480197966098785, + 0.02580893784761429, + 0.013362806290388107, + 0.010244818404316902, + 0.024246715009212494, + -0.0043122489005327225, + 0.0009594430448487401, + -0.02948855049908161, + 0.005044943653047085, + -0.004499457310885191, + -0.010373927652835846, + 0.0007040488417260349, + 0.012032981030642986, + 0.02039925940334797, + 0.02788759581744671, + 0.01807529479265213, + 0.008695507422089577, + 0.0015170335536822677, + 0.02059292420744896, + -0.012291199527680874, + 0.02706129662692547, + -0.009663826785981655, + 0.01101301796734333, + -0.013336984440684319, + 0.025705650448799133, + 0.006765324156731367, + 0.007197840139269829, + 0.024156339466571808, + -0.012975478544831276, + -0.03098621778190136, + -0.004870646167546511, + -0.000659667537547648, + -0.01186513900756836, + -0.007849842309951782, + -0.005797004792839289, + 0.022310076281428337, + -0.02099316194653511, + 0.0013346667401492596, + -0.011600465513765812, + -0.002236817730590701, + 0.020825320854783058, + 0.0010651513002812862, + -0.022826513275504112, + -0.6420344114303589, + 8.150020585162565e-05, + -0.014214927330613136, + -0.015841703861951828, + 0.02079949900507927, + 0.020205596461892128, + 0.037544965744018555, + 0.012265377677977085, + 0.0005870435852557421, + -0.01665509305894375, + 0.005919658578932285, + 0.013349895365536213, + 0.016577627509832382, + -0.01664218120276928, + 0.0006382837891578674, + -0.013969619758427143, + -0.017326461151242256, + -0.00033669269760139287, + -0.013027122244238853, + 0.00042283275979571044, + -0.00431870436295867, + 0.02161288633942604, + -0.007572256959974766, + 0.007262394763529301, + 0.019469672814011574, + 0.01372431218624115, + 0.001147458446212113, + -0.013479004614055157, + 0.014279481954872608, + 0.043587278574705124, + -0.027138762176036835, + 0.015118692070245743, + 8.61400694702752e-05, + 0.00968319270759821, + 0.04738309234380722, + 0.01579006016254425, + -0.026544859632849693, + 0.03506607189774513, + -0.022348809987306595, + 0.05510382354259491, + -0.01931474171578884, + 0.011671475134789944, + 0.02081240899860859, + -0.03098621778190136, + 0.0003318511007819325, + 0.021574154496192932, + 0.024272536858916283, + -0.015854615718126297, + 0.028378210961818695, + -0.015467287041246891, + 0.019689159467816353, + 0.005471004173159599, + 0.014718453399837017, + 0.0048641907051205635, + 0.00894081499427557, + 0.010845175944268703, + 0.030056631192564964, + -0.016538893803954124, + 0.012317021377384663, + 0.009366875514388084, + -0.003025997895747423, + 0.0029791956767439842, + -0.01434403657913208, + -0.019185632467269897, + -0.014976671896874905, + 0.03465292230248451, + -0.013788866810500622, + -0.013091676868498325, + -0.0024353230837732553, + -0.028791360557079315, + -0.005522647872567177, + -0.008630952797830105, + -0.02286524698138237, + 0.009418519213795662, + 0.00011145758617203683, + -0.0103932935744524, + 0.012342843227088451, + 0.017584679648280144, + -0.008288813754916191, + 0.009754203259944916, + 0.0016525982646271586, + -0.00712683005258441, + -0.005467776209115982, + 0.0034956326708197594, + 0.0353759340941906, + 0.013324073515832424, + -0.03535011038184166, + -0.04258022829890251, + 0.01322078611701727, + 0.011193770915269852, + 0.023756099864840508, + 0.030934574082493782, + 0.0018236680189147592, + -0.0009667054400779307, + -0.012588150799274445, + 0.003983020316809416, + -0.02369154617190361, + -0.015234890393912792, + -0.026299552991986275, + -0.007107463665306568, + 0.00779174268245697, + -0.015389821492135525, + -0.012310566380620003, + 0.008262991905212402, + 0.02664814703166485, + -0.0017284499481320381, + -0.0297467689961195, + 0.022607028484344482, + 0.023575346916913986, + -0.017326461151242256, + 0.020115219056606293, + -0.026751434430480003, + 0.0026580365374684334, + 0.003090552520006895, + 0.03596983477473259, + -0.02451784536242485, + 0.02471150830388069, + -0.003347157035022974, + -0.007533524185419083, + -0.02556362934410572, + 0.02933361940085888, + -0.013298251666128635, + -0.014279481954872608, + 0.007507702335715294, + 0.017571767792105675, + 0.00280489819124341, + -0.008424378000199795, + -0.0010514333844184875, + -0.0030469780322164297, + -0.0012862507719546556, + 0.021161004900932312, + -0.0022755505051463842, + -0.0011644039768725634, + 0.0031744735315442085, + -0.00047205566079355776, + -0.014576433226466179, + 0.004460724536329508, + -0.010031787678599358, + 0.008256535977125168, + -0.04513658955693245, + -0.019288919866085052, + -0.013233697041869164, + 0.00965091586112976, + 0.0026709474623203278, + -0.021884016692638397, + -0.03516935929656029, + -0.03281956911087036, + 0.008663230575621128, + -0.038784414529800415, + -0.010322283953428268, + -0.016474340111017227, + -0.013788866810500622, + -0.022568294778466225, + 0.03183833882212639, + 0.025834759697318077, + -0.0028807499911636114, + -0.02100607380270958, + -0.02249082922935486, + -0.01434403657913208, + -0.007365682162344456, + 0.01994737796485424, + 0.02972094714641571, + -0.008837527595460415, + -0.009457251988351345, + -0.013595202937722206, + -0.04121166840195656, + -0.009605727158486843, + 0.013111043721437454, + -0.010877453722059727, + -0.023368772119283676, + 0.012420308776199818, + -0.012820547446608543, + -0.006842789705842733, + 0.012523596175014973, + -0.005935797467827797, + 0.013646846637129784, + -0.006868611555546522, + -0.021264292299747467, + -0.002252956386655569, + -0.007681999821215868, + 0.00020627219055313617, + 0.009089291095733643, + -0.005713083781301975, + -0.005212785676121712, + 0.03496278449892998, + 0.001072413637302816, + 0.022090591490268707, + 0.07266268134117126, + -0.02431127056479454, + 0.032974500209093094, + -0.0030485920142382383, + 0.009289409965276718, + -0.01660344935953617, + 0.001254780450835824, + -0.01340153906494379, + 0.01103238482028246, + 0.010199629701673985, + -0.0026919275987893343, + -0.012142724357545376, + -0.005038488190621138, + 0.031709231436252594, + 0.023562436923384666, + 0.011781218461692333, + -0.003963653929531574, + 0.016164477914571762, + -0.02034761570394039, + 0.016745468601584435, + 0.0006649125716648996, + 0.008069328032433987, + 0.022168057039380074, + -0.0036215141881257296, + -0.03199326992034912, + -0.008366279304027557, + -0.014576433226466179, + 0.006668492220342159, + 0.0007762692985124886, + 0.00029594259103760123, + 0.010864542797207832, + -0.0174555703997612, + 0.013349895365536213, + 0.017984917387366295, + 0.010993652045726776, + 0.01976662501692772, + -0.013956708833575249, + -0.00499007198959589, + 0.007546435110270977, + 0.014498967677354813, + -0.0032164340373128653, + -0.01974080316722393, + -0.03395573049783707, + -0.013853421434760094, + -0.0065393829718232155, + -0.005961619317531586, + 0.0028016704600304365, + -0.005122409202158451, + 0.005061082076281309, + 0.01603536866605282, + -0.024595310911536217, + 0.03449799120426178, + 0.008217803202569485, + 0.01891450397670269, + 0.031683407723903656, + 0.005170824937522411, + 0.006481283809989691, + 0.04433611407876015, + -0.02637701854109764, + 0.0172231737524271, + 0.005474231671541929, + 0.0028710667975246906, + 0.0050417156890034676, + -0.026351196691393852, + -0.007681999821215868, + -0.04808028042316437, + 0.009780025109648705, + 0.011619831435382366, + -0.013982530683279037, + 0.014576433226466179, + -0.0004478476766962558, + 0.020864052698016167, + 0.017545945942401886, + 0.02428544871509075, + -0.019043613225221634, + 0.009986599907279015, + -0.01952131651341915, + 0.00379258394241333, + 0.008004773408174515, + 0.004909378942102194, + 0.003116374369710684, + -0.018785394728183746, + -0.008095149882137775, + 0.008701963350176811, + -0.0237173680216074, + 0.009082835167646408, + -0.02453075535595417, + -0.0049674781039357185, + 0.0127753596752882, + -0.003941059578210115, + -0.018165670335292816, + -0.00499007198959589, + 0.00441230833530426, + -0.010193174704909325, + -0.032328955829143524, + 0.004309020936489105, + 0.0170553307980299, + -0.005080448463559151, + -0.018630463629961014, + -0.00671368045732379, + 0.030237384140491486, + -0.026958009228110313, + 0.0016606675926595926, + 0.024375824257731438, + 0.033800799399614334, + 0.022619938477873802, + -0.0027839180547744036, + -0.0024272536393254995, + -0.02493099495768547, + 0.017829986289143562, + 0.004564011935144663, + 0.010690244846045971, + -0.00247244187630713, + 0.006426412612199783, + -0.006271481513977051, + -0.024220893159508705, + 0.008295268751680851, + 0.02227134443819523, + 0.017300639301538467, + 0.002096411306411028, + -0.00018418239778839052, + 0.00420250603929162, + -0.019430940970778465, + -0.010774166323244572, + -0.011903871782124043, + 0.0039023268036544323, + -0.00925713311880827, + 0.009276499040424824, + 0.015118692070245743, + -0.016383962705731392, + -0.018359335139393806, + 0.042270366102457047, + -0.013582292012870312, + 0.0026806306559592485, + -0.011206681840121746, + -0.014821740798652172, + 0.007075186353176832, + 0.05422588065266609, + -0.006026173941791058, + -0.010412660427391529, + 0.0015331722097471356, + 0.019676247611641884, + 0.012058802880346775, + -0.021303024142980576, + -0.02076076529920101, + 0.00893435999751091, + 0.004357437137514353, + -0.0068105123937129974, + 0.003177701262757182, + -0.014770097099244595, + 0.008469566702842712, + 0.0034052561968564987, + 0.001760727260261774, + -0.0002231169055448845, + -0.02892046980559826, + -0.006868611555546522, + -0.028326567262411118, + -0.014369858428835869, + 0.014395680278539658, + -0.005064310040324926, + 0.015467287041246891, + -0.010787077248096466, + 0.010832265019416809, + 0.038242157548666, + 0.018785394728183746, + 0.006449006497859955, + -0.020463814958930016, + 0.014679720625281334, + 0.0031486516818404198, + -0.007694910746067762, + 0.001307231024838984, + -0.030237384140491486, + -0.003976564854383469, + -0.020902786403894424, + -0.005809915717691183, + -0.01404708530753851, + -0.003650563769042492, + -0.003025997895747423, + 0.015660950914025307, + -0.014176194556057453, + -0.0116262873634696, + 0.01331116259098053, + -0.010535313747823238, + -0.014085818082094193, + 0.003834544448181987, + -0.013956708833575249, + 0.01422783825546503, + 0.007656177971512079, + -0.0012346070725470781, + -0.0008440516539849341, + -0.006145599763840437, + 0.0010465917875990272, + 0.0094766179099679, + -0.023188019171357155, + -0.0028339477721601725, + 0.01321433112025261, + -0.019689159467816353, + -0.0012321863323450089, + -0.022335898131132126, + 0.0003241852391511202, + 0.008256535977125168, + -0.011613376438617706, + -0.04136659950017929, + 0.005361261311918497, + -0.038242157548666, + -0.01059341337531805, + -0.014576433226466179, + -0.005667895544320345, + -0.027319515123963356, + -0.012704349122941494, + 0.01828186959028244, + 0.02349788136780262, + 0.02330421842634678, + 0.007236572913825512, + 0.00861804187297821, + 0.01975371316075325, + 0.01621612161397934, + -0.0014678107108920813, + -0.009424974210560322, + -0.006681403145194054, + -0.018772482872009277, + -0.0005394345498643816, + -0.0009868787601590157, + 0.0320449136197567, + -0.015635129064321518, + -0.01580297201871872, + 0.010122164152562618, + 0.016177387908101082, + -0.013259518891572952, + 0.03413648530840874, + -0.021057717502117157, + -0.00473508145660162, + 0.018152760341763496, + 0.011000107042491436, + 0.015919169411063194, + -0.004273516125977039, + -0.027758486568927765, + 0.008914993144571781, + -0.026983831077814102, + -0.0003104673814959824, + -0.02206476964056492, + 0.012168546207249165, + -0.00358600914478302, + -0.009308775886893272, + 0.0029097995720803738, + -0.018979057669639587, + -0.007385048549622297, + 0.010464304126799107, + -0.005532330833375454, + 0.004405852872878313, + 0.023562436923384666, + -0.006629759445786476, + 0.007101008202880621, + -0.023536615073680878, + 0.030857108533382416, + -0.00613914430141449, + -0.028817182406783104, + 0.012213733978569508, + -0.05587847903370857, + 0.0013596817152574658, + -0.0006209347629919648, + -0.022168057039380074, + 0.0028807499911636114, + 0.006303758826106787, + -0.00539999408647418, + 0.00671368045732379, + -0.0013120726216584444, + 0.002383679384365678, + 0.013149776495993137, + -0.007772376295179129, + -0.022568294778466225, + -0.04898404702544212, + -0.004215416964143515, + 0.011019473895430565, + 0.016345230862498283, + -0.004915834404528141, + -0.020463814958930016, + -0.01891450397670269, + 0.03300032392144203, + -0.015209068544209003, + -0.02121264860033989, + -0.03568579629063606, + -0.030624711886048317, + 0.033129431307315826, + 0.0057485890574753284, + -0.009941411204636097, + 0.02680307812988758, + -0.026364106684923172, + -0.00288559147156775, + -0.013995441608130932, + 0.014369858428835869, + -7.84742078394629e-05, + -0.014447323977947235, + -0.03196744993329048, + -0.017804164439439774, + 0.018385156989097595, + -0.005532330833375454, + 0.01112921629101038, + 0.015480197966098785, + 0.032742105424404144, + 0.011000107042491436, + -0.017197351902723312, + -0.010212540626525879, + -0.015441465191543102, + 0.002488580532371998, + -0.01600954681634903, + 0.012859280221164227, + 0.02429835870862007, + 0.014692631550133228, + 0.00968319270759821, + 0.00819843728095293, + 0.03116697072982788, + 0.022297166287899017, + 0.008689052425324917, + -0.01892741397023201, + -0.008863349445164204, + -0.02413051761686802, + -0.014653898775577545, + 0.005671123508363962, + -0.009625094011425972, + -0.00072664296021685, + 0.02493099495768547, + 0.009786480106413364, + 0.0253828763961792, + 0.017106974497437477, + -0.009689648635685444, + 0.004954567179083824, + 0.029798412695527077, + 0.010244818404316902, + 0.024569489061832428, + -0.005290251225233078, + 0.01206525880843401, + -0.03989475592970848, + -0.032948680222034454, + 0.0032067508436739445, + -0.024827707558870316, + -0.007230117451399565, + 0.0014653898542746902, + 0.009005369618535042, + 0.011961971409618855, + -0.0028016704600304365, + 0.011903871782124043, + 0.022374631837010384, + 0.014279481954872608, + 0.002787145785987377, + 0.008256535977125168, + -0.007920851930975914, + -0.0590287446975708, + -0.008179070428013802, + -0.04596288874745369, + -0.04172810539603233, + 0.0019027474336326122, + 0.006784690544009209, + -0.038552019745111465, + 0.026570681482553482, + 0.010012421756982803, + -0.002772620879113674, + -0.008153248578310013, + -0.0035827814135700464, + 0.00415731780230999, + -0.020334705710411072, + 0.0441037155687809, + -0.004292882513254881, + -0.00043211248703300953, + -0.009115112945437431, + 0.001920499955303967, + -0.016074100509285927, + -0.011755396611988544, + 0.03496278449892998, + 0.019418029114603996, + -0.001509771216660738, + -0.020864052698016167, + 0.022710315883159637, + 0.005758272018283606, + -0.015015404671430588, + -0.009192578494548798, + 0.004983616527169943, + 0.040230438113212585, + 0.0032842163927853107, + -0.039817288517951965, + 0.030185740441083908, + -0.02413051761686802, + 0.03341347351670265, + 0.0032083645928651094, + -0.018036561086773872, + 0.016732558608055115, + -0.02183237299323082, + 0.0003052223182749003, + 0.022723225876688957, + -0.017106974497437477, + 0.022568294778466225, + -0.00087632896611467, + 0.014176194556057453, + -0.01289155799895525, + 0.008753607049584389, + -0.022193878889083862, + -0.004238010849803686, + -0.0060584512539207935, + 0.0023304217029362917, + 0.01770087704062462, + 0.003155107144266367, + 0.011581098660826683, + 0.014628076925873756, + 0.0070170871913433075, + 0.01621612161397934, + 0.011774762533605099, + 0.027810130268335342, + -0.010141531005501747, + 0.014318214729428291, + -0.013737223111093044, + 0.0001642108109081164, + 0.0021545104682445526, + -0.0005850262241438031, + 0.0009626707760617137, + -0.0011571416398510337, + -0.0033891175407916307, + -0.015919169411063194, + 0.03881023824214935, + -0.00852766539901495, + -0.0292819757014513, + 0.01413746178150177, + 0.001689717173576355, + 0.009986599907279015, + -0.030908752232789993, + -0.017326461151242256, + 0.02330421842634678, + 0.0007924079545773566, + -0.03119279257953167, + -0.020257240161299706, + 3.0058245101827197e-05, + 0.018578819930553436, + 0.001744588604196906, + -0.012471952475607395, + -0.005761499982327223, + -0.0022077681496739388, + -0.020915696397423744, + 0.03488531708717346, + -0.007688455283641815, + 0.010548224672675133, + -0.009818757884204388, + 0.012323477305471897, + -0.0036150587256997824, + -0.04596288874745369, + 0.026983831077814102, + -0.01952131651341915, + -0.035453397780656815, + -0.011807040311396122, + 0.01847553253173828, + 0.014240749180316925, + -0.009547628462314606, + -0.0049707056023180485, + 0.0062262932769954205, + 0.006449006497859955, + -0.006158510688692331, + 0.0026919275987893343, + -0.016913311555981636, + 0.012736626900732517, + -0.008146793581545353, + -0.01372431218624115, + 0.015518930740654469, + -0.006048767827451229, + -0.005877698305994272, + -0.031915806233882904, + -0.005909975618124008, + -0.007139740977436304, + -0.031244436278939247, + -0.003595692338421941, + -0.0068105123937129974, + 0.036873601377010345, + -0.007165562827140093, + -0.014150372706353664, + -0.015183246694505215, + 0.0006019718130119145, + -0.01622903160750866, + 0.01874666102230549, + 0.012020070105791092, + -0.01619029976427555, + -0.017403926700353622, + 0.029462728649377823, + 0.022180967032909393, + 0.0210189837962389, + -0.007572256959974766, + -0.01644851826131344, + -0.01825604774057865, + -0.018385156989097595, + -0.01466680970042944, + -0.00905055832117796, + -0.0055839745327830315, + 0.027371158823370934, + 0.02597677893936634, + -0.04059194400906563, + -0.030857108533382416, + 0.023781921714544296, + -0.023420415818691254, + -0.025834759697318077, + 0.016371052712202072, + 0.004722170531749725, + -0.0015210682759061456, + 0.01724899560213089, + -0.004993299953639507, + 0.018991969525814056, + 0.004809319041669369, + -0.01748139224946499, + -0.019237276166677475, + 0.0008916606893762946, + 0.012743081897497177, + -0.030934574082493782, + 0.03842290863394737, + -0.025615273043513298, + -0.03036649338901043, + -0.005680806469172239, + 0.01932765357196331, + -0.0033923452720046043, + 0.0026725612115114927, + 0.004583378322422504, + 0.010361016727983952, + 0.019882822409272194, + -0.004883557092398405, + 0.033129431307315826, + -0.0001690524077275768, + 0.003650563769042492, + 0.009011825546622276, + -0.020063575357198715, + -0.02286524698138237, + -0.02081240899860859, + 0.03661538287997246, + -0.036073122173547745, + 0.013750134035944939, + 0.023162197321653366, + 0.012846369296312332, + -0.026958009228110313, + -0.019392207264900208, + -0.006219837814569473, + 0.006013263016939163, + -0.019043613225221634, + -0.001880153315141797, + 0.003411711659282446, + -0.014305303804576397, + -0.008359823375940323, + -0.011897416785359383, + -0.015867525711655617, + -0.006100411526858807, + -0.025499075651168823, + -0.013995441608130932, + -0.0001231581118190661, + 0.021483777090907097, + -0.0021464412566274405, + -0.0072236619889736176, + -0.016525983810424805, + 0.016061190515756607, + -0.01829477958381176, + -0.018578819930553436, + -0.02680307812988758, + -0.02726787142455578, + -0.01600954681634903, + 0.028972113505005836, + 0.016371052712202072, + -0.014382769353687763, + 0.007843386381864548, + -0.014692631550133228, + -0.007055819965898991, + 0.0005442761466838419, + -0.0042799715884029865, + 0.005874470341950655, + -0.04758966714143753, + 0.010361016727983952, + 0.009818757884204388, + -0.02969512529671192, + -0.003356840228661895, + -0.003760306630283594, + 0.007772376295179129, + 0.01788162998855114, + 0.03176087513566017, + 0.22434021532535553, + 0.022206788882613182, + -0.0009489529184065759, + 0.039171744138002396, + 0.0189532358199358, + 0.022387541830539703, + 0.02620917558670044, + 0.022168057039380074, + -0.0061326888389885426, + 0.026570681482553482, + 0.0018317373469471931, + 0.016990777105093002, + 0.0008521209820173681, + 0.00717201828956604, + 0.008237170055508614, + -0.007778831757605076, + -0.04635021835565567, + -0.00758516788482666, + -0.02014104090631008, + 0.0025369965005666018, + 0.005935797467827797, + -0.024453289806842804, + -0.021767817437648773, + -0.008986003696918488, + 0.0469699427485466, + 0.013530648313462734, + -0.004231555387377739, + 0.011878049932420254, + 0.004512368235737085, + -0.006113322451710701, + -0.002269095042720437, + 0.006681403145194054, + 0.00701063172891736, + -0.0016316180117428303, + -0.02034761570394039, + -0.0013120726216584444, + -0.012181457132101059, + -0.031657587736845016, + 0.02450493350625038, + 0.022916890680789948, + -0.025938047096133232, + 0.006946077104657888, + -0.018436800688505173, + 0.0010780622251331806, + -0.02056710235774517, + 0.01331116259098053, + -0.025912225246429443, + -0.018139848485589027, + 0.030082453042268753, + 0.006636214908212423, + -0.018862860277295113, + -0.0018220541533082724, + 0.032922856509685516, + 0.027164584025740623, + 0.0049674781039357185, + 0.004890012554824352, + 0.013375717215240002, + 0.001705855829641223, + -0.0007004176150076091, + 0.022826513275504112, + -0.016525983810424805, + 0.019172722473740578, + -0.014602255076169968, + 0.027371158823370934, + -0.010109253227710724, + -0.009250677190721035, + -0.027319515123963356, + -0.0037570788990706205, + 0.015699684619903564, + -0.006100411526858807, + -9.284770203521475e-05, + -0.006997720804065466, + 0.0019172722240909934, + 0.02329130657017231, + -0.00461565563455224, + -0.013685579411685467, + 0.005170824937522411, + -0.0017203806200996041, + 0.011639198288321495, + 0.016964955255389214, + -0.008856894448399544, + -0.013788866810500622, + -0.022206788882613182, + 0.013027122244238853, + -0.008327546529471874, + -0.012026526033878326, + 0.00020344792574178427, + 0.00208027265034616, + 0.001817212556488812, + -0.00914738979190588, + 0.002096411306411028, + 0.024801885709166527, + -0.006571660283952951, + -0.006784690544009209, + 0.014279481954872608, + 0.014150372706353664, + 0.0026709474623203278, + 0.008559943176805973, + -0.009076380170881748, + 0.01402126345783472, + -0.0292819757014513, + -0.004083079751580954, + 0.020283062011003494, + 0.012194368056952953, + -0.01624194346368313, + 0.008689052425324917, + -0.011761851608753204, + 0.003563415026292205, + 0.04289009049534798, + -0.0017591133946552873, + -0.009747747331857681, + 0.00556138064712286, + 0.018656285479664803, + -0.014382769353687763, + -0.0028823637403547764, + -0.005170824937522411, + -0.0009061854798346758, + -0.016138656064867973, + 0.003221275517717004, + -0.00014050716708879918, + -0.007094552740454674, + -0.022180967032909393, + -0.03075382113456726, + 0.01372431218624115, + -0.017403926700353622, + -0.007966040633618832, + -0.03653791546821594, + 0.013052944093942642, + 0.020115219056606293, + -0.03119279257953167, + 0.00556138064712286, + -0.0019156583584845066, + 0.02409178391098976, + -0.03305196762084961, + -0.01537691056728363, + 0.016500161960721016, + 0.015854615718126297, + -0.014008352532982826, + 0.014537700451910496, + -0.018036561086773872, + -0.01507995929569006, + -0.03488531708717346, + 0.02494390495121479, + -0.013763044960796833, + 0.005593657959252596, + -0.030289027839899063, + -0.024788973852992058, + 0.003569870488718152, + -0.015893347561359406, + -0.031115327030420303, + 0.007966040633618832, + -0.0341106615960598, + -0.009812301956117153, + -0.014524789527058601, + 0.016461428254842758, + -0.0013120726216584444, + -0.003531137714162469, + 0.004305793438106775, + 0.023988496512174606, + 0.014886295422911644, + -0.023846477270126343, + 0.0060584512539207935, + 0.027319515123963356, + 0.008185526356101036, + -0.01665509305894375, + -0.011871594935655594, + -0.16247107088565826, + 0.04035954922437668, + 0.017003687098622322, + -0.0315801203250885, + 0.0046995761804282665, + 0.011096939444541931, + -0.007197840139269829, + 0.012000704184174538, + -0.010193174704909325, + 0.016099922358989716, + 0.016500161960721016, + 0.004973933566361666, + -0.01971498131752014, + -0.029798412695527077, + -0.01080644316971302, + -0.0011305127991363406, + -0.032509706914424896, + 0.009599272161722183, + 0.03225148841738701, + 0.0255507193505764, + 0.003721573855727911, + -0.015454376116394997, + 0.022929800674319267, + 0.0010328739881515503, + 4.037815870105987e-06, + 0.005090131890028715, + -0.01528653409332037, + -0.004086307715624571, + 0.016964955255389214, + -0.014718453399837017, + -0.011671475134789944, + 0.005903520155698061, + 0.016706736758351326, + 0.01484756264835596, + 0.001228151610121131, + 0.0060294014401733875, + 0.009754203259944916, + 0.005745361093431711, + -0.0023772239219397306, + 0.02664814703166485, + -0.0033051965292543173, + 0.0022109958808869123, + 0.003171245800331235, + 0.02409178391098976, + -0.016745468601584435, + 0.02391103096306324, + 0.020502546802163124, + -0.01203943695873022, + -0.01030291710048914, + -0.018824126571416855, + 0.006219837814569473, + -0.01620320975780487, + 0.008772972971200943, + -0.004564011935144663, + 0.004709259606897831, + 0.015131602995097637, + 0.03558250889182091, + 0.00420250603929162, + 0.005432271398603916, + -0.014176194556057453, + -0.007094552740454674, + -0.007417325861752033, + 0.018772482872009277, + 0.0015840090345591307, + 0.017158618196845055, + -0.015196157619357109, + 0.0010005966760218143, + -0.0034407612401992083, + -0.022710315883159637, + 0.024840617552399635, + -0.025899313390254974, + -0.025279588997364044, + 0.003889415878802538, + -0.01059986837208271, + 0.0070493645034730434, + 0.009786480106413364, + 0.0005386276170611382, + -0.005629162769764662, + -0.017765432596206665, + -0.006481283809989691, + -0.04260604828596115, + 0.0211868267506361, + -0.015699684619903564, + 0.02015395276248455, + 0.005109498277306557, + 0.010193174704909325, + -0.015325266867876053, + 0.00905055832117796, + -0.017003687098622322, + -0.018630463629961014, + 0.032303132116794586, + -0.036279696971178055, + 0.01810111664235592, + -0.03912010043859482, + 0.025060104206204414, + 0.021741995587944984, + -0.0008488932508043945, + 0.01870792917907238, + -0.006171421613544226, + -0.0001905370008898899, + 0.017726698890328407, + -0.013763044960796833, + 0.0060907285660505295, + -0.0021157776936888695, + 0.030108274891972542, + 0.015712594613432884, + -0.012491319328546524, + 0.026067156344652176, + 0.03757078945636749, + 0.004628566559404135, + -0.027990883216261864, + 0.005409677047282457, + 0.036692846566438675, + 0.027500268071889877, + -0.02289106883108616, + 0.008275902830064297, + 0.013801777735352516, + -0.018036561086773872, + 0.01994737796485424, + 0.003921693190932274, + 0.05012020841240883, + -0.028972113505005836, + -0.011878049932420254, + 0.009670281782746315, + -0.0016542121302336454, + -0.004651160445064306, + -0.09636713564395905, + 0.013298251666128635, + 0.02558945119380951, + -0.008656774647533894, + 0.0031841567251831293, + 0.026880543678998947, + 0.010722522623836994, + 0.014731364324688911, + 0.011167949065566063, + 0.014989582821726799, + 0.00011952691420447081, + -0.015118692070245743, + -0.015351088717579842, + -0.014615166001021862, + -0.004676982294768095, + 0.007178473751991987, + -0.01321433112025261, + -0.0021851740311831236, + -0.034394703805446625, + 0.0041766841895878315, + -0.0012846369063481688, + -0.02619626559317112, + -0.016900399699807167, + -0.011309969238936901, + -0.01496376097202301, + -0.0008892398909665644, + -0.024698598310351372, + 0.011548821814358234, + 0.006468372885137796, + 0.02830074541270733, + -0.0017558856634423137, + -0.025873491540551186, + -0.007081641815602779, + -0.012032981030642986, + -0.026751434430480003, + -0.028145814314484596, + -0.0124590415507555, + 0.007075186353176832, + -0.0004353402182459831, + -0.020670389756560326, + 0.004770586267113686, + -0.014860473573207855, + 0.017829986289143562, + -0.013905065134167671, + 0.024982638657093048, + -0.020954430103302002, + -0.016125744208693504, + 0.018837038427591324, + 0.02428544871509075, + -0.003297127317637205, + -0.01994737796485424, + 0.006875067017972469, + -0.003363295691087842, + -0.0033277906477451324, + 0.030314849689602852, + -0.02930779755115509, + 0.012284744530916214, + 0.007184929214417934, + -0.014731364324688911, + -0.0052805677987635136, + -0.01622903160750866, + 0.027706842869520187, + -0.007468969561159611, + 0.018875770270824432, + -0.0013758203713223338, + 0.0021916294936090708, + -0.005780866369605064, + 0.008889171294867992, + 0.020915696397423744, + -0.022193878889083862, + -0.04263187199831009, + 0.005548469722270966, + -0.019004879519343376, + 0.0062262932769954205, + -0.032561350613832474, + 0.0063715409487485886, + -0.034807853400707245, + 0.009734836407005787, + -0.003019542433321476, + 0.0006003579474054277, + -0.014524789527058601, + -0.011251870542764664, + -0.014331125654280186, + -0.005874470341950655, + 0.0014960533007979393, + 0.043561458587646484, + 0.010348105803132057, + -0.006694314070045948, + -0.0012450972571969032, + -0.03240641951560974, + -0.01913398876786232, + 0.018152760341763496, + 0.0034536721650511026, + 0.0028178091160953045, + -0.00041839462937787175, + 0.014899206347763538, + 0.0057485890574753284, + 0.01018026378005743, + 0.03811304643750191, + -0.012452586553990841, + -0.011600465513765812, + -0.007972495630383492, + -0.06326352804899216, + 0.016977865248918533, + 0.01873375102877617, + -0.010858086869120598, + 0.02577020414173603, + 0.013775955885648727, + 0.027112940326333046, + 0.013479004614055157, + -0.009851034730672836, + -0.0170553307980299, + -0.008250080980360508, + 0.032535530626773834, + -0.0118586840108037, + -0.02180655114352703, + -0.025266679003834724, + 0.008049961179494858, + 0.024195071309804916, + 0.017972007393836975, + 0.011309969238936901, + 0.010832265019416809, + -0.021341757848858833, + 0.021135183051228523, + 0.02948855049908161, + 0.013905065134167671, + -0.023975586518645287, + -0.0034924049396067858, + -0.0065361554734408855, + -0.009063469246029854, + -0.025899313390254974, + 0.005367716774344444, + 0.02161288633942604, + -0.02096734009683132, + -0.0019414802081882954, + 0.04691829904913902, + -0.027371158823370934, + -0.008914993144571781, + 0.010380382649600506, + 0.019017791375517845, + 0.007972495630383492, + -0.020902786403894424, + -0.008166159503161907, + -0.025434520095586777, + -0.0012886716285720468, + -0.022206788882613182, + -0.015234890393912792, + 0.00441230833530426, + -0.009205489419400692, + 0.00014434009790420532, + 0.04059194400906563, + -0.008133882656693459, + 0.025666916742920876, + 0.018372245132923126, + -0.005380627699196339, + -0.004631794057786465, + 0.014214927330613136, + -0.026467394083738327, + 0.02014104090631008, + 0.004031436052173376, + 0.017145708203315735, + -0.008798794820904732, + 0.026092978194355965, + 0.0026644919998943806, + 0.021470867097377777, + 0.0034859494771808386, + 0.009224855341017246, + -0.00832109060138464, + -0.020205596461892128, + -0.01195551548153162, + 0.02597677893936634, + -0.011290603317320347, + -0.008805250748991966, + 0.00395074300467968, + 0.008953725919127464, + 0.007191384676843882, + 0.028145814314484596, + -0.020838230848312378, + 0.006842789705842733, + 0.003640880575403571, + -0.010612779296934605, + 0.03465292230248451, + 0.0011087256716564298, + 0.004305793438106775, + -0.05572354793548584, + 0.0075980788096785545, + 0.017933273687958717, + 0.006468372885137796, + -0.009760658256709576, + 0.0006330387550406158, + 0.004483318421989679, + 0.01786871999502182, + 0.02407887391746044, + -0.011084028519690037, + -0.04472343996167183, + 0.004089535214006901, + -0.008140337653458118, + -0.02079949900507927, + -0.006823423318564892, + -0.015854615718126297, + -0.001550117856822908, + 0.044413577765226364, + 0.019495494663715363, + 0.012730170972645283, + 0.017765432596206665, + -0.019637515768408775, + -0.016267765313386917, + 0.006419957149773836, + -0.013943797908723354, + -0.020437993109226227, + -0.008585765026509762, + 0.004725398030132055, + 0.004215416964143515, + -0.015196157619357109, + -0.0038506831042468548, + 0.012175001204013824, + -0.020231418311595917, + 0.012142724357545376, + -0.030056631192564964, + -0.021909838542342186, + 0.003108304925262928, + 0.02263285033404827, + -0.0094766179099679, + 0.00822425913065672, + 0.013020667247474194, + 0.005596885457634926, + 0.004270288161933422, + 0.006771779619157314, + 0.02207767963409424, + 0.0013701717834919691, + 0.03057306818664074, + 0.005603340920060873, + 0.021664530038833618, + -0.025421610102057457, + -0.0067459577694535255, + -0.017533035948872566, + 0.0064038182608783245, + -0.006187560502439737, + 0.040023863315582275, + 0.004673754330724478, + 0.0036118309944868088, + 0.050404246896505356, + 0.008488932624459267, + -0.031037861481308937, + -0.002519244095310569, + -0.008508299477398396, + 0.015944991260766983, + 0.017804164439439774, + 0.010845175944268703, + -0.02598969079554081, + -0.0043832589872181416, + 0.006277936976402998, + 0.010703155770897865, + 0.023446237668395042, + -0.005651757121086121, + -0.044207002967596054, + 0.011374523863196373, + -0.03535011038184166, + 0.007488335948437452, + -0.0061940159648656845, + -5.169412816030672e-06, + -0.0012289586011320353, + 0.0037635343614965677, + 0.01103238482028246, + 0.002398204058408737, + -0.015105781145393848, + -0.01289801299571991, + -0.015480197966098785, + -0.015944991260766983, + -0.02496972680091858, + -0.018824126571416855, + 0.013672668486833572, + -0.003145423950627446, + -0.04782206192612648, + -0.010154441930353642, + 0.008863349445164204, + -0.003411711659282446, + -0.005028804764151573, + 0.004906150978058577, + 0.005093359388411045, + 0.03612476587295532, + -0.018126938492059708, + 0.017403926700353622, + -0.03473038598895073, + -0.02283942513167858, + -0.0028016704600304365, + -0.004421991761773825, + -0.005022349301725626, + 0.002007648814469576, + -0.03757078945636749 + ], "DOT") LIMIT 3; +/* end::query-vectors-idx-filtered-whole[] */ \ No newline at end of file diff --git a/modules/vector-index/pages/gsi-with-vector.adoc b/modules/vector-index/pages/gsi-with-vector.adoc index 1bce8eb60..c219a0d2c 100644 --- a/modules/vector-index/pages/gsi-with-vector.adoc +++ b/modules/vector-index/pages/gsi-with-vector.adoc @@ -3,18 +3,18 @@ :page-ui-name: {ui-name} :page-product-name: {product-name} :description: You can extend a Couchbase {product-name}'s Global Secondary Index (GSI) with a single vector column to enable queries to find semantically-related content. +:stem: +:page-toclevels: 3 {description} -The added vector column lets your application perform a hybrid query using both the index's scalar. array, and object index entries plus a vector value. +The added vector column lets your application perform a hybrid query using both the index's scalar, array, and object index entries plus a vector value. See xref:learn:services-and-indexes/indexes/indexes.adoc[] for an overview of GSI and other indexes. == How the GSI's Vector Column Works You can add a single vector column to a GSI to enable semantic and similarity searches within your {sqlpp} queries. -When creating the index, you use a `VECTOR` key attribute to designate the attribute that contains the embedded vectors. -In the process of creating the index, the Index Service quantizes the data in the attribute to make it easier to scan and process. -For more information about quantization, see xref:use-vector-indexes.adoc#quantize[Reducing Vector Complexity]. +When creating the index, you use a `VECTOR` key attribute to designate the field that contains the embedded vectors. When your query contains a embedded vector, the Query Service uses any non-vector predicates in the query to filter index entries. Then it performs an index scan on the remaining index entries, using the similarity function you specify in the query to locate similar vectors. @@ -23,7 +23,7 @@ This behavior reduces the number of vector similarity comparisons the Query Serv == Prerequisites -* You must have the Index Service enabled on a node in your database. +* You must have the Index Service enabled on at least one node in your cluster. For more information about how to deploy a new node and Services on your database, see xref:manage:manage-nodes/node-management-overview.adoc[]. * You must have a bucket with scopes and collections in your database. @@ -35,7 +35,7 @@ For more information about how to create a bucket, see xref:manage:manage-bucket You can add a single vector to a GSI index. If your documents contain multiple embedded vectors, you can create multiple indexes---one for each vector attribute. + -Embeddings can be an array of floats or a base64 encoded string. +Embeddings can be an array of floating point numbers or a base64 encoded string. Couchbase {product-name} does not embed vectors itself. You must use an external embedding model to embed vectors into your data and add them to your documents. + @@ -45,52 +45,177 @@ include::vector-search:partial$download-sample-partial.adoc[] -- * You must know the number of dimensions the vector contains. -The embedding model you use to embed the vectors determines this value for you. -For example, OpenAI API's `text-embedding-ada-002` embedding model that was used for the sample data creates vectors that have 1536 dimensions. +The embedding model you use to embed the vectors may determine this value for you. +For example, OpenAI API's `text-embedding-ada-002` embedding model that embedded the sample data creates vectors that have 1536 dimensions. -You also have several options to choose before you create a GSI that has a vector column: +* You must decide what algorithms you want your index to use. +These algorithms affect how much memory your index uses and how much processing is required to train and search them. +See xref:vector-index:use-vector-indexes.adoc##index-algorithms[Indexing Algorithms] +[#algo_settings] +== Index Algorithm Settings -* The type of quantization you want to use when storing the vector in you your index. -GSI vector columns support two types of quantization: Scalar Quantization (SQ) and Product Quantization (PQ). -See xref:vector-index:use-vector-indexes.adoc#quantize[Reducing Vector Size] for more information about quantization. -+ -In addition to the quantization type, you can also supply a value that affects the quantization: +When creating an index that includes a vector field, you choose settings that affect how the index processes vectors. +The parameter named `description` is the primary setting that controls the indexing algorithms that Couchbase {product-name} to create the index. +Using it, you control how the index subdivides the dataset to improve performance and how it quantizes vectors to reduce memory and processing requirements. + +The `description` parameter is a string in the following format: + +[source,sqlpp] +---- +'IVF[],{PQ|SQ}' +---- + +The following sections describe the settings for centroids and quantization. + +=== Number of Centroids + +GSI indexes with a vector column always use the xref:vector-index:use-vector-indexes.adoc#IVF[Inverted File (IVF)] algorithm to subdivides the dataset. +Using this algorithm reduces the number of vector comparisons a vector search of the index must perform. +The key setting for IVF is the number of centroids it allocates for the index. +The number of centroids affects the performance of your index in two ways: + +* If the index has fewer centroids, each centroid has more vectors associated with it. +In this case, a vector search has to perform more comparisons which makes the search slower. +Having fewer centroids decreases the processing overhead for training the index. + +* A greater number of centroids results in a greater processing cost for training. +This increase is due to the training process having to search for more data cluster to identify more centroids. +However, it reduces the number of vectors associated with each centroid. +This reduction makes search faster by limiting the number of vector comparisons during a search. + +You can have Couchbase {product-name} choose a number of centroids for you by not providing a value after the `IVF` in your `description` parameter. +It chooses the number of centroids based on the number of vectors in the dataset: + +* If the number of vectors in the dataset is less than 1 million (1,000,000), Couchbase {product-name} sets the number of centroids to stem:["number of vectors" / 1000]. + +* If the number of vectors in greater than 1 million, Couchbase {product-name} sets the number of centroids to stem:[sqrt("number of vectors")]. + +You can manually set the number of centroids for the index by adding an integer value after the `IVF` in the `decription` parameter. +The number of centroids you set manually must be less than the number of vectors in the dataset. + +=== Quantization Setting + +GSI with a vector field always uses quantization to reduce the size of vectors stored in the index. +You must choose whether the index uses xref:vector-index:use-vector-indexes.adoc#sq[Scalar Quantization (SQ)] or xref:vector-index:use-vector-indexes.adoc#pq[Product Quantization (PQ)]. + +You select the quantization by adding a comma followed by either `PQ` or `SQ` to the `description` parameter after the IVF setting in the `description` value. + + +Each quantization method has additional settings explained in the following sections, + +==== SQ Settings + +For SQ, you set the number of bits the SQ algorithm uses for the bin index value or the number of bits it uses to store the centroid for each bin. +The values for SQ that Couchbase {product-name} supports are: + +[%autowidth] +|=== +| Setting | Effect + +| `SQ4` +| SQ uses a 4-bit index value splitting each vector dimension into 16 subspaces. + +| `SQ6` +| SQ uses a 6-bit index value splitting each vector dimension into 64 subspaces. + +| `SQ8` +| SQ uses an 8-bit index value splitting each vector dimension into 256 subspaces. + +| `SQfp16` +| SQ uses an 8-bit index value splitting each vector dimension into 256 subspaces. +However, it stores the centroid value as a 16-bit floating point number instead of a 32-bit floating point number. +This cuts the memory used to store the centroids in half. + +|=== + +==== PQ Settings + +If you choose to use PQ in your index, you must set two values: + +* The number of subquantizers (number of subspaces SQ splits the vector's dimensions into) to use. +This value must a divisor of the number of dimensions in the vector. +For example, if your vector has 99 dimensions you can only use the values 3, 9, 11, 33, and 99 for the subquantizers. +Using any other value returns an error. + +* The number of bits in the centroid's index value. +This value sets the number centroids to find in each subspace. +For example, setting this value to 8 has PQ store the index for the centroids in a byte. +This results in SQ using 256 centroids per subspace. + -** For SQ, the value sets the data type and number of bits that represent a dimension. For example, `SQ8` uses 8 bits to represent a dimension. `SQfp16` uses a 16-bit floating point value to represent a dimension. -** For PQ, the value sets the number of subquantizers and the number of bits each quantizers uses. For example `PQ8x8` uses 8 subquantizer each of which uses 8 bits. `PQ32x8` uses thirty two quantizers with 8 bits per quantizer. -* Optionally, choose the number of centroids to use if the quantization uses centroids. +The number of centroids you set using this value must be less than the number of vectors in the dataset. +For example, if you choose 32 for the centroid index size, your dataset must have at least 4,294,967,296 vectors in it. + +The larger you set either of these values, the more accurate the index's search results are. +The trade-off is that your index is larger, as it has to store data for more centroids. +A smaller value results in a smaller index that returns less accurate results. + +The format for the PQ settings is: + +[source,sqlpp] +---- +PQx +---- + +For example, `PQ32x8` has PQ break the vector's dimensions into 32 subspaces, each of which has 256 centroids. + +=== Algorithm Settings Examples + +The following table shows several `description` values along with an explanation. + +[%autowidth] +|=== +| Setting | Effect + +| `IVF,SQ8` +| Couchbase {product-name} chooses the number of centroids the IVF algorithm uses. +The index uses Scalar Quantization with an 8-bit index, meaning each dimension of the vector is broken into 256 bins. + +| `IVF1024,PQ8x8` +| IVF uses 1024 centroids to divide the dataset. +The index uses Product Quantization. +This setting has PQ break vector space into 8 subspaces, each of which uses 8-bits to represent centroids in the subspace. +This settings means each subspace has 256 centroids. + +|=== -* The proximity function to use when generating the index. -For the best results, use the same proximity function used to embed the == Create a GSI with a Vector Column Creating a GSI with a vector column is similar to creating a non-vector GSI index. -In the `CREATE INDEX` statement to create the GSI, add the `VECTOR` lead key attribute after the vector's to declare that the attribute contains an embedded vector. +See xref:guides:create-index.adoc[] for an overview of creating indexes. +In the `CREATE INDEX` statement to create the GSI, add the `VECTOR` lead key attribute after the vector's column name to declare it as an embedded vector. -You must also use the `WITH` clause to specify some additional information for the vector column: +You must also use the `WITH` clause to specify some additional information for the vector column. +The format for this clause with the most commonly-used parameters is: -* `dimension` in an integer value that sets the number of dimensions in the vector. -* `similarity` is a string that sets the distance function to use when comparing vectors during index creation. -For the highest accuracy, use the distance function you plan to use when querying or searching vector data. -* `description` is a string that sets the number of centroids and the quantization to use when creating the index. -The format for this string is: -+ [source,sqlpp] ---- -'IVF,[PQ|SQ]' +WITH { "dimension": , "similarity":"", "description":""}; ---- -// Note: I originally thought that the similarity function had to match the function used to embed the vectors, but -// embedding doesn't require a distance function? But there was a reference to keeping the function here and in the queries -// the same, so will mention that later. +* `dimension` in an integer value that sets the number of dimensions in the vector. +This value is determined by the embedded model you used to embed the vectors. +* `similarity` is a string that sets the distance function to use when comparing vectors during index creation. +Couchbase {product-name} uses the following strings to represent the proximity functions: ++ +-- +** `COSINE`: xref:use-vector-indexes.adoc#cosine[Cosine Similarity] +** `DOT`: xref:use-vector-indexes.adoc#dot[Dot Product] +** `L2`, `L2_SQUARED`, `EUCLIDEAN`, or `EUCLIDEAN_SQUARED`: xref:use-vector-indexes.adoc#euclidean[Euclidean Distance] +-- ++ +For the greatest accuracy, use the distance function you plan to use when querying vector data. +* `description` is the settings for the indexing algorithm. +See <<#algo_settings>> earlier in this page. + +For a full list of the parameters that affect a vector column in a GSI, see *FIXME:TDB*. [#examples] === Examples -The following examples show you how to create two Global Secondary Indexes with a vector column using the sample data. -They both use the data from the `color_data_2vectors.zip` file mentioned previously. +The following examples show you how to create two Global Secondary Indexes with a vector column using sample data. +They both use the data from the `color_data_2vectors.zip` file mentioned earlier. The data in `rgb.json` file looks like this: [source,json] @@ -146,8 +271,13 @@ In this example: * The number of dimensions is 3, because there are three values in the array containing the RGB value. * The similarity function is `L2`. -This is a slower, but more accurate function that other options. -* The description sets the index column to use SQ quantization, reducing dimension values to an 8-bit value. +This function works well to find related vectors which are close by the search vector. +In this example, finding similar colors depends more on proximity than the magnitude or alignment of the vectors. +See xref:gsi-with-vectors.adoc##vector_similarity[Vector Similarity] for a comparison of similarity functions. +* The `description` lets Couchbase {product-name} decide the number of centroids for the IVF algorithm. +It also chooses to use Scalar Quantization with an 8-bit index, splitting each dimension into 256 bins. +This setting does not actually save any space in the index, as each of the RGB dimensions are already 8-bit values. +However, in this example, memory use is not a concern as the dataset is small. The result of running example is: @@ -175,6 +305,11 @@ The following example creates a GSI that indexes the embedded vectors in the `em include::vector-index:example$gsi-vector-idx-examples.sqlpp[tag=create-vectors-idx] ---- +This example uses the Dot Product similarity function. +This function works better with the embedded text content than the Euclidean function used in the previous example. +It also uses the same algorithms as the previous example--Couchbase {product-name} chooses the number of centroids, and uses SQ quantization with 256 bins. + + If successful, Couchbase {product-name} responds with: [source, json] @@ -188,6 +323,9 @@ If successful, Couchbase {product-name} responds with: ] ---- +After Couchbase {product-name} creates the index, it begins training it. +Depending on your system, this training can take several seconds. + == Query with a GSI Vector Column You query embedded vector attributes that you have indexed in a GSI to find similar vectors and therefore similar semantic content. @@ -197,11 +335,14 @@ The first of these functions is faster, but less precise. The second is more precise, but slower. Which you choose depends on your use case. +You should also use a `LIMIT` clause to return just the number of vectors you need. +The query pushes the `LIMIT` clause down into the index scan so that the scan ends after finding the required number of matches. + === Query RGB Values Querying the RGB values in `rgb.colorvect_l2` requires a vector with only three values. -You can easily specify the vector by hand. -The following example finds colors that are similar to grey, which has an RGB value of 128, 128, 128: +You can just specify the vector by hand. +The following example finds colors that are similar to gray, which has an RGB value of 128, 128, 128: [source, sqlpp] ---- @@ -210,10 +351,12 @@ include::vector-index:example$gsi-vector-idx-examples.sqlpp[tag=query-rgb-idx] The query uses the `APPROX_VECTOR_DISTANCE` function to sort the results. You pass it the vector column to search, the vector to search for (in this case, the array `128, 128, 128`) and the distance function. + For the best accuracy, use the same distance function you specified when creating the GSI (in this case, `L2`). -The `LIMIT` clause is pushed down into the index scan, so once it finds the 5 entries that satify the query, it exits. +The query pushes the `LIMIT` clause down into the index scan, so once it finds the 5 entries that satisfy the query, it exits. -The top result is the entry for grey. The other results are all shades of grey: +The top result is the entry for gray. +The other results are all shades of gray: [source,json] ---- @@ -266,7 +409,7 @@ The top result is the entry for grey. The other results are all shades of grey: ---- You can also add other predicates to help reduce the workload of searching for similar vectors by excluding vectors. -The following example searches for colors similar to grey, which has an RGB value of 128, 128, 128 and have a brightness greater than 128: +The following example searches for colors similar to gray which has an RGB value of 128, 128, 128 and have a brightness greater than 128: [source, sqlpp] ---- @@ -372,7 +515,7 @@ The `couchbase_search_query.knn.vector` attribute contains the embedded vector f ---- -This example uses the more accurate `VECTOR_DISTANCE` function to order the results of querying the `embedding_vector_dot` column. +This example queries the `embedding_vector_dot` column. It appears here with most of the 1536 vectors omitted: [source,sqlpp] @@ -391,7 +534,7 @@ include::vector-index:example$gsi-vector-idx-examples.sqlpp[tag=query-vectors-id ---- ==== -Another option is to import the `rgb_questions.json` file into another collection in the `vector-sample` bucket's `colors` scope named `rgb-questions`. +Another option is to import the `rgb_questions.json` file into another collection in the `vector-sample` bucket's `color` scope named `rgb-questions`. Then you can use a subquery to get the vectors for the question and use it in your query of the `rgb` collection's `embedding_vector_dot` attribute: [source,sqlpp] @@ -428,4 +571,60 @@ In either case, the results of the query are the same: ] ---- -The second result, the color "papaya whip," matches the `rgb_questions` collection's `wanted_similar_color_from_search` attribute. \ No newline at end of file +The second result, the color "papaya whip," matches the `rgb_questions` collection's `wanted_similar_color_from_search` attribute. + +=== Adding a Scalar + +Using additional scalar fields in your search can improve your results and reduce the overhead of performing a vector search. +For example, filtering on an additional scalar field reuces the number of vectors an index scan has to compare. +Searching for scalar values requires less resources than vector searches. + +The example that created the `color_desc_idx` index added fields in addition to the `embedding_vector_dot` vector field. +The following example adds a filter based on the `brightness` field to reduce the number of vectors that get compared and also improve the results. + +The version of the query that performs a subquery of the `rgb-questions` to get the vector value is: + +[source,sqlpp] +---- +include::vector-index:example$gsi-vector-idx-examples.sqlpp[tag=query-vectors-idx-subquery-filtered] +---- + +The truncated version of the query is: + +[source,sqlpp] +---- +include::vector-index:example$gsi-vector-idx-examples.sqlpp[tag=query-vectors-idx-filtered-truncated] +---- + +You can expand the Show full example section to see and copy the entire query with all the vectors: + +.Show full example +[%collapsible] +==== +[source,sqlpp] +---- +include::vector-index:example$gsi-vector-idx-examples.sqlpp[tag=query-vectors-idx-filtered-whole] +---- +==== + +The results of this query moves the papaya whip entry to the top. + +[source,json] +---- +[{ + "color": "papaya whip", + "description": "Papaya whip is a soft and mellow color that can be described as a light shade of peach or coral. It has a calming and soothing effect, similar to the tropical fruit it is named after. This color is perfect for creating a warm and inviting atmosphere, and it pairs well with other pastel shades or neutral tones. Papaya whip is a versatile color that can be used in both fashion and interior design, adding a touch of elegance and sophistication to any space.", + "brightness": 240.82 + }, + { + "color": "pale turquoise", + "description": "Pale turquoise is a delicate and soothing color that can be described as a soft blend of blue and green. It has a calming effect and can evoke feelings of tranquility and serenity. The color is often associated with the ocean and can bring to mind images of clear, tropical waters. It has a gentle and subtle quality, making it a popular choice for creating a peaceful and serene atmosphere.", + "brightness": 219.163 + }, + { + "color": "light green", + "description": "Light green is a calming and refreshing color that evokes feelings of tranquility and new beginnings. It is a delicate shade that is often associated with nature and growth. The softness of this color can bring a sense of balance and harmony to any space, making it a popular choice for interior design. Light green is also known to have a rejuvenating effect, making it a perfect color for relaxation and self-care. Its gentle hue can bring a sense of peace and serenity to the mind, body, and soul.", + "brightness": 199.178 + } +] +---- diff --git a/modules/vector-index/pages/use-vector-indexes.adoc b/modules/vector-index/pages/use-vector-indexes.adoc index 8eeba94b9..a40a61423 100644 --- a/modules/vector-index/pages/use-vector-indexes.adoc +++ b/modules/vector-index/pages/use-vector-indexes.adoc @@ -77,19 +77,26 @@ You can embed audio using a model such as OpenL3. image::embedding-vectors.svg["Diagram showing text, image, and audio data being transformed by embedding models into a string of floating point numbers that represent vectors."] +=== How Embedding Models Work + Behind the scenes, embedding models use neural networks that mimic how the brain recognizes patterns. The neural nets distill the complex data into an array of floating point values. Beyond choosing an embedding model that's appropriate for your data, you generally do not worry about the details of how the model transforms data into a vector. +=== Embedding Model Compatibility + You can only compare the similarity of vectors generated by the same embedding model. For example, you cannot find the similarity of a vector generated by Word2Vec and one generated by GloVe. You also cannot compare a vector for a piece of text generated by Word2Vec with the vector for an image generated by ResNet. +=== Using Embedding Models with Couchbase {product-name} + Couchbase {product-name} does not implement any embedding models. You must use external embedding models to generate them and then store the resulting vectors in your documents. A common method of embedding vectors in your database is to call an https://openai.com/index/introducing-text-and-code-embeddings/[OpenAI Embedding API^] to generate vectors for your data. You then store the vector as an attribute in your document. +[#vector_similarity] == Vector Similarity Once you have embedded vectors in your database, you find documents with a similar meaning by finding similar vectors. @@ -100,6 +107,7 @@ This distance function must match the distance function the embedding model used Couchbase {product-name} supports three distance function: +[#euclidean] Euclidean Distance (also known as L2):: Calculates the geometric distance between two vectors by finding the distance between the individual dimensions in the vectors. This method is most sensitive to the distance between the vectors in space, rather than their alignment. @@ -111,6 +119,7 @@ image::euclidean-distance-example.svg["Three-dimensional plot showing two vector Euclidean Distance is useful for tasks such as image similarity searches. Vectors for similar images tend to form clusters within vector space. +[#dot] Dot Product:: Finds related vectors by comparing the magnitude and alignment of the vectors. In this method, the proximity of the vectors in space is less important than whether they point in a similar direction and have the a similar magnitude. @@ -121,6 +130,7 @@ image::dot-product-example.svg["Three-dimensional plot showing two vectors label + Use this method for tasks such as recommendation engines where you want to rank results from most to least related. +[#cosine] Cosine Similarity:: This method is similar to the dot product. However, it normalizes the vectors (making them the same length) during comparison. @@ -161,15 +171,16 @@ They consume a moderate amount of memory and can index billions of documents. * A Search index used for full-text and geospacial search can have an added vector attribute, The search results combine keyword matching of Full-Text Search with the semantic meaning matching of vectors to give you hybrid results. -Use Search indexes with a vector attribute when you want to query based on keywords, geospacial data, and a vector value. +Use Search indexes with a vector attribute when you want to query based on keywords or geospacial data plus a vector value. These indexes can index millions of documents. +[#index-algorithms] === Indexing Algorithms When you add a vector column to an index, you specify one or more algorithms that Couchbase {product-name} uses to process the vector values. These algorithms organize and consolidate vector data in the index to make it more efficient to search. -Couchbase {product-name} supports the following methods: +Couchbase {product-name} supports the following algorithms: Flat Index:: This algorithm just stores the full vector value in the index without performing any sort of optimization. @@ -178,7 +189,11 @@ Adding new vectors to a flat index is fast, and the index does not need training It also offers high precision, because search compares the full vector values. However, searching a flat index is inefficient, because the search must compare every vector in the index to find matchers. You should only use it for small data sets or for testing. ++ +NOTE: Only Search Indexes support using a flat index. +Vector indexes and GSI with a vector field only support the next algorithm, IVF. +[#IVF] Inverted File (IVF):: This algorithm partitions the vector space to limit the number of vectors that a search must compare. An IVF index trains itself during creation using a set of parameters you pass to it: @@ -200,7 +215,9 @@ The centroids chosen during the initial training may no longer accurately repres See <<#index-training>> for more information about index accuracy. + Use this method if you want a balance between precision and search speed. +Vector indexes and GSI always use IVF. +[#pq] Product Quantization (PQ):: Product Quantization simplifies vector data to reduce its storage and processing requirements. Quantization is similar to using a lossy image compression format, such as JPEG, on an picture to reduce its data size. @@ -209,12 +226,12 @@ It trades off some detail and accuracy for a smaller, more manageable data size. PQ processes vectors using the following steps: + -- -. It groups the vector's dimensions into chunks called subvectors. +. It groups the vector's dimensions into chunks called subspaces. For example, suppose the vectors contain 1024 dimensions. -Then PQ may break the vectors into 128 subvectors, each containing 8 dimensions. -. It finds groups of centroids in each subvector space and adds them to a data structure called a codebook. +Then PQ may break the vectors into 128 subspaces, each containing 8 dimensions. +. It finds groups of centroids in each subspace and adds them to a data structure called a codebook. The codebook assigns each centroid an index number. -. PQ then reduces the size of the vectors by replacing each subvector's dimensions with the index of the closest centroid in the codebook. +. PQ then reduces the size of the vectors by replacing each subspace's dimensions with the index of the closest centroid in the codebook. -- + image::pq-diagram.svg["Three-dimensional plot showing two vectors that are of equal length, with the angle between them labeled as theta."] @@ -223,13 +240,13 @@ PQ could quantize the vector in the previous example from 1024 64-bit floating p This data size reduction improves performance because integer operations are less intensive than floating point operations. It also reduces memory use because each vector requires less data to store (for example, from 64KB to 128 bytes). + -You often use PQ in addition to IVF---after quantization, the training process finds centroids in the dataset. +You often use PQ in addition to IVF--after quantization, the training process finds centroids in the dataset. The index stores the centroids the their related vectors in the inverted list using the quantized format. + A search of the PQ index performs the same steps on the vector you're searching for: + -- -. It breaks the search vector into subvectors and quantizes it using the codebook. +. It breaks the search vector into subspaces and quantizes it using the codebook. . It then locates closest centroids to the quantized query vector. . It searches the vectors related to the matching centroids for vectors that relate to the search vector. -- @@ -241,26 +258,30 @@ However, PQ reduces the amount of memory and processing time necessary when sear Using this indexing algorithm when: + * Your vectors contain a large number of dimensions. -* You're willing to trade higher processing requirements during training for lower memory use during searches. +* You're willing to trade higher processing requirements during training for smaller memory use and less CPU time during searches. * Your dataset is large (millions to billions of vectors). +[#sq] Scalar Quantization (SQ):: Scalar Quantization is a simpler form of quantization than PQ. -During training, SQ determines the maximum and minimum values for each dimension in the dataset. -It then partitions each dimension in the vector into equal segments (called bins) over the range of the dimension's values. +During training: ++ +. SQ determines the maximum and minimum values for each dimension in the dataset. +. It then partitions each dimension in the vector into equal segments (called bins) over the range of the dimension's values. For example, in the diagram, the first dimension's values range from 0 to 1, while the second dimension's range from 0.1 to 0.9. -SQ assigns each bin an index value that's an 8 or 16 bit integer value. -It stores the centroid value associated with the bin in the index as a 16 or 32 bit floating point number. -SQ then quantizes the vectors by replacing their dimensional values with the index of the bin the value falls into. +. SQ assigns each bin an index value that's from 4 to 8 bits in length. +. It find a centroid within the range associated with the bin. +It saves the centroid as a 16 or 32 bit floating point number. +. SQ then quantizes the vectors by replacing their dimensional values with the index value of the bin the value falls into. + image::sq-diagram.svg["Diagram showing each floating point dimension of a vector being converted to an 8-bit integer by looking up which bucket it falls into."] + -This quantization reduces the dimensions from 32 or 64 bit floating point values to 8 or 16 bit integers, reducing the memory needed for search. +This quantization reduces the dimensions from 32 or 64 bit floating point values to 8 or less bit integers, reducing the memory needed for search. It also makes search faster because integer operations are computationally less expensive than floating point operations. + A search on an SQ index reassembles vectors before comparing them. For each of the vector's dimensions, the integer bin number is replaced with the floating point centroid associated with the bin. -This recreation results in an approximation of the original vector, which the search compares to the search vector. +This recreation is an approximation of the original vector, because each dimension in the vector is the bin's centroid value rather than the original dimensional value. + Like the PQ algorithm, you often combine SQ and IVF. This combination limits the number of vectors that a search has to compare and reduces its memory and processing requirements. @@ -268,14 +289,13 @@ This combination limits the number of vectors that a search has to compare and r Because this method quantizes the vectors, it loses precision. It's less precise than the PQ method (which also quantizes vectors) because it assumes that each dimension can be evenly divided. Its accuracy suffers if your data has clusters. -However, the gain in performance is often worth the tradeoff. +It's best suited for data that's more evenly distributed and does not have high correlations. +For example, SQ may be a good fit for an IoT sensor dataset where the measured values (such as temperature) are evenly distributed over the range of measurements. + SQ has a lower training overhead compared to the PQ and IVF methods because it does not search for clusters of vectors. Its training just determines the range of values for each dimension. -It's best suited for data that's more evenly distributed and does not have high correlations. -For example, SQ may be a good fit for an IoT sensor dataset where the measured values (such as temperature) are evenly distributed over the range of measurements. + -Use this method if you want to gain some of the memory efficiency offered by vector quantization, but do not want the processing overhead of training a PQ index. +Use SQ if you want to gain some of the memory efficiency offered by vector quantization, but do not want the processing overhead of training a PQ index. [#index-training] === The Importance of Index Training @@ -297,12 +317,12 @@ Indexes using the SQ indexing algorithm can return inaccurate results if the ran If one or more dimensional values fall outside the range that SQ assign buckets to, they get assigned closest bucket. These inaccuracies can build over time, skewing results,. -To resolve these accuracy issues, retrain your indexes. +To resolve these accuracy issues, can retrain your indexes when you notice poor results. You can retrain indexes periodically, or after you have made significant changes to your dataset. You should consider the need to retrain your indexes when choosing which index algorithm to use. -For example, the PQ index method requires more resources to train than the IVF or SQ method. -If your dataset evolves rapidly, you may want avoid using PQ because you will need to perform more frequent retraining. +For example, the PQ algorithm requires more resources to train than the SQ algorithm. +If your dataset evolves rapidly, you may want avoid using PQ because you'll need to perform more frequent retraining. == Uses for Vectors in Couchbase {product-name} Indexes From d65058ee34d47646aa16eda99680a60d5bc1a1a8 Mon Sep 17 00:00:00 2001 From: Gary Gray <137797428+ggray-cb@users.noreply.github.com> Date: Fri, 31 Jan 2025 16:31:55 -0500 Subject: [PATCH 18/41] Last-minute fixes --- modules/vector-index/pages/gsi-with-vector.adoc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/modules/vector-index/pages/gsi-with-vector.adoc b/modules/vector-index/pages/gsi-with-vector.adoc index c219a0d2c..b9f585f3b 100644 --- a/modules/vector-index/pages/gsi-with-vector.adoc +++ b/modules/vector-index/pages/gsi-with-vector.adoc @@ -191,12 +191,12 @@ The format for this clause with the most commonly-used parameters is: [source,sqlpp] ---- -WITH { "dimension": , "similarity":"", "description":""}; +WITH { "dimension": , "similarity":, "description":}; ---- -* `dimension` in an integer value that sets the number of dimensions in the vector. -This value is determined by the embedded model you used to embed the vectors. -* `similarity` is a string that sets the distance function to use when comparing vectors during index creation. +* `dimensions` is an integer value that sets the number of dimensions in the vector. +This value is set by the embedded model you used to embed the vectors. +* `similarity-function` is a string that sets the distance function to use when comparing vectors during index creation. Couchbase {product-name} uses the following strings to represent the proximity functions: + -- @@ -206,7 +206,7 @@ Couchbase {product-name} uses the following strings to represent the proximity f -- + For the greatest accuracy, use the distance function you plan to use when querying vector data. -* `description` is the settings for the indexing algorithm. +* `algorithm-settings` is a string containing the settings for the indexing algorithms. See <<#algo_settings>> earlier in this page. For a full list of the parameters that affect a vector column in a GSI, see *FIXME:TDB*. From c96e55f42af731eb610d8ecdc2866cb916a7cfae Mon Sep 17 00:00:00 2001 From: Gary Gray <137797428+ggray-cb@users.noreply.github.com> Date: Wed, 26 Feb 2025 08:57:42 -0500 Subject: [PATCH 19/41] Edits based on Ankush's feedback. --- .../vector-index/pages/gsi-with-vector.adoc | 4 +- .../pages/use-vector-indexes.adoc | 353 ++---------------- .../pages/vectors-and-indexes-overview.adoc | 305 +++++++++++++++ modules/vector-index/partials/nav.adoc | 8 + 4 files changed, 352 insertions(+), 318 deletions(-) create mode 100644 modules/vector-index/pages/vectors-and-indexes-overview.adoc diff --git a/modules/vector-index/pages/gsi-with-vector.adoc b/modules/vector-index/pages/gsi-with-vector.adoc index b9f585f3b..215bec2e0 100644 --- a/modules/vector-index/pages/gsi-with-vector.adoc +++ b/modules/vector-index/pages/gsi-with-vector.adoc @@ -1,8 +1,8 @@ -= Use GSI with a Vector Column += Hybrid Search Using GSI with a Vector Column :page-topic-type: guide :page-ui-name: {ui-name} :page-product-name: {product-name} -:description: You can extend a Couchbase {product-name}'s Global Secondary Index (GSI) with a single vector column to enable queries to find semantically-related content. +:description: You can extend a Couchbase {product-name}'s Global Secondary Index (GSI) with a single vector column to enable hybrid queries to find semantically-related content. :stem: :page-toclevels: 3 diff --git a/modules/vector-index/pages/use-vector-indexes.adoc b/modules/vector-index/pages/use-vector-indexes.adoc index a40a61423..9945306c5 100644 --- a/modules/vector-index/pages/use-vector-indexes.adoc +++ b/modules/vector-index/pages/use-vector-indexes.adoc @@ -11,353 +11,74 @@ Vector Indexing lets you add vectors to Couchbase {product-name} indexes. You store index values as attributes in your documents, and then index those attributes. You can then find relevant data by executing queries on the vector attributes, which use the index to find similar vectors. -== About Vectors - -Vectors are a numerical representation of complex unstructured data such as text, images, or audio. -They distill this complex data into an array of floating-point values called dimensions. -The dimensions in vectors capture features of the data in a way that makes them easy to compare mathematically. -Similar data, such as text about the same topic or images of a similar subject, have similar vectors. -Similar vectors are close together the multi-dimensional space formed by all of the vectors in the dataset. -Vectors for dissimilar data (for example, articles discussing two different topics) have vectors that are further apart in this multi-dimensional space. - -=== Finding Semantically Similar Text Data - -By comparing two vectors, you can find the similarity between two pieces of data. -This similarity goes beyond just finding parts of the data that's identical (finding similar words in two pieces of text, for example). -The vectors represent features such as the meaning of text rather than just superficial similarities. - -For example, suppose you have three text articles. -The first is about feral cats, the second about domestic cats, and the third is about the UNIX/Linux `cat` command. -A text search for the term "cat" could return all three articles at the top of its search results due to their frequent use of the search term. -However, that does not mean that the articles are semantically related (about the same topic). - -By generating vectors for the articles and comparing them, you can determine any semantic relationship between them. -Vectors can be similar in a variety of ways. They may: - -* Point in similar directions. -* Be close to each other in the vector space made up of all the dimensions in the vectors. -* Have a similar magnitude (length). - -Because the first two articles are about cats, their vectors point in a similar direction and are in a similar location in space. -The third article, despite using the word "cat" as frequently as the two other articles, has a vector that has significant differences from the other two. - -image::vector-space-example.svg["Three-dimensional plot showing two vectors that are close by and parallel and a third vector that's away and points in another direction"] - -NOTE: Many diagrams in this document (and in other discussions available on the web) show vectors in three dimensions. -These diagrams are a simplification. -The vectors used in AI applications have hundreds to thousands of dimensions. -They're easy for computers to handle, but rather difficult for humans to visualize. -Also, vector dimension values in the diagrams show only 4 decimal places to conserve space. -The floating point dimensional values of actual vectors often use 6 or 7 decimal places. -When viewing these diagrams, remember that they only scratch the surface of the data encoded in a vector. - -=== Using Vectors to Find Similar Complex Data - -Vectors let you search for similarity in data that's hard to search using traditional techniques. -Image data, for example, is just a string of raw binary values. -Matching portions of this data within two image files does not mean they're of the same subject, or even have any resemblance. -Also, comparing megabytes of raw image data is computationally expensive. -Generating vectors of the images distills features of the image into a smaller, more manageable amount of data. -It also emphasizes features of the images that viewers find important, such as shapes and textures. -Comparing the vectors is more manageable, and actually results in finding similar images. - - - -== Embedding Vectors - -Embedding is the process of generating vectors that represent a piece of complex unstructured data. -You use an embedding model that's specific to the data's type to generate a vector to represent it. +As with other data types in Couchbase {product-name}, indexes make searching for similar vectors much faster. +Using indexes for vector searches is especially important due to the size of vector data. +Vectors contain hundreds to thousands of dimensions. +Using indexes reduces the resources needed to perform vector searches. -For example, to generate vectors from text, you can use a use models such as https://en.wikipedia.org/wiki/Word2vec[Word2Vec^], https://en.wikipedia.org/wiki/GloVe[Global Vectors for Word Representation (GloVe)^], or https://huggingface.co/sentence-transformers/all-MiniLM-L6-v2[all-MiniLM-L6-v2^]. -These models take into account the context around each potion of the text when generating a vector. -This context is what captures the semantic meaning of the text and embeds it in the vector's dimensions. +If you're unfamiliar with vectors and vector indexing, see xref:vectors-and-indexes-overview.adoc[] for an overview. -To generate vectors from images, you use different embedding models such as a https://en.wikipedia.org/wiki/Residual_neural_network[Residual Neural Network (ResNet)^]. -You can embed audio using a model such as OpenL3. +== Application Workflow with Vector Indexes -image::embedding-vectors.svg["Diagram showing text, image, and audio data being transformed by embedding models into a string of floating point numbers that represent vectors."] +The following diagram shows a typical workflow for an application that uses vector values stored in Couchbase {product-name}. -=== How Embedding Models Work +[plantuml,ai-app-workflow,svg] +.... +include::vector-index:partial$ai-app-workflow.puml[] +.... -Behind the scenes, embedding models use neural networks that mimic how the brain recognizes patterns. -The neural nets distill the complex data into an array of floating point values. -Beyond choosing an embedding model that's appropriate for your data, you generally do not worry about the details of how the model transforms data into a vector. +. Your application may need to load or update a document in Couchbase {product-name} that contains one or more attributes that store embedded vectors. +Before it can load the data into a Couchbase collection, it calls an embedding model to create vectors for these attributes. -=== Embedding Model Compatibility +. The application then sends the data including the embedded vector to Couchbase {product-name} for storage. +The Data Service handles creating or updating a document in a collection. -You can only compare the similarity of vectors generated by the same embedding model. -For example, you cannot find the similarity of a vector generated by Word2Vec and one generated by GloVe. -You also cannot compare a vector for a piece of text generated by Word2Vec with the vector for an image generated by ResNet. +. The addition or update of data in an indexed collection causes the Index Service to update the index. -=== Using Embedding Models with Couchbase {product-name} +. When your application needs to perform a query or search that includes a vector, it uses the embedding model to generate a vector for the search value. +It then passes this vector as part of the search request or query. -Couchbase {product-name} does not implement any embedding models. -You must use external embedding models to generate them and then store the resulting vectors in your documents. -A common method of embedding vectors in your database is to call an https://openai.com/index/introducing-text-and-code-embeddings/[OpenAI Embedding API^] to generate vectors for your data. -You then store the vector as an attribute in your document. +. Depending if the application is performing a search or a query, the Search Service or Query Service processes the request using the appropriate index -[#vector_similarity] -== Vector Similarity +. The Search or Query Service returns any results to your application. -Once you have embedded vectors in your database, you find documents with a similar meaning by finding similar vectors. -Several algorithms exist that you can use to find similar vectors (often referred to as the distance function). -When you add vectors to a Couchbase {product-name} index, you must specify which distance function to use to compare vectors. -Each function is suited for different types of data. -This distance function must match the distance function the embedding model used when generating the vectors. -Couchbase {product-name} supports three distance function: +== Uses for Vectors in Couchbase {product-name} Indexes -[#euclidean] -Euclidean Distance (also known as L2):: -Calculates the geometric distance between two vectors by finding the distance between the individual dimensions in the vectors. -This method is most sensitive to the distance between the vectors in space, rather than their alignment. -It's also sensitive to the scale of the vectors, where the length of one vector verses the other affects the relationship between the vectors. -Use this method when the proximity of the vectors and their magnitudes are important. -+ -image::euclidean-distance-example.svg["Three-dimensional plot showing two vectors with points along each vector joined by dotted lines, indicating the summing of corresponding points."] -+ -Euclidean Distance is useful for tasks such as image similarity searches. -Vectors for similar images tend to form clusters within vector space. +Here's some ways you can use vector indexes in your applications: -[#dot] -Dot Product:: -Finds related vectors by comparing the magnitude and alignment of the vectors. -In this method, the proximity of the vectors in space is less important than whether they point in a similar direction and have the a similar magnitude. -Vectors that point in similar directions (have a low angle between them) and have similar magnitude are strongly associated with each other. -This method uses the similarity of the vectors' magnitudes to rank their relation. -+ -image::dot-product-example.svg["Three-dimensional plot showing two vectors labeled with their magnitudes and the angle between them labeled with the theta symbol."] -+ -Use this method for tasks such as recommendation engines where you want to rank results from most to least related. +* Improve your application's search ability by querying not just for discrete values, but also based on similar content. +For example, suppose your application is a product catalog. +Using a GSI index extended with a vector column, it could find similar products based not just on attributes (such as color or size) but also the similarity of the product's description and customer reviews. +You can even offer the ability for customers to upload a picture and have your application find similar products. -[#cosine] -Cosine Similarity:: -This method is similar to the dot product. -However, it normalizes the vectors (making them the same length) during comparison. -Normalization means their magnitudes are not taken into account, just their alignment. -This normalization makes this method better for comparing textual data because it's less sensitive to the length of the data. -The magnitude of a vector generated by some textual data embedding models depend on the length of the source text. -Normalizing vector magnitudes emphasizes the semantic meaning when performing comparisons. -Therefore, Cosine Similarity can find the semantic relationship between a short question and a long article that's relevant to answering it. -+ -image::cosine-similarity-example.svg["Three-dimensional plot showing two vectors that are of equal length, with the angle between them labeled as theta."] -+ -Use this method when you're performing similarity searches on text. +* Create a customized chatbot based on your own data by implementing a Retrieval-Augmented Generation (RAG) workflow using a Vector Index. +When a user enters a question, convert it to a vector using the same embedding model you used to embed vectors into your database. +Perform a query using a Vector Index to find relevant documents in your database. +Then pass the user's question and the relevant documents to a Large Language Model (LLM) to generate a final response for the user. -== Vector Indexes -As with other data types in Couchbase {product-name}, indexes make searching for similar vectors much faster. -Using indexes for vector searches is especially important due to the size of the vector data. -Vectors can contain hundreds to even thousands of dimensions. -Using indexes helps limit the resources needed to perform vector searches. -=== Index Support for Vectors +== Index Support for Vectors You can include vectors in three types of indexes: * Vector Indexes are specifically designed for vector searches. +They perform vector similarity and semantic searches faster than the other types of indexes. They can index billions of documents. Most of the Vector Index resides in a highly optimized format on disk. -Use this type of index when you want to primarily query vector values with a low memory footprint. -They excel at traditional vector similarity and semantic searches. +Use this type of index when you want to primarily query vector values with a low memory footprint. This index offers high accuracy even for vectors with a large number of dimensions. * Global Secondary Indexes (GSI) can have a single vector column. -Adding a vector to a GSI is useful when your queries combine a single vector value with standard scalar attributes. -The scalar attributes in a query reduce the number of vectors the Couchbase {product-name} has to scan to find similar vectors. +Adding a vector to a GSI lets you perform a hybrid search combining a single vector value with standard scalar attributes that are also indexed in the GSI. +The scalar attributes in a query reduce the number of vectors the Couchbase {product-name} has to compare when performing an index scan to find similar vectors. Use GSI indexes with a vector column when you want to perform hybrid searches of documents using both scalars and a vector. They work well for cases where your queries are highly selective---returning a small number of results from a large dataset. They consume a moderate amount of memory and can index billions of documents. +To learn how to use GSI with vectors, see xref:gsi-with-vector.adoc[]. * A Search index used for full-text and geospacial search can have an added vector attribute, The search results combine keyword matching of Full-Text Search with the semantic meaning matching of vectors to give you hybrid results. Use Search indexes with a vector attribute when you want to query based on keywords or geospacial data plus a vector value. -These indexes can index millions of documents. - -[#index-algorithms] -=== Indexing Algorithms - -When you add a vector column to an index, you specify one or more algorithms that Couchbase {product-name} uses to process the vector values. -These algorithms organize and consolidate vector data in the index to make it more efficient to search. - -Couchbase {product-name} supports the following algorithms: - -Flat Index:: -This algorithm just stores the full vector value in the index without performing any sort of optimization. -Searches using this index use a brute-force method to find similar vectors. -Adding new vectors to a flat index is fast, and the index does not need training. -It also offers high precision, because search compares the full vector values. -However, searching a flat index is inefficient, because the search must compare every vector in the index to find matchers. -You should only use it for small data sets or for testing. -+ -NOTE: Only Search Indexes support using a flat index. -Vector indexes and GSI with a vector field only support the next algorithm, IVF. - -[#IVF] -Inverted File (IVF):: -This algorithm partitions the vector space to limit the number of vectors that a search must compare. -An IVF index trains itself during creation using a set of parameters you pass to it: -+ -. It samples vectors in the dataset to locate clusters of similar vectors. -. For each cluster it finds, it chooses a representative vector (called a centroid). -. It creates a data structure called an inverted list that associates all vectors with their closest centroid. -+ -image::ivf-diagram-with-vectors.svg["A plot showing clusters of points in a 3D graph being labelled and assigned centroid vectors. The centroids them point to multiple vectors."] -+ -When you search an IVF index, it first locates the centroids that are most relevant to the vector value you're searching for. -It then searches just the vectors associated to those centroids in the inverted list. -By limiting the number of vector comparisons to just the vectors close to the relevant centroids, IVF makes vector search faster. -+ -A drawback of this method is the possibility that the search could miss some relevant vectors. -Vectors can be missed if they're associated with a centroid that's not relevant to the search vector. -This risk increases as you add and delete data after you train the index. -The centroids chosen during the initial training may no longer accurately represent clusters in current dataset. -See <<#index-training>> for more information about index accuracy. -+ -Use this method if you want a balance between precision and search speed. -Vector indexes and GSI always use IVF. - -[#pq] -Product Quantization (PQ):: -Product Quantization simplifies vector data to reduce its storage and processing requirements. -Quantization is similar to using a lossy image compression format, such as JPEG, on an picture to reduce its data size. -It trades off some detail and accuracy for a smaller, more manageable data size. -+ -PQ processes vectors using the following steps: -+ --- -. It groups the vector's dimensions into chunks called subspaces. -For example, suppose the vectors contain 1024 dimensions. -Then PQ may break the vectors into 128 subspaces, each containing 8 dimensions. -. It finds groups of centroids in each subspace and adds them to a data structure called a codebook. -The codebook assigns each centroid an index number. -. PQ then reduces the size of the vectors by replacing each subspace's dimensions with the index of the closest centroid in the codebook. --- -+ -image::pq-diagram.svg["Three-dimensional plot showing two vectors that are of equal length, with the angle between them labeled as theta."] -+ -PQ could quantize the vector in the previous example from 1024 64-bit floating point values to 128 8 bit or 16 bit integer values. -This data size reduction improves performance because integer operations are less intensive than floating point operations. -It also reduces memory use because each vector requires less data to store (for example, from 64KB to 128 bytes). -+ -You often use PQ in addition to IVF--after quantization, the training process finds centroids in the dataset. -The index stores the centroids the their related vectors in the inverted list using the quantized format. -+ -A search of the PQ index performs the same steps on the vector you're searching for: -+ --- -. It breaks the search vector into subspaces and quantizes it using the codebook. -. It then locates closest centroids to the quantized query vector. -. It searches the vectors related to the matching centroids for vectors that relate to the search vector. --- -+ -PQ sacrifices some accuracy because it compares quantized vectors instead of their original raw values. -The process of quantization adds additional processing requirements to training. -This overhead makes training a PQ index more computationally expensive than the other methods. -However, PQ reduces the amount of memory and processing time necessary when searching for related vectors in a large dataset. -Using this indexing algorithm when: -+ -* Your vectors contain a large number of dimensions. -* You're willing to trade higher processing requirements during training for smaller memory use and less CPU time during searches. -* Your dataset is large (millions to billions of vectors). - -[#sq] -Scalar Quantization (SQ):: -Scalar Quantization is a simpler form of quantization than PQ. -During training: -+ -. SQ determines the maximum and minimum values for each dimension in the dataset. -. It then partitions each dimension in the vector into equal segments (called bins) over the range of the dimension's values. -For example, in the diagram, the first dimension's values range from 0 to 1, while the second dimension's range from 0.1 to 0.9. -. SQ assigns each bin an index value that's from 4 to 8 bits in length. -. It find a centroid within the range associated with the bin. -It saves the centroid as a 16 or 32 bit floating point number. -. SQ then quantizes the vectors by replacing their dimensional values with the index value of the bin the value falls into. -+ -image::sq-diagram.svg["Diagram showing each floating point dimension of a vector being converted to an 8-bit integer by looking up which bucket it falls into."] -+ -This quantization reduces the dimensions from 32 or 64 bit floating point values to 8 or less bit integers, reducing the memory needed for search. -It also makes search faster because integer operations are computationally less expensive than floating point operations. -+ -A search on an SQ index reassembles vectors before comparing them. -For each of the vector's dimensions, the integer bin number is replaced with the floating point centroid associated with the bin. -This recreation is an approximation of the original vector, because each dimension in the vector is the bin's centroid value rather than the original dimensional value. -+ -Like the PQ algorithm, you often combine SQ and IVF. -This combination limits the number of vectors that a search has to compare and reduces its memory and processing requirements. -+ -Because this method quantizes the vectors, it loses precision. -It's less precise than the PQ method (which also quantizes vectors) because it assumes that each dimension can be evenly divided. -Its accuracy suffers if your data has clusters. -It's best suited for data that's more evenly distributed and does not have high correlations. -For example, SQ may be a good fit for an IoT sensor dataset where the measured values (such as temperature) are evenly distributed over the range of measurements. -+ -SQ has a lower training overhead compared to the PQ and IVF methods because it does not search for clusters of vectors. -Its training just determines the range of values for each dimension. -+ -Use SQ if you want to gain some of the memory efficiency offered by vector quantization, but do not want the processing overhead of training a PQ index. - -[#index-training] -=== The Importance of Index Training - -Three of the four indexing algorithms rely on training the index on existing data. -For example, both PQ and IVF locate centroids that represent clusters of vectors in vector space. -This training reflects the content of dataset at training time. -For this training to give you accurate search results, the data in your dataset must represent the full range of data you expect to search. -If it does not, the centroids the PQ or IVF indexing method selects may not accurately represent clusters of data in the dataset. -Having accurate centroids are key to these indexing methods returning accurate results. - -Over time, you may find the accuracy of your vector searches decreasing. -Searches for similar vectors may miss relevant results or may rank less-related vectors higher than more relevant results. -These inaccuracies can occur because the data in the dataset changes over time as you add and remove documents. -The centroids identified by PQ and IVF may no longer adequately reflect the data in your database. -New clusters of vectors may have developed, and old ones may have dissipated. - -Indexes using the SQ indexing algorithm can return inaccurate results if the range of values in the dimensions change. -If one or more dimensional values fall outside the range that SQ assign buckets to, they get assigned closest bucket. -These inaccuracies can build over time, skewing results,. - -To resolve these accuracy issues, can retrain your indexes when you notice poor results. -You can retrain indexes periodically, or after you have made significant changes to your dataset. - -You should consider the need to retrain your indexes when choosing which index algorithm to use. -For example, the PQ algorithm requires more resources to train than the SQ algorithm. -If your dataset evolves rapidly, you may want avoid using PQ because you'll need to perform more frequent retraining. - -== Uses for Vectors in Couchbase {product-name} Indexes - -Here's some ways you can use vector indexes in your applications: - -* Improve your application's search ability by querying not just for discrete values, but also based on similar content. -For example, suppose your application is a product catalog. -Using a GSI index extended with a vector column, it could find similar products based not just on attributes (such as color or size) but also the similarity of the product's description and customer reviews. - -* Create a customized chatbot based on your own data by implementing a Retrieval-Augmented Generation (RAG) workflow using a Vector Index. -When a user enters a question, convert it to a vector using the same embedding model you used to embed vectors into your database. -Perform a query using a Vector Index to find relevant documents in your database. -Then pass the user's question and the relevant documents to a Large Language Model (LLM) to generate a final response for the user. - -== Application Workflow with Vector Indexes - -No matter which type of Couchbase {product-name} index you add vectors to, the workflow for your application to use them is similar. The following diagram shows a typical workflow. - -[plantuml,ai-app-workflow,svg] -.... -include::vector-index:partial$ai-app-workflow.puml[] -.... - -. Your application may need to load or update data that contains one or more attributes that have embedded vectors in Couchbase {product-name}. -Before it can load the data into a Couchbase collection, it calls an embedding model to create vectors for these attributes. - -. The application then sends the data including the embedded vector to Couchbase {product-name} for storage. -The Data Service handles creating or updating a document in a collection. - -. The addition or update of data in an indexed collection causes the Index Service to update the index. - -. When your application needs to perform a query or search that includes a vector, it uses the embedding model to generate a vector for the search value. -It then passes this vector as part of the search request or query. - -. Depending if the application is performing a search or a query, the Search Service or Query Service processes the request using the appropriate index - -. The Search or Query Service returns any results to your application. - +These indexes can index millions of documents. \ No newline at end of file diff --git a/modules/vector-index/pages/vectors-and-indexes-overview.adoc b/modules/vector-index/pages/vectors-and-indexes-overview.adoc new file mode 100644 index 000000000..1fed11b08 --- /dev/null +++ b/modules/vector-index/pages/vectors-and-indexes-overview.adoc @@ -0,0 +1,305 @@ += Vectors and Vector Indexes Overview +:page-topic-type: concept +:page-ui-name: {ui-name} +:page-product-name: {product-name} +:description: This page is a high-level overview of vectors and adding vector values to indexes. +:page-toclevels: 3 + +{description} + +== About Vectors + +Vectors are a numerical representation of complex unstructured data such as text, images, or audio. +They distill this complex data into an array of floating-point values called dimensions. +The dimensions in vectors capture features of the data in a way that makes them easy to compare mathematically. +Similar data, such as text about the same topic or images of a similar subject, have similar vectors. +Similar vectors are close together the multi-dimensional space formed by all of the vectors in the dataset. +Vectors for dissimilar data (articles discussing two different topics for example) have vectors that are further apart in this multi-dimensional space. + +=== Finding Semantically Similar Text Data + +By comparing two vectors, you can find the similarity between the two pieces of data they represent. +This similarity goes beyond just finding parts of the data that's identical (for example, finding similar words in two pieces of text). +The vectors represent features such as the meaning of text rather than just superficial similarities. +When two pieces of data have similar vectors, they have similar meanings or subjects (semantically related). + +For example, suppose you have three text articles. +The first is about feral cats, the second about domestic cats, and the third is about the UNIX/Linux `cat` command. +A text search for the term "cat" could return all three articles at the top of its search results due to their frequent use of the search term. +However, that does not mean that the articles are all semantically related. +By generating vectors for the articles and comparing them, you can determine any semantic relationship between them. + +Vectors can be similar in a variety of ways. +They may: + +* Point in similar directions. +* Be close to each other in the vector space made up of all the dimensions in the vectors. +* Have a similar magnitude (length). + +image::vector-space-example.svg["Three-dimensional plot showing two vectors that are close by and parallel and a third vector that's away and points in another direction"] + +Because the first two articles are about cats, their vectors point in a similar direction and are in a similar location in space. +The third article, despite using the word "cat" as frequently as the two other articles, has a vector that has significant differences from the other two. + +NOTE: Some diagrams in this document (and in other discussions available on the web) show vectors in three dimensions. +These diagrams are a simplification. +The vectors used in AI applications have hundreds to thousands of dimensions. +They're easy for computers to handle but are rather difficult for humans to visualize. +In addition, the vector dimension values in the diagrams show only 4 decimal places to conserve space. +The floating point dimensional values of actual vectors often use 6 or 7 decimal places. +When viewing these diagrams, remember that they only scratch the surface of the data encoded in a vector. + +=== Using Vectors to Find Similar Complex Data + +Vectors let you search for similarity in data that's hard to search using traditional techniques. +Image data, for example, is just a string of raw binary values. +Matching portions of this data within two image files does not mean they're of the same subject, or even have any resemblance. +Also, comparing megabytes of raw image data is computationally expensive. +Generating vectors of the images distills features of the image into a smaller, more manageable amount of data. +It also emphasizes features of the images that viewers find important, such as shapes and textures. +Comparing the vectors is more manageable, and actually results in finding similar images. + +== Embedding Vectors + +Embedding is the process of generating vectors that represent a piece of complex unstructured data. +You use an embedding model that's specific to the data's type to generate a vector to represent it. + +For example, to generate vectors from text, you can use a use models such as https://en.wikipedia.org/wiki/Word2vec[Word2Vec^], https://en.wikipedia.org/wiki/GloVe[Global Vectors for Word Representation (GloVe)^], or https://huggingface.co/sentence-transformers/all-MiniLM-L6-v2[all-MiniLM-L6-v2^]. +These models take into account the context around each potion of the text when generating a vector. +This context is what captures the semantic meaning of the text and embeds it in the vector's dimensions. + +To generate vectors from images, you use different embedding models such as a https://en.wikipedia.org/wiki/Residual_neural_network[Residual Neural Network (ResNet)^]. +You can embed audio using a model such as OpenL3. + +image::embedding-vectors.svg["Diagram showing text, image, and audio data being transformed by embedding models into a string of floating point numbers that represent vectors."] + +=== How Embedding Models Work + +Behind the scenes, embedding models use neural networks that mimic how the brain recognizes patterns. +The neural nets distill the complex data into an array of floating point values. +Beyond choosing an embedding model that's appropriate for your data, you generally do not worry about the details of how the model transforms data into a vector. + +=== Embedding Model Compatibility + +You can only compare the similarity of vectors generated by the same embedding model. +For example, you cannot find the similarity of a vector generated by Word2Vec and one generated by GloVe. +You also cannot compare a vector for a piece of text generated by Word2Vec with the vector for an image generated by ResNet. + +=== Using Embedding Models with Couchbase {product-name} + + +ifeval::['{product-name}' == 'Server'] +Couchbase {product-name} does not implement any embedding models. +You must use external embedding models to generate them and then store the resulting vectors in your documents. +A common method of embedding vectors in your database is to call an https://openai.com/index/introducing-text-and-code-embeddings/[OpenAI Embedding API^] to generate vectors for your data. +You then store the vector as an attribute in your document. + +Another option is to use Couchbase Capella along with Capella's AI Services which integrates several embedding models. +See https://www.couchbase.com/products/ai-services/[Capella AI Services] for more information. +endif::[] + +ifeval::['{product-name}' != 'Server'] +You can use external embedding models or https://www.couchbase.com/products/ai-services/[Capella AI Services] to generate vector embeddings. + +endif::[] + + +[#vector_similarity] +== Vector Similarity + +Once you have embedded vectors in your database, you find documents with a similar meaning by finding similar vectors. +Several algorithms exist that you can use to find similar vectors (often referred to as the distance function). +When you add vectors to a Couchbase {product-name} index, you must specify which distance function to use to compare vectors. +Each function is suited for different types of data. +This distance function must match the distance function the embedding model used when generating the vectors. + +Couchbase {product-name} supports three distance function: + +[#euclidean] +Euclidean Distance (also known as L2):: +Calculates the geometric distance between two vectors by finding the distance between the individual dimensions in the vectors. +This method is most sensitive to the distance between the vectors in space, rather than their alignment. +It's also sensitive to the scale of the vectors, where the length of one vector verses the other affects the relationship between the vectors. +Use this method when the proximity of the vectors and their magnitudes are important. ++ +image::euclidean-distance-example.svg["Three-dimensional plot showing two vectors with points along each vector joined by dotted lines, indicating the summing of corresponding points."] ++ +Euclidean Distance is useful for tasks such as image similarity searches. +Vectors for similar images tend to form clusters within vector space. + +[#dot] +Dot Product:: +Finds related vectors by comparing the magnitude and alignment of the vectors. +In this method, the proximity of the vectors in space is less important than whether they point in a similar direction and have the a similar magnitude. +Vectors that point in similar directions (have a low angle between them) and have similar magnitude are strongly associated with each other. +This method uses the similarity of the vectors' magnitudes to rank their relation. ++ +image::dot-product-example.svg["Three-dimensional plot showing two vectors labeled with their magnitudes and the angle between them labeled with the theta symbol."] ++ +Use this method for tasks such as recommendation engines where you want to rank results from most to least related. + +[#cosine] +Cosine Similarity:: +This method is similar to the dot product. +However, it normalizes the vectors (making them the same length) during comparison. +Normalization means their magnitudes are not taken into account, just their alignment. +This normalization makes this method better for comparing textual data because it's less sensitive to the length of the data. +The magnitude of a vector generated by some textual data embedding models depend on the length of the source text. +Normalizing vector magnitudes emphasizes the semantic meaning when performing comparisons. +Therefore, Cosine Similarity can find the semantic relationship between a short question and a long article that's relevant to answering it. ++ +image::cosine-similarity-example.svg["Three-dimensional plot showing two vectors that are of equal length, with the angle between them labeled as theta."] ++ +Use this method when you're performing similarity searches on text. + + + +[#index-algorithms] +=== Indexing Algorithms + +When you add a vector column to an index, you specify one or more algorithms that Couchbase {product-name} uses to process the vector values. +These algorithms organize and consolidate vector data in the index to make it more efficient to search. + +Couchbase {product-name} supports the following algorithms: + +Flat Index:: +This algorithm just stores the full vector value in the index without performing any sort of optimization. +Searches using this index use a brute-force method to find similar vectors. +Adding new vectors to a flat index is fast, and the index does not need training. +It also offers high precision, because search compares the full vector values. +However, searching a flat index is inefficient, because the search must compare every vector in the index to find matchers. +You should only use it for small data sets or for testing. ++ +NOTE: Only Search Indexes support using a flat index. +Vector indexes and GSI with a vector field only support the next algorithm, IVF. + +[#IVF] +Inverted File (IVF):: +This algorithm partitions the vector space to limit the number of vectors that a search must compare. +An IVF index trains itself during creation using a set of parameters you pass to it: ++ +. It samples vectors in the dataset to locate clusters of similar vectors. +. For each cluster it finds, it chooses a representative vector (called a centroid). +. It creates a data structure called an inverted list that associates all vectors with their closest centroid. ++ +image::ivf-diagram-with-vectors.svg["A plot showing clusters of points in a 3D graph being labelled and assigned centroid vectors. The centroids them point to multiple vectors."] ++ +When you search an IVF index, it first locates the centroids that are most relevant to the vector value you're searching for. +It then searches just the vectors associated to those centroids in the inverted list. +By limiting the number of vector comparisons to just the vectors close to the relevant centroids, IVF makes vector search faster. ++ +A drawback of this method is the possibility that the search could miss some relevant vectors. +Vectors can be missed if they're associated with a centroid that's not relevant to the search vector. +This risk increases as you add and delete data after you train the index. +The centroids chosen during the initial training may no longer accurately represent clusters in current dataset. +See <<#index-training>> for more information about index accuracy. ++ +Use this method if you want a balance between precision and search speed. +Vector indexes and GSI always use IVF. + +[#pq] +Product Quantization (PQ):: +Product Quantization simplifies vector data to reduce its storage and processing requirements. +Quantization is similar to using a lossy image compression format, such as JPEG, on an picture to reduce its data size. +It trades off some detail and accuracy for a smaller, more manageable data size. ++ +PQ processes vectors using the following steps: ++ +-- +. It groups the vector's dimensions into chunks called subspaces. +For example, suppose the vectors contain 1024 dimensions. +Then PQ may break the vectors into 128 subspaces, each containing 8 dimensions. +. It finds groups of centroids in each subspace and adds them to a data structure called a codebook. +The codebook assigns each centroid an index number. +. PQ then reduces the size of the vectors by replacing each subspace's dimensions with the index of the closest centroid in the codebook. +-- ++ +image::pq-diagram.svg["Three-dimensional plot showing two vectors that are of equal length, with the angle between them labeled as theta."] ++ +PQ could quantize the vector in the previous example from 1024 64-bit floating point values to 128 8 bit or 16 bit integer values. +This data size reduction improves performance because integer operations are less intensive than floating point operations. +It also reduces memory use because each vector requires less data to store (for example, from 64KB to 128 bytes). ++ +You often use PQ in addition to IVF--after quantization, the training process finds centroids in the dataset. +The index stores the centroids the their related vectors in the inverted list using the quantized format. ++ +A search of the PQ index performs the same steps on the vector you're searching for: ++ +-- +. It breaks the search vector into subspaces and quantizes it using the codebook. +. It then locates closest centroids to the quantized query vector. +. It searches the vectors related to the matching centroids for vectors that relate to the search vector. +-- ++ +PQ sacrifices some accuracy because it compares quantized vectors instead of their original raw values. +The process of quantization adds additional processing requirements to training. +This overhead makes training a PQ index more computationally expensive than the other methods. +However, PQ reduces the amount of memory and processing time necessary when searching for related vectors in a large dataset. +Using this indexing algorithm when: ++ +* Your vectors contain a large number of dimensions. +* You're willing to trade higher processing requirements during training for smaller memory use and less CPU time during searches. +* Your dataset is large (millions to billions of vectors). + +[#sq] +Scalar Quantization (SQ):: +Scalar Quantization is a simpler form of quantization than PQ. +During training: ++ +. SQ determines the maximum and minimum values for each dimension in the dataset. +. It then partitions each dimension in the vector into equal segments (called bins) over the range of the dimension's values. +For example, in the diagram, the first dimension's values range from 0 to 1, while the second dimension's range from 0.1 to 0.9. +. SQ assigns each bin an index value that's from 4 to 8 bits in length. +. It find a centroid within the range associated with the bin. +It saves the centroid as a 16 or 32 bit floating point number. +. SQ then quantizes the vectors by replacing their dimensional values with the index value of the bin the value falls into. ++ +image::sq-diagram.svg["Diagram showing each floating point dimension of a vector being converted to an 8-bit integer by looking up which bucket it falls into."] ++ +This quantization reduces the dimensions from 32 or 64 bit floating point values to 8 or less bit integers, reducing the memory needed for search. +It also makes search faster because integer operations are computationally less expensive than floating point operations. ++ +A search on an SQ index reassembles vectors before comparing them. +For each of the vector's dimensions, the integer bin number is replaced with the floating point centroid associated with the bin. +This recreation is an approximation of the original vector, because each dimension in the vector is the bin's centroid value rather than the original dimensional value. ++ +Like the PQ algorithm, you often combine SQ and IVF. +This combination limits the number of vectors that a search has to compare and reduces its memory and processing requirements. ++ +Because this method quantizes the vectors, it loses precision. +It's less precise than the PQ method (which also quantizes vectors) because it assumes that each dimension can be evenly divided. +Its accuracy suffers if your data has clusters. +It's best suited for data that's more evenly distributed and does not have high correlations. +For example, SQ may be a good fit for an IoT sensor dataset where the measured values (such as temperature) are evenly distributed over the range of measurements. ++ +SQ has a lower training overhead compared to the PQ and IVF methods because it does not search for clusters of vectors. +Its training just determines the range of values for each dimension. ++ +Use SQ if you want to gain some of the memory efficiency offered by vector quantization, but do not want the processing overhead of training a PQ index. + +[#index-training] +=== The Importance of Index Training + +Three of the four indexing algorithms rely on training the index on existing data. +For example, both PQ and IVF locate centroids that represent clusters of vectors in vector space. +This training reflects the content of dataset at training time. +For this training to give you accurate search results, the data in your dataset must represent the full range of data you expect to search. +If it does not, the centroids the PQ or IVF indexing method selects may not accurately represent clusters of data in the dataset. +Having accurate centroids are key to these indexing methods returning accurate results. + +Over time, you may find the accuracy of your vector searches decreasing. +Searches for similar vectors may miss relevant results or may rank less-related vectors higher than more relevant results. +These inaccuracies can occur because the data in the dataset changes over time as you add and remove documents. +The centroids identified by PQ and IVF may no longer adequately reflect the data in your database. +New clusters of vectors may have developed, and old ones may have dissipated. + +Indexes using the SQ indexing algorithm can return inaccurate results if the range of values in the dimensions change. +If one or more dimensional values fall outside the range that SQ assign buckets to, they get assigned closest bucket. +These inaccuracies can build over time, skewing results,. + +To resolve these accuracy issues, can retrain your indexes when you notice poor results. +You can retrain indexes periodically, or after you have made significant changes to your dataset. + +You should consider the need to retrain your indexes when choosing which index algorithm to use. +For example, the PQ algorithm requires more resources to train than the SQ algorithm. +If your dataset evolves rapidly, you may want avoid using PQ because you'll need to perform more frequent retraining. \ No newline at end of file diff --git a/modules/vector-index/partials/nav.adoc b/modules/vector-index/partials/nav.adoc index bd38107c9..59eeb3464 100644 --- a/modules/vector-index/partials/nav.adoc +++ b/modules/vector-index/partials/nav.adoc @@ -1,2 +1,10 @@ * xref:7.7@server:vector-index:use-vector-indexes.adoc[] ++ +-- +** xref:7.7@server:vector-index:vectors-and-indexes-overview.adoc[] ** xref:7.7@server:vector-index:gsi-with-vector.adoc[] +-- ++ +-- +include::vector-search:partial$nav.adoc[] +-- From d3c40e32ad820cf4bccc8dced3cfa34494b5097b Mon Sep 17 00:00:00 2001 From: Gary Gray <137797428+ggray-cb@users.noreply.github.com> Date: Tue, 4 Mar 2025 15:57:35 -0500 Subject: [PATCH 20/41] More or less complete draft after incorporqating Ankush's feedback and adding the Vector index (BHIVE) page. --- .../vector-index/pages/gsi-with-vector.adoc | 135 +------------- modules/vector-index/pages/vector-index.adoc | 166 ++++++++++++++++++ .../pages/vectors-and-indexes-overview.adoc | 15 +- .../partials/index-algorithm-settings.adoc | 126 +++++++++++++ modules/vector-index/partials/nav.adoc | 1 + 5 files changed, 313 insertions(+), 130 deletions(-) create mode 100644 modules/vector-index/pages/vector-index.adoc create mode 100644 modules/vector-index/partials/index-algorithm-settings.adoc diff --git a/modules/vector-index/pages/gsi-with-vector.adoc b/modules/vector-index/pages/gsi-with-vector.adoc index 215bec2e0..77db54182 100644 --- a/modules/vector-index/pages/gsi-with-vector.adoc +++ b/modules/vector-index/pages/gsi-with-vector.adoc @@ -5,6 +5,8 @@ :description: You can extend a Couchbase {product-name}'s Global Secondary Index (GSI) with a single vector column to enable hybrid queries to find semantically-related content. :stem: :page-toclevels: 3 +:index-name: GSI index with a vector column +:index-name-plural: GSI indexes with a vector column {description} @@ -16,7 +18,7 @@ See xref:learn:services-and-indexes/indexes/indexes.adoc[] for an overview of GS You can add a single vector column to a GSI to enable semantic and similarity searches within your {sqlpp} queries. When creating the index, you use a `VECTOR` key attribute to designate the field that contains the embedded vectors. -When your query contains a embedded vector, the Query Service uses any non-vector predicates in the query to filter index entries. +When your query contains an embedded vector, the Query Service uses any non-vector predicates in the query to filter index entries. Then it performs an index scan on the remaining index entries, using the similarity function you specify in the query to locate similar vectors. This behavior reduces the number of vector similarity comparisons the Query Service must do to find similar vectors. @@ -49,135 +51,10 @@ The embedding model you use to embed the vectors may determine this value for yo For example, OpenAI API's `text-embedding-ada-002` embedding model that embedded the sample data creates vectors that have 1536 dimensions. * You must decide what algorithms you want your index to use. -These algorithms affect how much memory your index uses and how much processing is required to train and search them. -See xref:vector-index:use-vector-indexes.adoc##index-algorithms[Indexing Algorithms] +These algorithms affect how much memory and processing Couchbase {product-name} uses to train and search them. +See xref:vector-index:vectors-and-indexes-overview.adoc#index-algorithms[Indexing Algorithms] -[#algo_settings] -== Index Algorithm Settings - -When creating an index that includes a vector field, you choose settings that affect how the index processes vectors. -The parameter named `description` is the primary setting that controls the indexing algorithms that Couchbase {product-name} to create the index. -Using it, you control how the index subdivides the dataset to improve performance and how it quantizes vectors to reduce memory and processing requirements. - -The `description` parameter is a string in the following format: - -[source,sqlpp] ----- -'IVF[],{PQ|SQ}' ----- - -The following sections describe the settings for centroids and quantization. - -=== Number of Centroids - -GSI indexes with a vector column always use the xref:vector-index:use-vector-indexes.adoc#IVF[Inverted File (IVF)] algorithm to subdivides the dataset. -Using this algorithm reduces the number of vector comparisons a vector search of the index must perform. -The key setting for IVF is the number of centroids it allocates for the index. -The number of centroids affects the performance of your index in two ways: - -* If the index has fewer centroids, each centroid has more vectors associated with it. -In this case, a vector search has to perform more comparisons which makes the search slower. -Having fewer centroids decreases the processing overhead for training the index. - -* A greater number of centroids results in a greater processing cost for training. -This increase is due to the training process having to search for more data cluster to identify more centroids. -However, it reduces the number of vectors associated with each centroid. -This reduction makes search faster by limiting the number of vector comparisons during a search. - -You can have Couchbase {product-name} choose a number of centroids for you by not providing a value after the `IVF` in your `description` parameter. -It chooses the number of centroids based on the number of vectors in the dataset: - -* If the number of vectors in the dataset is less than 1 million (1,000,000), Couchbase {product-name} sets the number of centroids to stem:["number of vectors" / 1000]. - -* If the number of vectors in greater than 1 million, Couchbase {product-name} sets the number of centroids to stem:[sqrt("number of vectors")]. - -You can manually set the number of centroids for the index by adding an integer value after the `IVF` in the `decription` parameter. -The number of centroids you set manually must be less than the number of vectors in the dataset. - -=== Quantization Setting - -GSI with a vector field always uses quantization to reduce the size of vectors stored in the index. -You must choose whether the index uses xref:vector-index:use-vector-indexes.adoc#sq[Scalar Quantization (SQ)] or xref:vector-index:use-vector-indexes.adoc#pq[Product Quantization (PQ)]. - -You select the quantization by adding a comma followed by either `PQ` or `SQ` to the `description` parameter after the IVF setting in the `description` value. - - -Each quantization method has additional settings explained in the following sections, - -==== SQ Settings - -For SQ, you set the number of bits the SQ algorithm uses for the bin index value or the number of bits it uses to store the centroid for each bin. -The values for SQ that Couchbase {product-name} supports are: - -[%autowidth] -|=== -| Setting | Effect - -| `SQ4` -| SQ uses a 4-bit index value splitting each vector dimension into 16 subspaces. - -| `SQ6` -| SQ uses a 6-bit index value splitting each vector dimension into 64 subspaces. - -| `SQ8` -| SQ uses an 8-bit index value splitting each vector dimension into 256 subspaces. - -| `SQfp16` -| SQ uses an 8-bit index value splitting each vector dimension into 256 subspaces. -However, it stores the centroid value as a 16-bit floating point number instead of a 32-bit floating point number. -This cuts the memory used to store the centroids in half. - -|=== - -==== PQ Settings - -If you choose to use PQ in your index, you must set two values: - -* The number of subquantizers (number of subspaces SQ splits the vector's dimensions into) to use. -This value must a divisor of the number of dimensions in the vector. -For example, if your vector has 99 dimensions you can only use the values 3, 9, 11, 33, and 99 for the subquantizers. -Using any other value returns an error. - -* The number of bits in the centroid's index value. -This value sets the number centroids to find in each subspace. -For example, setting this value to 8 has PQ store the index for the centroids in a byte. -This results in SQ using 256 centroids per subspace. -+ -The number of centroids you set using this value must be less than the number of vectors in the dataset. -For example, if you choose 32 for the centroid index size, your dataset must have at least 4,294,967,296 vectors in it. - -The larger you set either of these values, the more accurate the index's search results are. -The trade-off is that your index is larger, as it has to store data for more centroids. -A smaller value results in a smaller index that returns less accurate results. - -The format for the PQ settings is: - -[source,sqlpp] ----- -PQx ----- - -For example, `PQ32x8` has PQ break the vector's dimensions into 32 subspaces, each of which has 256 centroids. - -=== Algorithm Settings Examples - -The following table shows several `description` values along with an explanation. - -[%autowidth] -|=== -| Setting | Effect - -| `IVF,SQ8` -| Couchbase {product-name} chooses the number of centroids the IVF algorithm uses. -The index uses Scalar Quantization with an 8-bit index, meaning each dimension of the vector is broken into 256 bins. - -| `IVF1024,PQ8x8` -| IVF uses 1024 centroids to divide the dataset. -The index uses Product Quantization. -This setting has PQ break vector space into 8 subspaces, each of which uses 8-bits to represent centroids in the subspace. -This settings means each subspace has 256 centroids. - -|=== +include::partial$index-algorithm-settings.adoc[] == Create a GSI with a Vector Column diff --git a/modules/vector-index/pages/vector-index.adoc b/modules/vector-index/pages/vector-index.adoc new file mode 100644 index 000000000..c17663c01 --- /dev/null +++ b/modules/vector-index/pages/vector-index.adoc @@ -0,0 +1,166 @@ += Pure Vector Searches Using Vector Indexes +:page-topic-type: guide +:page-ui-name: {ui-name} +:page-product-name: {product-name} +:description: Vector indexes are are optimized to index a single vector column. They offer the highest performance of any index when it comes to vector data. +:stem: +:page-toclevels: 3 +:index-name: Vector index +:index-name-plural: Vector indexes + +{description} +Vector indexes can scale up to a billion documents containing vectors each of which have a large number of dimensions. + +Because they provide the best performance, consider testing a Vector index for your application before resorting to the other types of indexes. +If you find that the Vector index's performance does not meet your needs, then test using a GSI with vector column or a Search index. + + +== How the Vector Index Works + +The Vector index primarily relies on data stored in an optimized format on disk. +By relying on disk storage, Vector indexes have lesser memory requirements than other index types. + +You add a single vector column to a Vector index. +The vector value can be an array of floating point values. +This array can be nested, as long as you use an xref:n1ql:n1ql-language-reference/unnest.adoc[`UNNEST` clause] to extract the vector array from the containing array. +The vector can also be stored in a BASE64 string. + + +=== Filter Vector Index Scans with Scalar Columns + +The Vector index contains just the single vector column. +However, you can use non-vector values in your query to limit the number of vector comparisons. +The query uses columns you add to an `INCLUDE` clause to filter out index entries before performing the vector index scan. +See <<#filter-using-scalars-example>> for more information. + + +[#full-vector-persist] +=== Persisting the Full Vector Value + +The Vector index always quantizes the vectors it contains. +See xref:vectors-and-indexes-overview.adoc#quantization[Quantization] for more information about quantizing vectors. +You choose which type of quantization the Vector index uses when you create it. +It uses these quantized values when it scans for similar vectors. + +By default, Vector indexes also store a copy of the original vector value. +It uses the full value when ranking the search results to make the rankings more accurate. +You can choose to turn off this feature if the cost of storing and comparing full vector values during ranking causes performance issues. + +== Prerequisites + +Vector indexes have the following requirements: + +* You must have the Index Service enabled on at least one node in your cluster. +For more information about how to deploy a new node and Services on your database, see xref:manage:manage-nodes/node-management-overview.adoc[]. + +* You must have a bucket with scopes and collections in your database. +For more information about how to create a bucket, see xref:manage:manage-buckets/create-bucket.adoc[]. + +* Your account must have the xref:learn:security:roles.adoc#query-manage-index[Query Manage Index] role to be able to create an index. + +* You have documents in a collection that contain one or more vector embeddings. +You can add a single vector to a GSI index. +If your documents contain multiple embedded vectors, you can create multiple indexes---one for each vector attribute. ++ +Embeddings can be an array of floating point numbers or a base64 encoded string. +Couchbase {product-name} does not embed vectors itself. +You must use an external embedding model to embed vectors into your data and add them to your documents. + +* The vectors you add to an index must contain the same number of dimensions. +Also the values in the vector must be 32-bit floating point numbers. +If a vector does not meet both of these requirements, the vector index treats it as a NULL value and the document is not added to the index. + +* You must know the number of dimensions the vector contains. +The embedding model you use to embed the vectors may determine this value for you. +For example, OpenAI API's `text-embedding-ada-002` embedding model creates vectors that have 1536 dimensions. + +* You must decide what algorithms you want your index to use. +These algorithms affect how much memory your index uses and the amount of processing Couchbase {product-name} must perform to train and search them. +See xref:vector-index:vectors-and-indexes-overview.adoc#index-algorithms[Indexing Algorithms] + +include::partial$index-algorithm-settings.adoc[] + +== Create a Vector Index +Use the `CREATE VECTOR INDEX` statement to create a Vector index. +This statement is similar to the `CREATE INDEX` statement that you use to create Global Secondary Indexes (GSI). +See xref:guides:create-index.adoc[] for an overview of creating indexes. + +You must also use the `WITH` clause to specify some additional information for the vector column in the index. +The format for this clause with the most commonly used parameters is: + +[source,sqlpp] +---- +WITH { "dimension": , "similarity":, "description":}; +---- + +* `dimensions` is an integer value that sets the number of dimensions in the vector. +This value is set by the embedded model you used to embed the vectors. +* `similarity-function` is a string that sets the distance function to use when comparing vectors during index creation. +Couchbase {product-name} uses the following strings to represent the proximity functions: ++ +-- +** `COSINE`: xref:use-vector-indexes.adoc#cosine[Cosine Similarity] +** `DOT`: xref:use-vector-indexes.adoc#dot[Dot Product] +** `L2`, `L2_SQUARED`, `EUCLIDEAN`, or `EUCLIDEAN_SQUARED`: xref:use-vector-indexes.adoc#euclidean[Euclidean Distance] +-- ++ +For the greatest accuracy, use the distance function you plan to use when querying vector data. +* `algorithm-settings` is a string containing the settings for the indexing algorithms. +See <<#algo_settings>> earlier in this page. + +For a full list of the parameters that affect a vector column in a GSI, see *FIXME:TDB*. + +[#examples] +=== Create Vector Index Examples + +TBD + + + + + +[#prevent-vector-persistence] +=== Prevent Full Vector Persistence + +As mentioned in <<#full-vector-persist>>, by default the Vector index stores the full vector value in addition to its quantized form. +It uses the full vector during result ranking. +You can prevent the Vector index persisting the full vector by setting the `persist_full_vector` attribute in the `WITH` clause to false: + +[source,sqlpp] +---- +WITH { "dimension": , + "similarity":, + "description":, + "persist_full_vector":false + }; +---- + + +== Query with a Vector Index + +You query embedded vector attribute that you have indexed in a Vector index to find similar vectors and therefore similar semantic content. +To find the most similar vectors, use a `GROUP BY` clause in your query to return the most relevant vectors first. +In this clause, call the `APPROX_VECTOR_DISTANCE` function that performs the vector search. + + +NOTE: You can also call the function `VECTOR_DISTANCE` to find similar vectors. +However, this function does not use the Vector index to perform the vector search. +Instead, it performs a brute-force search for similar vectors. + + +You should also use a `LIMIT` clause to return just the number of vectors you need. +The query pushes the `LIMIT` clause down into the index scan so that the scan ends after finding the requested number of matches. + +=== Query Vector Index Examples + +**TBD** + +[#filter-using-scalars-example] +=== Filter Vector Index Searches Using Scalars + +The Vector index only allows a single vector column. +You may have queries where you'd like to use non-vector scalar columns to filter out vectors before performing an index scan. +You can add these columns to the query using an `INCLUDE` clause. +The query pushes the columns you name in the `INCLUDE` clause into the Vector index scan, helping to limit the number of vector comparisons needed to locate matching vectors. + +**Example TBD** \ No newline at end of file diff --git a/modules/vector-index/pages/vectors-and-indexes-overview.adoc b/modules/vector-index/pages/vectors-and-indexes-overview.adoc index 1fed11b08..c20d2b217 100644 --- a/modules/vector-index/pages/vectors-and-indexes-overview.adoc +++ b/modules/vector-index/pages/vectors-and-indexes-overview.adoc @@ -160,7 +160,11 @@ Use this method when you're performing similarity searches on text. When you add a vector column to an index, you specify one or more algorithms that Couchbase {product-name} uses to process the vector values. These algorithms organize and consolidate vector data in the index to make it more efficient to search. -Couchbase {product-name} supports the following algorithms: +Couchbase {product-name} supports the algorithms described in the following sections. + +==== Index Formats + +Couchbase Server supports two formats for the index, which controls how the index stores the vectors. Flat Index:: This algorithm just stores the full vector value in the index without performing any sort of optimization. @@ -197,6 +201,15 @@ See <<#index-training>> for more information about index accuracy. Use this method if you want a balance between precision and search speed. Vector indexes and GSI always use IVF. +[#quantization] +==== Quantization + +Quantization simplifies vector data to consume less storage space in memory and on disk. +Reducing the amount of data in a vector also makes vector comparison faster. +However, quantization does reduce the accuracy of a vector. + +Couchbase {product-name} supports two types of quantization: + [#pq] Product Quantization (PQ):: Product Quantization simplifies vector data to reduce its storage and processing requirements. diff --git a/modules/vector-index/partials/index-algorithm-settings.adoc b/modules/vector-index/partials/index-algorithm-settings.adoc new file mode 100644 index 000000000..afe55d0c0 --- /dev/null +++ b/modules/vector-index/partials/index-algorithm-settings.adoc @@ -0,0 +1,126 @@ +[#algo_settings] +== Index Algorithm Settings + +When creating an index that includes a vector field, you choose settings that affect how the index processes vectors. +The parameter named `description` is the primary setting that controls the indexing algorithms that Couchbase {product-name} to create the index. +Using it, you control how the index subdivides the dataset to improve performance and how it quantizes vectors to reduce memory and processing requirements. + +The `description` parameter is a string in the following format: + +[source,sqlpp] +---- +'IVF[],{PQ|SQ}' +---- + +The following sections describe the settings for centroids and quantization. + +=== Number of Centroids + +{index-name-plural} always use the xref:vector-index:use-vector-indexes.adoc#IVF[Inverted File (IVF)] algorithm to subdivides the dataset. +Using this algorithm reduces the number of vector comparisons a vector search of the index must perform. +The key setting for IVF is the number of centroids it allocates for the index. +The number of centroids affects the performance of your index in two ways: + +* If the index has fewer centroids, each centroid has more vectors associated with it. +In this case, a vector search has to perform more comparisons which makes the search slower. +Having fewer centroids decreases the processing overhead for training the index. + +* A greater number of centroids results in a greater processing cost for training. +This increase is due to the training process having to search for more data cluster to identify more centroids. +However, it reduces the number of vectors associated with each centroid. +This reduction makes search faster by limiting the number of vector comparisons during a search. + +You can have Couchbase {product-name} choose a number of centroids for you by not providing a value after the `IVF` in your `description` parameter. +It chooses the number of centroids based on the number of vectors in the dataset: + +* If the number of vectors in the dataset is less than 1 million (1,000,000), Couchbase {product-name} sets the number of centroids to stem:["number of vectors" / 1000]. + +* If the number of vectors in greater than 1 million, Couchbase {product-name} sets the number of centroids to stem:[sqrt("number of vectors")]. + +You can manually set the number of centroids for the index by adding an integer value after the `IVF` in the `description` parameter. +The number of centroids you set manually must be less than the number of vectors in the dataset. + +=== Quantization Setting + +{index-name} always uses quantization to reduce the size of vectors stored in the index. +You must choose whether the index uses xref:vector-index:use-vector-indexes.adoc#sq[Scalar Quantization (SQ)] or xref:vector-index:use-vector-indexes.adoc#pq[Product Quantization (PQ)]. + +You select the quantization by adding a comma followed by either `PQ` or `SQ` to the `description` parameter after the IVF setting in the `description` value. + + +Each quantization method has additional settings explained in the following sections. + +==== SQ Settings + +For SQ, you set the number of bits the SQ algorithm uses for the bin index value or the number of bits it uses to store the centroid for each bin. +The values for SQ that Couchbase {product-name} supports are: + +[%autowidth] +|=== +| Setting | Effect + +| `SQ4` +| SQ uses a 4-bit index value splitting each vector dimension into 16 subspaces. + +| `SQ6` +| SQ uses a 6-bit index value splitting each vector dimension into 64 subspaces. + +| `SQ8` +| SQ uses an 8-bit index value splitting each vector dimension into 256 subspaces. + +| `SQfp16` +| SQ uses an 8-bit index value splitting each vector dimension into 256 subspaces. +However, it stores the centroid value as a 16-bit floating point number instead of a 32-bit floating point number. +This cuts the memory used to store the centroids in half. + +|=== + +==== PQ Settings + +If you choose to use PQ in your index, you must set two values: + +* The number of subquantizers (number of subspaces SQ splits the vector's dimensions into) to use. +This value must a divisor of the number of dimensions in the vector. +For example, if your vector has 99 dimensions you can only use the values 3, 9, 11, 33, and 99 for the subquantizers. +Using any other value returns an error. + +* The number of bits in the centroid's index value. +This value sets the number centroids to find in each subspace. +For example, setting this value to 8 has PQ store the index for the centroids in a byte. +This results in SQ using 256 centroids per subspace. ++ +The number of centroids you set using this value must be less than the number of vectors in the dataset. +For example, if you choose 32 for the centroid index size, your dataset must have at least 4,294,967,296 vectors in it. + +The larger you set either of these values, the more accurate the index's search results are. +The trade-off is that your index is larger, as it has to store data for more centroids. +A smaller value results in a smaller index that returns less accurate results. + +The format for the PQ settings is: + +[source,sqlpp] +---- +PQx +---- + +For example, `PQ32x8` has PQ break the vector's dimensions into 32 subspaces, each of which has 256 centroids. + +=== Algorithm Settings Examples + +The following table shows several `description` values along with an explanation. + +[%autowidth] +|=== +| Setting | Effect + +| `IVF,SQ8` +| Couchbase {product-name} chooses the number of centroids the IVF algorithm uses. +The index uses Scalar Quantization with an 8-bit index, meaning each dimension of the vector is broken into 256 bins. + +| `IVF1024,PQ8x8` +| IVF uses 1024 centroids to divide the dataset. +The index uses Product Quantization. +PQ breaks the vector space into 8 subspaces, each of which uses 8-bits to represent centroids in the subspace. +This settings means each subspace has 256 centroids. + +|=== diff --git a/modules/vector-index/partials/nav.adoc b/modules/vector-index/partials/nav.adoc index 59eeb3464..0fdfcbcdd 100644 --- a/modules/vector-index/partials/nav.adoc +++ b/modules/vector-index/partials/nav.adoc @@ -2,6 +2,7 @@ + -- ** xref:7.7@server:vector-index:vectors-and-indexes-overview.adoc[] +** xref:7.7@server:vector-index:vector-index.adoc[] ** xref:7.7@server:vector-index:gsi-with-vector.adoc[] -- + From b74ae0b3463809e8a91158f4b6e5f27b5cdeee7e Mon Sep 17 00:00:00 2001 From: Gary Gray <137797428+ggray-cb@users.noreply.github.com> Date: Tue, 4 Mar 2025 16:46:43 -0500 Subject: [PATCH 21/41] Added cross-ref to new Vector index topic --- modules/vector-index/pages/use-vector-indexes.adoc | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/vector-index/pages/use-vector-indexes.adoc b/modules/vector-index/pages/use-vector-indexes.adoc index 9945306c5..e32c4a33e 100644 --- a/modules/vector-index/pages/use-vector-indexes.adoc +++ b/modules/vector-index/pages/use-vector-indexes.adoc @@ -69,6 +69,7 @@ They can index billions of documents. Most of the Vector Index resides in a highly optimized format on disk. Use this type of index when you want to primarily query vector values with a low memory footprint. This index offers high accuracy even for vectors with a large number of dimensions. +See xref:vector-index.adoc[] for more information. * Global Secondary Indexes (GSI) can have a single vector column. Adding a vector to a GSI lets you perform a hybrid search combining a single vector value with standard scalar attributes that are also indexed in the GSI. From 7767a0cc350bdbefb79244816496a26ce2954a94 Mon Sep 17 00:00:00 2001 From: Gary Gray <137797428+ggray-cb@users.noreply.github.com> Date: Mon, 7 Apr 2025 14:35:44 -0400 Subject: [PATCH 22/41] Checking in update to antora.yml so branch acts like it's 8.0 --- antora.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/antora.yml b/antora.yml index c922ead3a..1bde64866 100644 --- a/antora.yml +++ b/antora.yml @@ -1,5 +1,5 @@ name: server -version: '7.7' +version: '8.0' asciidoc: attributes: ui-name: Server Web Console From 1c34c78abefe5d175dd9951bf3eaff0ba533f3a1 Mon Sep 17 00:00:00 2001 From: Gary Gray <137797428+ggray-cb@users.noreply.github.com> Date: Tue, 27 May 2025 11:09:44 -0400 Subject: [PATCH 23/41] Minor fixes --- .../vector-index/pages/vectors-and-indexes-overview.adoc | 4 ++-- modules/vector-index/partials/nav.adoc | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/modules/vector-index/pages/vectors-and-indexes-overview.adoc b/modules/vector-index/pages/vectors-and-indexes-overview.adoc index c20d2b217..d955542d4 100644 --- a/modules/vector-index/pages/vectors-and-indexes-overview.adoc +++ b/modules/vector-index/pages/vectors-and-indexes-overview.adoc @@ -310,8 +310,8 @@ Indexes using the SQ indexing algorithm can return inaccurate results if the ran If one or more dimensional values fall outside the range that SQ assign buckets to, they get assigned closest bucket. These inaccuracies can build over time, skewing results,. -To resolve these accuracy issues, can retrain your indexes when you notice poor results. -You can retrain indexes periodically, or after you have made significant changes to your dataset. +To resolve these accuracy issues, you can retrain your indexes when you notice poor results. +You can also choose to retrain indexes periodically or after you have made significant changes to your dataset. You should consider the need to retrain your indexes when choosing which index algorithm to use. For example, the PQ algorithm requires more resources to train than the SQ algorithm. diff --git a/modules/vector-index/partials/nav.adoc b/modules/vector-index/partials/nav.adoc index 0fdfcbcdd..7e008a2ba 100644 --- a/modules/vector-index/partials/nav.adoc +++ b/modules/vector-index/partials/nav.adoc @@ -1,9 +1,9 @@ -* xref:7.7@server:vector-index:use-vector-indexes.adoc[] +* xref:server:vector-index:use-vector-indexes.adoc[] + -- -** xref:7.7@server:vector-index:vectors-and-indexes-overview.adoc[] -** xref:7.7@server:vector-index:vector-index.adoc[] -** xref:7.7@server:vector-index:gsi-with-vector.adoc[] +** xref:server:vector-index:vectors-and-indexes-overview.adoc[] +** xref:server:vector-index:vector-index.adoc[] +** xref:server:vector-index:gsi-with-vector.adoc[] -- + -- From 77ffce21aa56e603d5c5a88f63042a56fd1ce186 Mon Sep 17 00:00:00 2001 From: Gary Gray <137797428+ggray-cb@users.noreply.github.com> Date: Fri, 30 May 2025 17:13:05 -0400 Subject: [PATCH 24/41] Fixing nav issue --- modules/search/partials/nav.adoc | 120 ++++++++++++------------ modules/vector-search/partials/nav.adoc | 12 +-- 2 files changed, 66 insertions(+), 66 deletions(-) diff --git a/modules/search/partials/nav.adoc b/modules/search/partials/nav.adoc index 709190d5b..90c9cc38c 100644 --- a/modules/search/partials/nav.adoc +++ b/modules/search/partials/nav.adoc @@ -1,60 +1,60 @@ -* xref:7.7@server:search:search.adoc[] - ** xref:7.7@server:search:create-search-indexes.adoc[] - *** xref:7.7@server:search:create-search-index-ui.adoc[] - *** xref:7.7@server:search:create-search-index-rest-api.adoc[] - **** xref:7.7@server:search:search-index-params.adoc[] - *** xref:7.7@server:search:create-quick-index.adoc[] - **** xref:7.7@server:search:quick-index-field-options.adoc[] - **** xref:7.7@server:search:field-data-types-reference.adoc[] - **** xref:7.7@server:search:quick-index-supported-languages.adoc[] - *** xref:7.7@server:search:import-search-index.adoc[] - ** xref:7.7@server:search:view-index-details.adoc[] - ** xref:7.7@server:search:run-searches.adoc[] - *** xref:7.7@server:search:simple-search-ui.adoc[] - *** xref:7.7@server:search:geo-search-ui.adoc[] - *** xref:7.7@server:search:simple-search-rest-api.adoc[] - **** xref:7.7@server:search:search-request-params.adoc[] - **** xref:7.7@server:fts:fts-search-response.adoc[Search Response] - *** xref:7.7@server:search:geo-search-rest-api.adoc[] - ** xref:7.7@server:search:search-query-auto-complete.adoc[] - *** xref:7.7@server:search:search-query-auto-complete-ui.adoc[] - *** xref:7.7@server:search:search-query-auto-complete-code.adoc[] - ** xref:7.7@server:search:index-aliases.adoc[] - *** xref:7.7@server:search:create-search-index-alias.adoc[] - ** xref:7.7@server:search:customize-index.adoc[] - *** xref:7.7@server:search:set-type-identifier.adoc[] - *** xref:7.7@server:search:create-type-mapping.adoc[] - *** xref:7.7@server:search:create-child-field.adoc[] - **** xref:7.7@server:search:child-field-options-reference.adoc[] - *** xref:7.7@server:search:create-child-mapping.adoc[] - *** xref:7.7@server:search:create-xattrs-mapping.adoc[] - *** xref:7.7@server:search:create-custom-analyzer.adoc[] - *** xref:7.7@server:search:create-custom-character-filter.adoc[] - *** xref:7.7@server:search:create-custom-tokenizer.adoc[] - *** xref:7.7@server:search:create-custom-token-filter.adoc[] - *** xref:7.7@server:search:create-custom-wordlist.adoc[] - *** xref:7.7@server:search:create-custom-date-time-parser.adoc[] - *** xref:7.7@server:search:set-advanced-settings.adoc[] - *** xref:7.7@server:search:default-analyzers-reference.adoc[] - *** xref:7.7@server:search:default-character-filters-reference.adoc[] - *** xref:7.7@server:search:default-token-filters-reference.adoc[] - *** xref:7.7@server:search:default-tokenizers-reference.adoc[] - *** xref:7.7@server:search:default-wordlists-reference.adoc[] - *** xref:7.7@server:search:field-data-types-reference.adoc[] - ** xref:7.7@server:fts:fts-high-availability-for-search.adoc[High Availability for Search] - ** xref:7.7@server:fts:fts-architecture.adoc[Search Service Architecture] - *** xref:7.7@server:fts:fts-architecture-scatter-gather.adoc[Scatter Gather] - *** xref:7.7@server:fts:fts-architecture-ports-used.adoc[Ports Used By FTS] - *** xref:7.7@server:fts:fts-rebalance-failover.adoc[Rebalance/Failover] - ** xref:7.7@server:fts:fts-cluster-options.adoc[Cluster Level Options] - *** xref:7.7@server:fts:fts-advanced-settings-bleveMaxResultWindow.adoc[bleveMaxResultWindow] - *** xref:7.7@server:fts:fts-advanced-settings-bleveMaxClauseCount.adoc[bleveMaxClauseCount] - *** xref:7.7@server:fts:fts-advanced-settings-maxFeedsPerDCPAgent.adoc[maxFeedsPerDCPAgent] - *** xref:7.7@server:fts:fts-advance-settings-maxConcurrentPartitionMovesPerNode.adoc[maxConcurrentPartitionMovesPerNode] - *** xref:7.7@server:fts:fts-advanced-settings-enableVerboseLogging.adoc[enableVerboseLogging] - *** xref:7.7@server:fts:fts-advanced-settings-ftsMemoryQuota.adoc[ftsMemoryQuota] - *** xref:7.7@server:fts:fts-advanced-settings-maxReplicasAllowed.adoc[maxReplicasAllowed] - *** xref:7.7@server:fts:fts-advanced-settings-slowQueryLogTimeout.adoc[slowQueryLogTimeout] - *** xref:7.7@server:fts:fts-advanced-settings-CBFT-ENV-OPTIONS.adoc[CBFT_ENV_OPTIONS] - ** xref:7.7@server:fts:fts-monitor.adoc[Statistics and Monitoring] - ** xref:7.7@server:fts:fts-troubleshooting.adoc[Troubleshooting and FAQs] \ No newline at end of file +* xref:search:search.adoc[] + ** xref:search:create-search-indexes.adoc[] + *** xref:search:create-search-index-ui.adoc[] + *** xref:search:create-search-index-rest-api.adoc[] + **** xref:search:search-index-params.adoc[] + *** xref:search:create-quick-index.adoc[] + **** xref:search:quick-index-field-options.adoc[] + **** xref:search:field-data-types-reference.adoc[] + **** xref:search:quick-index-supported-languages.adoc[] + *** xref:search:import-search-index.adoc[] + ** xref:search:view-index-details.adoc[] + ** xref:search:run-searches.adoc[] + *** xref:search:simple-search-ui.adoc[] + *** xref:search:geo-search-ui.adoc[] + *** xref:search:simple-search-rest-api.adoc[] + **** xref:search:search-request-params.adoc[] + **** xref:fts:fts-search-response.adoc[Search Response] + *** xref:search:geo-search-rest-api.adoc[] + ** xref:search:search-query-auto-complete.adoc[] + *** xref:search:search-query-auto-complete-ui.adoc[] + *** xref:search:search-query-auto-complete-code.adoc[] + ** xref:search:index-aliases.adoc[] + *** xref:search:create-search-index-alias.adoc[] + ** xref:search:customize-index.adoc[] + *** xref:search:set-type-identifier.adoc[] + *** xref:search:create-type-mapping.adoc[] + *** xref:search:create-child-field.adoc[] + **** xref:search:child-field-options-reference.adoc[] + *** xref:search:create-child-mapping.adoc[] + *** xref:search:create-xattrs-mapping.adoc[] + *** xref:search:create-custom-analyzer.adoc[] + *** xref:search:create-custom-character-filter.adoc[] + *** xref:search:create-custom-tokenizer.adoc[] + *** xref:search:create-custom-token-filter.adoc[] + *** xref:search:create-custom-wordlist.adoc[] + *** xref:search:create-custom-date-time-parser.adoc[] + *** xref:search:set-advanced-settings.adoc[] + *** xref:search:default-analyzers-reference.adoc[] + *** xref:search:default-character-filters-reference.adoc[] + *** xref:search:default-token-filters-reference.adoc[] + *** xref:search:default-tokenizers-reference.adoc[] + *** xref:search:default-wordlists-reference.adoc[] + *** xref:search:field-data-types-reference.adoc[] + ** xref:fts:fts-high-availability-for-search.adoc[High Availability for Search] + ** xref:fts:fts-architecture.adoc[Search Service Architecture] + *** xref:fts:fts-architecture-scatter-gather.adoc[Scatter Gather] + *** xref:fts:fts-architecture-ports-used.adoc[Ports Used By FTS] + *** xref:fts:fts-rebalance-failover.adoc[Rebalance/Failover] + ** xref:fts:fts-cluster-options.adoc[Cluster Level Options] + *** xref:fts:fts-advanced-settings-bleveMaxResultWindow.adoc[bleveMaxResultWindow] + *** xref:fts:fts-advanced-settings-bleveMaxClauseCount.adoc[bleveMaxClauseCount] + *** xref:fts:fts-advanced-settings-maxFeedsPerDCPAgent.adoc[maxFeedsPerDCPAgent] + *** xref:fts:fts-advance-settings-maxConcurrentPartitionMovesPerNode.adoc[maxConcurrentPartitionMovesPerNode] + *** xref:fts:fts-advanced-settings-enableVerboseLogging.adoc[enableVerboseLogging] + *** xref:fts:fts-advanced-settings-ftsMemoryQuota.adoc[ftsMemoryQuota] + *** xref:fts:fts-advanced-settings-maxReplicasAllowed.adoc[maxReplicasAllowed] + *** xref:fts:fts-advanced-settings-slowQueryLogTimeout.adoc[slowQueryLogTimeout] + *** xref:fts:fts-advanced-settings-CBFT-ENV-OPTIONS.adoc[CBFT_ENV_OPTIONS] + ** xref:fts:fts-monitor.adoc[Statistics and Monitoring] + ** xref:fts:fts-troubleshooting.adoc[Troubleshooting and FAQs] \ No newline at end of file diff --git a/modules/vector-search/partials/nav.adoc b/modules/vector-search/partials/nav.adoc index d74856752..f823d0829 100644 --- a/modules/vector-search/partials/nav.adoc +++ b/modules/vector-search/partials/nav.adoc @@ -1,6 +1,6 @@ -* xref:7.7@server:vector-search:vector-search.adoc[] -** xref:7.7@server:vector-search:create-vector-search-index-ui.adoc[] -** xref:7.7@server:vector-search:create-vector-search-index-rest-api.adoc[] -** xref:7.7@server:vector-search:run-vector-search-ui.adoc[] -** xref:7.7@server:vector-search:run-vector-search-rest-api.adoc[] -** xref:7.7@server:vector-search:run-vector-search-sdk.adoc[] \ No newline at end of file +* xref:vector-search:vector-search.adoc[] +** xref:vector-search:create-vector-search-index-ui.adoc[] +** xref:vector-search:create-vector-search-index-rest-api.adoc[] +** xref:vector-search:run-vector-search-ui.adoc[] +** xref:vector-search:run-vector-search-rest-api.adoc[] +** xref:vector-search:run-vector-search-sdk.adoc[] \ No newline at end of file From 863b417c155baf0a8c5c19b3d0d9698931c863d2 Mon Sep 17 00:00:00 2001 From: Gary Gray <137797428+ggray-cb@users.noreply.github.com> Date: Mon, 2 Jun 2025 10:01:01 -0400 Subject: [PATCH 25/41] Grammar edits. --- .../pages/vectors-and-indexes-overview.adoc | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/modules/vector-index/pages/vectors-and-indexes-overview.adoc b/modules/vector-index/pages/vectors-and-indexes-overview.adoc index d955542d4..75c77fd6f 100644 --- a/modules/vector-index/pages/vectors-and-indexes-overview.adoc +++ b/modules/vector-index/pages/vectors-and-indexes-overview.adoc @@ -169,12 +169,13 @@ Couchbase Server supports two formats for the index, which controls how the inde Flat Index:: This algorithm just stores the full vector value in the index without performing any sort of optimization. Searches using this index use a brute-force method to find similar vectors. -Adding new vectors to a flat index is fast, and the index does not need training. -It also offers high precision, because search compares the full vector values. -However, searching a flat index is inefficient, because the search must compare every vector in the index to find matchers. +Adding new vectors to a flat index is fast and the index does not need training. +It also offers high precision because search compares the full vector values. +However, searching a flat index is inefficient. +The search must compare every vector in the index to find matches. You should only use it for small data sets or for testing. + -NOTE: Only Search Indexes support using a flat index. +NOTE: Only Search indexes support using a flat index. Vector indexes and GSI with a vector field only support the next algorithm, IVF. [#IVF] @@ -188,12 +189,12 @@ An IVF index trains itself during creation using a set of parameters you pass to + image::ivf-diagram-with-vectors.svg["A plot showing clusters of points in a 3D graph being labelled and assigned centroid vectors. The centroids them point to multiple vectors."] + -When you search an IVF index, it first locates the centroids that are most relevant to the vector value you're searching for. -It then searches just the vectors associated to those centroids in the inverted list. +When you search using an IVF index, it first locates the centroids that are most relevant to the vector value you're searching for. +It then searches just the vectors associated with those centroids in the inverted list. By limiting the number of vector comparisons to just the vectors close to the relevant centroids, IVF makes vector search faster. + A drawback of this method is the possibility that the search could miss some relevant vectors. -Vectors can be missed if they're associated with a centroid that's not relevant to the search vector. +A search can miss vectors if they're associated with a centroid that's not relevant to the search vector. This risk increases as you add and delete data after you train the index. The centroids chosen during the initial training may no longer accurately represent clusters in current dataset. See <<#index-training>> for more information about index accuracy. From 2e3623e8838f9fc7c5a2407178c84d750e57b18f Mon Sep 17 00:00:00 2001 From: Gary Gray <137797428+ggray-cb@users.noreply.github.com> Date: Wed, 11 Jun 2025 13:17:46 -0400 Subject: [PATCH 26/41] Added local build config --- .../pages/vectors-and-indexes-overview.adoc | 8 +++---- .../partials/index-algorithm-settings.adoc | 23 +++++++++++-------- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/modules/vector-index/pages/vectors-and-indexes-overview.adoc b/modules/vector-index/pages/vectors-and-indexes-overview.adoc index 75c77fd6f..9fc720947 100644 --- a/modules/vector-index/pages/vectors-and-indexes-overview.adoc +++ b/modules/vector-index/pages/vectors-and-indexes-overview.adoc @@ -231,7 +231,7 @@ The codebook assigns each centroid an index number. image::pq-diagram.svg["Three-dimensional plot showing two vectors that are of equal length, with the angle between them labeled as theta."] + PQ could quantize the vector in the previous example from 1024 64-bit floating point values to 128 8 bit or 16 bit integer values. -This data size reduction improves performance because integer operations are less intensive than floating point operations. +This data size reduction improves performance because integer operations are less computationally expensive than floating point operations. It also reduces memory use because each vector requires less data to store (for example, from 64KB to 128 bytes). + You often use PQ in addition to IVF--after quantization, the training process finds centroids in the dataset. @@ -274,8 +274,8 @@ This quantization reduces the dimensions from 32 or 64 bit floating point values It also makes search faster because integer operations are computationally less expensive than floating point operations. + A search on an SQ index reassembles vectors before comparing them. -For each of the vector's dimensions, the integer bin number is replaced with the floating point centroid associated with the bin. -This recreation is an approximation of the original vector, because each dimension in the vector is the bin's centroid value rather than the original dimensional value. +For each of the vector's dimensions, SQ replaces the the integer bin number with the floating point centroid associated with the bin. +This recreation is an approximation of the original vector, because each dimension in the vector is the bin's centroid value instead of the original dimensional value. + Like the PQ algorithm, you often combine SQ and IVF. This combination limits the number of vectors that a search has to compare and reduces its memory and processing requirements. @@ -316,4 +316,4 @@ You can also choose to retrain indexes periodically or after you have made signi You should consider the need to retrain your indexes when choosing which index algorithm to use. For example, the PQ algorithm requires more resources to train than the SQ algorithm. -If your dataset evolves rapidly, you may want avoid using PQ because you'll need to perform more frequent retraining. \ No newline at end of file +If your dataset evolves rapidly, you may want avoid using PQ because you'll need to perform more frequent retraining. diff --git a/modules/vector-index/partials/index-algorithm-settings.adoc b/modules/vector-index/partials/index-algorithm-settings.adoc index afe55d0c0..fe1b985f3 100644 --- a/modules/vector-index/partials/index-algorithm-settings.adoc +++ b/modules/vector-index/partials/index-algorithm-settings.adoc @@ -16,17 +16,17 @@ The following sections describe the settings for centroids and quantization. === Number of Centroids -{index-name-plural} always use the xref:vector-index:use-vector-indexes.adoc#IVF[Inverted File (IVF)] algorithm to subdivides the dataset. -Using this algorithm reduces the number of vector comparisons a vector search of the index must perform. +{index-name-plural} always use the xref:vector-index:use-vector-indexes.adoc#IVF[Inverted File (IVF)] algorithm to subdivide the dataset. +Using this algorithm reduces the number of vector comparisons a vector search of the index performs. The key setting for IVF is the number of centroids it allocates for the index. -The number of centroids affects the performance of your index in two ways: +This number affects the performance of your index in two ways: * If the index has fewer centroids, each centroid has more vectors associated with it. -In this case, a vector search has to perform more comparisons which makes the search slower. -Having fewer centroids decreases the processing overhead for training the index. +In this case, a vector search has to perform more comparisons, making the search slower. +However, having fewer centroids decreases the processing required to training the index. * A greater number of centroids results in a greater processing cost for training. -This increase is due to the training process having to search for more data cluster to identify more centroids. +This increase is due to the training process having to search for more data cluster to identify more centroids. However, it reduces the number of vectors associated with each centroid. This reduction makes search faster by limiting the number of vector comparisons during a search. @@ -47,7 +47,6 @@ You must choose whether the index uses xref:vector-index:use-vector-indexes.adoc You select the quantization by adding a comma followed by either `PQ` or `SQ` to the `description` parameter after the IVF setting in the `description` value. - Each quantization method has additional settings explained in the following sections. ==== SQ Settings @@ -75,13 +74,15 @@ This cuts the memory used to store the centroids in half. |=== +See xref:vector-index:vectors-and-indexes-overview.adoc#sq[Scalar Quantization] for more information about how SQ works. + ==== PQ Settings If you choose to use PQ in your index, you must set two values: -* The number of subquantizers (number of subspaces SQ splits the vector's dimensions into) to use. -This value must a divisor of the number of dimensions in the vector. -For example, if your vector has 99 dimensions you can only use the values 3, 9, 11, 33, and 99 for the subquantizers. +* The number of subquantizers (number of subspaces PQ splits the vector's dimensions into) to use. +This value must be a divisor of the number of dimensions in the vector. +For example, if your vector has 99 dimensions, you can only use the values 3, 9, 11, 33, and 99 for the subquantizers. Using any other value returns an error. * The number of bits in the centroid's index value. @@ -124,3 +125,5 @@ PQ breaks the vector space into 8 subspaces, each of which uses 8-bits to repres This settings means each subspace has 256 centroids. |=== + +See xref:vector-index:vectors-and-indexes-overview.adoc#pq[Product Quantization ] for more information about how PQ works. \ No newline at end of file From c8b193e913262b884ccba5a42f3a30e438a57950 Mon Sep 17 00:00:00 2001 From: Gary Gray <137797428+ggray-cb@users.noreply.github.com> Date: Wed, 25 Jun 2025 15:44:51 -0400 Subject: [PATCH 27/41] Rough draft of the Hypervector demo done. --- .../examples/hyperscale-idx-data.json | 100 ++++++ .../examples/hyperscale-idx-examples.sqlpp | 77 +++++ ...ector.adoc => composite-vector-index.adoc} | 49 ++- .../pages/hyperscale-vector-index.adoc | 293 ++++++++++++++++++ .../pages/use-vector-indexes.adoc | 246 ++++++++++++--- modules/vector-index/pages/vector-index.adoc | 166 ---------- .../pages/vectors-and-indexes-overview.adoc | 39 ++- .../composite-vector-app-workflow.puml | 82 +++++ .../partials/fts-vector-app-workflow.puml | 74 +++++ .../hyperscale-vector-app-workflow.puml | 82 +++++ modules/vector-index/partials/nav.adoc | 8 +- 11 files changed, 962 insertions(+), 254 deletions(-) create mode 100644 modules/vector-index/examples/hyperscale-idx-data.json create mode 100644 modules/vector-index/examples/hyperscale-idx-examples.sqlpp rename modules/vector-index/pages/{gsi-with-vector.adoc => composite-vector-index.adoc} (88%) create mode 100644 modules/vector-index/pages/hyperscale-vector-index.adoc delete mode 100644 modules/vector-index/pages/vector-index.adoc create mode 100644 modules/vector-index/partials/composite-vector-app-workflow.puml create mode 100644 modules/vector-index/partials/fts-vector-app-workflow.puml create mode 100644 modules/vector-index/partials/hyperscale-vector-app-workflow.puml diff --git a/modules/vector-index/examples/hyperscale-idx-data.json b/modules/vector-index/examples/hyperscale-idx-data.json new file mode 100644 index 000000000..077aac99f --- /dev/null +++ b/modules/vector-index/examples/hyperscale-idx-data.json @@ -0,0 +1,100 @@ +// tag::query-rgb-questions-output[] +[{ + "id": "#87CEEB", + "question": "What is the color that is often linked to feelings of peace and tranquility, and is reminiscent of the clear sky on a calm day?", + "wanted_similar_color_from_search": "sky blue", + "vector": [ + 0.024399276822805405, + -0.006973916664719582, + 0.025191623717546463, + -0.02188388630747795, + "..." + ] +}] +// end::query-rgb-questions-output[] + + +// tag::rgb-document[] +[{ + "id": "#87CEEB", + "color": "sky blue", + "brightness": 188.077, + "description": "Sky blue is a calming and serene color that evokes feelings of tranquility. It is a light shade of blue that resembles the color of the sky on a clear day. The color is often associated with peace, relaxation, and a sense of openness. It can also represent a sense of freedom and endless possibilities, as the sky seems to stretch on forever. Sky blue is a refreshing and soothing color that can bring a sense of calmness to any space.", + "vector": [ + 0.015966663137078285, + 0.018097303807735443, + -0.005783640779554844, + -0.020661966875195503, + "..." + ] +}] +// end::rgb-document[] + +// tag::query-rgb-color[] +[{ + "color": "deep sky blue", + "description": "Deep sky blue is a calming and refreshing color that evokes feelings + of tranquility and peace. It is a shade of blue that resembles the clear, open sky + on a sunny day. This color is often associated with serenity and relaxation, making + it a popular choice for interior design and clothing. Its cool and calming nature + makes it a perfect color for creating a peaceful and serene atmosphere.", + "wanted_similar_color_from_search": "sky blue" + }, + { + "color": "sky blue", + "description": "Sky blue is a calming and serene color that evokes feelings of + tranquility. It is a light shade of blue that resembles the color of the sky on a + clear day. The color is often associated with peace, relaxation, and a sense of + openness. It can also represent a sense of freedom and endless possibilities, as + the sky seems to stretch on forever. Sky blue is a refreshing and soothing color that + can bring a sense of calmness to any space.", + "wanted_similar_color_from_search": "sky blue" + }, + { + "color": "light sky blue", + "description": "Light sky blue is a soft and delicate color that evokes a sense of + tranquility and peace. It is a shade of blue that is reminiscent of a clear, sunny day + with a few fluffy clouds scattered across the sky. This color is often associated with + feelings of serenity and relaxation, making it a popular choice for bedrooms and spa-like + environments. The lightness of this shade adds a touch of freshness and purity, making it + a perfect color for creating a calming and inviting atmosphere.", + "wanted_similar_color_from_search": "sky blue" + } +] +// end::query-rgb-color[] + + +// tag::query-rgb-brightness[] +[{ + "color": "light sky blue", + "description": "Light sky blue is a soft and delicate color that evokes a sense of + tranquility and peace. It is a shade of blue that is reminiscent of a clear, sunny + day with a few fluffy clouds scattered across the sky. This color is often associated + with feelings of serenity and relaxation, making it a popular choice for bedrooms and + spa-like environments. The lightness of this shade adds a touch of freshness and purity, + making it a perfect color for creating a calming and inviting atmosphere.", + "brightness": 189.787, + "wanted_similar_color_from_search": "sky blue" + }, + { + "color": "pale turquoise", + "description": "Pale turquoise is a delicate and soothing color that can be described + as a soft blend of blue and green. It has a calming effect and can evoke feelings of + tranquility and serenity. The color is often associated with the ocean and can bring + to mind images of clear, tropical waters. It has a gentle and subtle quality, making + it a popular choice for creating a peaceful and serene atmosphere.", + "brightness": 219.163, + "wanted_similar_color_from_search": "sky blue" + }, + { + "color": "light cyan", + "description": "Light cyan is a soft and calming color that evokes feelings of + tranquility and serenity. It is a refreshing hue that brings a sense of peace and + relaxation. With its cool undertones, light cyan is often associated with water and the + sky, creating a sense of openness and spaciousness. This color is perfect for creating + a peaceful and serene atmosphere in any space.", + "brightness": 245.731, + "wanted_similar_color_from_search": "sky blue" + } +] +// end::query-rgb-brightness[] diff --git a/modules/vector-index/examples/hyperscale-idx-examples.sqlpp b/modules/vector-index/examples/hyperscale-idx-examples.sqlpp new file mode 100644 index 000000000..815f707da --- /dev/null +++ b/modules/vector-index/examples/hyperscale-idx-examples.sqlpp @@ -0,0 +1,77 @@ +/* tag::create-rgb-idx[] */ +CREATE VECTOR INDEX `color_desc_hyperscale` + ON `vector-sample`.`color`.`rgb`(`embedding_vector_dot` VECTOR) + WITH { "dimension":1536, "similarity":"L2", "description":"IVF8,SQ4" } +/* end::create-rgb-idx[] */ + +/* tag::rgb-entry[] */ +SELECT + d.id, + d.color, + d.brightness, + d.description, + ARRAY_CONCAT( + d.embedding_vector_dot[0:4], + ["..."] + ) AS vector +FROM `vector-sample`.`color`.`rgb` AS d +WHERE d.id = "#87CEEB"; +/* end::rgb-entry[] */ + + +/* tag::query-rgb-questions[] */ +SELECT + d.id, + d.question, + d.wanted_similar_color_from_search, + ARRAY_CONCAT( + d.couchbase_search_query.knn[0].vector[0:4], + ["..."] + ) AS vector +FROM `vector-sample`.`color`.`rgb-questions` AS d +WHERE d.id = "#87CEEB"; +/* end::query-rgb-questions[] */ + +/* tag::query-rgb-with-subquery[] */ +WITH question_vec AS ( + SELECT RAW couchbase_search_query.knn[0].vector + FROM `vector-sample`.`color`.`rgb-questions` + WHERE meta().id = "#87CEEB"), + question_answer AS ( + SELECT wanted_similar_color_from_search + FROM `vector-sample`.`color`.`rgb-questions` + WHERE meta().id = "#87CEEB") +SELECT b.color, b.description, q.wanted_similar_color_from_search + FROM `vector-sample`.`color`.`rgb` AS b, question_answer as q + ORDER BY APPROX_VECTOR_DISTANCE(b.embedding_vector_dot, + question_vec[0], "l2", 4) LIMIT 3; +/* end::query-rgb-with-subquery[] */ + +/* tag::create-idx-brightness[] */ +CREATE VECTOR INDEX `color_desc_hyperscale_brightness` + ON `vector-sample`.`color`.`rgb`(`embedding_vector_dot` VECTOR) + INCLUDE (`brightness`) + WITH { "dimension":1536, "similarity":"L2", "description":"IVF8,SQ4" } +/* end::create-idx-brightness[] */ + +/* tag::query-rgb-with-brightness[] */ +WITH question_vec AS ( + SELECT RAW couchbase_search_query.knn[0].vector + FROM `vector-sample`.`color`.`rgb-questions` + WHERE meta().id = "#87CEEB"), + question_answer AS ( + SELECT wanted_similar_color_from_search + FROM `vector-sample`.`color`.`rgb-questions` + WHERE meta().id = "#87CEEB") +SELECT b.color, b.description, b.brightness, q.wanted_similar_color_from_search + FROM `vector-sample`.`color`.`rgb` AS b, question_answer as q + WHERE b.brightness > 170.0 + ORDER BY APPROX_VECTOR_DISTANCE(b.embedding_vector_dot, + question_vec[0], "l2", 4) LIMIT 3; +/* end::query-rgb-with-brightness[] */ + +/* tag::create-rgb-no-persist[] */ +CREATE VECTOR INDEX `color_desc_hyperscale_no_persist` + ON `vector-sample`.`color`.`rgb`(`embedding_vector_dot` VECTOR) + WITH { "dimension":1536, "similarity":"L2", "description":"IVF8,SQ4", "persist_full_vector": false}; +/* end::create-rgb-no-persist[] */ diff --git a/modules/vector-index/pages/gsi-with-vector.adoc b/modules/vector-index/pages/composite-vector-index.adoc similarity index 88% rename from modules/vector-index/pages/gsi-with-vector.adoc rename to modules/vector-index/pages/composite-vector-index.adoc index 77db54182..e8d384760 100644 --- a/modules/vector-index/pages/gsi-with-vector.adoc +++ b/modules/vector-index/pages/composite-vector-index.adoc @@ -2,27 +2,25 @@ :page-topic-type: guide :page-ui-name: {ui-name} :page-product-name: {product-name} -:description: You can extend a Couchbase {product-name}'s Global Secondary Index (GSI) with a single vector column to enable hybrid queries to find semantically-related content. +:description: A Composite Vector Index is a Global Secondary Index (GSI) with a single vector column that enables hybrid queries to find semantically-related content. :stem: :page-toclevels: 3 -:index-name: GSI index with a vector column -:index-name-plural: GSI indexes with a vector column +:index-name: Composite Vector Index +:index-name-plural: Composite Vector Indexes {description} - The added vector column lets your application perform a hybrid query using both the index's scalar, array, and object index entries plus a vector value. See xref:learn:services-and-indexes/indexes/indexes.adoc[] for an overview of GSI and other indexes. -== How the GSI's Vector Column Works +== How the Composite Vector Index's Vector Column Works -You can add a single vector column to a GSI to enable semantic and similarity searches within your {sqlpp} queries. +A Composite Vector Index has a single vector column that enables semantic and similarity searches within your {sqlpp} queries. When creating the index, you use a `VECTOR` key attribute to designate the field that contains the embedded vectors. When your query contains an embedded vector, the Query Service uses any non-vector predicates in the query to filter index entries. Then it performs an index scan on the remaining index entries, using the similarity function you specify in the query to locate similar vectors. This behavior reduces the number of vector similarity comparisons the Query Service must do to find similar vectors. - == Prerequisites * You must have the Index Service enabled on at least one node in your cluster. @@ -34,7 +32,7 @@ For more information about how to create a bucket, see xref:manage:manage-bucket * Your account must have the xref:learn:security:roles.adoc#query-manage-index[Query Manage Index] role to be able to create an index. * You have documents in a collection that contain one or more vector embeddings. -You can add a single vector to a GSI index. +You can add a single vector to a Composite Vector Index. If your documents contain multiple embedded vectors, you can create multiple indexes---one for each vector attribute. + Embeddings can be an array of floating point numbers or a base64 encoded string. @@ -47,8 +45,8 @@ include::vector-search:partial$download-sample-partial.adoc[] -- * You must know the number of dimensions the vector contains. -The embedding model you use to embed the vectors may determine this value for you. -For example, OpenAI API's `text-embedding-ada-002` embedding model that embedded the sample data creates vectors that have 1536 dimensions. +The embedding model you use to embed the vectors may determine this value for you. +For example, OpenAI API's `text-embedding-ada-002` embedding model that embedded the sample data demonstrated later in this page creates vectors that have 1536 dimensions. * You must decide what algorithms you want your index to use. These algorithms affect how much memory and processing Couchbase {product-name} uses to train and search them. @@ -57,14 +55,14 @@ See xref:vector-index:vectors-and-indexes-overview.adoc#index-algorithms[Indexin include::partial$index-algorithm-settings.adoc[] -== Create a GSI with a Vector Column +== Create a Composite Vector Index -Creating a GSI with a vector column is similar to creating a non-vector GSI index. +Creating a Composite Vector Index is similar to creating a non-vector GSI index. See xref:guides:create-index.adoc[] for an overview of creating indexes. -In the `CREATE INDEX` statement to create the GSI, add the `VECTOR` lead key attribute after the vector's column name to declare it as an embedded vector. +In the `CREATE INDEX` statement to create the Composite Vector Index, add the `VECTOR` lead key attribute after the vector's column name to declare it as an embedded vector. You must also use the `WITH` clause to specify some additional information for the vector column. -The format for this clause with the most commonly-used parameters is: +The format for this clause with the most commonly used parameters is: [source,sqlpp] ---- @@ -91,7 +89,7 @@ For a full list of the parameters that affect a vector column in a GSI, see *FIX [#examples] === Examples -The following examples show you how to create two Global Secondary Indexes with a vector column using sample data. +The following examples show you how to create two Composite Vector Index with a vector column using sample data. They both use the data from the `color_data_2vectors.zip` file mentioned earlier. The data in `rgb.json` file looks like this: @@ -169,7 +167,7 @@ The result of running example is: ] ---- -==== Create a GSI Using the Embedded Vectors +==== Create a Composite Vector Index Using the Embedded Vectors The `embedding_vector_dot` attribute contains the embedded vectors for the text in the `description` attribute. The data sample shown in <<#examples>> truncated this attribute to several values. @@ -186,7 +184,6 @@ This example uses the Dot Product similarity function. This function works better with the embedded text content than the Euclidean function used in the previous example. It also uses the same algorithms as the previous example--Couchbase {product-name} chooses the number of centroids, and uses SQ quantization with 256 bins. - If successful, Couchbase {product-name} responds with: [source, json] @@ -203,11 +200,11 @@ If successful, Couchbase {product-name} responds with: After Couchbase {product-name} creates the index, it begins training it. Depending on your system, this training can take several seconds. -== Query with a GSI Vector Column +== Query with a Composite Vector Index Column -You query embedded vector attributes that you have indexed in a GSI to find similar vectors and therefore similar semantic content. -To find the most similar vectors, you use a `GROUP BY` clause in your query to return the most relevant vectors first. -In this clause, you call one of two functions that actually performs the vector comparisons: `APPROX_VECTOR_DISTANCE` or `VECTOR_DISTANCE`. +You query embedded vector attributes that you have indexed in a Composite Vector Index to find similar vectors and therefore similar semantic content. +To find the most similar vectors, use a `GROUP BY` clause in your query to return the most relevant vectors first. +In this clause, call one of two functions that actually performs the vector comparisons: `APPROX_VECTOR_DISTANCE` or `VECTOR_DISTANCE`. The first of these functions is faster, but less precise. The second is more precise, but slower. Which you choose depends on your use case. @@ -347,8 +344,8 @@ The result of running this query are: === Query the Embedded Vectors -To query the `color_desc_idx` GSI containing the embedded vector for the description attribute, you must supply a vector. -In a production environment, your application will call the same embedding model it called to generate the embedded vectors in your documents to generate a vector for the query value. +To query the `color_desc_idx` Composite Vector index containing the embedded vector for the description attribute, you must supply a vector. +In a production environment, your application calls the same embedding model it called to generate the embedded vectors in your documents to generate a vector for the query value. For this example, you can use embedded vectors in the `rgb_questions.json` file that's in the `color_data_2vectors.zip` file. This file contains a `question` attribute containing a search prompt for a particular color. @@ -400,7 +397,7 @@ It appears here with most of the 1536 vectors omitted: include::vector-index:example$gsi-vector-idx-examples.sqlpp[tag=query-vectors-idx-truncated] ---- -You can expand the following dropdown to see and copy the entire query with all the vectors: +You can expand the following section to see and copy the entire query with all the vectors: .Show full example [%collapsible] @@ -448,12 +445,12 @@ In either case, the results of the query are the same: ] ---- -The second result, the color "papaya whip," matches the `rgb_questions` collection's `wanted_similar_color_from_search` attribute. +The second result, the color papaya whip, matches the `rgb_questions` collection's `wanted_similar_color_from_search` attribute. === Adding a Scalar Using additional scalar fields in your search can improve your results and reduce the overhead of performing a vector search. -For example, filtering on an additional scalar field reuces the number of vectors an index scan has to compare. +For example, filtering on an additional scalar field reduces the number of vectors an index scan has to compare. Searching for scalar values requires less resources than vector searches. The example that created the `color_desc_idx` index added fields in addition to the `embedding_vector_dot` vector field. diff --git a/modules/vector-index/pages/hyperscale-vector-index.adoc b/modules/vector-index/pages/hyperscale-vector-index.adoc new file mode 100644 index 000000000..7403cf967 --- /dev/null +++ b/modules/vector-index/pages/hyperscale-vector-index.adoc @@ -0,0 +1,293 @@ += Vector Searches Using Hyperscale Vector Indexes +:page-topic-type: guide +:page-ui-name: {ui-name} +:page-product-name: {product-name} +:description: Hyperscale Vector Indexes are optimized to index a single vector column. They offer the highest performance of any index when it comes to vector data. +:stem: +:page-toclevels: 3 +:index-name: Hyperscale Vector index +:index-name-plural: Hyperscale Vector indexes + +{description} +They can scale up to a billion documents containing vectors with a large number of dimensions. + +Because they provide the best performance, consider testing a Hyperscale Vector index for your application before resorting to the other types of indexes. +If you find theirs performance does not meet your needs, then test using a Composite Vector Index or a FTS Vector Index. + + +== How the Hyperscale Vector Index Works + +The Hyperscale Vector Index primarily relies on data stored in an optimized format on disk. +By relying on disk storage, they have lower memory requirements than other index types. + +You add a single vector column to a Hyperscale Vector Index. +The vector value can be an array of floating point values. +You can nest the array in another array as long as you use an xref:n1ql:n1ql-language-reference/unnest.adoc[`UNNEST` clause] to extract the it from the containing array. +You can also store the vector in a BASE64 string. + +== Prerequisites + +Hyperscale Vector Indexes have the following requirements: + +* You must have the Index Service enabled on at least one node in your cluster. +For more information about how to deploy a new node and Services on your database, see xref:manage:manage-nodes/node-management-overview.adoc[]. + +* You must have a bucket with scopes and collections in your database. +For more information about how to create a bucket, see xref:manage:manage-buckets/create-bucket.adoc[]. + +* Your account must have the xref:learn:security:roles.adoc#query-manage-index[Query Manage Index] role, to be able to create an index. + +* You have documents in a collection that contain one or more vector embeddings. +You can add a single vector to a Hyperscale Vector Index. +If your documents contain multiple embedded vectors, you can create multiple indexes---one for each vector attribute. ++ +Embeddings can be an array of floating point numbers or a base64 encoded string. +Couchbase {product-name} does not embed vectors itself. +You must use an external embedding model to embed vectors into your data and add them to your documents. + +* The vectors you add to an index must contain the same number of dimensions. +Also the values in the vector must be 32-bit floating point numbers. +If a vector does not meet both of these requirements, the vector index treats it as a NULL value and the document is not added to the index. + +* You must know the number of dimensions the vector contains. +The embedding model you use to embed the vectors may determine this value for you. +For example, OpenAI API's `text-embedding-ada-002` embedding model creates vectors that have 1536 dimensions. + +* You must decide what algorithms you want your index to use. +These algorithms affect how much memory your index uses and the amount of processing Couchbase {product-name} must perform to train and search them. +See xref:vector-index:vectors-and-indexes-overview.adoc#index-algorithms[Indexing Algorithms] + +== Create a Hyperscale Vector Index +Use the `CREATE VECTOR INDEX` statement to create a Hyperscale Vector Index. +This statement is similar to the `CREATE INDEX` statement that you use to create Global Secondary Indexes (GSI). +See xref:guides:create-index.adoc[] for an overview of creating indexes. +You must also supply a `WITH` clause to set some additional information for the Hypsercale index needs about the vector column. + + +The syntax for the `CREATE VECTOR INDEX` with the most common parameters is: + +[source,sqlpp] +---- +CREATE VECTOR INDEX `` + ON ``(`` VECTOR) + WITH { "dimension": , + "similarity":, + "description": + }; +---- + +* `index-name` is a string that sets the name of the index. +* `collection` is the path of the collection to index. +* `key-name` is the name of the key containing the vector that you want to index. +The key value must be an array of floating point numbers or a base64 encoded string. +* `dimensions` is an integer value that sets the number of dimensions in the vector. +The embedded model you use to embed the vectors determines the number of dimensions in the vector. +* `similarity-function` is a string that sets the distance function to use when comparing vectors during index creation. +Couchbase {product-name} uses the following strings to represent the proximity functions: ++ +-- +** `COSINE`: xref:use-vector-indexes.adoc#cosine[Cosine Similarity] +** `DOT`: xref:use-vector-indexes.adoc#dot[Dot Product] +** `L2`, `L2_SQUARED`, `EUCLIDEAN`, or `EUCLIDEAN_SQUARED`: xref:use-vector-indexes.adoc#euclidean[Euclidean Distance] +-- ++ +For the greatest accuracy, use the distance function you plan to use to query the data. +* `algorithm-settings` is a string containing the settings for the indexing algorithms. +See <<#algo_settings>> in the next section for more information. + +include::partial$index-algorithm-settings.adoc[] + +For a full list of the parameters that affect a vector column in a GSI, see *FIXME:TDB*. + +[#examples] +=== Create Hyperscale Vector Index Examples + +The examples in this section use a dataset that contains information about colors, including a text description of the color. +There's also a field named `couchbase_search_query.knn.vector` that contains an embedded vector for the color description. + +include::vector-search:partial$download-sample-partial.adoc[] + +The following query returns a sample document from the data in the `vector-sample.color.rgb`collection, truncating the embedded vector to 4 values to make the result readable: + +[source,sqlpp] +---- +include::vector-index:example$hyperscale-idx-examples.sqlpp[tag=rgb-entry] +---- + +The result of running the query is: + +[source,json] +---- +include::vector-index:example$hyperscale-idx-data.json[tag=rgb-document] +---- + +The following example creates an Hyperscale vector index for the vector column named `embedding-vetor-dot`. + +[source,sqlpp] +---- +include::vector-index:example$hyperscale-idx-examples.sqlpp[tag=create-rgb-idx] +---- + +The key pieces of this example are: + +* The `CREATE VECTOR INDEX` statement creates a Hyperscale Vector index. +This differs from the `CREATE INDEX` statement used to create a Global Secondary Index (GSI). +* The `WITH` clause defines several settings specific to Hyperscale Vector indexes: +** It uses the Euclidean distance (`l2`) similarity function when locating centroids. +This function has high accuracy, which matters in a dataset with only 153 documents. +** Also, because the dataset is so small, the example sets the `description` to `IVF8,SQ4`. +This value has the xref:vector-index:vectors-and-indexes-overview.adoc#IVF[inverted file algorithm] use just 8 centroids. +It also uses 4-bit xref:vector-index:vectors-and-indexes-overview.adoc#sq[scalar quantization]. +These settings limit the fragmentation of the small dataset. + +In most cases, you'll not use these settings in a production environment. + +== Query with a Hyperscale Vector Index + +To use your Hyperscale Vector index, use the `SELECT` statement with a `WHERE` clause that contains a vector value. +A typical query looks like this: + +[source,sqlpp] +---- +SELECT + FROM > + ORDER BY APPROX_VECTOR_DISTANCE( + , + , + , + [] + ) LIMIT ; +---- + +The `search-vector-value` is the vector Couchbase {product-name} will search for in the index. +It can be an array of floating point numbers or a base64 encoded string. + +To return the most relevant vectors, use a `ORDER BY` clause to order the results based on the similarity of the vectors. +In this clause, the call to the `APPROX_VECTOR_DISTANCE` function (also known as `ANN`) performs the vector search. + +NOTE: You can also call the function `VECTOR_DISTANCE` to find similar vectors. +However, this function does not use the Hyperscale Vector index to perform the vector search. +Instead, it performs a brute-force search for similar vectors. + +Also use a `LIMIT` clause to return just the number of results you need. +The query pushes the `LIMIT` clause down into the index scan so that the scan ends after finding the requested number of matches. + +=== Hyperscale Vector Index Query Example + +You must supply a vector value in your query that Couchbase {product-name} can compare to the vectors in the index. +In actual use, your application generates a vector for the query value using the same embedding model it used to embed the vectors in your documents. + +To avoid the complication of calling an embedding function, this example uses embedded vectors in the `rgb_questions.json` file that's included in `color_data_2vectors.zip`. +The contents of this file are loaded into a collection named `vector-sample.color.rgb-questions`. +This collection contains a `question` attribute containing a search prompt for a particular color. +The `couchbase_search_query.knn.vector` attribute contains the embedded vector for the `question` attribute. +The following query lists several attributes from a document. +It truncates the `couchbase_search_query.knn.vector` attribute to just the first 4 dimensions of the vector for readability: + +[source,sqlpp] +---- +include::vector-index:example$hyperscale-idx-examples.sqlpp[tag=query-rgb-questions] +---- + +The output of the query looks like this: + +[source,json] +---- +include::vector-index:example$hyperscale-idx-data.json[tag=query-rgb-questions-output] +---- + +To use the embedded vector, you need to include the `couchbase_search_query.knn.vector` attribute in your query's the `SELECT` statement. +You can either directly cut & paste the entire array into your query or use a subquery to retrieve it from the `vector-sample.color.rgb-questions` collection. +The following example uses a subquery to get the vector, and also includes the `wanted_similar_color_from_search` attribute in the output which shows you the color that he query should return. + +[source,sqlpp] +---- +include::vector-index:example$hyperscale-idx-examples.sqlpp[tag=query-rgb-with-subquery] +---- + +In this example, the `APPROX_VECTOR_DISTANCE` function compares the vector in the `couchbase_search_query.knn.vector` attribute to the vectors in the index. +The parameters the example passes to this function are: + +* The `embedding-vector-dot` is the name of the indexed vector key. +* The vector value to compare to the vectors in the index, which is the result of the subquery that gets the `couchbase_search_query.knn[0].vector` from the `rgb-questions` collection. +* `l2` is the distance function to use. +* `4` is the number of centroids to probe for matching vectors. +This example sets this value to 4 because the dataset is small. +In a small dataset, it's more likely that relevant vectors are not associated with the same centroid. +This parameter broadens the search beyond a single centroid to find more relevant vectors. +If you re-run the query with the default value of 1, you'll see that the results are less relevant. + +The result of running the query is: + +[source,json] +---- +include::vector-index:example$hyperscale-idx-data.json[tag=query-rgb-color] +---- + +The second result, `sky blue`, matches the `wanted_similar_color_from_search` attribute as the most relevant color to the question posed in the `question` attribute. +All of the results are still relevant to the question. + + +== Filter Hyperscale Vector Index Scans with Scalar Columns + +The Hyperscale Vector index contains a single vector column. +However, you can reference non-vector attributes in an `INCLUDE` clause when creating your index. +These attributes are not indexed in the Hyperscale Vector index, but you can use them to filter the results of a vector search. +During the search, Couchbase {propduct-name} uses the attributes to filter the index entries before performing the vector index scan. + +The following example creates a new Hyperscale Vector index that indexes the `embedding-vector-dot` vector column and includes the `brightness` key `vector-sample.color.rgb` collection: + +[source,sqlpp] +---- +include::vector-index:example$hyperscale-idx-examples.sqlpp[tag=create-idx-brightness] +---- + +This example is identical to the earlier `CREATE VECTOR INDEX` example, except that it adds the `INCLUDE` clause to add the `brightness` key. + +When you query the vector key and add one of the included keys as a predicate, Couchbase {product-name} uses the predicate to filter the results before performing the vector index scan. + +The following example performs the same query ast he previous example, but adds the `brightness` key as a predicate in the `WHERE` clause: + +[source,sqlpp] +---- +include::vector-index:example$hyperscale-idx-examples.sqlpp[tag=query-rgb-with-brightness] +---- + +The result of running the query is: + +[source,json] +---- +include::vector-index:example$hyperscale-idx-data.json[tag=query-rgb-brightness] +---- + +[#prevent-vector-persistence] +== Prevent Full Vector Persistence + +The Hyperscale Vector index always quantizes the vectors it contains. +See xref:vectors-and-indexes-overview.adoc#quantization[Quantization] for more information about quantizing vectors. +You choose which type of quantization it uses when you create it. + +By default, a Hyperscale Vector index also stores a copy of the original vector value. +It uses the full value when ranking the search results to make the rankings more accurate. + +You can choose to turn off this feature if the cost of storing and comparing full vector values during ranking causes performance issues. +You can prevent persisting the full vector by setting the `persist_full_vector` attribute to false in the `WITH` clause when you create the index: + +[source,sqlpp] +---- +WITH { "dimension": , + "similarity":, + "description":, + "persist_full_vector":false + }; +---- + +The following example creates a Hyperscale Vector index that does not persist the full vector value: + +[source,sqlpp] +---- +include::vector-index:example$hyperscale-idx-examples.sqlpp[tag=create-rgb-no-persist] +---- + +The size of the resulting index is much smaller than the index that persists the full vector value (269KiB verses 1.17MiB). + diff --git a/modules/vector-index/pages/use-vector-indexes.adoc b/modules/vector-index/pages/use-vector-indexes.adoc index e32c4a33e..2410904a2 100644 --- a/modules/vector-index/pages/use-vector-indexes.adoc +++ b/modules/vector-index/pages/use-vector-indexes.adoc @@ -7,7 +7,7 @@ {description} -Vector Indexing lets you add vectors to Couchbase {product-name} indexes. +You cam add vectors to Couchbase {product-name} indexes. You store index values as attributes in your documents, and then index those attributes. You can then find relevant data by executing queries on the vector attributes, which use the index to find similar vectors. @@ -18,68 +18,224 @@ Using indexes reduces the resources needed to perform vector searches. If you're unfamiliar with vectors and vector indexing, see xref:vectors-and-indexes-overview.adoc[] for an overview. -== Application Workflow with Vector Indexes +You can include vectors in three types of Couchbase {product-name} indexes: -The following diagram shows a typical workflow for an application that uses vector values stored in Couchbase {product-name}. +Hyperscale Vector Indexes:: +These indexes are specifically designed for vector searches. +They perform vector similarity and semantic searches faster than the other types of indexes. +They can scale to index billions of documents compared to the million-ranges for the other index types. +Most of the Hyperscale Vector indexes resides in a highly optimized format on disk. +Use this type of index when you want to primarily query vector values with a low memory footprint. +It offers high accuracy even for vectors with a large number of dimensions. +It also supports concurrent searches and inserts for datasets that are constantly changing. + ++ +See xref:vector-index:hyperscale-vector-index.adoc[] for more information. + +Composite Vector Indexes:: +Composite Vector indexes combine a standard GSI index with a single vector column. +This combination lets you perform a hybrid search using a single vector value with standard scalar attributes that are also indexed in the Composite Vector Index. +The scalar attributes in a query reduce the number of vectors the Couchbase {product-name} has to compare when performing an index scan to find similar vectors. +Use GSI indexes with a vector column when you want to perform hybrid searches of documents using both scalars and a vector. +They work well for cases where your queries are highly selective---returning a small number of results from a large dataset. +They consume a moderate amount of memory and can index billions of documents. + ++ +To learn how to use Composite Vector indexes, see xref:vector-index:composite-vector-index.adoc[]. + + +FTS Vector Index:: +An FTS Vector index is a hybrid that combines a Couchbase {product-name} Search index with a single vector column. +This combination adds semantic search to the Search index's full-text and geospatial search capabilities. +These indexes can index millions of documents. + ++ +To learn how to use FTS Vector indexes, see xref:vector-search:vector-search.adoc[]. + +== Choosing the Right Index Type + +When choosing which type of index to use, you must consider: + +* The size of your dataset. +* Whether you need to perform hybrid searches that combine scalar value or text searches along with the vector search. +* The performance requirements of your application. + +The following table summarizes the differences between the three types of vector indexes: + +[%autowidth] +|=== +| Index Type | Dataset Size | Uses | Strength | Limitations + +| *Hyperscale Vector Index* +| Billions of documents +a| +* Pure vector searches +* Content discovery or recommendations +a| +* High performance for pure vector searches +* Low memory footprint +* Lowest TCO for huge datasets +* Best option for concurrent updates and searches +a| +* Overkill on smaller datasets +* Indexing can take longer relative to other index types + +| *Composite Vector Index* +| Tens to hundreds of millions +| Hybrid searches combining vector and scalar values +a| +* Scalar values pre-filter data to reduce the scope of vector searches +* Can restrict searches based on scalars for use cases such as compliance. +* Based familiar Global Secondary indexes (GSI) +a| +* Accuracy suffers in huge datasets compared to Hyperscale Vector index +* Scalar values always override vector values in queries, potentially missing relevant results + +| *FTS Vector Index* +| Tens of millions +| Hybrid searches combining vector and keywords or geospatial +a| +* Combines semantic and Full-Text search and geospatial search in a single pass. +* Uses familiar Search indexes +a| +* Not as efficient as Composite Vector indexes if the search includes purely numeric or scalar values +* Does not scale to the extent of the other index types. +Limited to approximately 100 million documents +|=== + + +When choosing which type of index to use, consider the following: + +* If your dataset will not grow beyond 100 million documents, you can consider Composite Vector or FTS Vector indexes, especially if you need to perform hybrid searches. +* If your dataset is larger than or may grow larger than 100 million documents, use a Hyperscale Vector index. +* When in doubt, try using a Hyperscale Vector index. +If you find that the performance is not what you need, you can try using one of the other index types. + +== Applications for Vector Indexes + +Each type of index is suited to different types of applications. +The following sections explain several common applications for each type of vector index. +They also describe the workflow your application follows when using each type of index. + +=== Hyperscale Vector Index Applications -[plantuml,ai-app-workflow,svg] +Hyperscale Vector indexes contain a single vector column. +They excel at huge dataset that can scale into the billions of documents. +They are optimized for pure vector searches, such as content discovery or recommendations. + +The Hyperscale Vector index works well for applications such as: + +Reverse image searches:: +Embedded vectors for images often contain up to thousands of dimensions, which Hyperscale Vector indexes handle better than other index types. + +Chatbot context matching:: +Chatbot context for workflows like retreival-augmented generation (RAG) requires a huge dataset for accurate results. +The large dataset gives the chatbot a depth of knowledge that's not necessary in simpler applications. + +Anomaly detection:: +Anomaly detection applications such as those used in Internet of Things (IoT) sensor networks, require huge datasets to find deviations from normally occurring patterns. +Hyperscale Vector indexes can handle the large datasets and perform these vector searches fast. + +When using a Hyperscale Vector index, your application follows the workflow shown in the following diagram: + +.Application Workflow with Hyperscale Vector Indexes +[plantuml,hyperscale-vector-app-workflow,svg] .... -include::vector-index:partial$ai-app-workflow.puml[] +include::vector-index:partial$hyperscale-vector-app-workflow.puml[] .... -. Your application may need to load or update a document in Couchbase {product-name} that contains one or more attributes that store embedded vectors. -Before it can load the data into a Couchbase collection, it calls an embedding model to create vectors for these attributes. +The steps shown in the diagram are: +. When your application loads data with a complex data field it wants to search semantically, it calls an embedding model to generate a vector for it. +. It sends the data, including the vector, to Couchbase {product-name} for storage. +. The Data Service sends the embedded vector to the Indexing Service for inclusion in the Hyperscale Vector index. +. When your application needs to perform a query that includes a vector, it uses the same embedding model to generate a vector for the search value. +. It sends the vector as part of the search request or query to teh Couchbase {product-name} Search Service. +. The Query Service performs an index scan in the Hyperscale Vector index to find similar vectors to the search vector. +. The Search Service returns results to your application. -. The application then sends the data including the embedded vector to Couchbase {product-name} for storage. -The Data Service handles creating or updating a document in a collection. +See xref:vector-index:hyperscale-vector-index.adoc[] for more information about Hyperscale Vector indexes. -. The addition or update of data in an indexed collection causes the Index Service to update the index. +=== Composite Vector Index Applications +Composite Vector indexes contain a single vector column and one or more scalar columns. +They apply scalar filters before performing a vector similarity search. +This is ideal for workflows where you want to exclude documents entirely to reduce the number of vectors that the index has to compare. +Composite Vector indexes work well for applications such as: -. When your application needs to perform a query or search that includes a vector, it uses the embedding model to generate a vector for the search value. -It then passes this vector as part of the search request or query. +Content Recommendations:: +Viewers often want hard constraints on their searches, such as genre, language, or favorites actors or directors. +Composite Vector indexes can filter using these constraints before performing a vector similarity search on fields such as the plot description or reviews. -. Depending if the application is performing a search or a query, the Search Service or Query Service processes the request using the appropriate index +Job Searches:: +Job seekers often want to filter jobs based on location, salary, or job title. +Composite Vector indexes can filter using these constraints before performing a vector similarity search on fields such as the job description or required skills. -. The Search or Query Service returns any results to your application. +Supply chain management:: +Supply chain management applications often need to query based on product type, supplier, or location. +Vector similarity searches can be added to these searches to find similar demand patterns. -== Uses for Vectors in Couchbase {product-name} Indexes +When using a Composite Vector index, your application follows the workflow shown in the following diagram: -Here's some ways you can use vector indexes in your applications: +.Application Workflow with Composite Vector Indexes +[plantuml,composite-vector-app-workflow,svg] +.... +include::vector-index:partial$composite-vector-app-workflow.puml[] +.... -* Improve your application's search ability by querying not just for discrete values, but also based on similar content. -For example, suppose your application is a product catalog. -Using a GSI index extended with a vector column, it could find similar products based not just on attributes (such as color or size) but also the similarity of the product's description and customer reviews. -You can even offer the ability for customers to upload a picture and have your application find similar products. +The steps shown in the diagram are: -* Create a customized chatbot based on your own data by implementing a Retrieval-Augmented Generation (RAG) workflow using a Vector Index. -When a user enters a question, convert it to a vector using the same embedding model you used to embed vectors into your database. -Perform a query using a Vector Index to find relevant documents in your database. -Then pass the user's question and the relevant documents to a Large Language Model (LLM) to generate a final response for the user. +. When your application loads data with a complex data field it wants to search semantically, it calls an embedding model to generate a vector for it. +. It sends the data, including the vector, to Couchbase {product-name} for storage. +. The Data Service sends the embedded vector along with scalar fields to the Indexing Service for inclusion in the Composite Vector index. +. When your application needs to perform a query that includes a vector, it uses the same embedding model to generate a vector for the search value. +. It sends the vector and scalar values as part of a query to the Couchbase {product-name} Query Service. +. The Query Service performs an index scan in the Composite Vector index to find documents that match the scalar fields. +Then it performs a vector similarity search in the documents using the search vector. +. The Search Service returns results to your application. +See xref:vector-index:composite-vector-index.adoc[] for more information about Composite Vector indexes. +[#fts] +=== FTS Vector Index Applications -== Index Support for Vectors +FTS Vector indexes contain a single vector column in addition to a full-text search index. +Some of the applications for FTS Vector indexes include: -You can include vectors in three types of indexes: +E-Commerce product recommendations:: +E-Commerce applications can use scalar, text, and vector searches to find products that match a customer's search. +For example, a customer could search for red sneakers (text) that cost less than $100 (scalar) that are similar to an uploaded image of a sneaker (vector). -* Vector Indexes are specifically designed for vector searches. -They perform vector similarity and semantic searches faster than the other types of indexes. -They can index billions of documents. -Most of the Vector Index resides in a highly optimized format on disk. -Use this type of index when you want to primarily query vector values with a low memory footprint. -This index offers high accuracy even for vectors with a large number of dimensions. -See xref:vector-index.adoc[] for more information. - -* Global Secondary Indexes (GSI) can have a single vector column. -Adding a vector to a GSI lets you perform a hybrid search combining a single vector value with standard scalar attributes that are also indexed in the GSI. -The scalar attributes in a query reduce the number of vectors the Couchbase {product-name} has to compare when performing an index scan to find similar vectors. -Use GSI indexes with a vector column when you want to perform hybrid searches of documents using both scalars and a vector. -They work well for cases where your queries are highly selective---returning a small number of results from a large dataset. -They consume a moderate amount of memory and can index billions of documents. -To learn how to use GSI with vectors, see xref:gsi-with-vector.adoc[]. +Travel recommendations:: +Users often want to search for hotels using multiple criteria: + ++ +* Limiting searches to a specific area (for example, "walking distance to the Louvre") which relies on geospacial data. +* Specific keywords for features they want ("quiet", "romantic", "gym") which requires Full-Text search. +* Semantic searches of descriptions and reviews for searches that do not rely on literal texzt matches ("modern beach resort with chic decor") which requires vector searches. + ++ +An FTS vector index can combine geospacial, keyword, and semantic searches into a single index. + +Real estate searches:: +Real estate applications can use FTS Vector indexes to find properties within a search region and have floor plan similar to an uploaded image. + + +When using a FTS Vector index, your application follows the workflow shown in the following diagram: + +.Application Workflow with FTS Vector Indexes +[plantuml,fts-app-workflow,svg] +.... +include::vector-index:partial$fts-vector-app-workflow.puml[] +.... + +The steps shown in the diagram are: + +. When your application loads data it wants to search semantically, it calls an embedding model to generate a vector for it. +. It sends the data and the vector, to Couchbase {product-name} for storage. +. The Data Service sends the embedded vector along with scalar fields to the Search Service for inclusion in the FTS Vector index. +. When your application needs to perform a search that includes a vector, it uses the same embedding model to generate a vector for the search value. +. It sends the search vector and text, geospacial, and other search values as part of a search request to the Couchbase {product-name} Search Service. +. The Search Service performs an index scan in the FTS Vector index to find documents that match the scalar fields. +Then it performs a vector similarity search in the documents using the search vector. +. The Search Service returns results to your application. -* A Search index used for full-text and geospacial search can have an added vector attribute, -The search results combine keyword matching of Full-Text Search with the semantic meaning matching of vectors to give you hybrid results. -Use Search indexes with a vector attribute when you want to query based on keywords or geospacial data plus a vector value. -These indexes can index millions of documents. \ No newline at end of file diff --git a/modules/vector-index/pages/vector-index.adoc b/modules/vector-index/pages/vector-index.adoc deleted file mode 100644 index c17663c01..000000000 --- a/modules/vector-index/pages/vector-index.adoc +++ /dev/null @@ -1,166 +0,0 @@ -= Pure Vector Searches Using Vector Indexes -:page-topic-type: guide -:page-ui-name: {ui-name} -:page-product-name: {product-name} -:description: Vector indexes are are optimized to index a single vector column. They offer the highest performance of any index when it comes to vector data. -:stem: -:page-toclevels: 3 -:index-name: Vector index -:index-name-plural: Vector indexes - -{description} -Vector indexes can scale up to a billion documents containing vectors each of which have a large number of dimensions. - -Because they provide the best performance, consider testing a Vector index for your application before resorting to the other types of indexes. -If you find that the Vector index's performance does not meet your needs, then test using a GSI with vector column or a Search index. - - -== How the Vector Index Works - -The Vector index primarily relies on data stored in an optimized format on disk. -By relying on disk storage, Vector indexes have lesser memory requirements than other index types. - -You add a single vector column to a Vector index. -The vector value can be an array of floating point values. -This array can be nested, as long as you use an xref:n1ql:n1ql-language-reference/unnest.adoc[`UNNEST` clause] to extract the vector array from the containing array. -The vector can also be stored in a BASE64 string. - - -=== Filter Vector Index Scans with Scalar Columns - -The Vector index contains just the single vector column. -However, you can use non-vector values in your query to limit the number of vector comparisons. -The query uses columns you add to an `INCLUDE` clause to filter out index entries before performing the vector index scan. -See <<#filter-using-scalars-example>> for more information. - - -[#full-vector-persist] -=== Persisting the Full Vector Value - -The Vector index always quantizes the vectors it contains. -See xref:vectors-and-indexes-overview.adoc#quantization[Quantization] for more information about quantizing vectors. -You choose which type of quantization the Vector index uses when you create it. -It uses these quantized values when it scans for similar vectors. - -By default, Vector indexes also store a copy of the original vector value. -It uses the full value when ranking the search results to make the rankings more accurate. -You can choose to turn off this feature if the cost of storing and comparing full vector values during ranking causes performance issues. - -== Prerequisites - -Vector indexes have the following requirements: - -* You must have the Index Service enabled on at least one node in your cluster. -For more information about how to deploy a new node and Services on your database, see xref:manage:manage-nodes/node-management-overview.adoc[]. - -* You must have a bucket with scopes and collections in your database. -For more information about how to create a bucket, see xref:manage:manage-buckets/create-bucket.adoc[]. - -* Your account must have the xref:learn:security:roles.adoc#query-manage-index[Query Manage Index] role to be able to create an index. - -* You have documents in a collection that contain one or more vector embeddings. -You can add a single vector to a GSI index. -If your documents contain multiple embedded vectors, you can create multiple indexes---one for each vector attribute. -+ -Embeddings can be an array of floating point numbers or a base64 encoded string. -Couchbase {product-name} does not embed vectors itself. -You must use an external embedding model to embed vectors into your data and add them to your documents. - -* The vectors you add to an index must contain the same number of dimensions. -Also the values in the vector must be 32-bit floating point numbers. -If a vector does not meet both of these requirements, the vector index treats it as a NULL value and the document is not added to the index. - -* You must know the number of dimensions the vector contains. -The embedding model you use to embed the vectors may determine this value for you. -For example, OpenAI API's `text-embedding-ada-002` embedding model creates vectors that have 1536 dimensions. - -* You must decide what algorithms you want your index to use. -These algorithms affect how much memory your index uses and the amount of processing Couchbase {product-name} must perform to train and search them. -See xref:vector-index:vectors-and-indexes-overview.adoc#index-algorithms[Indexing Algorithms] - -include::partial$index-algorithm-settings.adoc[] - -== Create a Vector Index -Use the `CREATE VECTOR INDEX` statement to create a Vector index. -This statement is similar to the `CREATE INDEX` statement that you use to create Global Secondary Indexes (GSI). -See xref:guides:create-index.adoc[] for an overview of creating indexes. - -You must also use the `WITH` clause to specify some additional information for the vector column in the index. -The format for this clause with the most commonly used parameters is: - -[source,sqlpp] ----- -WITH { "dimension": , "similarity":, "description":}; ----- - -* `dimensions` is an integer value that sets the number of dimensions in the vector. -This value is set by the embedded model you used to embed the vectors. -* `similarity-function` is a string that sets the distance function to use when comparing vectors during index creation. -Couchbase {product-name} uses the following strings to represent the proximity functions: -+ --- -** `COSINE`: xref:use-vector-indexes.adoc#cosine[Cosine Similarity] -** `DOT`: xref:use-vector-indexes.adoc#dot[Dot Product] -** `L2`, `L2_SQUARED`, `EUCLIDEAN`, or `EUCLIDEAN_SQUARED`: xref:use-vector-indexes.adoc#euclidean[Euclidean Distance] --- -+ -For the greatest accuracy, use the distance function you plan to use when querying vector data. -* `algorithm-settings` is a string containing the settings for the indexing algorithms. -See <<#algo_settings>> earlier in this page. - -For a full list of the parameters that affect a vector column in a GSI, see *FIXME:TDB*. - -[#examples] -=== Create Vector Index Examples - -TBD - - - - - -[#prevent-vector-persistence] -=== Prevent Full Vector Persistence - -As mentioned in <<#full-vector-persist>>, by default the Vector index stores the full vector value in addition to its quantized form. -It uses the full vector during result ranking. -You can prevent the Vector index persisting the full vector by setting the `persist_full_vector` attribute in the `WITH` clause to false: - -[source,sqlpp] ----- -WITH { "dimension": , - "similarity":, - "description":, - "persist_full_vector":false - }; ----- - - -== Query with a Vector Index - -You query embedded vector attribute that you have indexed in a Vector index to find similar vectors and therefore similar semantic content. -To find the most similar vectors, use a `GROUP BY` clause in your query to return the most relevant vectors first. -In this clause, call the `APPROX_VECTOR_DISTANCE` function that performs the vector search. - - -NOTE: You can also call the function `VECTOR_DISTANCE` to find similar vectors. -However, this function does not use the Vector index to perform the vector search. -Instead, it performs a brute-force search for similar vectors. - - -You should also use a `LIMIT` clause to return just the number of vectors you need. -The query pushes the `LIMIT` clause down into the index scan so that the scan ends after finding the requested number of matches. - -=== Query Vector Index Examples - -**TBD** - -[#filter-using-scalars-example] -=== Filter Vector Index Searches Using Scalars - -The Vector index only allows a single vector column. -You may have queries where you'd like to use non-vector scalar columns to filter out vectors before performing an index scan. -You can add these columns to the query using an `INCLUDE` clause. -The query pushes the columns you name in the `INCLUDE` clause into the Vector index scan, helping to limit the number of vector comparisons needed to locate matching vectors. - -**Example TBD** \ No newline at end of file diff --git a/modules/vector-index/pages/vectors-and-indexes-overview.adoc b/modules/vector-index/pages/vectors-and-indexes-overview.adoc index 9fc720947..d32389aa3 100644 --- a/modules/vector-index/pages/vectors-and-indexes-overview.adoc +++ b/modules/vector-index/pages/vectors-and-indexes-overview.adoc @@ -7,6 +7,11 @@ {description} +Couchbase {product-name} supports several types of vector indexes. +These indexes let you add similarity searches to your applications without relying on external services. +This page provides an overview of vectors. +If you're already familiar with vectors, you can skip to the next page, xref:vector-index:use-vector-indexes.adoc[Using Vector Indexes] for information about how to use vector indexes in your application. + == About Vectors Vectors are a numerical representation of complex unstructured data such as text, images, or audio. @@ -21,7 +26,7 @@ Vectors for dissimilar data (articles discussing two different topics for exampl By comparing two vectors, you can find the similarity between the two pieces of data they represent. This similarity goes beyond just finding parts of the data that's identical (for example, finding similar words in two pieces of text). The vectors represent features such as the meaning of text rather than just superficial similarities. -When two pieces of data have similar vectors, they have similar meanings or subjects (semantically related). +When two pieces of data have similar vectors, they have semantically related (having similar meanings or subjects). For example, suppose you have three text articles. The first is about feral cats, the second about domestic cats, and the third is about the UNIX/Linux `cat` command. @@ -57,7 +62,7 @@ Matching portions of this data within two image files does not mean they're of t Also, comparing megabytes of raw image data is computationally expensive. Generating vectors of the images distills features of the image into a smaller, more manageable amount of data. It also emphasizes features of the images that viewers find important, such as shapes and textures. -Comparing the vectors is more manageable, and actually results in finding similar images. +Comparing the vectors is more manageable and actually results in finding similar images. == Embedding Vectors @@ -77,7 +82,7 @@ image::embedding-vectors.svg["Diagram showing text, image, and audio data being Behind the scenes, embedding models use neural networks that mimic how the brain recognizes patterns. The neural nets distill the complex data into an array of floating point values. -Beyond choosing an embedding model that's appropriate for your data, you generally do not worry about the details of how the model transforms data into a vector. +Beyond choosing an embedding model that's appropriate for your data, you generally do not worry about how the model transforms data into a vector. === Embedding Model Compatibility @@ -87,7 +92,6 @@ You also cannot compare a vector for a piece of text generated by Word2Vec with === Using Embedding Models with Couchbase {product-name} - ifeval::['{product-name}' == 'Server'] Couchbase {product-name} does not implement any embedding models. You must use external embedding models to generate them and then store the resulting vectors in your documents. @@ -103,7 +107,6 @@ You can use external embedding models or https://www.couchbase.com/products/ai-s endif::[] - [#vector_similarity] == Vector Similarity @@ -111,7 +114,7 @@ Once you have embedded vectors in your database, you find documents with a simil Several algorithms exist that you can use to find similar vectors (often referred to as the distance function). When you add vectors to a Couchbase {product-name} index, you must specify which distance function to use to compare vectors. Each function is suited for different types of data. -This distance function must match the distance function the embedding model used when generating the vectors. +This distance function usually must match the distance function the embedding model used when generating the vectors. Couchbase {product-name} supports three distance function: @@ -144,7 +147,7 @@ This method is similar to the dot product. However, it normalizes the vectors (making them the same length) during comparison. Normalization means their magnitudes are not taken into account, just their alignment. This normalization makes this method better for comparing textual data because it's less sensitive to the length of the data. -The magnitude of a vector generated by some textual data embedding models depend on the length of the source text. +The magnitude of a vector generated by some textual data embedding models depend on the length of the source text. Normalizing vector magnitudes emphasizes the semantic meaning when performing comparisons. Therefore, Cosine Similarity can find the semantic relationship between a short question and a long article that's relevant to answering it. + @@ -152,12 +155,10 @@ image::cosine-similarity-example.svg["Three-dimensional plot showing two vectors + Use this method when you're performing similarity searches on text. - - [#index-algorithms] === Indexing Algorithms -When you add a vector column to an index, you specify one or more algorithms that Couchbase {product-name} uses to process the vector values. +When you add a vector to an index, you specify one or more algorithms that Couchbase {product-name} uses to process the vector values. These algorithms organize and consolidate vector data in the index to make it more efficient to search. Couchbase {product-name} supports the algorithms described in the following sections. @@ -274,7 +275,7 @@ This quantization reduces the dimensions from 32 or 64 bit floating point values It also makes search faster because integer operations are computationally less expensive than floating point operations. + A search on an SQ index reassembles vectors before comparing them. -For each of the vector's dimensions, SQ replaces the the integer bin number with the floating point centroid associated with the bin. +For each of the vector's dimensions, SQ replaces the integer bin number with the floating point centroid associated with the bin. This recreation is an approximation of the original vector, because each dimension in the vector is the bin's centroid value instead of the original dimensional value. + Like the PQ algorithm, you often combine SQ and IVF. @@ -291,6 +292,18 @@ Its training just determines the range of values for each dimension. + Use SQ if you want to gain some of the memory efficiency offered by vector quantization, but do not want the processing overhead of training a PQ index. +=== Choosing Quantization + +When choosing a quantization method, consider the following: + +* Use SQ when you want higher accuracy than PQ, at the cost of lower compression, and therefore more memory use. +* Use PQ when you're willing to trade some accuracy for higher compression. + +You should also consider the potential need to retrain the index if your dataset changes over time. +See the following section for more information about index training. + +Whichever quantization you choose, you should perform tests to verify it meets your needs. + [#index-training] === The Importance of Index Training @@ -309,10 +322,10 @@ New clusters of vectors may have developed, and old ones may have dissipated. Indexes using the SQ indexing algorithm can return inaccurate results if the range of values in the dimensions change. If one or more dimensional values fall outside the range that SQ assign buckets to, they get assigned closest bucket. -These inaccuracies can build over time, skewing results,. +These inaccuracies can build over time, skewing results. To resolve these accuracy issues, you can retrain your indexes when you notice poor results. -You can also choose to retrain indexes periodically or after you have made significant changes to your dataset. +You can also choose to retrain indexes periodically or after you make significant changes to your dataset. You should consider the need to retrain your indexes when choosing which index algorithm to use. For example, the PQ algorithm requires more resources to train than the SQ algorithm. diff --git a/modules/vector-index/partials/composite-vector-app-workflow.puml b/modules/vector-index/partials/composite-vector-app-workflow.puml new file mode 100644 index 000000000..ee0e2e85d --- /dev/null +++ b/modules/vector-index/partials/composite-vector-app-workflow.puml @@ -0,0 +1,82 @@ +@startuml ai-app-workflow + +!pragma layout smetana +!include +!include +!include +!include +!include +!include +!include +!include +!include +sprite Couchbase + + + +'title: Application Workflow with Composite Vector Indexes + +skinparam defaultTextAlignment center + +skinparam linetype ortho + +top to bottom direction + + + frame "Your Application" as APP { + card DL [ + Data + Loading + ] + card EM [ + Embedding + Models + ] + card SE [ + Search & Query Logic + ] + + DL --> EM : <$ma_numeric_1_box{scale=0.4}>Complex\nData + EM --> DL : Vectors + SE --> EM : <$ma_numeric_4_box{scale=0.4}>Complex\nData + EM --> SE : Vectors + + } + + frame "<$Couchbase{scale=0.15}> Couchbase Cluster" as CC { + database DS [ + <$Couchbase{scale=0.15,color=red}> + .. + Data + .. + Service + .. + ] + rectangle " <$Couchbase{scale=0.15}> Index Service" as IS { + card COMPOSITE [ + Composite + Vector + Index + ] + } + + rectangle "<$Couchbase{scale=0.15}> Query Service" as QS { + + } + + } + + +DL ----> DS : <$ma_numeric_2_box{scale=0.4}> Data &\nVectors +DS --> COMPOSITE : <$ma_numeric_3_box{scale=0.4}> Scalars &\nVectors + +QS <--> COMPOSITE : <$ma_numeric_6_box{scale=0.4}> Index\nScans + + +SE ----> QS : <$ma_numeric_5_box{scale=0.4}>Queries + +QS ----> SE :<$ma_numeric_7_box{scale=0.4}> Results + + +@enduml diff --git a/modules/vector-index/partials/fts-vector-app-workflow.puml b/modules/vector-index/partials/fts-vector-app-workflow.puml new file mode 100644 index 000000000..2e5a3074d --- /dev/null +++ b/modules/vector-index/partials/fts-vector-app-workflow.puml @@ -0,0 +1,74 @@ +@startuml ai-app-workflow + +!pragma layout smetana +!include +!include +!include +!include +!include +!include +!include +!include +!include +sprite Couchbase + + + +'title: Application Workflow with FTS Vector Indexes + +skinparam defaultTextAlignment center + +skinparam linetype ortho + +top to bottom direction + + + frame "Your Application" as APP { + card DL [ + Data + Loading + ] + card EM [ + Embedding + Models + ] + card SE [ + Search & Query Logic + ] + + DL --> EM : <$ma_numeric_1_box{scale=0.4}>Complex\nData + EM -d-> DL : Vectors + SE --> EM : <$ma_numeric_4_box{scale=0.4}>Complex\nData + EM --> SE : Vectors + + } + + frame "<$Couchbase{scale=0.15}> Couchbase Cluster" as CC { + database DS [ + <$Couchbase{scale=0.15,color=red}> + .. + Data + .. + Service + .. + ] + + rectangle " <$Couchbase{scale=0.15}> Search Service" as SSERV { + card SI [ + FTS Vector + Index + ] + } + + } + + +DS ----> SI : Text &\nVectors +DL ----> DS : <$ma_numeric_2_box{scale=0.4}> Data &\nVectors + +SE ----> SSERV : <$ma_numeric_5_box{scale=0.4}>Searches + +SSERV ----> SE :<$ma_numeric_6_box{scale=0.4}> Results + +@enduml diff --git a/modules/vector-index/partials/hyperscale-vector-app-workflow.puml b/modules/vector-index/partials/hyperscale-vector-app-workflow.puml new file mode 100644 index 000000000..ff46cda4b --- /dev/null +++ b/modules/vector-index/partials/hyperscale-vector-app-workflow.puml @@ -0,0 +1,82 @@ +@startuml ai-app-workflow + +!pragma layout smetana +!include +!include +!include +!include +!include +!include +!include +!include +!include +sprite Couchbase + + + +'title: Application Workflow with Hyperscale Vector Indexes + +skinparam defaultTextAlignment center + +skinparam linetype ortho + +top to bottom direction + + + frame "Your Application" as APP { + card DL [ + Data + Loading + ] + card EM [ + Embedding + Models + ] + card SE [ + Search & Query Logic + ] + + DL --> EM : <$ma_numeric_1_box{scale=0.4}>Complex\nData + EM --> DL : Vectors + SE --> EM : <$ma_numeric_4_box{scale=0.4}>Complex\nData + EM --> SE : Vectors + + } + + frame "<$Couchbase{scale=0.15}> Couchbase Cluster" as CC { + database DS [ + <$Couchbase{scale=0.15,color=red}> + .. + Data + .. + Service + .. + ] + rectangle " <$Couchbase{scale=0.15}> Index Service" as IS { + card HVI [ + Hyperscale + Vector + Index + ] + } + + rectangle "<$Couchbase{scale=0.15}> Query Service" as QS { + + } + + } + + +DL ----> DS : <$ma_numeric_2_box{scale=0.4}> Data &\nVectors +DS --> HVI : <$ma_numeric_3_box{scale=0.4}> Vectors + +QS <--> HVI : <$ma_numeric_6_box{scale=0.4}> Index\nScans + + +SE ----> QS : <$ma_numeric_5_box{scale=0.4}>Queries + +QS ----> SE :<$ma_numeric_7_box{scale=0.4}> Results + + +@enduml diff --git a/modules/vector-index/partials/nav.adoc b/modules/vector-index/partials/nav.adoc index 7e008a2ba..cd1e8ef86 100644 --- a/modules/vector-index/partials/nav.adoc +++ b/modules/vector-index/partials/nav.adoc @@ -1,9 +1,9 @@ -* xref:server:vector-index:use-vector-indexes.adoc[] +* xref:server:vector-index:vectors-and-indexes-overview.adoc[] + -- -** xref:server:vector-index:vectors-and-indexes-overview.adoc[] -** xref:server:vector-index:vector-index.adoc[] -** xref:server:vector-index:gsi-with-vector.adoc[] +** xref:server:vector-index:use-vector-indexes.adoc[] +** xref:server:vector-index:hyperscale-vector-index.adoc[] +** xref:server:vector-index:composite-vector-index.adoc[] -- + -- From 9481075a9bec56541b403ee81e87dd396a3241b4 Mon Sep 17 00:00:00 2001 From: Gary Gray <137797428+ggray-cb@users.noreply.github.com> Date: Thu, 26 Jun 2025 16:25:10 -0400 Subject: [PATCH 28/41] Added best practices draft --- .../pages/hyperscale-vector-index.adoc | 149 +++++++++++++++++- 1 file changed, 148 insertions(+), 1 deletion(-) diff --git a/modules/vector-index/pages/hyperscale-vector-index.adoc b/modules/vector-index/pages/hyperscale-vector-index.adoc index 7403cf967..dfa4acce3 100644 --- a/modules/vector-index/pages/hyperscale-vector-index.adoc +++ b/modules/vector-index/pages/hyperscale-vector-index.adoc @@ -227,7 +227,6 @@ include::vector-index:example$hyperscale-idx-data.json[tag=query-rgb-color] The second result, `sky blue`, matches the `wanted_similar_color_from_search` attribute as the most relevant color to the question posed in the `question` attribute. All of the results are still relevant to the question. - == Filter Hyperscale Vector Index Scans with Scalar Columns The Hyperscale Vector index contains a single vector column. @@ -291,3 +290,151 @@ include::vector-index:example$hyperscale-idx-examples.sqlpp[tag=create-rgb-no-pe The size of the resulting index is much smaller than the index that persists the full vector value (269KiB verses 1.17MiB). +== Hypervector Index Best Practices + +When creating and querying Hyperscale Vector indexes, you have several options to set that can affect the speed and accuracy of your results. +Couchbase has performed testing to determine how these options affect the performance of Hyperscale Vector indexes. +The following sections describe the results of the testing and recommendations besed on these results. + +=== Tuning Index Creation + +When you create a Hyperscale Vector index, you can set the parameters in the following list. +Each of them has the potential to affect the performance of box creating the index and the speed and accuracy of queries that use the index. + +nList:: +Sets the number of clusters (centroids) in the index. +You set the nList by supplying a value after the `IVF` in the `description` parameter when you create your index. +This value affects the accuracy of the index and the speed of queries that use it. +The default value for this value depends on the size of your dataset. +For datasets with less than 1 million vectors, the default value is the number of vedctors divided by 1000. +For datasets with more than 1 million vectors, the default value is the square root of the number of vectors. + ++ +Tests show that increasing nList beyond the default does not affect the build time of the index. +However, it does improve the queries per second (QPS) that the index can handle. +It also lowers the latency of queries that use the index. + ++ +*Recommendation:* if you find that your query throughput and latency is not meeting your needs, you can try rebuilding the index with a larger nList value. + +Trainlist:: +Sets the number of vectors that Couchbase {product-name} considers when searching for centroids in the dataset. +You set it using the `trainlist` key in the `WITH` clause when you create your index. +The default value is roughly 50 times the number of centroids in the index. + ++ +Tests show that increasing the trainlist improves QPS and reduces latency, but slightly increases memory usage for the index. + ++ +*Recommendation:* if you find that increasing the nList does not improve your query performance, you can try increasing the trainlist value. + +Partitions:: +Sets how the index is split among logical shards. +This setting affects the scalability, memory distribution, and parrarlelism of the index. +You set this value using the `PARTITION BY` clause in the `CREATE VECTOR INDEX` statement. + ++ +Tests show that increasing the number of partitions results in a linear reduction of both the time it takes to build and train the index and index's memory use. +These changes do not affect the QPS or latency of queries that use the index. + ++ +*Recommendation:* if the length of time it takes to build the index or the amount of memory the index uses is a concern, you can try increasing the number of partitions. + +Replicas:: +Sets the number of replicas for the index. +This setting affects the fault tolerance, query throughput, and memory footprint of the index. +You set this value using the `num_replicas` key in the `WITH` clause when you create or alter your index. + ++ +Tests show that increasing the number of replicas results in a linear increase in the QPS and linear reduction in latency of queries that use the index. +However, it also linearly increased the memory footprint of the index. +Adding replicas does not affect the time it takes to build the index. + ++ +*Recommendation:* if you find that your query throughput or latency is not meeting your needs, you can try increasing the number of replicas for the index if you can afford the additional memory usage. + +Quantization:: +Sets the quantization method used by the index. +Couchbase {product-name} supports two quantization methods: xref:vector-index:vectors-and-indexes-overview.adoc#sq[scalar quantization (SQ)] and xref:vector-index:vectors-and-indexes-overview.adoc#pq[product quantization (PQ)]. +You set the quantization method using the `description` parameter in the `WITH` clause when you create your index. + ++ +Couchbase tested different quantization settings using datasets that differed in size and number of dimensions. +The results of these tests appear in the following table: + ++ +[%autowidth, options="header"] +|=== +| Dataset | Quantization Setting | Build Time | Memory Use | Recall Accuracy | QPS | Latency + +| 100 Million 128 dimensions +| SQ8 +| Lowest +| Highest +| Best +| Best +| Best + +| 5 Million, 1536 dimensions +| PQ32x8 +| Slightly higher than SQ8 +| 75% less than SQ8 +| lower than SQ8 +| Lower than SQ8 +| Lower than SQ8 + +|=== + ++ +NOTE: Couchbase also tested 1 billion vectors with 128 dimensions with SQ4 quantization. +The result showed acceptable recall accuracy and similar performance to SQ8 on smaller datasets. + ++ +*Recommendations:* + ++ +-- +* SQ8 provides the best balance between memory use, recall, for lower dimensional datasets. +* If you have a low-dimensional dataset that is in the billion vector range, consider using SQ4 quantization. +* Use PQ for higher-dimensional datasets where you want to reduce memory use with the tradeoff of less accurate recall, lower QPS, and higher latency. +-- +// Similarity Function:: +// Sets the function the index uses when determining the similarity of vectors when identifying centroids. +// Couchbase {product-name} supports two similarity +// +// Holding off on simlarity because the best practice doc is mute on it, also lacks testing for dot? + + +== Tuning Queries + +When querying a Hyperscale Vector index, you can set several parameters in the `APPROX_VECTOR_DISTANCE` (`ANN`) function that affect the performance of the query. +The following list describes the parameters you can set in the function: + +nProbes:: +Sets the number of centroids in the Hyperscale Vector index to ton search for similar vectors. +You optionally set this value as the fourth parameter in the `APPROX_VECTOR_DISTANCE` function call in your query. +The default value for this value is 1, meaning that the query only searches for similar vectors in the centroid that is closest to the search vector. + ++ +Testing found that increasing nProbes beyond the default improves the accuracy of results non-linearly (higher values show diminishing improvements). +However, it caused a linear decrease in QPS and increase in latency. + ++ +*Recommendation:* if you find that your query recall is not meeting your needs, you can try increasing the nProbes value. +However, increasing this value reduces QPS and increases latency. + +[#reranking] +Reranking:: +Sets whether the query performs a second ranking phase where it compares the full vector values of the results to the search vector. +This setting is disabled by default. +You can enable it by passing TRUE as the fifth parameter in the `APPROX_VECTOR_DISTANCE` function call in your query. + ++ +Testing has shown that enabling reranking improves the accuracy of recall in only a few cases and significantly decrease QPS. + ++ +*Recommendation:* if you find recall accuracy is not meeting your needs and you are using SQ4 or PQ128x8 or below quantization, you can try enabling reranking. +You must also have your index set to persist the full vector value, which increases memory use. + + + From 148fab98515f3afc7e57524b2994967bea9c9d6a Mon Sep 17 00:00:00 2001 From: Gary Gray <137797428+ggray-cb@users.noreply.github.com> Date: Wed, 2 Jul 2025 16:03:01 -0400 Subject: [PATCH 29/41] Checkin before holday/vacation and sending out to reviewers. --- .../images/hypserscale-w-scalar-plan.svg | 1101 +++++++++++++++++ .../examples/composite-vector-data.json | 66 + .../examples/find-reranking-cases.py | 75 ++ .../examples/gsi-vector-idx-examples.sqlpp | 22 + .../examples/hyperscale-idx-data.json | 167 ++- .../examples/hyperscale-idx-examples.sqlpp | 35 +- .../pages/composite-vector-index.adoc | 134 +- .../vector-index/pages/hyperscale-filter.adoc | 58 + .../pages/hyperscale-reranking.adoc | 89 ++ .../pages/hyperscale-vector-index.adoc | 246 +--- .../pages/use-vector-indexes.adoc | 30 +- .../pages/vector-index-best-practices.adoc | 162 +++ .../pages/vectors-and-indexes-overview.adoc | 9 +- modules/vector-index/partials/nav.adoc | 4 + 14 files changed, 1817 insertions(+), 381 deletions(-) create mode 100644 modules/vector-index/assets/images/hypserscale-w-scalar-plan.svg create mode 100644 modules/vector-index/examples/composite-vector-data.json create mode 100644 modules/vector-index/examples/find-reranking-cases.py create mode 100644 modules/vector-index/pages/hyperscale-filter.adoc create mode 100644 modules/vector-index/pages/hyperscale-reranking.adoc create mode 100644 modules/vector-index/pages/vector-index-best-practices.adoc diff --git a/modules/vector-index/assets/images/hypserscale-w-scalar-plan.svg b/modules/vector-index/assets/images/hypserscale-w-scalar-plan.svg new file mode 100644 index 000000000..d97f91b3a --- /dev/null +++ b/modules/vector-index/assets/images/hypserscale-w-scalar-plan.svg @@ -0,0 +1,1101 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Main Query + + + + + + + + Sub Queries + + + + + + + + Stream + 00:00.002 (9.3%) + 3 in / 3 out + + + + + + Subquery + select raw ((((`rgb-questions`.`cou... + + + + + + + Limit + 3 + 00:00.000 + 3 in / 3 out + + + + + Collect + 1 in + + + + + + + Project + 3 terms + 00:00.000 (0.2%) + 3 in / 3 out + + + + + Project + 1 terms + 1 in / 1 out + + + + + + Filter + (170 < (`b`.`brightness`)) + 00:00.000 (0.1%) + 3 in / 3 out + + + + + Filter + ((meta(`rgb-questions`).`id`) = "#8... + 1 in / 1 out + + + + + + Fetch + rgb as b + 00:00.003 (12.3%) + 3 in / 3 out + + + + + Fetch + rgb-questions + 1 in / 1 out + + + + + + IndexScan3 + rgb.color_desc_hyperscale_brightnes... + as: b + 3 + 00:00.022 (77%) + + + + IndexScan3 + rgb-questions.#sequentialscan + 1 in / 1 out + + + + + + With + 00:00.000 (1.2%) + + + + + + + Authorize + 00:00.000 + + + + + + + + + + + + + + + + diff --git a/modules/vector-index/examples/composite-vector-data.json b/modules/vector-index/examples/composite-vector-data.json new file mode 100644 index 000000000..95d494f73 --- /dev/null +++ b/modules/vector-index/examples/composite-vector-data.json @@ -0,0 +1,66 @@ +// tag::sample-doc[] +[{ + "brightness": 240.82, + "color": "papaya whip", + "colorvect_l2": [ + 255, + 239, + 213 + ], + "description": "Papaya whip is a soft and mellow color that can be + described as a light shade of peach or coral. It has + a calming and soothing effect, similar to the tropical + fruit it is named after. This color is perfect for + creating a warm and inviting atmosphere, and it pairs + well with other pastel shades or neutral tones. Papaya + whip is a versatile color that can be used in both fashion + and interior design, adding a touch of elegance and + sophistication to any space.", + "embedding_model": "text-embedding-ada-002-v2", + "embedding_vector_dot": [ + -0.014644118957221508, + 0.017003899440169334, + -0.013450744561851025, + 0.0021356006618589163, + "..." + ], + "id": "#FFEFD5", + "verbs": [ + "soften", + "mellow", + "lighten" + ], + "wheel_pos": "other" +}] +// end::sample-doc[] + +// tag::sample-doc-question[] +[{ + "couchbase_search_query": { + "fields": [ + "*" + ], + "knn": [{ + "field": "embedding_vector_dot", + "k": 3, + "vector": [ + 0.005115953739732504, + 0.004331615287810564, + 0.014279481954872608, + 0.000619320897385478, + "..." + ] + }], + "query": { + "match_none": {} + }, + "sort": [ + "-_score" + ] + }, + "embedding_model": "text-embedding-ada-002-v2", + "id": "#FFEFD5", + "question": "What is the name of the color that is reminiscent of a tropical fruit and has a calming effect, often used in fashion and interior design?", + "wanted_similar_color_from_search": "papaya whip" +}] +// end::sample-doc-question[] diff --git a/modules/vector-index/examples/find-reranking-cases.py b/modules/vector-index/examples/find-reranking-cases.py new file mode 100644 index 000000000..d4eb73652 --- /dev/null +++ b/modules/vector-index/examples/find-reranking-cases.py @@ -0,0 +1,75 @@ +# This script just iterates over all of the colors in the example dataset to find cases +# where reranking imporved the search results. + +import sys +from couchbase.cluster import Cluster, ClusterOptions +from couchbase.auth import PasswordAuthenticator +from couchbase.options import QueryOptions +from datetime import timedelta + + +# --- Configuration --- +COUCHBASE_URL = "couchbase://localhost" +USERNAME = "Administrator" +PASSWORD = "password" +BUCKET_NAME = "vector-sample" + +# --- Connect to Cluster --- +cluster = Cluster(COUCHBASE_URL, ClusterOptions(PasswordAuthenticator(USERNAME, PASSWORD))) +cluster.wait_until_ready(timedelta(seconds=10)) + +# --- Get all search-color IDs --- +get_ids_query = "SELECT META().id AS id FROM `vector-sample`.`color`.`rgb`" +search_colors = cluster.query(get_ids_query) +search_color_ids = [row["id"] for row in search_colors] + +# --- Function to run vector queries --- +def run_vector_query(search_color_id, use_rerank=False, limit=10): + rerank_str = "TRUE" if use_rerank else "FALSE" + query = f""" + WITH question_vec AS ( + SELECT RAW couchbase_search_query.knn[0].vector + FROM `vector-sample`.`color`.`rgb-questions` + WHERE meta().id = "{search_color_id}") + SELECT b.color, b.description, b.id + FROM `vector-sample`.`color`.`rgb` AS b + ORDER BY APPROX_VECTOR_DISTANCE(b.embedding_vector_dot, question_vec[0], "l2", 4, {rerank_str}) + LIMIT {limit}; + """ + return list(cluster.query(query)) + +# --- Analyze and compare results --- +for search_color_id in search_color_ids: + # print(f"\n🔍 Search Color: {search_color_id}") + + try: + # Run both queries + results1 = run_vector_query(search_color_id, use_rerank=False) + results2 = run_vector_query(search_color_id, use_rerank=True) + except Exception as e: + print(f"⚠️ Query error for {search_color_id}: {e}") + continue + + ids1 = [doc["id"] for doc in results1] + ids2 = [doc["id"] for doc in results2] + + in_both = search_color_id in ids1 and search_color_id in ids2 + + if in_both: + idx1 = ids1.index(search_color_id) + idx2 = ids2.index(search_color_id) + if idx2 < idx1: + print(f"✅ Reranking improved rank for {search_color_id}: {idx1} ➜ {idx2}") + # sys.exit(0) + # else: + # print(f"→ No improvement (Rank: {idx1} ➜ {idx2})") + # else: + # if search_color_id in ids1: + # print("⚠️ Present only in first query, not in reranked results.") + # elif search_color_id in ids2: + # print("⚠️ Present only in reranked results, not in first query.") + # else: + # print("❌ Not present in either result set.") + +# --- Final Message --- +# print("\n❌ Reranking did not improve the rank of any search-color.") diff --git a/modules/vector-index/examples/gsi-vector-idx-examples.sqlpp b/modules/vector-index/examples/gsi-vector-idx-examples.sqlpp index 51b779770..5cbd1303e 100644 --- a/modules/vector-index/examples/gsi-vector-idx-examples.sqlpp +++ b/modules/vector-index/examples/gsi-vector-idx-examples.sqlpp @@ -1,3 +1,25 @@ +/* tag::get-sample-doc[] */ +SELECT RAW OBJECT_PUT(d, "embedding_vector_dot", + ARRAY_CONCAT(d.embedding_vector_dot[0:4], ["..."]) +) +FROM `vector-sample`.`color`.`rgb` AS d +USE KEYS ["#FFEFD5"]; +/* end::get-sample-doc[] */ + +/* tag::get-sample-doc-question[] */ +SELECT RAW OBJECT_PUT(d, "couchbase_search_query", + OBJECT_PUT(d.couchbase_search_query, "knn", + ARRAY OBJECT_PUT(k, "vector", + ARRAY_CONCAT(k.vector[0:4], ["..."]) + ) + FOR k IN d.couchbase_search_query.knn END + ) +) +FROM `vector-sample`.`color`.`rgb-questions` AS d +USE KEYS ["#FFEFD5"]; +/* end::get-sample-doc-question[] */ + + /* tag::create-rgb-idx[] */ CREATE INDEX `color_vectors_idx` ON `vector-sample`.`color`.`rgb` (`colorvect_l2` VECTOR, color, brightness) diff --git a/modules/vector-index/examples/hyperscale-idx-data.json b/modules/vector-index/examples/hyperscale-idx-data.json index 077aac99f..590bf9e88 100644 --- a/modules/vector-index/examples/hyperscale-idx-data.json +++ b/modules/vector-index/examples/hyperscale-idx-data.json @@ -1,7 +1,8 @@ // tag::query-rgb-questions-output[] [{ "id": "#87CEEB", - "question": "What is the color that is often linked to feelings of peace and tranquility, and is reminiscent of the clear sky on a calm day?", + "question": "What is the color that is often linked to feelings of peace and + tranquility, and is reminiscent of the clear sky on a calm day?", "wanted_similar_color_from_search": "sky blue", "vector": [ 0.024399276822805405, @@ -19,8 +20,14 @@ "id": "#87CEEB", "color": "sky blue", "brightness": 188.077, - "description": "Sky blue is a calming and serene color that evokes feelings of tranquility. It is a light shade of blue that resembles the color of the sky on a clear day. The color is often associated with peace, relaxation, and a sense of openness. It can also represent a sense of freedom and endless possibilities, as the sky seems to stretch on forever. Sky blue is a refreshing and soothing color that can bring a sense of calmness to any space.", - "vector": [ + "description": "Sky blue is a calming and serene color that evokes feelings of + tranquility. It is a light shade of blue that resembles the color + of the sky on a clear day. The color is often associated with + peace, relaxation, and a sense of openness. It can also represent + a sense of freedom and endless possibilities, as the sky seems + to stretch on forever. Sky blue is a refreshing and soothing color + that can bring a sense of calmness to any space.", + "embedding_vector_dot": [ 0.015966663137078285, 0.018097303807735443, -0.005783640779554844, @@ -33,31 +40,36 @@ // tag::query-rgb-color[] [{ "color": "deep sky blue", - "description": "Deep sky blue is a calming and refreshing color that evokes feelings - of tranquility and peace. It is a shade of blue that resembles the clear, open sky - on a sunny day. This color is often associated with serenity and relaxation, making - it a popular choice for interior design and clothing. Its cool and calming nature - makes it a perfect color for creating a peaceful and serene atmosphere.", + "description": "Deep sky blue is a calming and refreshing color that evokes + feelings of tranquility and peace. It is a shade of blue + that resembles the clear, open sky on a sunny day. This + color is often associated with serenity and relaxation, + making it a popular choice for interior design and clothing. + Its cool and calming nature makes it a perfect color for + creating a peaceful and serene atmosphere.", "wanted_similar_color_from_search": "sky blue" }, { "color": "sky blue", "description": "Sky blue is a calming and serene color that evokes feelings of - tranquility. It is a light shade of blue that resembles the color of the sky on a - clear day. The color is often associated with peace, relaxation, and a sense of - openness. It can also represent a sense of freedom and endless possibilities, as - the sky seems to stretch on forever. Sky blue is a refreshing and soothing color that - can bring a sense of calmness to any space.", + tranquility. It is a light shade of blue that resembles the + color of the sky on a clear day. The color is often associated + with peace, relaxation, and a sense of openness. It can also + represent a sense of freedom and endless possibilities, as the + sky seems to stretch on forever. Sky blue is a refreshing and + soothing color that can bring a sense of calmness to any space.", "wanted_similar_color_from_search": "sky blue" }, { "color": "light sky blue", "description": "Light sky blue is a soft and delicate color that evokes a sense of - tranquility and peace. It is a shade of blue that is reminiscent of a clear, sunny day - with a few fluffy clouds scattered across the sky. This color is often associated with - feelings of serenity and relaxation, making it a popular choice for bedrooms and spa-like - environments. The lightness of this shade adds a touch of freshness and purity, making it - a perfect color for creating a calming and inviting atmosphere.", + tranquility and peace. It is a shade of blue that is reminiscent + of a clear, sunny day with a few fluffy clouds scattered across the + sky. This color is often associated with feelings of serenity and + relaxation, making it a popular choice for bedrooms and spa-like + environments. The lightness of this shade adds a touch of freshness + and purity, making it a perfect color for creating a calming and + inviting atmosphere.", "wanted_similar_color_from_search": "sky blue" } ] @@ -66,35 +78,106 @@ // tag::query-rgb-brightness[] [{ + "color": "sky blue", + "description": "Sky blue is a calming and serene color that evokes + feelings of tranquility. It is a light shade of blue + that resembles the color of the sky on a clear day. + The color is often associated with peace, relaxation, + and a sense of openness. It can also represent a sense + of freedom and endless possibilities, as the sky seems + to stretch on forever. Sky blue is a refreshing and + soothing color that can bring a sense of calmness to + any space.", + "brightness": 188.077 + }, + { "color": "light sky blue", - "description": "Light sky blue is a soft and delicate color that evokes a sense of - tranquility and peace. It is a shade of blue that is reminiscent of a clear, sunny - day with a few fluffy clouds scattered across the sky. This color is often associated - with feelings of serenity and relaxation, making it a popular choice for bedrooms and - spa-like environments. The lightness of this shade adds a touch of freshness and purity, - making it a perfect color for creating a calming and inviting atmosphere.", - "brightness": 189.787, - "wanted_similar_color_from_search": "sky blue" + "description": "Light sky blue is a soft and delicate color that evokes + a sense of tranquility and peace. It is a shade of blue + that is reminiscent of a clear, sunny day with a few fluffy + clouds scattered across the sky. This color is often + associated with feelings of serenity and relaxation, making + it a popular choice for bedrooms and spa-like environments. + The lightness of this shade adds a touch of freshness and + purity, making it a perfect color for creating a calming + and inviting atmosphere.", + "brightness": 189.787 }, { "color": "pale turquoise", - "description": "Pale turquoise is a delicate and soothing color that can be described - as a soft blend of blue and green. It has a calming effect and can evoke feelings of - tranquility and serenity. The color is often associated with the ocean and can bring - to mind images of clear, tropical waters. It has a gentle and subtle quality, making - it a popular choice for creating a peaceful and serene atmosphere.", - "brightness": 219.163, - "wanted_similar_color_from_search": "sky blue" + "description": "Pale turquoise is a delicate and soothing color that can be + described as a soft blend of blue and green. It has a calming + effect and can evoke feelings of tranquility and serenity. The + color is often associated with the ocean and can bring to mind + images of clear, tropical waters. It has a gentle and subtle + quality, making it a popular choice for creating a peaceful and + serene atmosphere.", + "brightness": 219.163 + } +] +// end::query-rgb-brightness[] + + +// tag::rerank-before[] +[{ + "color": "peach", + "description": "Peach is a soft and warm color that can enliven any space. It has + a delicate and gentle quality, like the softness of a peach's skin. + This color can soften the harshness of other colors and bring a sense + of warmth and comfort. It is a versatile color that can be both calming + and invigorating, making it a popular choice in interior design. Peach + is a color that evokes feelings of happiness and positivity, making it + a perfect addition to any room.", + "id": "#FF8C3C" }, { - "color": "light cyan", - "description": "Light cyan is a soft and calming color that evokes feelings of - tranquility and serenity. It is a refreshing hue that brings a sense of peace and - relaxation. With its cool undertones, light cyan is often associated with water and the - sky, creating a sense of openness and spaciousness. This color is perfect for creating - a peaceful and serene atmosphere in any space.", - "brightness": 245.731, - "wanted_similar_color_from_search": "sky blue" + "color": "apricot", + "description": "Apricot is a warm and inviting color, reminiscent of the soft glow of + a sunset. It has the ability to soften the harshness of other colors and + enliven any space it is used in. It is a delicate and soothing hue, + perfect for creating a cozy and welcoming atmosphere.", + "id": "#FB8737" + }, + { + "color": "light yellow", + "description": "Light yellow is a delicate and gentle color that can soften the overall + tone of a room. It has a bright and cheerful quality that can brighten up + any space. This color also has the ability to illuminate a room, making it + feel more open and airy. Light yellow is a perfect choice for creating + a warm and inviting atmosphere.", + "id": "#FFFFE0" } ] -// end::query-rgb-brightness[] +// end::rerank-before[] + +// tag::rerank-after[] +[{ + "color": "peach", + "description": "Peach is a soft and warm color that can enliven any space. It has + a delicate and gentle quality, like the softness of a peach's skin. + This color can soften the harshness of other colors and bring a sense + of warmth and comfort. It is a versatile color that can be both calming + and invigorating, making it a popular choice in interior design. Peach + is a color that evokes feelings of happiness and positivity, making it + a perfect addition to any room.", + "id": "#FF8C3C" + }, + { + "color": "light yellow", + "description": "Light yellow is a delicate and gentle color that can soften the overall + tone of a room. It has a bright and cheerful quality that can brighten up + any space. This color also has the ability to illuminate a room, making it + feel more open and airy. Light yellow is a perfect choice for creating a + warm and inviting atmosphere.", + "id": "#FFFFE0" + }, + { + "color": "apricot", + "description": "Apricot is a warm and inviting color, reminiscent of the soft glow of a + sunset. It has the ability to soften the harshness of other colors and + enliven any space it is used in. It is a delicate and soothing hue, perfect + for creating a cozy and welcoming atmosphere.", + "id": "#FB8737" + } +] +// end::rerank-after[] diff --git a/modules/vector-index/examples/hyperscale-idx-examples.sqlpp b/modules/vector-index/examples/hyperscale-idx-examples.sqlpp index 815f707da..cb0efc862 100644 --- a/modules/vector-index/examples/hyperscale-idx-examples.sqlpp +++ b/modules/vector-index/examples/hyperscale-idx-examples.sqlpp @@ -13,7 +13,7 @@ SELECT ARRAY_CONCAT( d.embedding_vector_dot[0:4], ["..."] - ) AS vector + ) AS embedding_vector_dot FROM `vector-sample`.`color`.`rgb` AS d WHERE d.id = "#87CEEB"; /* end::rgb-entry[] */ @@ -58,13 +58,9 @@ CREATE VECTOR INDEX `color_desc_hyperscale_brightness` WITH question_vec AS ( SELECT RAW couchbase_search_query.knn[0].vector FROM `vector-sample`.`color`.`rgb-questions` - WHERE meta().id = "#87CEEB"), - question_answer AS ( - SELECT wanted_similar_color_from_search - FROM `vector-sample`.`color`.`rgb-questions` WHERE meta().id = "#87CEEB") -SELECT b.color, b.description, b.brightness, q.wanted_similar_color_from_search - FROM `vector-sample`.`color`.`rgb` AS b, question_answer as q +SELECT b.color, b.description, b.brightness + FROM `vector-sample`.`color`.`rgb` AS b WHERE b.brightness > 170.0 ORDER BY APPROX_VECTOR_DISTANCE(b.embedding_vector_dot, question_vec[0], "l2", 4) LIMIT 3; @@ -73,5 +69,28 @@ SELECT b.color, b.description, b.brightness, q.wanted_similar_color_from_search /* tag::create-rgb-no-persist[] */ CREATE VECTOR INDEX `color_desc_hyperscale_no_persist` ON `vector-sample`.`color`.`rgb`(`embedding_vector_dot` VECTOR) - WITH { "dimension":1536, "similarity":"L2", "description":"IVF8,SQ4", "persist_full_vector": false}; + WITH { "dimension":1536, "similarity":"L2", "description":"IVF8,SQ4", + "persist_full_vector": false}; /* end::create-rgb-no-persist[] */ + +/* tag::rerank-before-example[] */ +WITH question_vec AS ( + SELECT RAW couchbase_search_query.knn[0].vector + FROM `vector-sample`.`color`.`rgb-questions` + WHERE meta().id = "#FFFFE0") + SELECT b.color, b.description, b.id + FROM `vector-sample`.`color`.`rgb` AS b + ORDER BY APPROX_VECTOR_DISTANCE(b.embedding_vector_dot, question_vec[0], "l2", 4) + LIMIT 3; +/* end::rerank-before-example[] */ + +/* tag::rerank-after-example[] */ +WITH question_vec AS ( + SELECT RAW couchbase_search_query.knn[0].vector + FROM `vector-sample`.`color`.`rgb-questions` + WHERE meta().id = "#FFFFE0") + SELECT b.color, b.description, b.id + FROM `vector-sample`.`color`.`rgb` AS b + ORDER BY APPROX_VECTOR_DISTANCE(b.embedding_vector_dot, question_vec[0], "l2", 4, TRUE) + LIMIT 3; +/* end::rerank-after-example[] */ diff --git a/modules/vector-index/pages/composite-vector-index.adoc b/modules/vector-index/pages/composite-vector-index.adoc index e8d384760..22bb48f07 100644 --- a/modules/vector-index/pages/composite-vector-index.adoc +++ b/modules/vector-index/pages/composite-vector-index.adoc @@ -1,25 +1,24 @@ -= Hybrid Search Using GSI with a Vector Column += Hybrid Search Using Composite Vector Index :page-topic-type: guide :page-ui-name: {ui-name} :page-product-name: {product-name} -:description: A Composite Vector Index is a Global Secondary Index (GSI) with a single vector column that enables hybrid queries to find semantically-related content. +:description: A Composite Vector index is a Global Secondary Index (GSI) with a single vector column that combines scalar queries with semantic search. :stem: :page-toclevels: 3 -:index-name: Composite Vector Index -:index-name-plural: Composite Vector Indexes +:index-name: Composite Vector index +:index-name-plural: Composite Vector indexes {description} -The added vector column lets your application perform a hybrid query using both the index's scalar, array, and object index entries plus a vector value. -See xref:learn:services-and-indexes/indexes/indexes.adoc[] for an overview of GSI and other indexes. +The added vector column lets your application perform a hybrid query using both the index's scalar, array, and object index entries plus a vector similarity search. == How the Composite Vector Index's Vector Column Works -A Composite Vector Index has a single vector column that enables semantic and similarity searches within your {sqlpp} queries. -When creating the index, you use a `VECTOR` key attribute to designate the field that contains the embedded vectors. +The Composite Vector index's single vector column enables semantic and similarity searches within your {sqlpp} queries. +When creating the index, you use a `VECTOR` key attribute to identify the key that contains the embedded vectors. When your query contains an embedded vector, the Query Service uses any non-vector predicates in the query to filter index entries. -Then it performs an index scan on the remaining index entries, using the similarity function you specify in the query to locate similar vectors. -This behavior reduces the number of vector similarity comparisons the Query Service must do to find similar vectors. +Then it performs a vector similarity search to locate semantically related vectors. +Handling the non-vector predicates first reduces the number of vector similarity comparisons the Query Service must do to find similar vectors. == Prerequisites @@ -29,10 +28,10 @@ For more information about how to deploy a new node and Services on your databas * You must have a bucket with scopes and collections in your database. For more information about how to create a bucket, see xref:manage:manage-buckets/create-bucket.adoc[]. -* Your account must have the xref:learn:security:roles.adoc#query-manage-index[Query Manage Index] role to be able to create an index. +* Your account must have the xref:learn:security:roles.adoc#query-manage-index[Query Manage Index] or an administrator role to be able to create an index. * You have documents in a collection that contain one or more vector embeddings. -You can add a single vector to a Composite Vector Index. +You can add a single vector to a Composite Vector index. If your documents contain multiple embedded vectors, you can create multiple indexes---one for each vector attribute. + Embeddings can be an array of floating point numbers or a base64 encoded string. @@ -57,16 +56,19 @@ include::partial$index-algorithm-settings.adoc[] == Create a Composite Vector Index -Creating a Composite Vector Index is similar to creating a non-vector GSI index. +Creating a Composite Vector index is similar to creating a non-vector GSI index. See xref:guides:create-index.adoc[] for an overview of creating indexes. -In the `CREATE INDEX` statement to create the Composite Vector Index, add the `VECTOR` lead key attribute after the vector's column name to declare it as an embedded vector. +In the `CREATE INDEX` statement to create the Composite Vector index, add the `VECTOR` lead key attribute after the vector's key name to declare it as an embedded vector. You must also use the `WITH` clause to specify some additional information for the vector column. The format for this clause with the most commonly used parameters is: [source,sqlpp] ---- -WITH { "dimension": , "similarity":, "description":}; +WITH { "dimension": , + "similarity":, + "description": + }; ---- * `dimensions` is an integer value that sets the number of dimensions in the vector. @@ -75,9 +77,9 @@ This value is set by the embedded model you used to embed the vectors. Couchbase {product-name} uses the following strings to represent the proximity functions: + -- -** `COSINE`: xref:use-vector-indexes.adoc#cosine[Cosine Similarity] -** `DOT`: xref:use-vector-indexes.adoc#dot[Dot Product] -** `L2`, `L2_SQUARED`, `EUCLIDEAN`, or `EUCLIDEAN_SQUARED`: xref:use-vector-indexes.adoc#euclidean[Euclidean Distance] +** `COSINE`: xref:vector-index:vectors-and-indexes-overview.adoc#cosine[Cosine Similarity] +** `DOT`: xref:vector-index:vectors-and-indexes-overview.adoc#dot[Dot Product] +** `L2`, `L2_SQUARED`, `EUCLIDEAN`, or `EUCLIDEAN_SQUARED`: xref:vector-index:vectors-and-indexes-overview.adoc#euclidean[Euclidean Distance] -- + For the greatest accuracy, use the distance function you plan to use when querying vector data. @@ -89,46 +91,22 @@ For a full list of the parameters that affect a vector column in a GSI, see *FIX [#examples] === Examples -The following examples show you how to create two Composite Vector Index with a vector column using sample data. +The following examples show you how to create two Composite Vector index with a vector column using sample data. They both use the data from the `color_data_2vectors.zip` file mentioned earlier. -The data in `rgb.json` file looks like this: + +The following query gets a single document from the `rgb` collection in the `vector-sample` bucket's `color` scope. +It truncates the `embedding_vector_dot` attribute to the first four values to improve readability. + +[source,sqlpp] +---- +include::vector-index:example$gsi-vector-idx-examples.sqlpp[tag=get-sample-doc] +---- + +The result of running this query is: [source,json] ---- -[ - { - "id": "#FFEFD5", - "color": "papaya whip", - "brightness": 240.82, - "colorvect_l2": [ - 255, - 239, - 213 - ], - "wheel_pos": "other", - "verbs": [ - "soften", - "mellow", - "lighten" - ], - "description": "Papaya whip is a soft and mellow color that can be described as a light shade of - peach or coral. It has a calming and soothing effect, similar to the tropical fruit it is named - after. This color is perfect for creating a warm and inviting atmosphere, and it pairs well with - other pastel shades or neutral tones. Papaya whip is a versatile color that can be used in both - fashion and interior design, adding a touch of elegance and sophistication to any space.", - "embedding_model": "text-embedding-ada-002-v2", - "embedding_vector_dot": [ - -0.014644118957221508, - 0.017003899440169334, - -0.013450744561851025, - 0.0021356006618589163, - 0.006283756345510483, - 0.01162360142916441, - // . . . - ] - }, - // . . . -] +include::vector-index:example$composite-vector-data.json[tag=sample-doc] ---- ==== Index the RGB Values @@ -202,7 +180,7 @@ Depending on your system, this training can take several seconds. == Query with a Composite Vector Index Column -You query embedded vector attributes that you have indexed in a Composite Vector Index to find similar vectors and therefore similar semantic content. +You query embedded vector attributes that you have indexed in a Composite Vector index to find similar vectors and therefore similar semantic content. To find the most similar vectors, use a `GROUP BY` clause in your query to return the most relevant vectors first. In this clause, call one of two functions that actually performs the vector comparisons: `APPROX_VECTOR_DISTANCE` or `VECTOR_DISTANCE`. The first of these functions is faster, but less precise. @@ -349,45 +327,23 @@ In a production environment, your application calls the same embedding model it For this example, you can use embedded vectors in the `rgb_questions.json` file that's in the `color_data_2vectors.zip` file. This file contains a `question` attribute containing a search prompt for a particular color. -The `couchbase_search_query.knn.vector` attribute contains the embedded vector for the `question` attribute: +The following query gets a single document from the `rgb_questions` collection in the `vector-sample` bucket's `color` scope. +It truncates the `couchbase_search_query.knn.vector` attribute to the first four values to improve readability. + +[source,sqlpp] +---- +include::vector-index:example$gsi-vector-idx-examples.sqlpp[tag=get-sample-doc-question] +---- + +The result of the query shows the content of one of the documents: + [source,json] ---- -[ - { - "id": "#FFEFD5", - "question": "What is the name of the color that is reminiscent of a tropical fruit and has a calming - effect, often used in fashion and interior design?", - "wanted_similar_color_from_search": "papaya whip", - "embedding_model": "text-embedding-ada-002-v2", - "couchbase_search_query": { - "fields": [ - "*" - ], - "knn": [ - { - "field": "embedding_vector_dot", - "k": 3, - "vector": [ - 0.005115953739732504, - 0.004331615287810564, - 0.014279481954872608, - // .... - ] - } - ], - "query": { - "match_none": {} - }, - "sort": [ - "-_score" - ] - } - }, - // ... -] +include::vector-index:example$composite-vector-data.json[tag=sample-doc-question] ---- +The `couchbase_search_query.knn.vector` attribute contains the embedded vector for the `question` attribute. This example queries the `embedding_vector_dot` column. It appears here with most of the 1536 vectors omitted: diff --git a/modules/vector-index/pages/hyperscale-filter.adoc b/modules/vector-index/pages/hyperscale-filter.adoc new file mode 100644 index 000000000..ef1b67936 --- /dev/null +++ b/modules/vector-index/pages/hyperscale-filter.adoc @@ -0,0 +1,58 @@ += Use Scalar Columns to Filter Hyperscale Vector Index Scans +:page-topic-type: guide +:page-ui-name: {ui-name} +:page-product-name: {product-name} +:description: You can reduce the number of vectors a query that uses a Hyperscale Vector index by adding scalar values. +:stem: +:page-toclevels: 3 +:index-name: Hyperscale Vector index +:index-name-plural: Hyperscale Vector indexes + +[abstract] +{description} +A Hyperscale Vector index has a single column that indexes the vector. +However, you can include scalar values in the index that you can use to filter the vector search. +These included values are stored along with the vector in the index, but they're not indexed. + +In your queries that use a Hypserscale Vector index, you add the included scalar values as predicates in the `WHERE` clause. +During the index scan, Couchbase {propduct-name} uses the included scalar values to filter out vectors that do not meet the filter restriction. +If the filter matches the vector entry, Couchbase {product-name} performs the more expensive vector comparison operation to see if the vector matches the search vector. + +== Creating a Hyperscale Vector Index with Included Scalar Values + +When you create a Hyperscale Vector index, you can add scalar values to the index using the `INCLUDE` clause in the `CREATE VECTOR INDEX` statement. + +The following example creates a new Hyperscale Vector index for the `embedding-vector-dot` vector column from the xref:vector-index:hyperscale-vector-index.adoc#query-example[Hyperscale Vector Index Query Example]. +It also includes the `brightness` key from the document. + + +[source,sqlpp] +---- +include::vector-index:example$hyperscale-idx-examples.sqlpp[tag=create-idx-brightness] +---- + +This example is the same as the example from xref:vector-index:hyperscale-vector-index.adoc#examples[Create Hyperscale Vector Index Example], except that it adds the `INCLUDE` clause to add the `brightness` key. + +=== Querying a Hyperscale Vector Index with Included Scalar Values + +When you query a Hyperscale Vector index, you can use the included scalar values as predicates in the `WHERE` clause of your query. + +When your query adds predicate, Couchbase {product-name} uses it to filter the results before performing the vector index scan. + +The following example performs the same query as the example from xref:vector-index:hyperscale-vector-index.adoc#example[Query with a Hyperscale Vector Index], but adds the `brightness` key as a predicate in the `WHERE` clause: + +[source,sqlpp] +---- +include::vector-index:example$hyperscale-idx-examples.sqlpp[tag=query-rgb-with-brightness] +---- + +The result of running the query is: + +[source,json] +---- +include::vector-index:example$hyperscale-idx-data.json[tag=query-rgb-brightness] +---- + +Querying with the `brightness` attribute changes makes `sky blue` the top result compared to the results from the example in xref:vector-index:hyperscale-vector-index.adoc#query-example[Query with a Hyperscale Vector Index]. +The restriction can also make the query faster. +On a system running a three-node cluster in Docker containers, the query ran in (43{nbsp}ms verses 219{nbsp}ms for the query without the filter. diff --git a/modules/vector-index/pages/hyperscale-reranking.adoc b/modules/vector-index/pages/hyperscale-reranking.adoc new file mode 100644 index 000000000..85791f4be --- /dev/null +++ b/modules/vector-index/pages/hyperscale-reranking.adoc @@ -0,0 +1,89 @@ += Hyperscale Vector Index Reranking and Full Vector Persistence +:page-title: Reranking and Full Vector Persistence +:page-topic-type: guide +:page-ui-name: {ui-name} +:page-product-name: {product-name} +:description: You can enable reranking in queries using a Hyperscale Vector index to potentially improve the query results. +:stem: +:page-toclevels: 3 +:index-name: Hyperscale Vector index +:index-name-plural: Hyperscale Vector indexes + +[abstract] +{description} +It uses non-quantized versions of the search and indexed vectors to return more accurate results. +After the query locates similar vectors in the index, it performs a second round of comparisons using the full vector values stored in the index to reorder the results. +This reranking can make the most relevant vectors to the search vector appear higher in the search results. + +== Enabling Reraniking + +To enable reranking, your index must have a copy the full vector value in addition to the quantized value. +The `CREATE VECTOR INDEX` statement adds this copy of the full vector value to the index by default. + +Queries do not perform reranking by default. +To enable it, you must pass `TRUE` as the fifth parameter in the `APPROX_VECTOR_DISTANCE` function call in your query. + +For example, the following query on the sample RGB dataset does not perform reranking: + +[source,sqlpp] +---- +include::vector-index:example$hyperscale-idx-examples.sqlpp[tag=rerank-before-example] +---- + +The results of this query are: + +[source,json] +---- +include::vector-index:example$hyperscale-idx-data.json[tag=rerank-before] +---- + +The color that's most relevant to the search vector, `#FFFFE0` Light Yellow, is third in the results. + +The following query enables reranking by passing `TRUE` as the fifth parameter in the `APPROX_VECTOR_DISTANCE` function call: + +[source,sqlpp] +---- +include::vector-index:example$hyperscale-idx-examples.sqlpp[tag=rerank-after-example] +---- + +The results of this query are: + +[source,json] +---- +include::vector-index:example$hyperscale-idx-data.json[tag=rerank-after] +---- + +The result for Light Yellow improved from position 3 to position 2. + +[#prevent-vector-persistence] +== Preventing Vector Persistence + +Reranking can improve the accuracy of recall in some cases. +However, it always decreases queries per second (QPS) when enabled. +In many cases, you can achieve acceptable recall accuracy without reranking. +See xref:vector-index:vector-index-best-practices.adoc#reranking[Reranking] to learn in which cases reranking is useful. + +Storing the full vector in the index significantly increases the size of the index. +If you do not plan to use reranking, you can save space in your index by having it not save the full vector value. + +To prevent persisting the full vector, set the `persist_full_vector` attribute to `False` in the `WITH` clause of the `CREATE VECTOR INDEX` statement you use to create the index: + +[source,sqlpp] +---- +WITH { "dimension": , + "similarity":, + "description":, + "persist_full_vector":false + }; +---- + +The following example creates a Hyperscale Vector index from the example RGB dataset that does not persist the full vector value: + +[source,sqlpp] +---- +include::vector-index:example$hyperscale-idx-examples.sqlpp[tag=create-rgb-no-persist] +---- + +The size of the resulting index is much smaller than the index that persists the full vector value (269KiB verses 1.17MiB). + +The actual savings you see in your own indexes depends on the number of dimensions in your vectors. diff --git a/modules/vector-index/pages/hyperscale-vector-index.adoc b/modules/vector-index/pages/hyperscale-vector-index.adoc index dfa4acce3..17a5e912c 100644 --- a/modules/vector-index/pages/hyperscale-vector-index.adoc +++ b/modules/vector-index/pages/hyperscale-vector-index.adoc @@ -8,6 +8,7 @@ :index-name: Hyperscale Vector index :index-name-plural: Hyperscale Vector indexes +[abstract] {description} They can scale up to a billion documents containing vectors with a large number of dimensions. @@ -35,7 +36,7 @@ For more information about how to deploy a new node and Services on your databas * You must have a bucket with scopes and collections in your database. For more information about how to create a bucket, see xref:manage:manage-buckets/create-bucket.adoc[]. -* Your account must have the xref:learn:security:roles.adoc#query-manage-index[Query Manage Index] role, to be able to create an index. +* Your account must have the xref:learn:security:roles.adoc#query-manage-index[Query Manage Index] or an administrator role to be able to create an index. * You have documents in a collection that contain one or more vector embeddings. You can add a single vector to a Hyperscale Vector Index. @@ -55,13 +56,14 @@ For example, OpenAI API's `text-embedding-ada-002` embedding model creates vect * You must decide what algorithms you want your index to use. These algorithms affect how much memory your index uses and the amount of processing Couchbase {product-name} must perform to train and search them. -See xref:vector-index:vectors-and-indexes-overview.adoc#index-algorithms[Indexing Algorithms] +See xref:vector-index:vectors-and-indexes-overview.adoc#index-algorithms[Indexing Algorithms]. +[#create-index] == Create a Hyperscale Vector Index Use the `CREATE VECTOR INDEX` statement to create a Hyperscale Vector Index. This statement is similar to the `CREATE INDEX` statement that you use to create Global Secondary Indexes (GSI). See xref:guides:create-index.adoc[] for an overview of creating indexes. -You must also supply a `WITH` clause to set some additional information for the Hypsercale index needs about the vector column. +You must also supply a `WITH` clause to set some additional information about the vector column that the Hypsercale index needs. The syntax for the `CREATE VECTOR INDEX` with the most common parameters is: @@ -86,9 +88,9 @@ The embedded model you use to embed the vectors determines the number of dimensi Couchbase {product-name} uses the following strings to represent the proximity functions: + -- -** `COSINE`: xref:use-vector-indexes.adoc#cosine[Cosine Similarity] -** `DOT`: xref:use-vector-indexes.adoc#dot[Dot Product] -** `L2`, `L2_SQUARED`, `EUCLIDEAN`, or `EUCLIDEAN_SQUARED`: xref:use-vector-indexes.adoc#euclidean[Euclidean Distance] +** `COSINE`: xref:vector-index:vectors-and-indexes-overview.adoc#cosine[Cosine Similarity] +** `DOT`: xref:vector-index:vectors-and-indexes-overview.adoc#dot[Dot Product] +** `L2`, `L2_SQUARED`, `EUCLIDEAN`, or `EUCLIDEAN_SQUARED`: xref:vector-index:vectors-and-indexes-overview.adoc#euclidean[Euclidean Distance] -- + For the greatest accuracy, use the distance function you plan to use to query the data. @@ -97,17 +99,17 @@ See <<#algo_settings>> in the next section for more information. include::partial$index-algorithm-settings.adoc[] -For a full list of the parameters that affect a vector column in a GSI, see *FIXME:TDB*. + [#examples] -=== Create Hyperscale Vector Index Examples +=== Create Hyperscale Vector Index Example The examples in this section use a dataset that contains information about colors, including a text description of the color. There's also a field named `couchbase_search_query.knn.vector` that contains an embedded vector for the color description. include::vector-search:partial$download-sample-partial.adoc[] -The following query returns a sample document from the data in the `vector-sample.color.rgb`collection, truncating the embedded vector to 4 values to make the result readable: +The following query returns a sample document from the data in the `vector-sample.color.rgb` collection, truncating the embedded vector to 4 values to make the result readable: [source,sqlpp] ---- @@ -116,6 +118,7 @@ include::vector-index:example$hyperscale-idx-examples.sqlpp[tag=rgb-entry] The result of running the query is: +[#example-results] [source,json] ---- include::vector-index:example$hyperscale-idx-data.json[tag=rgb-document] @@ -144,7 +147,8 @@ In most cases, you'll not use these settings in a production environment. == Query with a Hyperscale Vector Index -To use your Hyperscale Vector index, use the `SELECT` statement with a `WHERE` clause that contains a vector value. +To use your Hyperscale Vector index, use the `SELECT` statement with a `ORDER BY` clause containing a call to the `APPROX_VECTOR_DISTANCE` function. +This function performs the vector search using the Hyperscale Vector index. A typical query looks like this: [source,sqlpp] @@ -162,9 +166,6 @@ SELECT The `search-vector-value` is the vector Couchbase {product-name} will search for in the index. It can be an array of floating point numbers or a base64 encoded string. -To return the most relevant vectors, use a `ORDER BY` clause to order the results based on the similarity of the vectors. -In this clause, the call to the `APPROX_VECTOR_DISTANCE` function (also known as `ANN`) performs the vector search. - NOTE: You can also call the function `VECTOR_DISTANCE` to find similar vectors. However, this function does not use the Hyperscale Vector index to perform the vector search. Instead, it performs a brute-force search for similar vectors. @@ -172,6 +173,7 @@ Instead, it performs a brute-force search for similar vectors. Also use a `LIMIT` clause to return just the number of results you need. The query pushes the `LIMIT` clause down into the index scan so that the scan ends after finding the requested number of matches. +[#query-example] === Hyperscale Vector Index Query Example You must supply a vector value in your query that Couchbase {product-name} can compare to the vectors in the index. @@ -179,9 +181,9 @@ In actual use, your application generates a vector for the query value using th To avoid the complication of calling an embedding function, this example uses embedded vectors in the `rgb_questions.json` file that's included in `color_data_2vectors.zip`. The contents of this file are loaded into a collection named `vector-sample.color.rgb-questions`. -This collection contains a `question` attribute containing a search prompt for a particular color. +This collection contains a `question` attribute which is a search prompt for a particular color. The `couchbase_search_query.knn.vector` attribute contains the embedded vector for the `question` attribute. -The following query lists several attributes from a document. +The following query lists several attributes from a document in the collection. It truncates the `couchbase_search_query.knn.vector` attribute to just the first 4 dimensions of the vector for readability: [source,sqlpp] @@ -209,14 +211,17 @@ In this example, the `APPROX_VECTOR_DISTANCE` function compares the vector in th The parameters the example passes to this function are: * The `embedding-vector-dot` is the name of the indexed vector key. -* The vector value to compare to the vectors in the index, which is the result of the subquery that gets the `couchbase_search_query.knn[0].vector` from the `rgb-questions` collection. +* The `couchbase_search_query.knn[0].vector`` is the vector value to compare to the vectors in the index. +This value is the result of the subquery that gets the vector from the `rgb-questions` collection. * `l2` is the distance function to use. * `4` is the number of centroids to probe for matching vectors. +This value defaults to `1`. This example sets this value to 4 because the dataset is small. In a small dataset, it's more likely that relevant vectors are not associated with the same centroid. This parameter broadens the search beyond a single centroid to find more relevant vectors. If you re-run the query with the default value of 1, you'll see that the results are less relevant. + The result of running the query is: [source,json] @@ -227,214 +232,5 @@ include::vector-index:example$hyperscale-idx-data.json[tag=query-rgb-color] The second result, `sky blue`, matches the `wanted_similar_color_from_search` attribute as the most relevant color to the question posed in the `question` attribute. All of the results are still relevant to the question. -== Filter Hyperscale Vector Index Scans with Scalar Columns - -The Hyperscale Vector index contains a single vector column. -However, you can reference non-vector attributes in an `INCLUDE` clause when creating your index. -These attributes are not indexed in the Hyperscale Vector index, but you can use them to filter the results of a vector search. -During the search, Couchbase {propduct-name} uses the attributes to filter the index entries before performing the vector index scan. - -The following example creates a new Hyperscale Vector index that indexes the `embedding-vector-dot` vector column and includes the `brightness` key `vector-sample.color.rgb` collection: - -[source,sqlpp] ----- -include::vector-index:example$hyperscale-idx-examples.sqlpp[tag=create-idx-brightness] ----- - -This example is identical to the earlier `CREATE VECTOR INDEX` example, except that it adds the `INCLUDE` clause to add the `brightness` key. - -When you query the vector key and add one of the included keys as a predicate, Couchbase {product-name} uses the predicate to filter the results before performing the vector index scan. - -The following example performs the same query ast he previous example, but adds the `brightness` key as a predicate in the `WHERE` clause: - -[source,sqlpp] ----- -include::vector-index:example$hyperscale-idx-examples.sqlpp[tag=query-rgb-with-brightness] ----- - -The result of running the query is: - -[source,json] ----- -include::vector-index:example$hyperscale-idx-data.json[tag=query-rgb-brightness] ----- - -[#prevent-vector-persistence] -== Prevent Full Vector Persistence - -The Hyperscale Vector index always quantizes the vectors it contains. -See xref:vectors-and-indexes-overview.adoc#quantization[Quantization] for more information about quantizing vectors. -You choose which type of quantization it uses when you create it. - -By default, a Hyperscale Vector index also stores a copy of the original vector value. -It uses the full value when ranking the search results to make the rankings more accurate. - -You can choose to turn off this feature if the cost of storing and comparing full vector values during ranking causes performance issues. -You can prevent persisting the full vector by setting the `persist_full_vector` attribute to false in the `WITH` clause when you create the index: - -[source,sqlpp] ----- -WITH { "dimension": , - "similarity":, - "description":, - "persist_full_vector":false - }; ----- - -The following example creates a Hyperscale Vector index that does not persist the full vector value: - -[source,sqlpp] ----- -include::vector-index:example$hyperscale-idx-examples.sqlpp[tag=create-rgb-no-persist] ----- - -The size of the resulting index is much smaller than the index that persists the full vector value (269KiB verses 1.17MiB). - -== Hypervector Index Best Practices - -When creating and querying Hyperscale Vector indexes, you have several options to set that can affect the speed and accuracy of your results. -Couchbase has performed testing to determine how these options affect the performance of Hyperscale Vector indexes. -The following sections describe the results of the testing and recommendations besed on these results. - -=== Tuning Index Creation - -When you create a Hyperscale Vector index, you can set the parameters in the following list. -Each of them has the potential to affect the performance of box creating the index and the speed and accuracy of queries that use the index. - -nList:: -Sets the number of clusters (centroids) in the index. -You set the nList by supplying a value after the `IVF` in the `description` parameter when you create your index. -This value affects the accuracy of the index and the speed of queries that use it. -The default value for this value depends on the size of your dataset. -For datasets with less than 1 million vectors, the default value is the number of vedctors divided by 1000. -For datasets with more than 1 million vectors, the default value is the square root of the number of vectors. - -+ -Tests show that increasing nList beyond the default does not affect the build time of the index. -However, it does improve the queries per second (QPS) that the index can handle. -It also lowers the latency of queries that use the index. - -+ -*Recommendation:* if you find that your query throughput and latency is not meeting your needs, you can try rebuilding the index with a larger nList value. - -Trainlist:: -Sets the number of vectors that Couchbase {product-name} considers when searching for centroids in the dataset. -You set it using the `trainlist` key in the `WITH` clause when you create your index. -The default value is roughly 50 times the number of centroids in the index. - -+ -Tests show that increasing the trainlist improves QPS and reduces latency, but slightly increases memory usage for the index. - -+ -*Recommendation:* if you find that increasing the nList does not improve your query performance, you can try increasing the trainlist value. - -Partitions:: -Sets how the index is split among logical shards. -This setting affects the scalability, memory distribution, and parrarlelism of the index. -You set this value using the `PARTITION BY` clause in the `CREATE VECTOR INDEX` statement. - -+ -Tests show that increasing the number of partitions results in a linear reduction of both the time it takes to build and train the index and index's memory use. -These changes do not affect the QPS or latency of queries that use the index. - -+ -*Recommendation:* if the length of time it takes to build the index or the amount of memory the index uses is a concern, you can try increasing the number of partitions. - -Replicas:: -Sets the number of replicas for the index. -This setting affects the fault tolerance, query throughput, and memory footprint of the index. -You set this value using the `num_replicas` key in the `WITH` clause when you create or alter your index. - -+ -Tests show that increasing the number of replicas results in a linear increase in the QPS and linear reduction in latency of queries that use the index. -However, it also linearly increased the memory footprint of the index. -Adding replicas does not affect the time it takes to build the index. - -+ -*Recommendation:* if you find that your query throughput or latency is not meeting your needs, you can try increasing the number of replicas for the index if you can afford the additional memory usage. - -Quantization:: -Sets the quantization method used by the index. -Couchbase {product-name} supports two quantization methods: xref:vector-index:vectors-and-indexes-overview.adoc#sq[scalar quantization (SQ)] and xref:vector-index:vectors-and-indexes-overview.adoc#pq[product quantization (PQ)]. -You set the quantization method using the `description` parameter in the `WITH` clause when you create your index. - -+ -Couchbase tested different quantization settings using datasets that differed in size and number of dimensions. -The results of these tests appear in the following table: - -+ -[%autowidth, options="header"] -|=== -| Dataset | Quantization Setting | Build Time | Memory Use | Recall Accuracy | QPS | Latency - -| 100 Million 128 dimensions -| SQ8 -| Lowest -| Highest -| Best -| Best -| Best - -| 5 Million, 1536 dimensions -| PQ32x8 -| Slightly higher than SQ8 -| 75% less than SQ8 -| lower than SQ8 -| Lower than SQ8 -| Lower than SQ8 - -|=== - -+ -NOTE: Couchbase also tested 1 billion vectors with 128 dimensions with SQ4 quantization. -The result showed acceptable recall accuracy and similar performance to SQ8 on smaller datasets. - -+ -*Recommendations:* - -+ --- -* SQ8 provides the best balance between memory use, recall, for lower dimensional datasets. -* If you have a low-dimensional dataset that is in the billion vector range, consider using SQ4 quantization. -* Use PQ for higher-dimensional datasets where you want to reduce memory use with the tradeoff of less accurate recall, lower QPS, and higher latency. --- -// Similarity Function:: -// Sets the function the index uses when determining the similarity of vectors when identifying centroids. -// Couchbase {product-name} supports two similarity -// -// Holding off on simlarity because the best practice doc is mute on it, also lacks testing for dot? - - -== Tuning Queries - -When querying a Hyperscale Vector index, you can set several parameters in the `APPROX_VECTOR_DISTANCE` (`ANN`) function that affect the performance of the query. -The following list describes the parameters you can set in the function: - -nProbes:: -Sets the number of centroids in the Hyperscale Vector index to ton search for similar vectors. -You optionally set this value as the fourth parameter in the `APPROX_VECTOR_DISTANCE` function call in your query. -The default value for this value is 1, meaning that the query only searches for similar vectors in the centroid that is closest to the search vector. - -+ -Testing found that increasing nProbes beyond the default improves the accuracy of results non-linearly (higher values show diminishing improvements). -However, it caused a linear decrease in QPS and increase in latency. - -+ -*Recommendation:* if you find that your query recall is not meeting your needs, you can try increasing the nProbes value. -However, increasing this value reduces QPS and increases latency. - -[#reranking] -Reranking:: -Sets whether the query performs a second ranking phase where it compares the full vector values of the results to the search vector. -This setting is disabled by default. -You can enable it by passing TRUE as the fifth parameter in the `APPROX_VECTOR_DISTANCE` function call in your query. - -+ -Testing has shown that enabling reranking improves the accuracy of recall in only a few cases and significantly decrease QPS. - -+ -*Recommendation:* if you find recall accuracy is not meeting your needs and you are using SQ4 or PQ128x8 or below quantization, you can try enabling reranking. -You must also have your index set to persist the full vector value, which increases memory use. - diff --git a/modules/vector-index/pages/use-vector-indexes.adoc b/modules/vector-index/pages/use-vector-indexes.adoc index 2410904a2..e8f20a231 100644 --- a/modules/vector-index/pages/use-vector-indexes.adoc +++ b/modules/vector-index/pages/use-vector-indexes.adoc @@ -7,7 +7,7 @@ {description} -You cam add vectors to Couchbase {product-name} indexes. +Couchbase {product-name} suports three types of vector indexes. You store index values as attributes in your documents, and then index those attributes. You can then find relevant data by executing queries on the vector attributes, which use the index to find similar vectors. @@ -18,7 +18,7 @@ Using indexes reduces the resources needed to perform vector searches. If you're unfamiliar with vectors and vector indexing, see xref:vectors-and-indexes-overview.adoc[] for an overview. -You can include vectors in three types of Couchbase {product-name} indexes: +The three types of Couchbase {product-name} indexes that support vector searches are: Hyperscale Vector Indexes:: These indexes are specifically designed for vector searches. @@ -36,7 +36,7 @@ Composite Vector Indexes:: Composite Vector indexes combine a standard GSI index with a single vector column. This combination lets you perform a hybrid search using a single vector value with standard scalar attributes that are also indexed in the Composite Vector Index. The scalar attributes in a query reduce the number of vectors the Couchbase {product-name} has to compare when performing an index scan to find similar vectors. -Use GSI indexes with a vector column when you want to perform hybrid searches of documents using both scalars and a vector. +Use Composite VectorI indexes when you want to perform hybrid searches of documents using both scalars and a vector. They work well for cases where your queries are highly selective---returning a small number of results from a large dataset. They consume a moderate amount of memory and can index billions of documents. @@ -106,22 +106,22 @@ Limited to approximately 100 million documents When choosing which type of index to use, consider the following: -* If your dataset will not grow beyond 100 million documents, you can consider Composite Vector or FTS Vector indexes, especially if you need to perform hybrid searches. +* If your dataset will not grow beyond 100 million documents, consider Composite Vector or FTS Vector indexes, especially if you need to perform hybrid searches. * If your dataset is larger than or may grow larger than 100 million documents, use a Hyperscale Vector index. * When in doubt, try using a Hyperscale Vector index. If you find that the performance is not what you need, you can try using one of the other index types. == Applications for Vector Indexes -Each type of index is suited to different types of applications. +Each type of index works best for different types of applications. The following sections explain several common applications for each type of vector index. They also describe the workflow your application follows when using each type of index. === Hyperscale Vector Index Applications Hyperscale Vector indexes contain a single vector column. -They excel at huge dataset that can scale into the billions of documents. -They are optimized for pure vector searches, such as content discovery or recommendations. +They excel at indexing huge datasets that can scale into the billions of documents. +They're optimized for pure vector searches, such as content discovery or recommendations. The Hyperscale Vector index works well for applications such as: @@ -133,9 +133,11 @@ Chatbot context for workflows like retreival-augmented generation (RAG) requires The large dataset gives the chatbot a depth of knowledge that's not necessary in simpler applications. Anomaly detection:: -Anomaly detection applications such as those used in Internet of Things (IoT) sensor networks, require huge datasets to find deviations from normally occurring patterns. +Anomaly detection applications such as those used in Internet of Things (IoT) sensor networks, require huge datasets to find deviations from normally occurring patterns. Hyperscale Vector indexes can handle the large datasets and perform these vector searches fast. +=== Hyperscale Vector Index Application Workflow + When using a Hyperscale Vector index, your application follows the workflow shown in the following diagram: .Application Workflow with Hyperscale Vector Indexes @@ -145,6 +147,7 @@ include::vector-index:partial$hyperscale-vector-app-workflow.puml[] .... The steps shown in the diagram are: + . When your application loads data with a complex data field it wants to search semantically, it calls an embedding model to generate a vector for it. . It sends the data, including the vector, to Couchbase {product-name} for storage. . The Data Service sends the embedded vector to the Indexing Service for inclusion in the Hyperscale Vector index. @@ -173,6 +176,7 @@ Supply chain management:: Supply chain management applications often need to query based on product type, supplier, or location. Vector similarity searches can be added to these searches to find similar demand patterns. +=== Composite Vector Index Application Workflow When using a Composite Vector index, your application follows the workflow shown in the following diagram: @@ -198,20 +202,20 @@ See xref:vector-index:composite-vector-index.adoc[] for more information about C [#fts] === FTS Vector Index Applications -FTS Vector indexes contain a single vector column in addition to a full-text search index. +FTS Vector indexes contain a single vector column in addition to a Full-Text Search index. Some of the applications for FTS Vector indexes include: E-Commerce product recommendations:: E-Commerce applications can use scalar, text, and vector searches to find products that match a customer's search. -For example, a customer could search for red sneakers (text) that cost less than $100 (scalar) that are similar to an uploaded image of a sneaker (vector). +For example, a customer could search for red sneakers (text) that cost less than $100 (scalar) and are similar to an uploaded image of a sneaker (vector). Travel recommendations:: Users often want to search for hotels using multiple criteria: + * Limiting searches to a specific area (for example, "walking distance to the Louvre") which relies on geospacial data. -* Specific keywords for features they want ("quiet", "romantic", "gym") which requires Full-Text search. -* Semantic searches of descriptions and reviews for searches that do not rely on literal texzt matches ("modern beach resort with chic decor") which requires vector searches. +* Specific keywords for features they want ("quiet", "romantic", "gym") which requires Full-Text Search. +* Semantic searches of descriptions and reviews for searches that do not rely on literal text matches ("modern beach resort with chic decor") which requires vector searches. + An FTS vector index can combine geospacial, keyword, and semantic searches into a single index. @@ -231,7 +235,7 @@ include::vector-index:partial$fts-vector-app-workflow.puml[] The steps shown in the diagram are: . When your application loads data it wants to search semantically, it calls an embedding model to generate a vector for it. -. It sends the data and the vector, to Couchbase {product-name} for storage. +. It sends the data and the vector to Couchbase {product-name} for storage. . The Data Service sends the embedded vector along with scalar fields to the Search Service for inclusion in the FTS Vector index. . When your application needs to perform a search that includes a vector, it uses the same embedding model to generate a vector for the search value. . It sends the search vector and text, geospacial, and other search values as part of a search request to the Couchbase {product-name} Search Service. diff --git a/modules/vector-index/pages/vector-index-best-practices.adoc b/modules/vector-index/pages/vector-index-best-practices.adoc new file mode 100644 index 000000000..9274a9b82 --- /dev/null +++ b/modules/vector-index/pages/vector-index-best-practices.adoc @@ -0,0 +1,162 @@ += Hyperscale and Composite Vector Index Best Practices +:page-topic-type: guide +:page-ui-name: {ui-name} +:page-product-name: {product-name} +:description: When creating and querying Hyperscale and Composite Vector indexes, you have several options to set that can affect the speed and accuracy of your results. +:stem: +:page-toclevels: 3 + +[abstract] +{description} +Couchbase has performed testing to determine how index creation and query options affect the performance of Hyperscale and Composite Vector indexes. +The following sections describe the results of the testing and recommendations based on these results. + +NOTE: Most of the tests were performed using the Hyperscale Vector index. +However, many of the the results also apply to Composite Vector indexes where the two index types share the same settings. + +== Tuning Index Creation + +When you create a Hyperscale Vector index, you can set the parameters in the following list. +Each of them has the potential to affect the performance of box creating the index and the speed and accuracy of queries that use the index. + +nList:: +Sets the number of clusters (centroids) in the index. +You set the `nList` by supplying a value after the `IVF` in the `description` parameter when you create your index. +This value affects the accuracy of the index and the speed of queries that use it. +The default value for this value depends on the size of your dataset. +For datasets with less than 1 million vectors, the default value is the number of vectors divided by 1000. +For datasets with more than 1 million vectors, the default value is the square root of the number of vectors. + ++ +Tests show that increasing `nList` beyond the default does not affect the build time of the index. +However, it does improve the queries per second (QPS) that the index can handle. +It also lowers the latency of queries that use the index. + ++ +*Recommendation:* if you find that your query throughput and latency is not meeting your needs, you can try rebuilding the index with a larger `nList` value. + +Trainlist:: +Sets the number of vectors that Couchbase {product-name} considers when searching for centroids in the dataset. +You set it using the `trainlist` key in the `WITH` clause when you create your index. +The default value is roughly 50 times the number of centroids in the index. + ++ +Tests show that increasing the `trainlist` improves QPS and reduces latency, but slightly increases memory usage for the index. + ++ +*Recommendation:* if you find that increasing the `nList` does not improve your query performance, you can try increasing the `trainlist` value. + +Partitions:: +Sets how the index is split among logical shards. +This setting affects the scalability, memory distribution, and parallelism of the index. +You set this value using the `PARTITION BY` clause in the `CREATE [VECTOR] INDEX` statement. + ++ +Tests show that increasing the number of partitions linearly reduces both the time it takes to build and train the index and index's memory use. +These changes do not affect the QPS or latency of queries that use the index. + ++ +*Recommendation:* if the length of time it takes to build the index or the amount of memory the index uses is a concern, you can try increasing the number of partitions. + +Replicas:: +Sets the number of replicas for the index. +This setting affects the fault tolerance, query throughput, and memory footprint of the index. +You set this value using the `num_replicas` key in the `WITH` clause when you create or alter your index. + ++ +Tests show that increasing the number of replicas learly increases the QPS and linerly reduces the latency of queries that use the index. +However, it also linearly increased the memory footprint of the index. +Adding replicas does not affect the time it takes to build the index. + ++ +*Recommendation:* if you find that your query throughput or latency is not meeting your needs, you can try increasing the number of replicas for the index if you can afford the additional memory usage. + +Quantization:: +Sets the quantization method used by the index. +Couchbase {product-name} supports two quantization methods: xref:vector-index:vectors-and-indexes-overview.adoc#sq[scalar quantization (SQ)] and xref:vector-index:vectors-and-indexes-overview.adoc#pq[product quantization (PQ)]. +You set the quantization method using the `description` parameter in the `WITH` clause when you create your index. + ++ +Couchbase tested different quantization settings using datasets that differed in size and number of dimensions. +The results of these tests appear in the following table: + ++ +[%autowidth, options="header"] +|=== +| Dataset | Index Type | Quantization Setting | Build Time | Memory Use | Recall Accuracy | QPS | Latency + +| 100 million 128 dimensions +| Hyperscale +| SQ8 +| Lowest +| Highest +| Best +| Best +| Best + +| 5 million, 1536 dimensions +| Composite +| PQ32x8 +| Slightly higher than SQ8 +| 75% less than SQ8 +| lower than SQ8 +| Lower than SQ8 +| Lower than SQ8 + +|=== + ++ +NOTE: Couchbase also tested Hyperscale Vector indexes containing 1 billion vectors with 128 dimensions using SQ4 quantization. +The results showed acceptable recall accuracy and similar performance to SQ8 on smaller datasets. + ++ +*Recommendations:* + ++ +-- +* SQ8 provides the best balance between memory use, recall, for lower dimensional datasets. +* If you have a low-dimensional dataset that's in the billion vector range, consider using SQ4 quantization. +* Use PQ for higher-dimensional datasets where you want to reduce memory use with the tradeoff of less accurate recall, decreased QPS, and increased latency. +-- + +// Similarity Function:: +// Sets the function the index uses when determining the similarity of vectors when identifying centroids. +// Couchbase {product-name} supports two similarity +// +// Holding off on simlarity because the best practice doc is mute on it, also lacks testing for dot? + + +== Tuning Queries + +When querying a Hyperscale Vector index, you can set several parameters in the `APPROX_VECTOR_DISTANCE` (`ANN`) function that affect the performance of the query. +The following list describes the parameters you can set in the function: + +nProbes:: +Sets the number of centroids in the Hyperscale Vector index to ton search for similar vectors. +You optionally set this value as the fourth parameter in the `APPROX_VECTOR_DISTANCE` function call in your query. +The default value for this value is 1, which only only searches for similar vectors in the centroid that's closest to the search vector. + ++ +Tests found that increasing `nProbes` beyond the default improves the accuracy of results non-linearly (larger values show diminishing improvements). +However, it caused a linear decrease in QPS and increase in latency. + ++ +*Recommendation:* if you find that your query recall is not meeting your needs, you can try increasing the `nProbes`` value. +However, increasing this value reduces QPS and increases latency. + +[#reranking] +Reranking:: +Sets whether a query of a Hyperscale Vector index performs a second ranking phase where it compares the full vector values of the results to the search vector. +See xref:vector-index:hyperscale-reranking.adoc[] for more information about how reranking works. +This setting is off by default. +You can enable it by passing `TRUE` as the fifth parameter in the `APPROX_VECTOR_DISTANCE` function call in your query. + ++ +Testing has shown that enabling reranking improves the accuracy of recall in only a few cases and significantly decrease QPS. + ++ +*Recommendation:* if you find recall accuracy is not meeting your needs and you're using SQ4 or PQ128x8 or below quantization, you can try enabling reranking. +You must also have your index set to persist the full vector value, which increases memory use. +If you do not enable reranking, consider preventing the persistence of the full vector value in the index to reduce memory and disk use. +See xref:vector-index:hyperscale-reranking.adoc#prevent-vector-persistence[Preventing Vector Persistence] to learn how to turn off full vector persistence. + diff --git a/modules/vector-index/pages/vectors-and-indexes-overview.adoc b/modules/vector-index/pages/vectors-and-indexes-overview.adoc index d32389aa3..bb47b8562 100644 --- a/modules/vector-index/pages/vectors-and-indexes-overview.adoc +++ b/modules/vector-index/pages/vectors-and-indexes-overview.adoc @@ -10,7 +10,7 @@ Couchbase {product-name} supports several types of vector indexes. These indexes let you add similarity searches to your applications without relying on external services. This page provides an overview of vectors. -If you're already familiar with vectors, you can skip to the next page, xref:vector-index:use-vector-indexes.adoc[Using Vector Indexes] for information about how to use vector indexes in your application. +If you're already familiar with vectors, you can skip to the next page, xref:vector-index:use-vector-indexes.adoc[] for information about how to use vector indexes in your application. == About Vectors @@ -176,8 +176,8 @@ However, searching a flat index is inefficient. The search must compare every vector in the index to find matches. You should only use it for small data sets or for testing. + -NOTE: Only Search indexes support using a flat index. -Vector indexes and GSI with a vector field only support the next algorithm, IVF. +NOTE: Only FTS Vector indexes support using a flat index. +Hyperscale Vector and Composite Vector indexes only support the next algorithm, IVF. [#IVF] Inverted File (IVF):: @@ -201,7 +201,7 @@ The centroids chosen during the initial training may no longer accurately repres See <<#index-training>> for more information about index accuracy. + Use this method if you want a balance between precision and search speed. -Vector indexes and GSI always use IVF. +Hyperscale Vector and Composite Vector indexes always use IVF. [#quantization] ==== Quantization @@ -303,6 +303,7 @@ You should also consider the potential need to retrain the index if your dataset See the following section for more information about index training. Whichever quantization you choose, you should perform tests to verify it meets your needs. +See xref:vector-index:vector-index-best-practices.adoc[Vector Index Best Practices] for more information about choosing quantization for your Hyperscale Vector and Composite Vector indexes. [#index-training] === The Importance of Index Training diff --git a/modules/vector-index/partials/nav.adoc b/modules/vector-index/partials/nav.adoc index cd1e8ef86..eab2f8610 100644 --- a/modules/vector-index/partials/nav.adoc +++ b/modules/vector-index/partials/nav.adoc @@ -3,9 +3,13 @@ -- ** xref:server:vector-index:use-vector-indexes.adoc[] ** xref:server:vector-index:hyperscale-vector-index.adoc[] +*** xref:server:vector-index:hyperscale-filter.adoc[] +*** xref:server:vector-index:hyperscale-reranking.adoc[] ** xref:server:vector-index:composite-vector-index.adoc[] +** xref:server:vector-index:vector-index-best-practices.adoc[] -- + -- include::vector-search:partial$nav.adoc[] -- + From 80bbd8e6698acf7839e1c301e69116ce2f6c4047 Mon Sep 17 00:00:00 2001 From: Gary Gray <137797428+ggray-cb@users.noreply.github.com> Date: Tue, 15 Jul 2025 16:37:28 -0400 Subject: [PATCH 30/41] Adding anchor to quantization section --- modules/vector-index/pages/vector-index-best-practices.adoc | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/vector-index/pages/vector-index-best-practices.adoc b/modules/vector-index/pages/vector-index-best-practices.adoc index 9274a9b82..5a9abdf38 100644 --- a/modules/vector-index/pages/vector-index-best-practices.adoc +++ b/modules/vector-index/pages/vector-index-best-practices.adoc @@ -71,6 +71,7 @@ Adding replicas does not affect the time it takes to build the index. + *Recommendation:* if you find that your query throughput or latency is not meeting your needs, you can try increasing the number of replicas for the index if you can afford the additional memory usage. +[#quantization] Quantization:: Sets the quantization method used by the index. Couchbase {product-name} supports two quantization methods: xref:vector-index:vectors-and-indexes-overview.adoc#sq[scalar quantization (SQ)] and xref:vector-index:vectors-and-indexes-overview.adoc#pq[product quantization (PQ)]. From 182f1265d67e2e2b0468a691c80ac6304552bc79 Mon Sep 17 00:00:00 2001 From: Gary Gray <137797428+ggray-cb@users.noreply.github.com> Date: Tue, 15 Jul 2025 16:49:21 -0400 Subject: [PATCH 31/41] Various cleanups I missed before rushing off on vacation. --- .../pages/vector-index-best-practices.adoc | 24 ++++++++++--------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/modules/vector-index/pages/vector-index-best-practices.adoc b/modules/vector-index/pages/vector-index-best-practices.adoc index 5a9abdf38..6a61d0dfc 100644 --- a/modules/vector-index/pages/vector-index-best-practices.adoc +++ b/modules/vector-index/pages/vector-index-best-practices.adoc @@ -12,12 +12,12 @@ Couchbase has performed testing to determine how index creation and query option The following sections describe the results of the testing and recommendations based on these results. NOTE: Most of the tests were performed using the Hyperscale Vector index. -However, many of the the results also apply to Composite Vector indexes where the two index types share the same settings. +However, many of the results also apply to Composite Vector indexes where the two index types share the same settings. == Tuning Index Creation When you create a Hyperscale Vector index, you can set the parameters in the following list. -Each of them has the potential to affect the performance of box creating the index and the speed and accuracy of queries that use the index. +Each has the potential to affect the performance of creating the index and the speed and accuracy of queries that use the index. nList:: Sets the number of clusters (centroids) in the index. @@ -38,7 +38,7 @@ It also lowers the latency of queries that use the index. Trainlist:: Sets the number of vectors that Couchbase {product-name} considers when searching for centroids in the dataset. You set it using the `trainlist` key in the `WITH` clause when you create your index. -The default value is roughly 50 times the number of centroids in the index. +The default value is approximately 50 times the number of centroids in the index. + Tests show that increasing the `trainlist` improves QPS and reduces latency, but slightly increases memory usage for the index. @@ -115,9 +115,9 @@ The results showed acceptable recall accuracy and similar performance to SQ8 on + -- -* SQ8 provides the best balance between memory use, recall, for lower dimensional datasets. -* If you have a low-dimensional dataset that's in the billion vector range, consider using SQ4 quantization. -* Use PQ for higher-dimensional datasets where you want to reduce memory use with the tradeoff of less accurate recall, decreased QPS, and increased latency. +* SQ8 provides the best balance between memory use and recall for lower dimensional datasets. +* If you have a low-dimensional dataset that's in the range of a billion vectors, consider using SQ4 quantization. +* Use PQ for higher-dimensional datasets if you want to reduce memory use and are willing to accept less accurate recall, decreased QPS, and increased latency. -- // Similarity Function:: @@ -135,14 +135,14 @@ The following list describes the parameters you can set in the function: nProbes:: Sets the number of centroids in the Hyperscale Vector index to ton search for similar vectors. You optionally set this value as the fourth parameter in the `APPROX_VECTOR_DISTANCE` function call in your query. -The default value for this value is 1, which only only searches for similar vectors in the centroid that's closest to the search vector. +The default value for this value is 1, which only searches for similar vectors in the centroid that's closest to the search vector. + Tests found that increasing `nProbes` beyond the default improves the accuracy of results non-linearly (larger values show diminishing improvements). However, it caused a linear decrease in QPS and increase in latency. + -*Recommendation:* if you find that your query recall is not meeting your needs, you can try increasing the `nProbes`` value. +*Recommendation:* if you find that your query recall is not meeting your needs, you can try increasing the `nProbes` value. However, increasing this value reduces QPS and increases latency. [#reranking] @@ -153,11 +153,13 @@ This setting is off by default. You can enable it by passing `TRUE` as the fifth parameter in the `APPROX_VECTOR_DISTANCE` function call in your query. + -Testing has shown that enabling reranking improves the accuracy of recall in only a few cases and significantly decrease QPS. +Testing has shown that enabling reranking improves the accuracy of recall in limited cases and decreases QPS. + ++ +*Recommendation:* if you find recall accuracy is not meeting your needs and you're using SQ4 or PQ128x8 or below quantization, try enabling reranking. +You must have your index set to persist the full vector value, which increases memory use. + -*Recommendation:* if you find recall accuracy is not meeting your needs and you're using SQ4 or PQ128x8 or below quantization, you can try enabling reranking. -You must also have your index set to persist the full vector value, which increases memory use. If you do not enable reranking, consider preventing the persistence of the full vector value in the index to reduce memory and disk use. See xref:vector-index:hyperscale-reranking.adoc#prevent-vector-persistence[Preventing Vector Persistence] to learn how to turn off full vector persistence. From e45cedef7c6ffa720875e7d5ba811b55f66d26ed Mon Sep 17 00:00:00 2001 From: Gary Gray <137797428+ggray-cb@users.noreply.github.com> Date: Wed, 23 Jul 2025 16:41:14 -0400 Subject: [PATCH 32/41] Some updates based on Ankush's feedback. Went down a rabbithole on L2 vs. L2 Square. Also decoupled the discussion of IVF and quantization because you really don't have a say whether IVF is used, and it's orthagonal to choosing a quantization method anyhow. --- .../pages/vectors-and-indexes-overview.adoc | 166 +++++++++++++----- 1 file changed, 118 insertions(+), 48 deletions(-) diff --git a/modules/vector-index/pages/vectors-and-indexes-overview.adoc b/modules/vector-index/pages/vectors-and-indexes-overview.adoc index bb47b8562..d0054e53c 100644 --- a/modules/vector-index/pages/vectors-and-indexes-overview.adoc +++ b/modules/vector-index/pages/vectors-and-indexes-overview.adoc @@ -1,6 +1,7 @@ = Vectors and Vector Indexes Overview :page-topic-type: concept :page-ui-name: {ui-name} +:stem: latexmath :page-product-name: {product-name} :description: This page is a high-level overview of vectors and adding vector values to indexes. :page-toclevels: 3 @@ -111,12 +112,12 @@ endif::[] == Vector Similarity Once you have embedded vectors in your database, you find documents with a similar meaning by finding similar vectors. -Several algorithms exist that you can use to find similar vectors (often referred to as the distance function). -When you add vectors to a Couchbase {product-name} index, you must specify which distance function to use to compare vectors. -Each function is suited for different types of data. -This distance function usually must match the distance function the embedding model used when generating the vectors. +You use metrics to (also referred to as distance functions) to find similar vectors. +When you add vectors to a Couchbase {product-name} index, you must specify which metric to use to compare vectors. +Each metric works best for different types of data. +In most cases, the metric you select when comparing vectors matches the metric the embedding model used when generating the vectors. -Couchbase {product-name} supports three distance function: +Couchbase {product-name} supports four metrics: [#euclidean] Euclidean Distance (also known as L2):: @@ -127,33 +128,88 @@ Use this method when the proximity of the vectors and their magnitudes are impor + image::euclidean-distance-example.svg["Three-dimensional plot showing two vectors with points along each vector joined by dotted lines, indicating the summing of corresponding points."] + -Euclidean Distance is useful for tasks such as image similarity searches. -Vectors for similar images tend to form clusters within vector space. +Euclidean Distance is useful for tasks such as: + ++ +* . +* 3D motion capture where you're detecting similar positions or trajectories of joints, objects, where finding real-world values for thresholds is important. +* Geographic or spatial searches where you care about exact (and often real-world) distances. +* Other cases in which the results are used to in filters in calculations that require the actual distance between the vectors. + ++ +NOTE: Only Hyperscale Vector and Composite Vector indexes support this metric. +FTS Vector indexes do not support it. + +[#euclidean-squared] +Euclidean Squared Distance (also known as L2 Squared or L2^2^):: +This method is similar to Euclidean Distance, but it does not take the square root of the sum distances between the vectors: + ++ +*Euclidean Distance Formula:* latexmath:[L2(x, y) = \sqrt{\sum_{i=1}^n (x_i - y_i)^2}] + ++ +*Euclidean Squared Distance Formula:* latexmath:[L2^2(x, y) = \sum_{i=1}^n (x_i - y_i)^2] + ++ +Because it does not take the square root of the sums, Euclidean Squared Distance is faster to calculate than Euclidean Distance. +However, it does not represent the actual distance between points on the vectors. +The results of a vector search using L2 Squared as a metric always returns the same rankings that an L2 search returns. +However, in cases where the dimensions of the vectors represent real-world values, L2 is more intuitive to use because it returns the actual distance between the vectors. + ++ +Use this method when you need higher performance than Euclidean Distance. +It's better in cases where comparing literal distances is less important than performance and having the ranking of search results is enough. + ++ +For example: + ++ +* Image recognition tasks where real-world distances between vectors are not a factor, including: +** Searching for products that are visually similar to an image uploaded by a shopper. +** Facial recognition. + + ++ +NOTE: Only Hyperscale Vector and Composite Vector indexes support this metric. +FTS Vector indexes do not support it. [#dot] Dot Product:: -Finds related vectors by comparing the magnitude and alignment of the vectors. -In this method, the proximity of the vectors in space is less important than whether they point in a similar direction and have the a similar magnitude. +This metric finds related vectors by comparing the magnitude (length) and alignment of the vectors. +Here, the proximity of the vectors in space is less important than whether they point in a similar direction and have the a similar magnitude. Vectors that point in similar directions (have a low angle between them) and have similar magnitude are strongly associated with each other. This method uses the similarity of the vectors' magnitudes to rank their relation. + image::dot-product-example.svg["Three-dimensional plot showing two vectors labeled with their magnitudes and the angle between them labeled with the theta symbol."] + -Use this method for tasks such as recommendation engines where you want to rank results from most to least related. +Use this method for tasks where ranking confidence is key. +The magnitude of the vectors is important when determining the strength of the relationship. +For example: + ++ +* Recommending related products based on a shopper's previous purchases. +* Personalizing a music service's user home page based on the user's likes and dislikes of artists. +* Targeting ads based on a user's interests and previous interactions with the service. [#cosine] Cosine Similarity:: -This method is similar to the dot product. +This metric is similar to the dot product. However, it normalizes the vectors (making them the same length) during comparison. Normalization means their magnitudes are not taken into account, just their alignment. This normalization makes this method better for comparing textual data because it's less sensitive to the length of the data. -The magnitude of a vector generated by some textual data embedding models depend on the length of the source text. +The magnitude of a vector generated by some text embedding models depend on the length of the source text. Normalizing vector magnitudes emphasizes the semantic meaning when performing comparisons. Therefore, Cosine Similarity can find the semantic relationship between a short question and a long article that's relevant to answering it. + image::cosine-similarity-example.svg["Three-dimensional plot showing two vectors that are of equal length, with the angle between them labeled as theta."] + -Use this method when you're performing similarity searches on text. +Use this method when you're performing searches that rely on semantic meaning, such as: + ++ +* Find relevant articles to answer a question posed by a user. +* Locate code snippets based on a user's question about how to perform a task. +* Organize scanned documents in a document management system based on their semantic meaning. + [#index-algorithms] === Indexing Algorithms @@ -166,6 +222,8 @@ Couchbase {product-name} supports the algorithms described in the following sect ==== Index Formats Couchbase Server supports two formats for the index, which controls how the index stores the vectors. +It automatically chooses which algorithm to use, based on the type of the index and the size of the dataset. +However, you can set parameters when you create the index that affect how the algorithm organizes data. Flat Index:: This algorithm just stores the full vector value in the index without performing any sort of optimization. @@ -176,7 +234,7 @@ However, searching a flat index is inefficient. The search must compare every vector in the index to find matches. You should only use it for small data sets or for testing. + -NOTE: Only FTS Vector indexes support using a flat index. +NOTE: FTS Vector indexes use a flat index when indexing smaller datasets. Hyperscale Vector and Composite Vector indexes only support the next algorithm, IVF. [#IVF] @@ -188,7 +246,7 @@ An IVF index trains itself during creation using a set of parameters you pass to . For each cluster it finds, it chooses a representative vector (called a centroid). . It creates a data structure called an inverted list that associates all vectors with their closest centroid. + -image::ivf-diagram-with-vectors.svg["A plot showing clusters of points in a 3D graph being labelled and assigned centroid vectors. The centroids them point to multiple vectors."] +image::ivf-diagram-with-vectors.svg["A plot showing clusters of points in a 3D graph labelled and assigned to centroid vectors. The centroids then point to multiple vectors in an inverted list."] + When you search using an IVF index, it first locates the centroids that are most relevant to the vector value you're searching for. It then searches just the vectors associated with those centroids in the inverted list. @@ -200,25 +258,31 @@ This risk increases as you add and delete data after you train the index. The centroids chosen during the initial training may no longer accurately represent clusters in current dataset. See <<#index-training>> for more information about index accuracy. + -Use this method if you want a balance between precision and search speed. Hyperscale Vector and Composite Vector indexes always use IVF. +FTS Vector indexes automatically uses IVF when the indexing larger datasets. +In addition to IVF, Hyperscale Vector indexes also use proprietary optimizations to improve performance for billion-scale indexes. [#quantization] ==== Quantization -Quantization simplifies vector data to consume less storage space in memory and on disk. +Quantization simplifies vector data so it consumes less space in memory and on disk. Reducing the amount of data in a vector also makes vector comparison faster. However, quantization does reduce the accuracy of a vector. +It's similar to using a lossy image compression format, such as JPEG, on an picture to reduce its data size. +It trades off some detail and accuracy for a smaller, more manageable data size. + +Unlike the indexing algorithms, you choose the quantization method you want Couchbase Server to use when you create a Hyperscale Vector or Composite Vector index. Couchbase {product-name} supports two types of quantization: [#pq] Product Quantization (PQ):: -Product Quantization simplifies vector data to reduce its storage and processing requirements. -Quantization is similar to using a lossy image compression format, such as JPEG, on an picture to reduce its data size. -It trades off some detail and accuracy for a smaller, more manageable data size. +Product Quantization simplifies vectors by breaking their dimensions into chunks called subspaces. +It then replaces each set of dimensions within the with a single value that represents the nearest centroid in the subspace. +This method reduces the size of the vector by replacing the original floating point values with smaller integers that represent the centroid. + + -PQ processes vectors using the following steps: +PQ processes vectors by following these steps: + -- . It groups the vector's dimensions into chunks called subspaces. @@ -235,9 +299,6 @@ PQ could quantize the vector in the previous example from 1024 64-bit floating p This data size reduction improves performance because integer operations are less computationally expensive than floating point operations. It also reduces memory use because each vector requires less data to store (for example, from 64KB to 128 bytes). + -You often use PQ in addition to IVF--after quantization, the training process finds centroids in the dataset. -The index stores the centroids the their related vectors in the inverted list using the quantized format. -+ A search of the PQ index performs the same steps on the vector you're searching for: + -- @@ -250,7 +311,9 @@ PQ sacrifices some accuracy because it compares quantized vectors instead of the The process of quantization adds additional processing requirements to training. This overhead makes training a PQ index more computationally expensive than the other methods. However, PQ reduces the amount of memory and processing time necessary when searching for related vectors in a large dataset. -Using this indexing algorithm when: + ++ +Use PQ quantization when: + * Your vectors contain a large number of dimensions. * You're willing to trade higher processing requirements during training for smaller memory use and less CPU time during searches. @@ -259,15 +322,20 @@ Using this indexing algorithm when: [#sq] Scalar Quantization (SQ):: Scalar Quantization is a simpler form of quantization than PQ. -During training: +Instead of breaking the vector into subspaces, it quantizes each dimension of the vector independently. +Its quantized vectors are larger, but are a more precise represenation than than those quantized using PQ. + ++ +SQ follows these steps to process vectors: + . SQ determines the maximum and minimum values for each dimension in the dataset. . It then partitions each dimension in the vector into equal segments (called bins) over the range of the dimension's values. For example, in the diagram, the first dimension's values range from 0 to 1, while the second dimension's range from 0.1 to 0.9. +This means the second dimension's bins will only cover the range from 0.1 to 0.9. . SQ assigns each bin an index value that's from 4 to 8 bits in length. . It find a centroid within the range associated with the bin. It saves the centroid as a 16 or 32 bit floating point number. -. SQ then quantizes the vectors by replacing their dimensional values with the index value of the bin the value falls into. +. SQ then quantizes the vectors by replacing their dimensional values with the index value of the bin the dimnesional value falls into. + image::sq-diagram.svg["Diagram showing each floating point dimension of a vector being converted to an 8-bit integer by looking up which bucket it falls into."] + @@ -278,56 +346,58 @@ A search on an SQ index reassembles vectors before comparing them. For each of the vector's dimensions, SQ replaces the integer bin number with the floating point centroid associated with the bin. This recreation is an approximation of the original vector, because each dimension in the vector is the bin's centroid value instead of the original dimensional value. + -Like the PQ algorithm, you often combine SQ and IVF. -This combination limits the number of vectors that a search has to compare and reduces its memory and processing requirements. -+ Because this method quantizes the vectors, it loses precision. It's less precise than the PQ method (which also quantizes vectors) because it assumes that each dimension can be evenly divided. Its accuracy suffers if your data has clusters. It's best suited for data that's more evenly distributed and does not have high correlations. For example, SQ may be a good fit for an IoT sensor dataset where the measured values (such as temperature) are evenly distributed over the range of measurements. + -SQ has a lower training overhead compared to the PQ and IVF methods because it does not search for clusters of vectors. +SQ has a lower training overhead compared to PQ because it does not search for clusters of vectors. Its training just determines the range of values for each dimension. + -Use SQ if you want to gain some of the memory efficiency offered by vector quantization, but do not want the processing overhead of training a PQ index. +Use SQ if you do not want the processing overhead of training a PQ index. +You can also use it if you have a smaller dataset (hundreds of thousands to millions of vectors). === Choosing Quantization -When choosing a quantization method, consider the following: +When creating a Hypsercale Vector or Composite Index, you choose which quantization method to use. +When deciding, consider the following: -* Use SQ when you want higher accuracy than PQ, at the cost of lower compression, and therefore more memory use. -* Use PQ when you're willing to trade some accuracy for higher compression. +* Use SQ when you want higher accuracy than PQ, at the cost of lower compression and therefore more memory use. +* Use PQ when you're willing to trade some accuracy for higher compression and less memory use. +PQ is a good choice for larger datasets (millions to billions of vectors) where you want to reduce memory use and improve search performance. You should also consider the potential need to retrain the index if your dataset changes over time. See the following section for more information about index training. Whichever quantization you choose, you should perform tests to verify it meets your needs. -See xref:vector-index:vector-index-best-practices.adoc[Vector Index Best Practices] for more information about choosing quantization for your Hyperscale Vector and Composite Vector indexes. +See xref:vector-index:vector-index-best-practices.adoc[] for more information about choosing quantization for your Hyperscale Vector and Composite Vector indexes. [#index-training] === The Importance of Index Training -Three of the four indexing algorithms rely on training the index on existing data. -For example, both PQ and IVF locate centroids that represent clusters of vectors in vector space. -This training reflects the content of dataset at training time. +The IVF indexing algorithm and the PQ ans SQ quantization algorithms rely on training the index on existing data. +Both PQ and IVF locate centroids that represent clusters of vectors in vector space. +The SQ quantization samples vectors to determine the range of values in each dimension. +This training reflects the content of dataset when you create the index. For this training to give you accurate search results, the data in your dataset must represent the full range of data you expect to search. -If it does not, the centroids the PQ or IVF indexing method selects may not accurately represent clusters of data in the dataset. + +If the ddataset is not representative, the centroids the PQ or IVF indexing method selects may not accurately represent clusters of data in the dataset. Having accurate centroids are key to these indexing methods returning accurate results. +For indexes using SQ quantization, the range of values in the dimensions may not accurately represent the data in the dataset. +If one or more dimensional values fall outside the range that SQ assign buckets to, they get assigned closest bucket. +As youir dataset changes, these inaccuracies can build, skewing results. -Over time, you may find the accuracy of your vector searches decreasing. +Over time, may find your vector search's recall (percentage of the nearest neighbors of the search vector returned by a query) decreases. Searches for similar vectors may miss relevant results or may rank less-related vectors higher than more relevant results. These inaccuracies can occur because the data in the dataset changes over time as you add and remove documents. The centroids identified by PQ and IVF may no longer adequately reflect the data in your database. New clusters of vectors may have developed, and old ones may have dissipated. +For indexes using SQ quantization, the range of values in the dimensions may have changed. -Indexes using the SQ indexing algorithm can return inaccurate results if the range of values in the dimensions change. -If one or more dimensional values fall outside the range that SQ assign buckets to, they get assigned closest bucket. -These inaccuracies can build over time, skewing results. - -To resolve these accuracy issues, you can retrain your indexes when you notice poor results. +To resolve these accuracy issues, you can retrain your indexes when you notice poor recall. You can also choose to retrain indexes periodically or after you make significant changes to your dataset. -You should consider the need to retrain your indexes when choosing which index algorithm to use. -For example, the PQ algorithm requires more resources to train than the SQ algorithm. +You should consider the need to retrain your indexes when choosing which quantization to use. +For example, the PQ quantization requires more resources to train than SQ. If your dataset evolves rapidly, you may want avoid using PQ because you'll need to perform more frequent retraining. From 3c1ae6e70f20f4cda88389123142737a7155d0a5 Mon Sep 17 00:00:00 2001 From: Gary Gray <137797428+ggray-cb@users.noreply.github.com> Date: Fri, 25 Jul 2025 16:43:47 -0400 Subject: [PATCH 33/41] Interim checkin based on Ankush's feedback. --- .../pages/hyperscale-vector-index.adoc | 43 ++++-- .../pages/use-vector-indexes.adoc | 122 +++++++++++------- .../pages/vectors-and-indexes-overview.adoc | 67 ++++++---- .../composite-vector-app-workflow.puml | 7 +- .../hyperscale-vector-app-workflow.puml | 6 +- .../partials/index-algorithm-settings.adoc | 16 ++- 6 files changed, 163 insertions(+), 98 deletions(-) diff --git a/modules/vector-index/pages/hyperscale-vector-index.adoc b/modules/vector-index/pages/hyperscale-vector-index.adoc index 17a5e912c..2c0309a91 100644 --- a/modules/vector-index/pages/hyperscale-vector-index.adoc +++ b/modules/vector-index/pages/hyperscale-vector-index.adoc @@ -66,7 +66,10 @@ See xref:guides:create-index.adoc[] for an overview of creating indexes. You must also supply a `WITH` clause to set some additional information about the vector column that the Hypsercale index needs. -The syntax for the `CREATE VECTOR INDEX` with the most common parameters is: +The following syntax for the `CREATE VECTOR INDEX` shows the minimum required parameters. +For the full syntax, see CREATE VECTOR INDEX in the SQL++ for Query Reference. + +// FIXME: Link goes here [source,sqlpp] ---- @@ -84,16 +87,17 @@ CREATE VECTOR INDEX `` The key value must be an array of floating point numbers or a base64 encoded string. * `dimensions` is an integer value that sets the number of dimensions in the vector. The embedded model you use to embed the vectors determines the number of dimensions in the vector. -* `similarity-function` is a string that sets the distance function to use when comparing vectors during index creation. -Couchbase {product-name} uses the following strings to represent the proximity functions: +* `similarity-metric` is a string that sets the distance metric to use when comparing vectors during index creation. +Couchbase {product-name} uses the following strings to represent the distance metrics: + -- ** `COSINE`: xref:vector-index:vectors-and-indexes-overview.adoc#cosine[Cosine Similarity] ** `DOT`: xref:vector-index:vectors-and-indexes-overview.adoc#dot[Dot Product] -** `L2`, `L2_SQUARED`, `EUCLIDEAN`, or `EUCLIDEAN_SQUARED`: xref:vector-index:vectors-and-indexes-overview.adoc#euclidean[Euclidean Distance] +** `L2` or `EUCLIDEAN`: xref:vector-index:vectors-and-indexes-overview.adoc#euclidean[Euclidean Distance] +** `L2_SQUARED` or `EUCLIDEAN_SQUARED`: xref:vector-index:vectors-and-indexes-overview.adoc#euclidean-squared[Euclidean Squared Distance] -- + -For the greatest accuracy, use the distance function you plan to use to query the data. +For the greatest accuracy, use the distance metric you plan to use to query the data. * `algorithm-settings` is a string containing the settings for the indexing algorithms. See <<#algo_settings>> in the next section for more information. @@ -104,7 +108,7 @@ include::partial$index-algorithm-settings.adoc[] [#examples] === Create Hyperscale Vector Index Example -The examples in this section use a dataset that contains information about colors, including a text description of the color. +The examples in this section use a dataset that contains information about colors including a text description of the color. There's also a field named `couchbase_search_query.knn.vector` that contains an embedded vector for the color description. include::vector-search:partial$download-sample-partial.adoc[] @@ -124,7 +128,7 @@ The result of running the query is: include::vector-index:example$hyperscale-idx-data.json[tag=rgb-document] ---- -The following example creates an Hyperscale vector index for the vector column named `embedding-vetor-dot`. +The following example creates an Hyperscale vector index for the vector column named `embedding-vector-dot`. [source,sqlpp] ---- @@ -149,6 +153,7 @@ In most cases, you'll not use these settings in a production environment. To use your Hyperscale Vector index, use the `SELECT` statement with a `ORDER BY` clause containing a call to the `APPROX_VECTOR_DISTANCE` function. This function performs the vector search using the Hyperscale Vector index. + A typical query looks like this: [source,sqlpp] @@ -158,17 +163,31 @@ SELECT ORDER BY APPROX_VECTOR_DISTANCE( , , - , + , [] ) LIMIT ; ---- -The `search-vector-value` is the vector Couchbase {product-name} will search for in the index. +The parameters in the `APPROX_VECTOR_DISTANCE` function are: + +* `collection-vector-column` is the name of the key containing the vector in the collection. +* `search-vector-value` is the vector value to to search for ibn the collection column. It can be an array of floating point numbers or a base64 encoded string. +* `distance-metric` is the distance metric to use when comparing the vectors. +This value should match the distance metric you set when you created the index. +* `centroids-to-probe` is an optional integer value that sets the number of centroids to probe for matching vectors. +By default, the vector search only probes a single centroid. + + +For the full syntax of the `APPROX_VECTOR_DISTANCE` function in the SQL++ reference. + +// FIXME: add link when available. NOTE: You can also call the function `VECTOR_DISTANCE` to find similar vectors. However, this function does not use the Hyperscale Vector index to perform the vector search. Instead, it performs a brute-force search for similar vectors. +It's useful to determine the recall rate of your Hyperscale Vector index. +See xref:vector-index/vector-index-best-practices.adoc[] for more information about comparing recall rates. Also use a `LIMIT` clause to return just the number of results you need. The query pushes the `LIMIT` clause down into the index scan so that the scan ends after finding the requested number of matches. @@ -179,8 +198,8 @@ The query pushes the `LIMIT` clause down into the index scan so that the scan en You must supply a vector value in your query that Couchbase {product-name} can compare to the vectors in the index. In actual use, your application generates a vector for the query value using the same embedding model it used to embed the vectors in your documents. -To avoid the complication of calling an embedding function, this example uses embedded vectors in the `rgb_questions.json` file that's included in `color_data_2vectors.zip`. -The contents of this file are loaded into a collection named `vector-sample.color.rgb-questions`. +To avoid the complication of calling an embedding mopdel, this example uses embedded vectors in the `rgb_questions.json` file that's included in `color_data_2vectors.zip`. +For this example, the contents of this file are loaded into a collection named `vector-sample.color.rgb-questions`. This collection contains a `question` attribute which is a search prompt for a particular color. The `couchbase_search_query.knn.vector` attribute contains the embedded vector for the `question` attribute. The following query lists several attributes from a document in the collection. @@ -200,7 +219,7 @@ include::vector-index:example$hyperscale-idx-data.json[tag=query-rgb-questions-o To use the embedded vector, you need to include the `couchbase_search_query.knn.vector` attribute in your query's the `SELECT` statement. You can either directly cut & paste the entire array into your query or use a subquery to retrieve it from the `vector-sample.color.rgb-questions` collection. -The following example uses a subquery to get the vector, and also includes the `wanted_similar_color_from_search` attribute in the output which shows you the color that he query should return. +The following example uses a subquery to get the vector, and also includes the `wanted_similar_color_from_search` attribute in the output which shows you the color that the query should return. [source,sqlpp] ---- diff --git a/modules/vector-index/pages/use-vector-indexes.adoc b/modules/vector-index/pages/use-vector-indexes.adoc index e8f20a231..89a15add3 100644 --- a/modules/vector-index/pages/use-vector-indexes.adoc +++ b/modules/vector-index/pages/use-vector-indexes.adoc @@ -2,14 +2,14 @@ :page-topic-type: concept :page-ui-name: {ui-name} :page-product-name: {product-name} -:description: Use Couchbase {page-product-name}'s Vector Index features to find documents based on content similarity or semantic meaning. +:description: Use Couchbase {page-product-name}'s vector indexes to find documents based on content similarity or semantic meaning. :page-toclevels: 3 {description} -Couchbase {product-name} suports three types of vector indexes. -You store index values as attributes in your documents, and then index those attributes. -You can then find relevant data by executing queries on the vector attributes, which use the index to find similar vectors. +Couchbase {product-name} supports three types of vector indexes. +You store vectors as attributes in your documents and index them using one of the three types of vector indexes. +You can then find relevant data by executing queries of the vector attributes which use the index to find similar vectors. As with other data types in Couchbase {product-name}, indexes make searching for similar vectors much faster. Using indexes for vector searches is especially important due to the size of vector data. @@ -18,36 +18,53 @@ Using indexes reduces the resources needed to perform vector searches. If you're unfamiliar with vectors and vector indexing, see xref:vectors-and-indexes-overview.adoc[] for an overview. -The three types of Couchbase {product-name} indexes that support vector searches are: +The three types of Couchbase {product-name} vector indexes are: Hyperscale Vector Indexes:: -These indexes are specifically designed for vector searches. -They perform vector similarity and semantic searches faster than the other types of indexes. -They can scale to index billions of documents compared to the million-ranges for the other index types. -Most of the Hyperscale Vector indexes resides in a highly optimized format on disk. ++ +-- +* Specifically designed for vector searches +* Perform vector similarity and semantic searches faster than the other types of indexes +* Designed to scale to billions of vectors +* Most of the index resides in a highly optimized format on disk +* High accuracy even for vectors with a large number of dimensions +* Supports concurrent searches and inserts for datasets that are constantly changing +-- + ++ Use this type of index when you want to primarily query vector values with a low memory footprint. -It offers high accuracy even for vectors with a large number of dimensions. -It also supports concurrent searches and inserts for datasets that are constantly changing. +In general, Hyperscale Vector indexes are the best choice for most applications that use vector searches. + See xref:vector-index:hyperscale-vector-index.adoc[] for more information. Composite Vector Indexes:: -Composite Vector indexes combine a standard GSI index with a single vector column. -This combination lets you perform a hybrid search using a single vector value with standard scalar attributes that are also indexed in the Composite Vector Index. -The scalar attributes in a query reduce the number of vectors the Couchbase {product-name} has to compare when performing an index scan to find similar vectors. -Use Composite VectorI indexes when you want to perform hybrid searches of documents using both scalars and a vector. -They work well for cases where your queries are highly selective---returning a small number of results from a large dataset. -They consume a moderate amount of memory and can index billions of documents. ++ +-- +* Combines a standard xref:learn:services-and-indexes/indexes/indexing-and-query-perf.adoc#secondary-index[Global Secondary index (GSI)] with a single vector column +* Designed for searches using a single vector value along with standard scalar values that filter out large portions of the dataset. +The scalar attributes in a query reduce the number of vectors the Couchbase {product-name} has to compare when performing a vector search to find similar vectors. +* Consume a moderate amount of memory and can index billions of documents. +* Work well for cases where your queries are highly selective---returning a small number of results from a large dataset +-- + ++ +Use Composite Vector indexes when you want to perform searches of documents using both scalars and a vector where the scalar values filter out large portions of the dataset. + To learn how to use Composite Vector indexes, see xref:vector-index:composite-vector-index.adoc[]. FTS Vector Index:: -An FTS Vector index is a hybrid that combines a Couchbase {product-name} Search index with a single vector column. -This combination adds semantic search to the Search index's full-text and geospatial search capabilities. -These indexes can index millions of documents. ++ +-- +* Combines a Couchbase {product-name} Search index with a single vector column +* Allows hybrid searches that combine vector searches with Full-Text Search (FTS) and geospatial searches. +* Can index millions of documents +-- + ++ +Use this index type when you need to perform hybrid searches that combine vectors with full-text or geospatial searches. + To learn how to use FTS Vector indexes, see xref:vector-search:vector-search.adoc[]. @@ -64,9 +81,10 @@ The following table summarizes the differences between the three types of vector [%autowidth] |=== -| Index Type | Dataset Size | Uses | Strength | Limitations +| Index Type | Available in Version | Dataset Size | Uses | Strength | Limitations | *Hyperscale Vector Index* +| 8.0 | Billions of documents a| * Pure vector searches @@ -76,40 +94,44 @@ a| * Low memory footprint * Lowest TCO for huge datasets * Best option for concurrent updates and searches +* Scalars in query do not override the vector values a| -* Overkill on smaller datasets * Indexing can take longer relative to other index types +* Not as efficient as Composite Vector indexes when using scalar values to filter large portions of dataset | *Composite Vector Index* -| Tens to hundreds of millions -| Hybrid searches combining vector and scalar values +| 8.0 +| Tens of millions to billion +| Searches combining vector and scalar values a| * Scalar values pre-filter data to reduce the scope of vector searches -* Can restrict searches based on scalars for use cases such as compliance. -* Based familiar Global Secondary indexes (GSI) +* Can restrict searches based on scalars for use cases such as compliance +* Based on familiar Global Secondary indexes (GSI) +* Good option for extreme filtering of dataset before performing a vector search a| * Accuracy suffers in huge datasets compared to Hyperscale Vector index * Scalar values always override vector values in queries, potentially missing relevant results | *FTS Vector Index* +| 7.6 | Tens of millions | Hybrid searches combining vector and keywords or geospatial a| -* Combines semantic and Full-Text search and geospatial search in a single pass. +* Combines semantic and Full-Text search and geospatial search in a single pass * Uses familiar Search indexes a| * Not as efficient as Composite Vector indexes if the search includes purely numeric or scalar values -* Does not scale to the extent of the other index types. +* Does not scale to the extent of the other index types Limited to approximately 100 million documents |=== When choosing which type of index to use, consider the following: -* If your dataset will not grow beyond 100 million documents, consider Composite Vector or FTS Vector indexes, especially if you need to perform hybrid searches. -* If your dataset is larger than or may grow larger than 100 million documents, use a Hyperscale Vector index. -* When in doubt, try using a Hyperscale Vector index. +* In most cases, test using a Hyperscale Vector index. If you find that the performance is not what you need, you can try using one of the other index types. +* If your index searches include scalar values that filter out large portions of the dataset, consider using a Composite Vector index. +* If your dataset will not grow beyond 100 million documents and you need to perform hybrid searches that combine vector searches with Full-Text Search or geospatial searches, use an FTS Vector index. == Applications for Vector Indexes @@ -133,12 +155,13 @@ Chatbot context for workflows like retreival-augmented generation (RAG) requires The large dataset gives the chatbot a depth of knowledge that's not necessary in simpler applications. Anomaly detection:: -Anomaly detection applications such as those used in Internet of Things (IoT) sensor networks, require huge datasets to find deviations from normally occurring patterns. +Anomaly detection applications such as those used in Internet of Things (IoT) sensor networks, require huge datasets to find deviations from expected patterns. Hyperscale Vector indexes can handle the large datasets and perform these vector searches fast. === Hyperscale Vector Index Application Workflow -When using a Hyperscale Vector index, your application follows the workflow shown in the following diagram: + +After you create a Hyperscale Vector index, your application follows the workflow shown in the following diagram: .Application Workflow with Hyperscale Vector Indexes [plantuml,hyperscale-vector-app-workflow,svg] @@ -151,17 +174,19 @@ The steps shown in the diagram are: . When your application loads data with a complex data field it wants to search semantically, it calls an embedding model to generate a vector for it. . It sends the data, including the vector, to Couchbase {product-name} for storage. . The Data Service sends the embedded vector to the Indexing Service for inclusion in the Hyperscale Vector index. -. When your application needs to perform a query that includes a vector, it uses the same embedding model to generate a vector for the search value. -. It sends the vector as part of the search request or query to teh Couchbase {product-name} Search Service. -. The Query Service performs an index scan in the Hyperscale Vector index to find similar vectors to the search vector. -. The Search Service returns results to your application. +. When your application needs to search for documents related to a complex piece of data, it uses the same embedding model to generate a vector for the search value. +. It sends the vector as part of the query to the Couchbase {product-name} Query Service. +. The Query Service sends a request to the Index Service for an index scan. +. The Index Service performs an index scan in the Hyperscale Vector index to find similar vectors to the search vector. +It sends the results of the scan back to the Query Service. +. The Query Service returns query results to your application. See xref:vector-index:hyperscale-vector-index.adoc[] for more information about Hyperscale Vector indexes. === Composite Vector Index Applications Composite Vector indexes contain a single vector column and one or more scalar columns. They apply scalar filters before performing a vector similarity search. -This is ideal for workflows where you want to exclude documents entirely to reduce the number of vectors that the index has to compare. +This is ideal for workflows where you want to exclude large portions of the dataset to reduce the number of vectors that the vector search has to compare. Composite Vector indexes work well for applications such as: Content Recommendations:: @@ -178,7 +203,7 @@ Vector similarity searches can be added to these searches to find similar demand === Composite Vector Index Application Workflow -When using a Composite Vector index, your application follows the workflow shown in the following diagram: +After you create a Composite Vector index, your application follows the workflow shown in the following diagram: .Application Workflow with Composite Vector Indexes [plantuml,composite-vector-app-workflow,svg] @@ -193,9 +218,11 @@ The steps shown in the diagram are: . The Data Service sends the embedded vector along with scalar fields to the Indexing Service for inclusion in the Composite Vector index. . When your application needs to perform a query that includes a vector, it uses the same embedding model to generate a vector for the search value. . It sends the vector and scalar values as part of a query to the Couchbase {product-name} Query Service. -. The Query Service performs an index scan in the Composite Vector index to find documents that match the scalar fields. -Then it performs a vector similarity search in the documents using the search vector. -. The Search Service returns results to your application. +. The Query Service requests index scans for the scalar values and a vector similarity search from the Indexing Service. +. The Indexing Service performs an index scan in the Composite Vector index to find documents that match the scalar fields. +It then performs the vector similarity search on the results of the scalar index scan. +Finally, it sends the results of the similarity search back to the Query Service. +. The Query Service returns the query results to your application. See xref:vector-index:composite-vector-index.adoc[] for more information about Composite Vector indexes. @@ -214,8 +241,8 @@ Users often want to search for hotels using multiple criteria: + * Limiting searches to a specific area (for example, "walking distance to the Louvre") which relies on geospacial data. -* Specific keywords for features they want ("quiet", "romantic", "gym") which requires Full-Text Search. -* Semantic searches of descriptions and reviews for searches that do not rely on literal text matches ("modern beach resort with chic decor") which requires vector searches. +* Specific keywords for features they want, such as "quiet", "romantic", or "gym", which requires Full-Text Search. +* Semantic searches of descriptions and reviews for searches that do not rely on literal text matches, such as "modern beach resort with chic décor", which requires vector searches. + An FTS vector index can combine geospacial, keyword, and semantic searches into a single index. @@ -223,8 +250,9 @@ An FTS vector index can combine geospacial, keyword, and semantic searches into Real estate searches:: Real estate applications can use FTS Vector indexes to find properties within a search region and have floor plan similar to an uploaded image. +=== FTS Vector Index Application Workflow -When using a FTS Vector index, your application follows the workflow shown in the following diagram: +After you create an FTS Vector index, your application follows the workflow shown in the following diagram: .Application Workflow with FTS Vector Indexes [plantuml,fts-app-workflow,svg] @@ -239,7 +267,7 @@ The steps shown in the diagram are: . The Data Service sends the embedded vector along with scalar fields to the Search Service for inclusion in the FTS Vector index. . When your application needs to perform a search that includes a vector, it uses the same embedding model to generate a vector for the search value. . It sends the search vector and text, geospacial, and other search values as part of a search request to the Couchbase {product-name} Search Service. -. The Search Service performs an index scan in the FTS Vector index to find documents that match the scalar fields. -Then it performs a vector similarity search in the documents using the search vector. +. The Search Service performs an index scan in the FTS Vector index to find documents that match the text or geospacial portions of the query. +Then it performs a vector similarity search on the results using the search vector. . The Search Service returns results to your application. diff --git a/modules/vector-index/pages/vectors-and-indexes-overview.adoc b/modules/vector-index/pages/vectors-and-indexes-overview.adoc index d0054e53c..12c587353 100644 --- a/modules/vector-index/pages/vectors-and-indexes-overview.adoc +++ b/modules/vector-index/pages/vectors-and-indexes-overview.adoc @@ -109,7 +109,7 @@ You can use external embedding models or https://www.couchbase.com/products/ai-s endif::[] [#vector_similarity] -== Vector Similarity +== Vector Similarity Metrics Once you have embedded vectors in your database, you find documents with a similar meaning by finding similar vectors. You use metrics to (also referred to as distance functions) to find similar vectors. @@ -212,17 +212,11 @@ Use this method when you're performing searches that rely on semantic meaning, s [#index-algorithms] -=== Indexing Algorithms +== Index Formats -When you add a vector to an index, you specify one or more algorithms that Couchbase {product-name} uses to process the vector values. -These algorithms organize and consolidate vector data in the index to make it more efficient to search. - -Couchbase {product-name} supports the algorithms described in the following sections. - -==== Index Formats - -Couchbase Server supports two formats for the index, which controls how the index stores the vectors. -It automatically chooses which algorithm to use, based on the type of the index and the size of the dataset. +Couchbase Server supports two formats that the Vector indexes use when storing their data. +These formats control how the index stores the vectors. +Couchbase Server automatically chooses which algorithm to use, based on the type of the index and the size of the dataset. However, you can set parameters when you create the index that affect how the algorithm organizes data. Flat Index:: @@ -234,7 +228,7 @@ However, searching a flat index is inefficient. The search must compare every vector in the index to find matches. You should only use it for small data sets or for testing. + -NOTE: FTS Vector indexes use a flat index when indexing smaller datasets. +NOTE: FTS Vector indexes use a flat index when indexing datasets with 1000 or fewer vectors. Hyperscale Vector and Composite Vector indexes only support the next algorithm, IVF. [#IVF] @@ -258,12 +252,17 @@ This risk increases as you add and delete data after you train the index. The centroids chosen during the initial training may no longer accurately represent clusters in current dataset. See <<#index-training>> for more information about index accuracy. + -Hyperscale Vector and Composite Vector indexes always use IVF. -FTS Vector indexes automatically uses IVF when the indexing larger datasets. -In addition to IVF, Hyperscale Vector indexes also use proprietary optimizations to improve performance for billion-scale indexes. +Hyperscale Vector and Composite Vector indexes always use IVF as the basis of their indexes. +In addition, they use a Hierarchical Navigable Small World (HNSW) graph to index the IVF's centroids. +This graph connects related centroids together so that a similarity search can quickly traverse the graph to find the centroids that are closest to the search vector. +Hyperscale also adds other proprietary optimizations that allow it to scale to billions of vectors. + ++ +FTS Vector indexes automatically uses IVF when the indexing datasets larger than 1000 vectors. + [#quantization] -==== Quantization +== Quantization Quantization simplifies vector data so it consumes less space in memory and on disk. Reducing the amount of data in a vector also makes vector comparison faster. @@ -319,6 +318,10 @@ Use PQ quantization when: * You're willing to trade higher processing requirements during training for smaller memory use and less CPU time during searches. * Your dataset is large (millions to billions of vectors). ++ +Hyoerscale Vector and Composite Vector indexes support PQ quantization. +FTS Vector indexes do not support it. + [#sq] Scalar Quantization (SQ):: Scalar Quantization is a simpler form of quantization than PQ. @@ -335,7 +338,7 @@ This means the second dimension's bins will only cover the range from 0.1 to 0.9 . SQ assigns each bin an index value that's from 4 to 8 bits in length. . It find a centroid within the range associated with the bin. It saves the centroid as a 16 or 32 bit floating point number. -. SQ then quantizes the vectors by replacing their dimensional values with the index value of the bin the dimnesional value falls into. +. SQ then quantizes the vectors by replacing their dimensional values with the index value of the bin the dimensional value falls into. + image::sq-diagram.svg["Diagram showing each floating point dimension of a vector being converted to an 8-bit integer by looking up which bucket it falls into."] + @@ -358,9 +361,19 @@ Its training just determines the range of values for each dimension. Use SQ if you do not want the processing overhead of training a PQ index. You can also use it if you have a smaller dataset (hundreds of thousands to millions of vectors). ++ +All three types of vector indexes support SQ quantization. + + === Choosing Quantization -When creating a Hypsercale Vector or Composite Index, you choose which quantization method to use. +You do not choose a quantization method for FTS vector indexes. +Instead, they automatically choose whether to use quantization: + +* FTS Vector indexes do not use quantization for datasets smaller than 10000 vectors. +* FTS Vector indexes automatically use 8-bit SQ quantization for datasets with 10000 vectors or larger. + +When creating a Hyperscale Vector or Composite Index, you choose which quantization method to use when creating the index. When deciding, consider the following: * Use SQ when you want higher accuracy than PQ, at the cost of lower compression and therefore more memory use. @@ -370,23 +383,23 @@ PQ is a good choice for larger datasets (millions to billions of vectors) where You should also consider the potential need to retrain the index if your dataset changes over time. See the following section for more information about index training. -Whichever quantization you choose, you should perform tests to verify it meets your needs. +No matter which quantization you choose, you should perform tests to verify it meets your needs. See xref:vector-index:vector-index-best-practices.adoc[] for more information about choosing quantization for your Hyperscale Vector and Composite Vector indexes. [#index-training] -=== The Importance of Index Training +== The Importance of Index Training -The IVF indexing algorithm and the PQ ans SQ quantization algorithms rely on training the index on existing data. +The IVF indexing algorithm and the PQ ans SQ quantizations rely on training the index on existing data. Both PQ and IVF locate centroids that represent clusters of vectors in vector space. The SQ quantization samples vectors to determine the range of values in each dimension. -This training reflects the content of dataset when you create the index. +These training techniques reflect the content of dataset at the time you create the index. For this training to give you accurate search results, the data in your dataset must represent the full range of data you expect to search. -If the ddataset is not representative, the centroids the PQ or IVF indexing method selects may not accurately represent clusters of data in the dataset. +If the dataset is not representative, the centroids that the PQ quantization or IVF indexing method selects may not accurately represent clusters of data in the dataset. Having accurate centroids are key to these indexing methods returning accurate results. For indexes using SQ quantization, the range of values in the dimensions may not accurately represent the data in the dataset. -If one or more dimensional values fall outside the range that SQ assign buckets to, they get assigned closest bucket. -As youir dataset changes, these inaccuracies can build, skewing results. +If one or more dimensional values fall outside the range that SQ assign bins to, they get assigned closest bin which may not properly represent the value. +As your dataset changes, these inaccuracies can build, skewing results. Over time, may find your vector search's recall (percentage of the nearest neighbors of the search vector returned by a query) decreases. Searches for similar vectors may miss relevant results or may rank less-related vectors higher than more relevant results. @@ -397,7 +410,9 @@ For indexes using SQ quantization, the range of values in the dimensions may hav To resolve these accuracy issues, you can retrain your indexes when you notice poor recall. You can also choose to retrain indexes periodically or after you make significant changes to your dataset. +To retrain an index, you create a new index with the same (or tweaked) settings as the existing index, but with a different name. +After Couchbase {product-name} builds and trains the new index, you can drop the old index. You should consider the need to retrain your indexes when choosing which quantization to use. For example, the PQ quantization requires more resources to train than SQ. -If your dataset evolves rapidly, you may want avoid using PQ because you'll need to perform more frequent retraining. +If your dataset evolves rapidly, you may choose to not use PQ because you'll need to perform more frequent retraining. diff --git a/modules/vector-index/partials/composite-vector-app-workflow.puml b/modules/vector-index/partials/composite-vector-app-workflow.puml index ee0e2e85d..e64ef1ce6 100644 --- a/modules/vector-index/partials/composite-vector-app-workflow.puml +++ b/modules/vector-index/partials/composite-vector-app-workflow.puml @@ -71,12 +71,13 @@ top to bottom direction DL ----> DS : <$ma_numeric_2_box{scale=0.4}> Data &\nVectors DS --> COMPOSITE : <$ma_numeric_3_box{scale=0.4}> Scalars &\nVectors -QS <--> COMPOSITE : <$ma_numeric_6_box{scale=0.4}> Index\nScans +QS --> COMPOSITE : <$ma_numeric_6_box{scale=0.4}> Scan\nRequest +QS <-- COMPOSITE : <$ma_numeric_7_box{scale=0.4}> Index Scan\nResults -SE ----> QS : <$ma_numeric_5_box{scale=0.4}>Queries +SE ----> QS : <$ma_numeric_5_box{scale=0.4}> Queries -QS ----> SE :<$ma_numeric_7_box{scale=0.4}> Results +QS ----> SE :<$ma_numeric_8_box{scale=0.4}> Query Results @enduml diff --git a/modules/vector-index/partials/hyperscale-vector-app-workflow.puml b/modules/vector-index/partials/hyperscale-vector-app-workflow.puml index ff46cda4b..59bf46d23 100644 --- a/modules/vector-index/partials/hyperscale-vector-app-workflow.puml +++ b/modules/vector-index/partials/hyperscale-vector-app-workflow.puml @@ -71,12 +71,12 @@ top to bottom direction DL ----> DS : <$ma_numeric_2_box{scale=0.4}> Data &\nVectors DS --> HVI : <$ma_numeric_3_box{scale=0.4}> Vectors -QS <--> HVI : <$ma_numeric_6_box{scale=0.4}> Index\nScans - +QS --> HVI : <$ma_numeric_6_box{scale=0.4}> Scan\nRequest +QS <-- HVI : <$ma_numeric_7_box{scale=0.4}> Index\nScan\nResult SE ----> QS : <$ma_numeric_5_box{scale=0.4}>Queries -QS ----> SE :<$ma_numeric_7_box{scale=0.4}> Results +QS ----> SE :<$ma_numeric_8_box{scale=0.4}> Query\nResults @enduml diff --git a/modules/vector-index/partials/index-algorithm-settings.adoc b/modules/vector-index/partials/index-algorithm-settings.adoc index fe1b985f3..3d0802792 100644 --- a/modules/vector-index/partials/index-algorithm-settings.adoc +++ b/modules/vector-index/partials/index-algorithm-settings.adoc @@ -16,14 +16,16 @@ The following sections describe the settings for centroids and quantization. === Number of Centroids -{index-name-plural} always use the xref:vector-index:use-vector-indexes.adoc#IVF[Inverted File (IVF)] algorithm to subdivide the dataset. -Using this algorithm reduces the number of vector comparisons a vector search of the index performs. +{index-name} uses several algorithms to organize data in its index to improve its performance. +One of these algorithms, xref:vector-index:use-vector-indexes.adoc#IVF[Inverted File (IVF)], has a setting you can adjust to control how it subdivides the dataset. +The other algorithms that it uses do not have settings you can adjust. + The key setting for IVF is the number of centroids it allocates for the index. This number affects the performance of your index in two ways: * If the index has fewer centroids, each centroid has more vectors associated with it. In this case, a vector search has to perform more comparisons, making the search slower. -However, having fewer centroids decreases the processing required to training the index. +However, having fewer centroids decreases the processing required to train the index. * A greater number of centroids results in a greater processing cost for training. This increase is due to the training process having to search for more data cluster to identify more centroids. @@ -67,10 +69,10 @@ The values for SQ that Couchbase {product-name} supports are: | `SQ8` | SQ uses an 8-bit index value splitting each vector dimension into 256 subspaces. -| `SQfp16` -| SQ uses an 8-bit index value splitting each vector dimension into 256 subspaces. -However, it stores the centroid value as a 16-bit floating point number instead of a 32-bit floating point number. -This cuts the memory used to store the centroids in half. +// | `SQfp16` +// | SQ uses an 8-bit index value splitting each vector dimension into 256 subspaces. +// However, it stores the centroid value as a 16-bit floating point number instead of a 32-bit floating point number. +// This cuts the memory used to store the centroids in half. |=== From fd5707063b6ec6b1e0dc6de872ce04406557f8bf Mon Sep 17 00:00:00 2001 From: Gary Gray <137797428+ggray-cb@users.noreply.github.com> Date: Tue, 29 Jul 2025 10:31:41 -0400 Subject: [PATCH 34/41] Wrapped up Ankush's feedback. Also added section on determining recall, and refectored the best practices to use subheadings instead of definition lists. --- .../examples/hyperscale-idx-data.json | 212 ++++++++++++++++++ .../examples/hyperscale-idx-examples.sqlpp | 136 +++++++++++ .../pages/composite-vector-index.adoc | 16 +- .../vector-index/pages/hyperscale-filter.adoc | 4 +- .../pages/hyperscale-vector-index.adoc | 47 ++-- .../pages/vector-index-best-practices.adoc | 174 ++++++++++---- .../partials/distance-metric-list.adoc | 8 + 7 files changed, 528 insertions(+), 69 deletions(-) create mode 100644 modules/vector-index/partials/distance-metric-list.adoc diff --git a/modules/vector-index/examples/hyperscale-idx-data.json b/modules/vector-index/examples/hyperscale-idx-data.json index 590bf9e88..1f539e697 100644 --- a/modules/vector-index/examples/hyperscale-idx-data.json +++ b/modules/vector-index/examples/hyperscale-idx-data.json @@ -181,3 +181,215 @@ } ] // end::rerank-after[] + + +// tag::query-rgb-distance[] +[{ + "color": "deep sky blue", + "description": "Deep sky blue is a calming and refreshing color that + evokes feelings of tranquility and peace. It is a shade + of blue that resembles the clear, open sky on a sunny + day. This color is often associated with serenity and + relaxation, making it a popular choice for interior + design and clothing. Its cool and calming nature makes + it a perfect color for creating a peaceful and serene + atmosphere.", + "wanted_similar_color_from_search": "sky blue", + "approx_distance": 0.5202313646339596 + }, + { + "color": "sky blue", + "description": "Sky blue is a calming and serene color that evokes + feelings of tranquility. It is a light shade of blue + that resembles the color of the sky on a clear day. + The color is often associated with peace, relaxation, + and a sense of openness. It can also represent a sense + of freedom and endless possibilities, as the sky seems + to stretch on forever. Sky blue is a refreshing and + soothing color that can bring a sense of calmness to + any space.", + "wanted_similar_color_from_search": "sky blue", + "approx_distance": 0.5205406483903239 + }, + { + "color": "light sky blue", + "description": "Light sky blue is a soft and delicate color that evokes + a sense of tranquility and peace. It is a shade of blue + that is reminiscent of a clear, sunny day with a few + fluffy clouds scattered across the sky. This color is + often associated with feelings of serenity and + relaxation, making it a popular choice for bedrooms and + spa-like environments. The lightness of this shade adds + a touch of freshness and purity, making it a perfect + color for creating a calming and inviting atmosphere.", + "wanted_similar_color_from_search": "sky blue", + "approx_distance": 0.5315537216573907 + } +] +// end::query-rgb-distance[] + +// tag::untuned-query-results[] +[ + [{ + "color": "pale turquoise" + }, + { + "color": "slate blue" + }, + { + "color": "cadet blue" + }, + { + "color": "teal" + }, + { + "color": "snow" + }, + { + "color": "medium turquoise" + }, + { + "color": "slate gray" + }, + { + "color": "grey" + }, + { + "color": "medium slate blue" + }, + { + "color": "linen" + } + ] +] +// end::untuned-query-results[] + +// tag::exact-query-results[] +[ + [{ + "color": "deep sky blue" + }, + { + "color": "sky blue" + }, + { + "color": "light sky blue" + }, + { + "color": "pale turquoise" + }, + { + "color": "blue" + }, + { + "color": "slate blue" + }, + { + "color": "light cyan" + }, + { + "color": "cadet blue" + }, + { + "color": "light blue" + }, + { + "color": "medium blue" + } + ] +] +// end::exact-query-results[] + +// tag::recall-rate-results[] +[{ + "total_returned_items": 10, + "matching_color_list": [{ + "color": "cadet blue" + }, + { + "color": "pale turquoise" + }, + { + "color": "slate blue" + } + ], + "matching_color_count": 3, + "recall_percentage": 30 +}] +// end::recall-rate-results[] + +// tag::recall-rate-tuned-results[] +[{ + "total_returned_items": 10, + "matching_color_list": [{ + "color": "blue" + }, + { + "color": "cadet blue" + }, + { + "color": "deep sky blue" + }, + { + "color": "light blue" + }, + { + "color": "light cyan" + }, + { + "color": "light sky blue" + }, + { + "color": "medium blue" + }, + { + "color": "pale turquoise" + }, + { + "color": "sky blue" + }, + { + "color": "slate blue" + } + ], + "matching_color_count": 10, + "recall_percentage": 100 +}] +// end::recall-rate-tuned-results[] + + +// tag::tuned-query-results[] +[ + [{ + "color": "deep sky blue" + }, + { + "color": "sky blue" + }, + { + "color": "light sky blue" + }, + { + "color": "pale turquoise" + }, + { + "color": "light cyan" + }, + { + "color": "slate blue" + }, + { + "color": "blue" + }, + { + "color": "cadet blue" + }, + { + "color": "light blue" + }, + { + "color": "medium blue" + } + ] +] +// end::tuned-query-results[] diff --git a/modules/vector-index/examples/hyperscale-idx-examples.sqlpp b/modules/vector-index/examples/hyperscale-idx-examples.sqlpp index cb0efc862..d5f01a430 100644 --- a/modules/vector-index/examples/hyperscale-idx-examples.sqlpp +++ b/modules/vector-index/examples/hyperscale-idx-examples.sqlpp @@ -94,3 +94,139 @@ WITH question_vec AS ( ORDER BY APPROX_VECTOR_DISTANCE(b.embedding_vector_dot, question_vec[0], "l2", 4, TRUE) LIMIT 3; /* end::rerank-after-example[] */ + + +/* tag::query-rgb-with-distance[] */ +WITH question_vec AS ( + SELECT RAW couchbase_search_query.knn[0].vector + FROM `vector-sample`.`color`.`rgb-questions` + WHERE meta().id = "#87CEEB"), + question_answer AS ( + SELECT wanted_similar_color_from_search + FROM `vector-sample`.`color`.`rgb-questions` + WHERE meta().id = "#87CEEB") +SELECT b.color, b.description, q.wanted_similar_color_from_search, approx_distance + FROM `vector-sample`.`color`.`rgb` AS b, question_answer as q, + APPROX_VECTOR_DISTANCE(b.embedding_vector_dot, question_vec[0], "l2", 4) + as approx_distance + ORDER BY approx_distance LIMIT 3; +/* end::query-rgb-with-distance[] */ + +/* tag::untuned-query[] */ +WITH question_vec AS ( + SELECT RAW couchbase_search_query.knn[0].vector + FROM `vector-sample`.`color`.`rgb-questions` + WHERE meta().id = "#87CEEB" + ), +colors AS ( + SELECT b.color + FROM `vector-sample`.`color`.`rgb` AS b + ORDER BY APPROX_VECTOR_DISTANCE(b.embedding_vector_dot, question_vec[0], "l2") + LIMIT 10 ) +SELECT RAW colors; +/* end::untuned-query[] */ + + +/* tag::exact-query[] */ +WITH question_vec AS ( + SELECT RAW couchbase_search_query.knn[0].vector + FROM `vector-sample`.`color`.`rgb-questions` + WHERE meta().id = "#87CEEB" + ), +colors AS ( + SELECT b.color + FROM `vector-sample`.`color`.`rgb` AS b + ORDER BY VECTOR_DISTANCE(b.embedding_vector_dot, question_vec[0], "l2") + LIMIT 10 ) +SELECT RAW colors; +/* end::exact-query[] */ + +/* tag::recall-rate-query[] */ +-- Get the vector for the question +WITH question_vec AS ( + SELECT RAW couchbase_search_query.knn[0].vector + FROM `vector-sample`.`color`.`rgb-questions` + WHERE meta().id = "#87CEEB" +), +-- Exact Search results +GroundTruthResults AS ( + SELECT b.color + FROM `vector-sample`.`color`.`rgb` AS b + ORDER BY VECTOR_DISTANCE(b.embedding_vector_dot, + question_vec[0], "l2") LIMIT 10 +), +-- Approximate Search results +ApproximateResults AS ( + SELECT b.color + FROM `vector-sample`.`color`.`rgb` AS b + ORDER BY APPROX_VECTOR_DISTANCE(b.embedding_vector_dot, + question_vec[0], "l2") LIMIT 10 +) +SELECT + -- List the stats based on the merges in the following clauses + COUNT(DISTINCT gr.color) AS total_returned_items, + ARRAY_AGG(intersection_results) AS matching_color_list, + COUNT(DISTINCT intersection_results.color) AS matching_color_count, + (COUNT(DISTINCT intersection_results.color) * 100.0 / COUNT(DISTINCT gr.color)) AS recall_percentage +FROM + GroundTruthResults AS gr +LEFT JOIN + ApproximateResults AS ar ON gr.color = ar.color +LEFT JOIN + -- Use INTERSECT SELECT to find the shared members of the two result sets + (SELECT t1.color FROM GroundTruthResults AS t1 INTERSECT SELECT t2.color FROM ApproximateResults AS t2) AS intersection_results + ON gr.color = intersection_results.color; +/* end::recall-rate-query[] */ + +/* tag::recall-rate-tuned[] */ +-- Get the vector for the question +WITH question_vec AS ( + SELECT RAW couchbase_search_query.knn[0].vector + FROM `vector-sample`.`color`.`rgb-questions` + WHERE meta().id = "#87CEEB" +), +-- Exact Search results +GroundTruthResults AS ( + SELECT b.color + FROM `vector-sample`.`color`.`rgb` AS b + ORDER BY VECTOR_DISTANCE(b.embedding_vector_dot, + question_vec[0], "l2") LIMIT 10 +), +-- Approximate Search results, this timw with nProbes set to 4: +ApproximateResults AS ( + SELECT b.color + FROM `vector-sample`.`color`.`rgb` AS b + ORDER BY APPROX_VECTOR_DISTANCE(b.embedding_vector_dot, + question_vec[0], "l2", 4) LIMIT 10 +) +SELECT + -- List the stats based on the merges in the following clauses + COUNT(DISTINCT gr.color) AS total_returned_items, + ARRAY_AGG(intersection_results) AS matching_color_list, + COUNT(DISTINCT intersection_results.color) AS matching_color_count, + (COUNT(DISTINCT intersection_results.color) * 100.0 / COUNT(DISTINCT gr.color)) AS recall_percentage +FROM + GroundTruthResults AS gr +LEFT JOIN + ApproximateResults AS ar ON gr.color = ar.color +LEFT JOIN + -- Use INTERSECT SELECT to find the shared members of the two result sets + (SELECT t1.color FROM GroundTruthResults AS t1 INTERSECT SELECT t2.color FROM ApproximateResults AS t2) AS intersection_results + ON gr.color = intersection_results.color; +/* end::recall-rate-tuned[] */ + + +/* tag::tuned-query[] */ +WITH question_vec AS ( + SELECT RAW couchbase_search_query.knn[0].vector + FROM `vector-sample`.`color`.`rgb-questions` + WHERE meta().id = "#87CEEB" + ), +colors AS ( + SELECT b.color + FROM `vector-sample`.`color`.`rgb` AS b + ORDER BY APPROX_VECTOR_DISTANCE(b.embedding_vector_dot, question_vec[0], "l2", 4) + LIMIT 10 ) +SELECT RAW colors; +/* end::tuned-query[] */ + diff --git a/modules/vector-index/pages/composite-vector-index.adoc b/modules/vector-index/pages/composite-vector-index.adoc index 22bb48f07..d8fc7be58 100644 --- a/modules/vector-index/pages/composite-vector-index.adoc +++ b/modules/vector-index/pages/composite-vector-index.adoc @@ -1,4 +1,4 @@ -= Hybrid Search Using Composite Vector Index += Filtered Search Using Composite Vector Index :page-topic-type: guide :page-ui-name: {ui-name} :page-product-name: {product-name} @@ -9,7 +9,7 @@ :index-name-plural: Composite Vector indexes {description} -The added vector column lets your application perform a hybrid query using both the index's scalar, array, and object index entries plus a vector similarity search. +The added vector column lets your application perform a query using both the index's scalar, array, and object index entries to pre-filter the dataset before peroforming a vector similarity search. == How the Composite Vector Index's Vector Column Works @@ -66,21 +66,17 @@ The format for this clause with the most commonly used parameters is: [source,sqlpp] ---- WITH { "dimension": , - "similarity":, + "similarity":, "description": }; ---- * `dimensions` is an integer value that sets the number of dimensions in the vector. This value is set by the embedded model you used to embed the vectors. -* `similarity-function` is a string that sets the distance function to use when comparing vectors during index creation. -Couchbase {product-name} uses the following strings to represent the proximity functions: +* `similarity-metric` is a string that sets the distance metric to use when comparing vectors during index creation. + --- -** `COSINE`: xref:vector-index:vectors-and-indexes-overview.adoc#cosine[Cosine Similarity] -** `DOT`: xref:vector-index:vectors-and-indexes-overview.adoc#dot[Dot Product] -** `L2`, `L2_SQUARED`, `EUCLIDEAN`, or `EUCLIDEAN_SQUARED`: xref:vector-index:vectors-and-indexes-overview.adoc#euclidean[Euclidean Distance] --- +include::partial$distance-metric-list.adoc[] + + For the greatest accuracy, use the distance function you plan to use when querying vector data. * `algorithm-settings` is a string containing the settings for the indexing algorithms. diff --git a/modules/vector-index/pages/hyperscale-filter.adoc b/modules/vector-index/pages/hyperscale-filter.adoc index ef1b67936..81b5fcb4f 100644 --- a/modules/vector-index/pages/hyperscale-filter.adoc +++ b/modules/vector-index/pages/hyperscale-filter.adoc @@ -12,7 +12,8 @@ {description} A Hyperscale Vector index has a single column that indexes the vector. However, you can include scalar values in the index that you can use to filter the vector search. -These included values are stored along with the vector in the index, but they're not indexed. +The index stores these included values along with the vector, but they're not indexed. +Because they're not indexed, using scalars to filter out large portions of the dataset in a query of a Hyperscale Vector index may be less efficient than Composite Vector index. In your queries that use a Hypserscale Vector index, you add the included scalar values as predicates in the `WHERE` clause. During the index scan, Couchbase {propduct-name} uses the included scalar values to filter out vectors that do not meet the filter restriction. @@ -36,7 +37,6 @@ This example is the same as the example from xref:vector-index:hyperscale-vector === Querying a Hyperscale Vector Index with Included Scalar Values When you query a Hyperscale Vector index, you can use the included scalar values as predicates in the `WHERE` clause of your query. - When your query adds predicate, Couchbase {product-name} uses it to filter the results before performing the vector index scan. The following example performs the same query as the example from xref:vector-index:hyperscale-vector-index.adoc#example[Query with a Hyperscale Vector Index], but adds the `brightness` key as a predicate in the `WHERE` clause: diff --git a/modules/vector-index/pages/hyperscale-vector-index.adoc b/modules/vector-index/pages/hyperscale-vector-index.adoc index 2c0309a91..bf5f06dee 100644 --- a/modules/vector-index/pages/hyperscale-vector-index.adoc +++ b/modules/vector-index/pages/hyperscale-vector-index.adoc @@ -76,7 +76,7 @@ For the full syntax, see CREATE VECTOR INDEX in the SQL++ for Query Reference. CREATE VECTOR INDEX `` ON ``(`` VECTOR) WITH { "dimension": , - "similarity":, + "similarity":, "description": }; ---- @@ -88,14 +88,9 @@ The key value must be an array of floating point numbers or a base64 encoded str * `dimensions` is an integer value that sets the number of dimensions in the vector. The embedded model you use to embed the vectors determines the number of dimensions in the vector. * `similarity-metric` is a string that sets the distance metric to use when comparing vectors during index creation. -Couchbase {product-name} uses the following strings to represent the distance metrics: + --- -** `COSINE`: xref:vector-index:vectors-and-indexes-overview.adoc#cosine[Cosine Similarity] -** `DOT`: xref:vector-index:vectors-and-indexes-overview.adoc#dot[Dot Product] -** `L2` or `EUCLIDEAN`: xref:vector-index:vectors-and-indexes-overview.adoc#euclidean[Euclidean Distance] -** `L2_SQUARED` or `EUCLIDEAN_SQUARED`: xref:vector-index:vectors-and-indexes-overview.adoc#euclidean-squared[Euclidean Squared Distance] --- +include::partial$distance-metric-list.adoc[] + + For the greatest accuracy, use the distance metric you plan to use to query the data. * `algorithm-settings` is a string containing the settings for the indexing algorithms. @@ -171,15 +166,14 @@ SELECT The parameters in the `APPROX_VECTOR_DISTANCE` function are: * `collection-vector-column` is the name of the key containing the vector in the collection. -* `search-vector-value` is the vector value to to search for ibn the collection column. +* `search-vector-value` is the vector value to search for in the collection column. It can be an array of floating point numbers or a base64 encoded string. * `distance-metric` is the distance metric to use when comparing the vectors. -This value should match the distance metric you set when you created the index. +This value should match the distance metric you used when you created the index. * `centroids-to-probe` is an optional integer value that sets the number of centroids to probe for matching vectors. By default, the vector search only probes a single centroid. - -For the full syntax of the `APPROX_VECTOR_DISTANCE` function in the SQL++ reference. +For the full syntax, see `APPROX_VECTOR_DISTANCE` in the SQL++ reference. // FIXME: add link when available. @@ -229,16 +223,16 @@ include::vector-index:example$hyperscale-idx-examples.sqlpp[tag=query-rgb-with-s In this example, the `APPROX_VECTOR_DISTANCE` function compares the vector in the `couchbase_search_query.knn.vector` attribute to the vectors in the index. The parameters the example passes to this function are: -* The `embedding-vector-dot` is the name of the indexed vector key. -* The `couchbase_search_query.knn[0].vector`` is the vector value to compare to the vectors in the index. -This value is the result of the subquery that gets the vector from the `rgb-questions` collection. -* `l2` is the distance function to use. +* The `embedding-vector-dot` is the name of the indexed vector key in the collection. +* The `couchbase_search_query.knn[0].vector`` is the vector search value to compare to the vectors in the index. +This value is the result of the subquery that gets the vector from the `rgb-questions` collection. +* `l2` is the distance metric to use. * `4` is the number of centroids to probe for matching vectors. This value defaults to `1`. -This example sets this value to 4 because the dataset is small. +This example sets this value to `4`` because the dataset is small. In a small dataset, it's more likely that relevant vectors are not associated with the same centroid. This parameter broadens the search beyond a single centroid to find more relevant vectors. -If you re-run the query with the default value of 1, you'll see that the results are less relevant. +If you re-run the query with the default value of `1``, you'll see that the results are less relevant. The result of running the query is: @@ -251,5 +245,22 @@ include::vector-index:example$hyperscale-idx-data.json[tag=query-rgb-color] The second result, `sky blue`, matches the `wanted_similar_color_from_search` attribute as the most relevant color to the question posed in the `question` attribute. All of the results are still relevant to the question. +=== Getting the Vector Distance + +You can use the `APPROX_VECTOR_DISTANCE` function as a predicate to return the distance between the search vector and the vectors in the index. +You may want to get this value when the distance is meaningful, such as when it represents a real-world measurement such as temperature or distance. + +The following example returns the distance between the search vector and the vectors in the index by adding an alias for the results of the `APPROX_VECTOR_DISTANCE` function in the `SELECT` statement as well as the `ORDER BY` clause: +[source,sqlpp] +---- +include::vector-index:example$hyperscale-idx-examples.sqlpp[tag=query-rgb-with-distance] +---- + +The result of running the query is: + +[source,json] +---- +include::vector-index:example$hyperscale-idx-data.json[tag=query-rgb-distance] +---- diff --git a/modules/vector-index/pages/vector-index-best-practices.adoc b/modules/vector-index/pages/vector-index-best-practices.adoc index 6a61d0dfc..4e36be085 100644 --- a/modules/vector-index/pages/vector-index-best-practices.adoc +++ b/modules/vector-index/pages/vector-index-best-practices.adoc @@ -14,74 +14,76 @@ The following sections describe the results of the testing and recommendations b NOTE: Most of the tests were performed using the Hyperscale Vector index. However, many of the results also apply to Composite Vector indexes where the two index types share the same settings. -== Tuning Index Creation +== Tune Index Creation When you create a Hyperscale Vector index, you can set the parameters in the following list. Each has the potential to affect the performance of creating the index and the speed and accuracy of queries that use the index. -nList:: -Sets the number of clusters (centroids) in the index. +=== nList + +The `nList` setting controls the number of clusters (centroids) in the index. You set the `nList` by supplying a value after the `IVF` in the `description` parameter when you create your index. This value affects the accuracy of the index and the speed of queries that use it. The default value for this value depends on the size of your dataset. For datasets with less than 1 million vectors, the default value is the number of vectors divided by 1000. For datasets with more than 1 million vectors, the default value is the square root of the number of vectors. -+ + Tests show that increasing `nList` beyond the default does not affect the build time of the index. However, it does improve the queries per second (QPS) that the index can handle. It also lowers the latency of queries that use the index. -+ + *Recommendation:* if you find that your query throughput and latency is not meeting your needs, you can try rebuilding the index with a larger `nList` value. -Trainlist:: -Sets the number of vectors that Couchbase {product-name} considers when searching for centroids in the dataset. +=== TrainList + +The `TrainList` setting controls the number of vectors that Couchbase {product-name} considers when searching for centroids in the dataset. You set it using the `trainlist` key in the `WITH` clause when you create your index. The default value is approximately 50 times the number of centroids in the index. -+ + Tests show that increasing the `trainlist` improves QPS and reduces latency, but slightly increases memory usage for the index. -+ + *Recommendation:* if you find that increasing the `nList` does not improve your query performance, you can try increasing the `trainlist` value. -Partitions:: -Sets how the index is split among logical shards. +=== Partitions + +The number of partitions the index controls how the index is split among logical shards. This setting affects the scalability, memory distribution, and parallelism of the index. You set this value using the `PARTITION BY` clause in the `CREATE [VECTOR] INDEX` statement. +See xref:n1ql:n1ql-language-reference/index-partitioning.adoc[] for more information about partitioning indexes. -+ Tests show that increasing the number of partitions linearly reduces both the time it takes to build and train the index and index's memory use. These changes do not affect the QPS or latency of queries that use the index. -+ *Recommendation:* if the length of time it takes to build the index or the amount of memory the index uses is a concern, you can try increasing the number of partitions. -Replicas:: -Sets the number of replicas for the index. -This setting affects the fault tolerance, query throughput, and memory footprint of the index. +=== Replicas +The number of replicas you set affects the fault tolerance, query throughput, and memory footprint of the index. You set this value using the `num_replicas` key in the `WITH` clause when you create or alter your index. + + Tests show that increasing the number of replicas learly increases the QPS and linerly reduces the latency of queries that use the index. However, it also linearly increased the memory footprint of the index. Adding replicas does not affect the time it takes to build the index. -+ + *Recommendation:* if you find that your query throughput or latency is not meeting your needs, you can try increasing the number of replicas for the index if you can afford the additional memory usage. [#quantization] -Quantization:: -Sets the quantization method used by the index. +=== Quantization +Vector indexes always use quantization to compress the vectors they index. Couchbase {product-name} supports two quantization methods: xref:vector-index:vectors-and-indexes-overview.adoc#sq[scalar quantization (SQ)] and xref:vector-index:vectors-and-indexes-overview.adoc#pq[product quantization (PQ)]. You set the quantization method using the `description` parameter in the `WITH` clause when you create your index. -+ + Couchbase tested different quantization settings using datasets that differed in size and number of dimensions. The results of these tests appear in the following table: -+ + [%autowidth, options="header"] |=== | Dataset | Index Type | Quantization Setting | Build Time | Memory Use | Recall Accuracy | QPS | Latency @@ -106,19 +108,17 @@ The results of these tests appear in the following table: |=== -+ + NOTE: Couchbase also tested Hyperscale Vector indexes containing 1 billion vectors with 128 dimensions using SQ4 quantization. The results showed acceptable recall accuracy and similar performance to SQ8 on smaller datasets. -+ + *Recommendations:* -+ --- * SQ8 provides the best balance between memory use and recall for lower dimensional datasets. * If you have a low-dimensional dataset that's in the range of a billion vectors, consider using SQ4 quantization. * Use PQ for higher-dimensional datasets if you want to reduce memory use and are willing to accept less accurate recall, decreased QPS, and increased latency. --- + // Similarity Function:: // Sets the function the index uses when determining the similarity of vectors when identifying centroids. @@ -127,39 +127,135 @@ The results showed acceptable recall accuracy and similar performance to SQ8 on // Holding off on simlarity because the best practice doc is mute on it, also lacks testing for dot? -== Tuning Queries +== Tune Queries -When querying a Hyperscale Vector index, you can set several parameters in the `APPROX_VECTOR_DISTANCE` (`ANN`) function that affect the performance of the query. +When querying a Hyperscale Vector index, you can set several parameters in the `APPROX_VECTOR_DISTANCE` function that affect the performance of the query. The following list describes the parameters you can set in the function: -nProbes:: -Sets the number of centroids in the Hyperscale Vector index to ton search for similar vectors. +[#nprobes] +=== nProbes + +`nProbes` sets the number of centroids in the Hyperscale Vector index to search for similar vectors. You optionally set this value as the fourth parameter in the `APPROX_VECTOR_DISTANCE` function call in your query. The default value for this value is 1, which only searches for similar vectors in the centroid that's closest to the search vector. -+ -Tests found that increasing `nProbes` beyond the default improves the accuracy of results non-linearly (larger values show diminishing improvements). + +Tests show that increasing `nProbes` beyond the default improves the accuracy of results non-linearly (larger values show diminishing improvements). However, it caused a linear decrease in QPS and increase in latency. -+ *Recommendation:* if you find that your query recall is not meeting your needs, you can try increasing the `nProbes` value. However, increasing this value reduces QPS and increases latency. [#reranking] -Reranking:: -Sets whether a query of a Hyperscale Vector index performs a second ranking phase where it compares the full vector values of the results to the search vector. +=== Reranking + +A query can perform a reranking phase after a vector search. +This reranking phase reorders the results by comparing the full vector values of the results to the search vector. See xref:vector-index:hyperscale-reranking.adoc[] for more information about how reranking works. This setting is off by default. You can enable it by passing `TRUE` as the fifth parameter in the `APPROX_VECTOR_DISTANCE` function call in your query. -+ -Testing has shown that enabling reranking improves the accuracy of recall in limited cases and decreases QPS. +Testing shows that enabling reranking improves the accuracy of recall in limited cases and decreases QPS. -+ *Recommendation:* if you find recall accuracy is not meeting your needs and you're using SQ4 or PQ128x8 or below quantization, try enabling reranking. You must have your index set to persist the full vector value, which increases memory use. -+ If you do not enable reranking, consider preventing the persistence of the full vector value in the index to reduce memory and disk use. See xref:vector-index:hyperscale-reranking.adoc#prevent-vector-persistence[Preventing Vector Persistence] to learn how to turn off full vector persistence. +[#recall-accuracy] +== Determine Recall Rate + +To understand how well your index and queries are performing, you can determine the recall of your queries. +To do this, compare the results of running a query using the `APPROX_VECTOR_DISTANCE` function to the results of running the same query using the `VECTOR_DISTANCE` function. +The `VECTOR_DISTANCE` function performs a brute-force full vector comparison, so it returns the most accurate results. +Based on the results of this comparison, you can decide whether you need to adjust your index or query settings to improve recall accuracy. + +IMPORTANT: The `VECDOR_DISTANCE` function is very expensive to run because it compares all vectors in the dataset. +You should only use it on a testing system with a smaller dataset. + + +For example, suppose you run the following query against a Hyperscale Vector index: + +[source,sqlpp] +---- +include::vector-index:example$hyperscale-idx-examples.sqlpp[tag=untuned-query] +---- + +The results of running this query against the RGB sample dataset are: + +[source,json] +---- +include::vector-index:example$hyperscale-idx-data.json[tag=untuned-query-results] +---- + +You can then run the same query using the `VECTOR_DISTANCE` function to get the most accurate results. +The following example uses the `VECTOR_DISTANCE` function instead of the `APPROX_VECTOR_DISTANCE` function: + +[source,sqlpp] +---- +include::vector-index:example$hyperscale-idx-examples.sqlpp[tag=exact-query] +---- + +Running the query returns the following results: + +[source,json] +---- +include::vector-index:example$hyperscale-idx-data.json[tag=exact-query-results] +---- + + +You can see the results of the two queries share only a few common results. +You can perform a more complex query that determines the common results between the two queries and calculates the recall rate. +The following example executes both of the previous queries as subqueries, then finsd the intersection of the results. +It calculates the recall rate based on the 10 results the queries return (called the recall@10 due to the sample size): + +[source,sqlpp] +---- +include::vector-index:example$hyperscale-idx-examples.sqlpp[tag=recall-rate-query] +---- + +The result of running the recall rate query is: + +---- +include::vector-index:example$hyperscale-idx-data.json[tag=recall-rate-results] +---- + +The recall rate shown in the example is 30%, which indicates poor results. + +A low recall rate means you need to perform some tuning to improve the recall accuracy of the query or the index. +One way to improve the recall accuracy is to increase the `nProbes` value in the `APPROX_VECTOR_DISTANCE` function call. +It increases the number of centroids the query searches for similar vectors. +See <> for more information about this setting. +The following example shows how to increase this value to `4` in the approximate vector query: + +[source,sqlpp] +---- +include::vector-index:example$hyperscale-idx-examples.sqlpp[tag=tuned-query] +---- + +The results of running the tuned query are: + +[source,json] +---- +include::vector-index:example$hyperscale-idx-data.json[tag=tuned-query-results] +---- + +The results look more similar to the results of the exact query. +To verify, you can re-run the recall rate query using the new `nProbes` value. +The following example shows the recall rate query with the `APPROX_VECTOR_DISTANCE` function call wupdated with the new `nProbes` value: + +[source,sqlpp] +---- +include::vector-index:example$hyperscale-idx-examples.sqlpp[tag=recall-rate-tuned] +---- + +The result of this update are: + +[source,json] +---- +include::vector-index:example$hyperscale-idx-data.json[tag=recall-rate-tuned-results] +---- + +The new recall rate is 100%, which means the result of the change makes the `APPROX_VECTOR_DISTANCE` function as accurate as the `VECTOR_DISTANCE` function. +This means the query calling `APPROX_VECTOR_DISTANCE` is now returning the most accurate results possible. diff --git a/modules/vector-index/partials/distance-metric-list.adoc b/modules/vector-index/partials/distance-metric-list.adoc new file mode 100644 index 000000000..55283c226 --- /dev/null +++ b/modules/vector-index/partials/distance-metric-list.adoc @@ -0,0 +1,8 @@ +Couchbase {product-name} uses the following strings to represent the distance metrics: ++ +-- +** `COSINE`: xref:vector-index:vectors-and-indexes-overview.adoc#cosine[Cosine Similarity] +** `DOT`: xref:vector-index:vectors-and-indexes-overview.adoc#dot[Dot Product] +** `L2` or `EUCLIDEAN`: xref:vector-index:vectors-and-indexes-overview.adoc#euclidean[Euclidean Distance] +** `L2_SQUARED` or `EUCLIDEAN_SQUARED`: xref:vector-index:vectors-and-indexes-overview.adoc#euclidean-squared[Euclidean Squared Distance] +-- From 2b2dc5279fa5d6a818aafb547f49bd8c7d24725b Mon Sep 17 00:00:00 2001 From: Gary Gray <137797428+ggray-cb@users.noreply.github.com> Date: Tue, 29 Jul 2025 14:25:14 -0400 Subject: [PATCH 35/41] * Added in includes for the Capella UI create index instructions (I hope...) * More cleanup and removing of definition lists in favor of actual headings. * Fixes for COmposite Vector Index topic to match the Hyperscale. --- .../pages/composite-vector-index.adoc | 37 +++-- .../pages/hyperscale-vector-index.adoc | 30 ++-- .../pages/vector-index-best-practices.adoc | 1 + .../pages/vectors-and-indexes-overview.adoc | 134 ++++++++---------- .../partials/index-algorithm-settings.adoc | 26 ++-- 5 files changed, 124 insertions(+), 104 deletions(-) diff --git a/modules/vector-index/pages/composite-vector-index.adoc b/modules/vector-index/pages/composite-vector-index.adoc index d8fc7be58..a940e138e 100644 --- a/modules/vector-index/pages/composite-vector-index.adoc +++ b/modules/vector-index/pages/composite-vector-index.adoc @@ -1,4 +1,4 @@ -= Filtered Search Using Composite Vector Index += Filtered Searches Using Composite Vector Index :page-topic-type: guide :page-ui-name: {ui-name} :page-product-name: {product-name} @@ -9,7 +9,7 @@ :index-name-plural: Composite Vector indexes {description} -The added vector column lets your application perform a query using both the index's scalar, array, and object index entries to pre-filter the dataset before peroforming a vector similarity search. +The added vector column lets your application perform a query using both the index's scalar, array, and object index entries to pre-filter the dataset before performing a vector similarity search. == How the Composite Vector Index's Vector Column Works @@ -47,14 +47,21 @@ include::vector-search:partial$download-sample-partial.adoc[] The embedding model you use to embed the vectors may determine this value for you. For example, OpenAI API's `text-embedding-ada-002` embedding model that embedded the sample data demonstrated later in this page creates vectors that have 1536 dimensions. -* You must decide what algorithms you want your index to use. -These algorithms affect how much memory and processing Couchbase {product-name} uses to train and search them. -See xref:vector-index:vectors-and-indexes-overview.adoc#index-algorithms[Indexing Algorithms] +* You must decide what distance metric and quantization you want your index to use. +The metrics affect how the index compares vectors. +The quantization determines how much memory your index uses and the amount of processing Couchbase {product-name} must perform to train and search them. +See xref:vector-index:vectors-and-indexes-overview.adoc#vector_similarity[Vector Similarity Metrics] and xref:vector-index:vectors-and-indexes-overview.adoc#quantization[Quantization] for more information. -include::partial$index-algorithm-settings.adoc[] +[#create-index] +ifeval::['{product-name}' == 'Capella'] +include::vector-index:partial$create-composite-index-capella-ui.adoc[] -== Create a Composite Vector Index +== Create a Composite Vector Index Using SQL++ +endif::[] +ifeval::['{product-name}' == 'Server'] +== Create a Hyperscale Vector Index +endif::[] Creating a Composite Vector index is similar to creating a non-vector GSI index. See xref:guides:create-index.adoc[] for an overview of creating indexes. @@ -67,7 +74,7 @@ The format for this clause with the most commonly used parameters is: ---- WITH { "dimension": , "similarity":, - "description": + "description": }; ---- @@ -79,10 +86,12 @@ include::partial$distance-metric-list.adoc[] + For the greatest accuracy, use the distance function you plan to use when querying vector data. -* `algorithm-settings` is a string containing the settings for the indexing algorithms. -See <<#algo_settings>> earlier in this page. +* `centroids-and-quantization` is a string containing the settings for the quantization and index algorithms. +See <<#algo_settings>> in the next section for more information. + +For a full list of the parameters that affect a Composite Vector index, see Composite Vector Index in the SQL++ reference. -For a full list of the parameters that affect a vector column in a GSI, see *FIXME:TDB*. +include::partial$index-algorithm-settings.adoc[] [#examples] === Examples @@ -109,7 +118,7 @@ include::vector-index:example$composite-vector-data.json[tag=sample-doc] The `rgb.json` file's `colorvect_l2` attribute defines an array containing the RGB values for the entry's color. While this technically is not an embedded vector, you can still create a vector index column for this array. -The following example creates a GSI for this attribute as an embedded vector as well as the color's name and brightness. +The following example creates a Composite Vector index for this attribute as an embedded vector as well as the color's name and brightness. [source,sqlpp] ---- @@ -147,7 +156,7 @@ The `embedding_vector_dot` attribute contains the embedded vectors for the text The data sample shown in <<#examples>> truncated this attribute to several values. The embedded vector contains 1536 dimensions. -The following example creates a GSI that indexes the embedded vectors in the `embedding_vector_dot` as well as indexing the scalar `color` that contains the color's name and `brightness.` +The following example creates a Composite Vector index that indexes the embedded vectors in the `embedding_vector_dot` as well as indexing the scalar `color` that contains the color's name and `brightness.` [source,sqlpp] ---- @@ -200,7 +209,7 @@ include::vector-index:example$gsi-vector-idx-examples.sqlpp[tag=query-rgb-idx] The query uses the `APPROX_VECTOR_DISTANCE` function to sort the results. You pass it the vector column to search, the vector to search for (in this case, the array `128, 128, 128`) and the distance function. -For the best accuracy, use the same distance function you specified when creating the GSI (in this case, `L2`). +For the best accuracy, use the same distance function you specified when creating the Composite Vector index (in this case, `L2`). The query pushes the `LIMIT` clause down into the index scan, so once it finds the 5 entries that satisfy the query, it exits. The top result is the entry for gray. diff --git a/modules/vector-index/pages/hyperscale-vector-index.adoc b/modules/vector-index/pages/hyperscale-vector-index.adoc index bf5f06dee..ab37476bb 100644 --- a/modules/vector-index/pages/hyperscale-vector-index.adoc +++ b/modules/vector-index/pages/hyperscale-vector-index.adoc @@ -45,6 +45,11 @@ If your documents contain multiple embedded vectors, you can create multiple ind Embeddings can be an array of floating point numbers or a base64 encoded string. Couchbase {product-name} does not embed vectors itself. You must use an external embedding model to embed vectors into your data and add them to your documents. ++ +[TIP] +-- +include::vector-search:partial$download-sample-partial.adoc[] +-- * The vectors you add to an index must contain the same number of dimensions. Also the values in the vector must be 32-bit floating point numbers. @@ -54,12 +59,21 @@ If a vector does not meet both of these requirements, the vector index treats it The embedding model you use to embed the vectors may determine this value for you. For example, OpenAI API's `text-embedding-ada-002` embedding model creates vectors that have 1536 dimensions. -* You must decide what algorithms you want your index to use. -These algorithms affect how much memory your index uses and the amount of processing Couchbase {product-name} must perform to train and search them. -See xref:vector-index:vectors-and-indexes-overview.adoc#index-algorithms[Indexing Algorithms]. +* You must decide what distance metric and quantization you want your index to use. +The metrics affect how the index compares vectors. +The quantization determines how much memory your index uses and the amount of processing Couchbase {product-name} must perform to train and search them. +See xref:vector-index:vectors-and-indexes-overview.adoc#vector_similarity[Vector Similarity Metrics] and xref:vector-index:vectors-and-indexes-overview.adoc#quantization[Quantization] for more information. [#create-index] +ifeval::['{product-name}' == 'Capella'] +include::vector-index:partial$create-hyperscale-index-capella-ui.adoc[] + +== Create a Hyperscale Vector Index Using SQL++ +endif::[] +ifeval::['{product-name}' == 'Server'] == Create a Hyperscale Vector Index +endif::[] + Use the `CREATE VECTOR INDEX` statement to create a Hyperscale Vector Index. This statement is similar to the `CREATE INDEX` statement that you use to create Global Secondary Indexes (GSI). See xref:guides:create-index.adoc[] for an overview of creating indexes. @@ -77,7 +91,7 @@ CREATE VECTOR INDEX `` ON ``(`` VECTOR) WITH { "dimension": , "similarity":, - "description": + "description": }; ---- @@ -93,7 +107,7 @@ include::partial$distance-metric-list.adoc[] + For the greatest accuracy, use the distance metric you plan to use to query the data. -* `algorithm-settings` is a string containing the settings for the indexing algorithms. +* `centroids-and-quantization` is a string containing the settings for the quantization and index algorithms. See <<#algo_settings>> in the next section for more information. include::partial$index-algorithm-settings.adoc[] @@ -180,11 +194,11 @@ For the full syntax, see `APPROX_VECTOR_DISTANCE` in the SQL++ reference. NOTE: You can also call the function `VECTOR_DISTANCE` to find similar vectors. However, this function does not use the Hyperscale Vector index to perform the vector search. Instead, it performs a brute-force search for similar vectors. -It's useful to determine the recall rate of your Hyperscale Vector index. -See xref:vector-index/vector-index-best-practices.adoc[] for more information about comparing recall rates. +It's useful to measure the recall of your Hyperscale Vector index. +See xref:vector-index:vector-index-best-practices.adoc#recall-accuracy[Determine Recall Rate] for more information about measuring recall. Also use a `LIMIT` clause to return just the number of results you need. -The query pushes the `LIMIT` clause down into the index scan so that the scan ends after finding the requested number of matches. +The query pushes the `LIMIT` clause down into the index scan so that the scan ends after finding the number of matches you need. [#query-example] === Hyperscale Vector Index Query Example diff --git a/modules/vector-index/pages/vector-index-best-practices.adoc b/modules/vector-index/pages/vector-index-best-practices.adoc index 4e36be085..7b85a76c4 100644 --- a/modules/vector-index/pages/vector-index-best-practices.adoc +++ b/modules/vector-index/pages/vector-index-best-practices.adoc @@ -19,6 +19,7 @@ However, many of the results also apply to Composite Vector indexes where the tw When you create a Hyperscale Vector index, you can set the parameters in the following list. Each has the potential to affect the performance of creating the index and the speed and accuracy of queries that use the index. +[#nlist] === nList The `nList` setting controls the number of clusters (centroids) in the index. diff --git a/modules/vector-index/pages/vectors-and-indexes-overview.adoc b/modules/vector-index/pages/vectors-and-indexes-overview.adoc index 12c587353..f9819a069 100644 --- a/modules/vector-index/pages/vectors-and-indexes-overview.adoc +++ b/modules/vector-index/pages/vectors-and-indexes-overview.adoc @@ -113,86 +113,85 @@ endif::[] Once you have embedded vectors in your database, you find documents with a similar meaning by finding similar vectors. You use metrics to (also referred to as distance functions) to find similar vectors. -When you add vectors to a Couchbase {product-name} index, you must specify which metric to use to compare vectors. -Each metric works best for different types of data. -In most cases, the metric you select when comparing vectors matches the metric the embedding model used when generating the vectors. +When you create an index or perform a vector search, you must specify which metric to use to compare vectors. +Each metric works best for certain applications and types of data. Couchbase {product-name} supports four metrics: [#euclidean] -Euclidean Distance (also known as L2):: -Calculates the geometric distance between two vectors by finding the distance between the individual dimensions in the vectors. +=== Euclidean Distance (also known as L2) + +Euclidean distance calculates the geometric distance between two vectors by finding the distance between the individual dimensions in the vectors. This method is most sensitive to the distance between the vectors in space, rather than their alignment. It's also sensitive to the scale of the vectors, where the length of one vector verses the other affects the relationship between the vectors. -Use this method when the proximity of the vectors and their magnitudes are important. -+ +Use this method when the actual distance of the vectors and their magnitudes are important. +This method is useful if the distance between vectors represents a real-world value. + image::euclidean-distance-example.svg["Three-dimensional plot showing two vectors with points along each vector joined by dotted lines, indicating the summing of corresponding points."] -+ + Euclidean Distance is useful for tasks such as: -+ -* . * 3D motion capture where you're detecting similar positions or trajectories of joints, objects, where finding real-world values for thresholds is important. * Geographic or spatial searches where you care about exact (and often real-world) distances. -* Other cases in which the results are used to in filters in calculations that require the actual distance between the vectors. +* Other cases where you use the results as filters in calculations that require the actual distance between the vectors. -+ NOTE: Only Hyperscale Vector and Composite Vector indexes support this metric. FTS Vector indexes do not support it. [#euclidean-squared] -Euclidean Squared Distance (also known as L2 Squared or L2^2^):: +=== Euclidean Squared Distance (also known as L2 Squared or L2^2^) + This method is similar to Euclidean Distance, but it does not take the square root of the sum distances between the vectors: -+ -*Euclidean Distance Formula:* latexmath:[L2(x, y) = \sqrt{\sum_{i=1}^n (x_i - y_i)^2}] -+ -*Euclidean Squared Distance Formula:* latexmath:[L2^2(x, y) = \sum_{i=1}^n (x_i - y_i)^2] +Euclidean Distance Formula:: + latexmath:[L2(x, y) = \sqrt{\sum_{i=1}^n (x_i - y_i)^2}] + + +Euclidean Squared Distance Formula:: +latexmath:[L2^2(x, y) = \sum_{i=1}^n (x_i - y_i)^2] + -+ Because it does not take the square root of the sums, Euclidean Squared Distance is faster to calculate than Euclidean Distance. -However, it does not represent the actual distance between points on the vectors. +However, it does not represent the actual distance between the vectors. The results of a vector search using L2 Squared as a metric always returns the same rankings that an L2 search returns. -However, in cases where the dimensions of the vectors represent real-world values, L2 is more intuitive to use because it returns the actual distance between the vectors. +In cases where the dimensions of the vectors represent real-world values, L2 is more intuitive to use because it returns the actual distance between the vectors. -+ Use this method when you need higher performance than Euclidean Distance. -It's better in cases where comparing literal distances is less important than performance and having the ranking of search results is enough. +It's better in cases when comparing literal distances is less important than performance and where having the ranking of search results is sufficient. -+ For example: -+ * Image recognition tasks where real-world distances between vectors are not a factor, including: ** Searching for products that are visually similar to an image uploaded by a shopper. ** Facial recognition. +* Audio recognition tasks such as identifying who's speaking in a recording. +* Locating similar genomic and biological sequences in a dataset, such as related gene profiles. - -+ NOTE: Only Hyperscale Vector and Composite Vector indexes support this metric. FTS Vector indexes do not support it. [#dot] -Dot Product:: +=== Dot Product + This metric finds related vectors by comparing the magnitude (length) and alignment of the vectors. Here, the proximity of the vectors in space is less important than whether they point in a similar direction and have the a similar magnitude. Vectors that point in similar directions (have a low angle between them) and have similar magnitude are strongly associated with each other. This method uses the similarity of the vectors' magnitudes to rank their relation. -+ + image::dot-product-example.svg["Three-dimensional plot showing two vectors labeled with their magnitudes and the angle between them labeled with the theta symbol."] -+ + Use this method for tasks where ranking confidence is key. The magnitude of the vectors is important when determining the strength of the relationship. For example: -+ * Recommending related products based on a shopper's previous purchases. -* Personalizing a music service's user home page based on the user's likes and dislikes of artists. +* Personalizing a music service's user home page based on the user's likes and dislikes of artists and songs. * Targeting ads based on a user's interests and previous interactions with the service. [#cosine] -Cosine Similarity:: +=== Cosine Similarity:: + This metric is similar to the dot product. However, it normalizes the vectors (making them the same length) during comparison. Normalization means their magnitudes are not taken into account, just their alignment. @@ -200,12 +199,11 @@ This normalization makes this method better for comparing textual data because i The magnitude of a vector generated by some text embedding models depend on the length of the source text. Normalizing vector magnitudes emphasizes the semantic meaning when performing comparisons. Therefore, Cosine Similarity can find the semantic relationship between a short question and a long article that's relevant to answering it. -+ + image::cosine-similarity-example.svg["Three-dimensional plot showing two vectors that are of equal length, with the angle between them labeled as theta."] -+ + Use this method when you're performing searches that rely on semantic meaning, such as: -+ * Find relevant articles to answer a question posed by a user. * Locate code snippets based on a user's question about how to perform a task. * Organize scanned documents in a document management system based on their semantic meaning. @@ -219,7 +217,7 @@ These formats control how the index stores the vectors. Couchbase Server automatically chooses which algorithm to use, based on the type of the index and the size of the dataset. However, you can set parameters when you create the index that affect how the algorithm organizes data. -Flat Index:: +=== Flat Index This algorithm just stores the full vector value in the index without performing any sort of optimization. Searches using this index use a brute-force method to find similar vectors. Adding new vectors to a flat index is fast and the index does not need training. @@ -227,39 +225,38 @@ It also offers high precision because search compares the full vector values. However, searching a flat index is inefficient. The search must compare every vector in the index to find matches. You should only use it for small data sets or for testing. -+ + NOTE: FTS Vector indexes use a flat index when indexing datasets with 1000 or fewer vectors. Hyperscale Vector and Composite Vector indexes only support the next algorithm, IVF. [#IVF] -Inverted File (IVF):: +=== Inverted File (IVF) This algorithm partitions the vector space to limit the number of vectors that a search must compare. An IVF index trains itself during creation using a set of parameters you pass to it: -+ + . It samples vectors in the dataset to locate clusters of similar vectors. . For each cluster it finds, it chooses a representative vector (called a centroid). . It creates a data structure called an inverted list that associates all vectors with their closest centroid. -+ + image::ivf-diagram-with-vectors.svg["A plot showing clusters of points in a 3D graph labelled and assigned to centroid vectors. The centroids then point to multiple vectors in an inverted list."] -+ + When you search using an IVF index, it first locates the centroids that are most relevant to the vector value you're searching for. It then searches just the vectors associated with those centroids in the inverted list. By limiting the number of vector comparisons to just the vectors close to the relevant centroids, IVF makes vector search faster. -+ + A drawback of this method is the possibility that the search could miss some relevant vectors. A search can miss vectors if they're associated with a centroid that's not relevant to the search vector. This risk increases as you add and delete data after you train the index. The centroids chosen during the initial training may no longer accurately represent clusters in current dataset. See <<#index-training>> for more information about index accuracy. -+ + Hyperscale Vector and Composite Vector indexes always use IVF as the basis of their indexes. In addition, they use a Hierarchical Navigable Small World (HNSW) graph to index the IVF's centroids. This graph connects related centroids together so that a similarity search can quickly traverse the graph to find the centroids that are closest to the search vector. Hyperscale also adds other proprietary optimizations that allow it to scale to billions of vectors. -+ -FTS Vector indexes automatically uses IVF when the indexing datasets larger than 1000 vectors. +FTS Vector indexes automatically uses IVF when the indexing datasets larger than 1000 vectors. [#quantization] == Quantization @@ -275,62 +272,58 @@ Unlike the indexing algorithms, you choose the quantization method you want Couc Couchbase {product-name} supports two types of quantization: [#pq] -Product Quantization (PQ):: +=== Product Quantization (PQ) Product Quantization simplifies vectors by breaking their dimensions into chunks called subspaces. It then replaces each set of dimensions within the with a single value that represents the nearest centroid in the subspace. This method reduces the size of the vector by replacing the original floating point values with smaller integers that represent the centroid. -+ PQ processes vectors by following these steps: -+ --- + . It groups the vector's dimensions into chunks called subspaces. For example, suppose the vectors contain 1024 dimensions. Then PQ may break the vectors into 128 subspaces, each containing 8 dimensions. . It finds groups of centroids in each subspace and adds them to a data structure called a codebook. The codebook assigns each centroid an index number. . PQ then reduces the size of the vectors by replacing each subspace's dimensions with the index of the closest centroid in the codebook. --- -+ + + image::pq-diagram.svg["Three-dimensional plot showing two vectors that are of equal length, with the angle between them labeled as theta."] -+ + PQ could quantize the vector in the previous example from 1024 64-bit floating point values to 128 8 bit or 16 bit integer values. This data size reduction improves performance because integer operations are less computationally expensive than floating point operations. It also reduces memory use because each vector requires less data to store (for example, from 64KB to 128 bytes). -+ + A search of the PQ index performs the same steps on the vector you're searching for: -+ --- + . It breaks the search vector into subspaces and quantizes it using the codebook. . It then locates closest centroids to the quantized query vector. . It searches the vectors related to the matching centroids for vectors that relate to the search vector. --- -+ + PQ sacrifices some accuracy because it compares quantized vectors instead of their original raw values. The process of quantization adds additional processing requirements to training. This overhead makes training a PQ index more computationally expensive than the other methods. However, PQ reduces the amount of memory and processing time necessary when searching for related vectors in a large dataset. -+ + Use PQ quantization when: -+ + * Your vectors contain a large number of dimensions. * You're willing to trade higher processing requirements during training for smaller memory use and less CPU time during searches. * Your dataset is large (millions to billions of vectors). -+ + Hyoerscale Vector and Composite Vector indexes support PQ quantization. FTS Vector indexes do not support it. [#sq] -Scalar Quantization (SQ):: +=== Scalar Quantization (SQ) Scalar Quantization is a simpler form of quantization than PQ. Instead of breaking the vector into subspaces, it quantizes each dimension of the vector independently. Its quantized vectors are larger, but are a more precise represenation than than those quantized using PQ. -+ + SQ follows these steps to process vectors: -+ + . SQ determines the maximum and minimum values for each dimension in the dataset. . It then partitions each dimension in the vector into equal segments (called bins) over the range of the dimension's values. For example, in the diagram, the first dimension's values range from 0 to 1, while the second dimension's range from 0.1 to 0.9. @@ -339,33 +332,32 @@ This means the second dimension's bins will only cover the range from 0.1 to 0.9 . It find a centroid within the range associated with the bin. It saves the centroid as a 16 or 32 bit floating point number. . SQ then quantizes the vectors by replacing their dimensional values with the index value of the bin the dimensional value falls into. -+ + image::sq-diagram.svg["Diagram showing each floating point dimension of a vector being converted to an 8-bit integer by looking up which bucket it falls into."] -+ + This quantization reduces the dimensions from 32 or 64 bit floating point values to 8 or less bit integers, reducing the memory needed for search. It also makes search faster because integer operations are computationally less expensive than floating point operations. -+ + A search on an SQ index reassembles vectors before comparing them. For each of the vector's dimensions, SQ replaces the integer bin number with the floating point centroid associated with the bin. This recreation is an approximation of the original vector, because each dimension in the vector is the bin's centroid value instead of the original dimensional value. -+ + Because this method quantizes the vectors, it loses precision. It's less precise than the PQ method (which also quantizes vectors) because it assumes that each dimension can be evenly divided. Its accuracy suffers if your data has clusters. It's best suited for data that's more evenly distributed and does not have high correlations. For example, SQ may be a good fit for an IoT sensor dataset where the measured values (such as temperature) are evenly distributed over the range of measurements. -+ + SQ has a lower training overhead compared to PQ because it does not search for clusters of vectors. Its training just determines the range of values for each dimension. -+ + Use SQ if you do not want the processing overhead of training a PQ index. You can also use it if you have a smaller dataset (hundreds of thousands to millions of vectors). -+ All three types of vector indexes support SQ quantization. -=== Choosing Quantization +=== Choosing a Quantization Method You do not choose a quantization method for FTS vector indexes. Instead, they automatically choose whether to use quantization: diff --git a/modules/vector-index/partials/index-algorithm-settings.adoc b/modules/vector-index/partials/index-algorithm-settings.adoc index 3d0802792..390da620a 100644 --- a/modules/vector-index/partials/index-algorithm-settings.adoc +++ b/modules/vector-index/partials/index-algorithm-settings.adoc @@ -1,8 +1,8 @@ [#algo_settings] -== Index Algorithm Settings +=== Quantization and Centroid settings When creating an index that includes a vector field, you choose settings that affect how the index processes vectors. -The parameter named `description` is the primary setting that controls the indexing algorithms that Couchbase {product-name} to create the index. +The parameter named `description` is the primary setting that controls the quantization and the number of centroids Couchbase {product-name} to create the index. Using it, you control how the index subdivides the dataset to improve performance and how it quantizes vectors to reduce memory and processing requirements. The `description` parameter is a string in the following format: @@ -14,11 +14,11 @@ The `description` parameter is a string in the following format: The following sections describe the settings for centroids and quantization. -=== Number of Centroids +==== Number of Centroids -{index-name} uses several algorithms to organize data in its index to improve its performance. -One of these algorithms, xref:vector-index:use-vector-indexes.adoc#IVF[Inverted File (IVF)], has a setting you can adjust to control how it subdivides the dataset. -The other algorithms that it uses do not have settings you can adjust. +{index-name} uses several algorithms to organize its data to improve its performance. +One of these algorithms, xref:vector-index:use-vector-indexes.adoc#IVF[Inverted File (IVF)], has a setting you can adjust to control how it subdivides the dataset. +The other algorithms that {index-name} uses do not have settings you can adjust. The key setting for IVF is the number of centroids it allocates for the index. This number affects the performance of your index in two ways: @@ -42,16 +42,19 @@ It chooses the number of centroids based on the number of vectors in the dataset You can manually set the number of centroids for the index by adding an integer value after the `IVF` in the `description` parameter. The number of centroids you set manually must be less than the number of vectors in the dataset. -=== Quantization Setting +See xref:vector-index:vector-index-best-practices.adoc#nlist[nList] for guidance on choosing the number of centroids for the index. + +==== Quantization Setting {index-name} always uses quantization to reduce the size of vectors stored in the index. You must choose whether the index uses xref:vector-index:use-vector-indexes.adoc#sq[Scalar Quantization (SQ)] or xref:vector-index:use-vector-indexes.adoc#pq[Product Quantization (PQ)]. +See xref:vector-index:vector-index-best-practices.adoc#quantization[Quantization] for guidance on choosing the quantization method for the index. You select the quantization by adding a comma followed by either `PQ` or `SQ` to the `description` parameter after the IVF setting in the `description` value. Each quantization method has additional settings explained in the following sections. -==== SQ Settings +===== SQ Settings For SQ, you set the number of bits the SQ algorithm uses for the bin index value or the number of bits it uses to store the centroid for each bin. The values for SQ that Couchbase {product-name} supports are: @@ -78,7 +81,8 @@ The values for SQ that Couchbase {product-name} supports are: See xref:vector-index:vectors-and-indexes-overview.adoc#sq[Scalar Quantization] for more information about how SQ works. -==== PQ Settings + +===== PQ Settings If you choose to use PQ in your index, you must set two values: @@ -107,8 +111,9 @@ PQx ---- For example, `PQ32x8` has PQ break the vector's dimensions into 32 subspaces, each of which has 256 centroids. +See xref:vector-index:vectors-and-indexes-overview.adoc#pq[Product Quantization] for more information about how PQ works. -=== Algorithm Settings Examples +==== Algorithm Settings Examples The following table shows several `description` values along with an explanation. @@ -128,4 +133,3 @@ This settings means each subspace has 256 centroids. |=== -See xref:vector-index:vectors-and-indexes-overview.adoc#pq[Product Quantization ] for more information about how PQ works. \ No newline at end of file From 3c30227094badad181a264e2b32e90b5a6e52d99 Mon Sep 17 00:00:00 2001 From: Gary Gray <137797428+ggray-cb@users.noreply.github.com> Date: Tue, 29 Jul 2025 15:19:00 -0400 Subject: [PATCH 36/41] Minor edit --- modules/vector-index/pages/hyperscale-vector-index.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/vector-index/pages/hyperscale-vector-index.adoc b/modules/vector-index/pages/hyperscale-vector-index.adoc index ab37476bb..10bc5c647 100644 --- a/modules/vector-index/pages/hyperscale-vector-index.adoc +++ b/modules/vector-index/pages/hyperscale-vector-index.adoc @@ -262,7 +262,7 @@ All of the results are still relevant to the question. === Getting the Vector Distance You can use the `APPROX_VECTOR_DISTANCE` function as a predicate to return the distance between the search vector and the vectors in the index. -You may want to get this value when the distance is meaningful, such as when it represents a real-world measurement such as temperature or distance. +You may want to get this value when the distance is meaningful, such as when it represents a real-world measurement. The following example returns the distance between the search vector and the vectors in the index by adding an alias for the results of the `APPROX_VECTOR_DISTANCE` function in the `SELECT` statement as well as the `ORDER BY` clause: From c456dea23601457ce44b7031a4974280312c1958 Mon Sep 17 00:00:00 2001 From: Gary Gray <137797428+ggray-cb@users.noreply.github.com> Date: Tue, 29 Jul 2025 15:35:33 -0400 Subject: [PATCH 37/41] Typo fix --- modules/vector-index/pages/hyperscale-reranking.adoc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/vector-index/pages/hyperscale-reranking.adoc b/modules/vector-index/pages/hyperscale-reranking.adoc index 85791f4be..56c1d77fb 100644 --- a/modules/vector-index/pages/hyperscale-reranking.adoc +++ b/modules/vector-index/pages/hyperscale-reranking.adoc @@ -15,7 +15,7 @@ It uses non-quantized versions of the search and indexed vectors to return more After the query locates similar vectors in the index, it performs a second round of comparisons using the full vector values stored in the index to reorder the results. This reranking can make the most relevant vectors to the search vector appear higher in the search results. -== Enabling Reraniking +== Enabling Reranking To enable reranking, your index must have a copy the full vector value in addition to the quantized value. The `CREATE VECTOR INDEX` statement adds this copy of the full vector value to the index by default. @@ -63,10 +63,10 @@ However, it always decreases queries per second (QPS) when enabled. In many cases, you can achieve acceptable recall accuracy without reranking. See xref:vector-index:vector-index-best-practices.adoc#reranking[Reranking] to learn in which cases reranking is useful. -Storing the full vector in the index significantly increases the size of the index. +Storing the full vector significantly increases the size of the index. If you do not plan to use reranking, you can save space in your index by having it not save the full vector value. -To prevent persisting the full vector, set the `persist_full_vector` attribute to `False` in the `WITH` clause of the `CREATE VECTOR INDEX` statement you use to create the index: +To prevent an index from persisting the full vector, set the `persist_full_vector` attribute to `False` in the `WITH` clause of the `CREATE VECTOR INDEX` statement you use to create it: [source,sqlpp] ---- From 13a187cb085896684817c7e08212b518414815f4 Mon Sep 17 00:00:00 2001 From: Gary Gray <137797428+ggray-cb@users.noreply.github.com> Date: Mon, 25 Aug 2025 15:54:43 -0400 Subject: [PATCH 38/41] Typo fix in modules/vector-index/examples/find-reranking-cases.py Co-authored-by: Simon Dew <39966290+simon-dew@users.noreply.github.com> --- modules/vector-index/examples/find-reranking-cases.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/vector-index/examples/find-reranking-cases.py b/modules/vector-index/examples/find-reranking-cases.py index d4eb73652..30fae2822 100644 --- a/modules/vector-index/examples/find-reranking-cases.py +++ b/modules/vector-index/examples/find-reranking-cases.py @@ -1,5 +1,5 @@ # This script just iterates over all of the colors in the example dataset to find cases -# where reranking imporved the search results. +# where reranking improved the search results. import sys from couchbase.cluster import Cluster, ClusterOptions From a3c9a2cf6720fe381e8a5e05dddfdf2e1e8bd161 Mon Sep 17 00:00:00 2001 From: Gary Gray <137797428+ggray-cb@users.noreply.github.com> Date: Tue, 2 Sep 2025 16:58:49 -0400 Subject: [PATCH 39/41] Wrapping us most of the textual changes from John, Simon, and Deppkaran's feedback. --- .../examples/hyperscale-idx-examples.sqlpp | 7 ++ .../vector-index/pages/hyperscale-filter.adoc | 11 ++- .../pages/hyperscale-vector-index.adoc | 37 +++++---- .../pages/use-vector-indexes.adoc | 77 +++++++++++-------- .../pages/vector-index-best-practices.adoc | 44 +++++++---- .../pages/vectors-and-indexes-overview.adoc | 23 +++--- .../partials/index-algorithm-settings.adoc | 43 ++++++++--- 7 files changed, 147 insertions(+), 95 deletions(-) diff --git a/modules/vector-index/examples/hyperscale-idx-examples.sqlpp b/modules/vector-index/examples/hyperscale-idx-examples.sqlpp index d5f01a430..ba9637253 100644 --- a/modules/vector-index/examples/hyperscale-idx-examples.sqlpp +++ b/modules/vector-index/examples/hyperscale-idx-examples.sqlpp @@ -230,3 +230,10 @@ colors AS ( SELECT RAW colors; /* end::tuned-query[] */ +/* tag::train-list[] */ +CREATE VECTOR INDEX `squad-context-index` +ON `demo`.`squad`.`context`(`vector` VECTOR) + WITH { "dimension":384, "similarity":"L2", + "description":"IVF,SQ8", + "train_list":15000}; +/* end::train-list[] */ diff --git a/modules/vector-index/pages/hyperscale-filter.adoc b/modules/vector-index/pages/hyperscale-filter.adoc index 81b5fcb4f..4cf963392 100644 --- a/modules/vector-index/pages/hyperscale-filter.adoc +++ b/modules/vector-index/pages/hyperscale-filter.adoc @@ -13,11 +13,10 @@ A Hyperscale Vector index has a single column that indexes the vector. However, you can include scalar values in the index that you can use to filter the vector search. The index stores these included values along with the vector, but they're not indexed. -Because they're not indexed, using scalars to filter out large portions of the dataset in a query of a Hyperscale Vector index may be less efficient than Composite Vector index. In your queries that use a Hypserscale Vector index, you add the included scalar values as predicates in the `WHERE` clause. -During the index scan, Couchbase {propduct-name} uses the included scalar values to filter out vectors that do not meet the filter restriction. -If the filter matches the vector entry, Couchbase {product-name} performs the more expensive vector comparison operation to see if the vector matches the search vector. +During the index scan, Couchbase {product-name} uses the included scalar values to filter out vectors that do not meet the filter restriction. +If the filter matches the entry, Couchbase {product-name} performs the more expensive vector comparison operation to determine the distance between the vector value and the search vector. == Creating a Hyperscale Vector Index with Included Scalar Values @@ -34,10 +33,10 @@ include::vector-index:example$hyperscale-idx-examples.sqlpp[tag=create-idx-brigh This example is the same as the example from xref:vector-index:hyperscale-vector-index.adoc#examples[Create Hyperscale Vector Index Example], except that it adds the `INCLUDE` clause to add the `brightness` key. -=== Querying a Hyperscale Vector Index with Included Scalar Values +== Querying a Hyperscale Vector Index with Included Scalar Values When you query a Hyperscale Vector index, you can use the included scalar values as predicates in the `WHERE` clause of your query. -When your query adds predicate, Couchbase {product-name} uses it to filter the results before performing the vector index scan. +Couchbase {product-name} uses the predicates to filter the results before performing the vector comparison. The following example performs the same query as the example from xref:vector-index:hyperscale-vector-index.adoc#example[Query with a Hyperscale Vector Index], but adds the `brightness` key as a predicate in the `WHERE` clause: @@ -55,4 +54,4 @@ include::vector-index:example$hyperscale-idx-data.json[tag=query-rgb-brightness] Querying with the `brightness` attribute changes makes `sky blue` the top result compared to the results from the example in xref:vector-index:hyperscale-vector-index.adoc#query-example[Query with a Hyperscale Vector Index]. The restriction can also make the query faster. -On a system running a three-node cluster in Docker containers, the query ran in (43{nbsp}ms verses 219{nbsp}ms for the query without the filter. +On a laptop running a three-node cluster in Docker containers, the query ran in (43{nbsp}ms verses 219{nbsp}ms for the query without the filter. diff --git a/modules/vector-index/pages/hyperscale-vector-index.adoc b/modules/vector-index/pages/hyperscale-vector-index.adoc index 10bc5c647..761f561fa 100644 --- a/modules/vector-index/pages/hyperscale-vector-index.adoc +++ b/modules/vector-index/pages/hyperscale-vector-index.adoc @@ -33,11 +33,11 @@ Hyperscale Vector Indexes have the following requirements: * You must have the Index Service enabled on at least one node in your cluster. For more information about how to deploy a new node and Services on your database, see xref:manage:manage-nodes/node-management-overview.adoc[]. -* You must have a bucket with scopes and collections in your database. -For more information about how to create a bucket, see xref:manage:manage-buckets/create-bucket.adoc[]. - * Your account must have the xref:learn:security:roles.adoc#query-manage-index[Query Manage Index] or an administrator role to be able to create an index. +* You must have a bucket your database. +For more information about how to create a bucket, see xref:manage:manage-buckets/create-bucket.adoc[]. + * You have documents in a collection that contain one or more vector embeddings. You can add a single vector to a Hyperscale Vector Index. If your documents contain multiple embedded vectors, you can create multiple indexes---one for each vector attribute. @@ -61,7 +61,7 @@ For example, OpenAI API's `text-embedding-ada-002` embedding model creates vect * You must decide what distance metric and quantization you want your index to use. The metrics affect how the index compares vectors. -The quantization determines how much memory your index uses and the amount of processing Couchbase {product-name} must perform to train and search them. +The quantization determines how much memory your index uses and the amount of processing Couchbase {product-name} must perform to train and search them. See xref:vector-index:vectors-and-indexes-overview.adoc#vector_similarity[Vector Similarity Metrics] and xref:vector-index:vectors-and-indexes-overview.adoc#quantization[Quantization] for more information. [#create-index] @@ -79,29 +79,30 @@ This statement is similar to the `CREATE INDEX` statement that you use to create See xref:guides:create-index.adoc[] for an overview of creating indexes. You must also supply a `WITH` clause to set some additional information about the vector column that the Hypsercale index needs. - -The following syntax for the `CREATE VECTOR INDEX` shows the minimum required parameters. -For the full syntax, see CREATE VECTOR INDEX in the SQL++ for Query Reference. - -// FIXME: Link goes here +The following syntax shows the minimum required parameters to create a Hyperscale Vector index: [source,sqlpp] ---- CREATE VECTOR INDEX `` - ON ``(`` VECTOR) + ON ``(`` VECTOR) WITH { "dimension": , - "similarity":, + "similarity":, "description": }; ---- +NOTE: This syntax for the `CREATE VECTOR INDEX` shows the minimum required parameters to get you started. +For the full syntax, see xref:n1ql:n1ql-language-reference/createvectorindex.adoc[`CREATE VECTOR INDEX`] in the SQL++ for Query Reference. + +The parameters in this statement are: + * `index-name` is a string that sets the name of the index. * `collection` is the path of the collection to index. * `key-name` is the name of the key containing the vector that you want to index. The key value must be an array of floating point numbers or a base64 encoded string. -* `dimensions` is an integer value that sets the number of dimensions in the vector. +* `dimensions` The number of dimensions in the vector as an integer. The embedded model you use to embed the vectors determines the number of dimensions in the vector. -* `similarity-metric` is a string that sets the distance metric to use when comparing vectors during index creation. +* `distance-metric` is a string that sets the distance metric to use when comparing vectors during index creation. + include::partial$distance-metric-list.adoc[] @@ -113,7 +114,6 @@ See <<#algo_settings>> in the next section for more information. include::partial$index-algorithm-settings.adoc[] - [#examples] === Create Hyperscale Vector Index Example @@ -237,17 +237,16 @@ include::vector-index:example$hyperscale-idx-examples.sqlpp[tag=query-rgb-with-s In this example, the `APPROX_VECTOR_DISTANCE` function compares the vector in the `couchbase_search_query.knn.vector` attribute to the vectors in the index. The parameters the example passes to this function are: -* The `embedding-vector-dot` is the name of the indexed vector key in the collection. -* The `couchbase_search_query.knn[0].vector`` is the vector search value to compare to the vectors in the index. +* The `embedding-vector-dot` is the name of the indexed vector key in the collection. +* The `couchbase_search_query.knn[0].vector` is the vector search value to compare to the vectors in the index. This value is the result of the subquery that gets the vector from the `rgb-questions` collection. * `l2` is the distance metric to use. * `4` is the number of centroids to probe for matching vectors. This value defaults to `1`. -This example sets this value to `4`` because the dataset is small. +This example sets this value to `4` because the dataset is small. In a small dataset, it's more likely that relevant vectors are not associated with the same centroid. This parameter broadens the search beyond a single centroid to find more relevant vectors. -If you re-run the query with the default value of `1``, you'll see that the results are less relevant. - +If you re-run the query with the default value of `1`, you'll see that the results are less relevant. The result of running the query is: diff --git a/modules/vector-index/pages/use-vector-indexes.adoc b/modules/vector-index/pages/use-vector-indexes.adoc index 89a15add3..e6af94783 100644 --- a/modules/vector-index/pages/use-vector-indexes.adoc +++ b/modules/vector-index/pages/use-vector-indexes.adoc @@ -79,58 +79,69 @@ When choosing which type of index to use, you must consider: The following table summarizes the differences between the three types of vector indexes: + [%autowidth] |=== -| Index Type | Available in Version | Dataset Size | Uses | Strength | Limitations +| | Hyperscale Vector Index | Composite Vector Index | FTS Vector Index -| *Hyperscale Vector Index* -| 8.0 -| Billions of documents -a| -* Pure vector searches +| *First Available in Version* +| 8.0 +| 8.0 +| 7.6 + +| *Dataset Size* +| Tens of millions to billions of documents +| Tens of millions to billion +| Tens of millions + +| *Uses* +a| * Pure vector searches * Content discovery or recommendations a| -* High performance for pure vector searches +* Searches combining vector and scalar values where scalar values are less selective (20% or less) +* Searches where scalars should exclude vectors, such as compliance uses +a| +* Hybrid searches combining vector and keywords or geospatial + +| *Strengths* +a| * High performance for pure vector searches +* Higher accuracy at lower quantizations (fewer bits per vector) * Low memory footprint * Lowest TCO for huge datasets * Best option for concurrent updates and searches -* Scalars in query do not override the vector values -a| -* Indexing can take longer relative to other index types -* Not as efficient as Composite Vector indexes when using scalar values to filter large portions of dataset - -| *Composite Vector Index* -| 8.0 -| Tens of millions to billion -| Searches combining vector and scalar values +* Scalars and vector values compared at the same time a| * Scalar values pre-filter data to reduce the scope of vector searches +* Efficient when scalar values have low selectivity (exclude less than 20% of dataset) * Can restrict searches based on scalars for use cases such as compliance -* Based on familiar Global Secondary indexes (GSI) -* Good option for extreme filtering of dataset before performing a vector search +* Based on familiar Global Secondary Indexes (GSI) a| -* Accuracy suffers in huge datasets compared to Hyperscale Vector index -* Scalar values always override vector values in queries, potentially missing relevant results +* Combines semantic and Full-Text Search and geospatial search in a single pass +* Uses familiar Search indexes -| *FTS Vector Index* -| 7.6 -| Tens of millions -| Hybrid searches combining vector and keywords or geospatial +| *Limitations* +a| * Indexing can take longer relative to other index types a| -* Combines semantic and Full-Text search and geospatial search in a single pass -* Uses familiar Search indexes +* Lower accuracy than Hyperscalar when when using lower quantizations (fewer bits per vector) +* Scalar values filter data before vector search, potentially missing relevant results (see <>) a| * Not as efficient as Composite Vector indexes if the search includes purely numeric or scalar values * Does not scale to the extent of the other index types Limited to approximately 100 million documents + |=== +[#scalar-handling] +NOTE: A key difference between Hyperscale and Composite Vector indexes is how they handle scalar values in queries. +Hyperscale Vector indexes compare vectors and scalar values at the same time. +Composite Vector indexes always apply scalar filters first, and only perform vector searches on the results. +This behavior means Composite Index searches can exclude relevant vectors from the search result. +However, it's useful for cases where you must exclude some vectors (even the nearest neighbors) based on scalar values. For example, it's useful when meeting compliance requirements. When choosing which type of index to use, consider the following: * In most cases, test using a Hyperscale Vector index. If you find that the performance is not what you need, you can try using one of the other index types. -* If your index searches include scalar values that filter out large portions of the dataset, consider using a Composite Vector index. * If your dataset will not grow beyond 100 million documents and you need to perform hybrid searches that combine vector searches with Full-Text Search or geospatial searches, use an FTS Vector index. == Applications for Vector Indexes @@ -155,7 +166,7 @@ Chatbot context for workflows like retreival-augmented generation (RAG) requires The large dataset gives the chatbot a depth of knowledge that's not necessary in simpler applications. Anomaly detection:: -Anomaly detection applications such as those used in Internet of Things (IoT) sensor networks, require huge datasets to find deviations from expected patterns. +Anomaly detection applications, such as those used in Internet of Things (IoT) sensor networks, require huge datasets to find deviations from expected patterns. Hyperscale Vector indexes can handle the large datasets and perform these vector searches fast. === Hyperscale Vector Index Application Workflow @@ -240,12 +251,12 @@ Travel recommendations:: Users often want to search for hotels using multiple criteria: + -* Limiting searches to a specific area (for example, "walking distance to the Louvre") which relies on geospacial data. +* Limiting searches to a specific area (for example, "walking distance to the Louvre") which relies on geospatial data. * Specific keywords for features they want, such as "quiet", "romantic", or "gym", which requires Full-Text Search. -* Semantic searches of descriptions and reviews for searches that do not rely on literal text matches, such as "modern beach resort with chic décor", which requires vector searches. +* Semantic searches of descriptions and reviews for searches that do not rely on literal text matches, such as "modern beach resort with chic décor," which requires vector searches. + -An FTS vector index can combine geospacial, keyword, and semantic searches into a single index. +An FTS vector index can combine geospatial, keyword, and semantic searches into a single index. Real estate searches:: Real estate applications can use FTS Vector indexes to find properties within a search region and have floor plan similar to an uploaded image. @@ -266,8 +277,8 @@ The steps shown in the diagram are: . It sends the data and the vector to Couchbase {product-name} for storage. . The Data Service sends the embedded vector along with scalar fields to the Search Service for inclusion in the FTS Vector index. . When your application needs to perform a search that includes a vector, it uses the same embedding model to generate a vector for the search value. -. It sends the search vector and text, geospacial, and other search values as part of a search request to the Couchbase {product-name} Search Service. -. The Search Service performs an index scan in the FTS Vector index to find documents that match the text or geospacial portions of the query. +. It sends the search vector and text, geospatial, and other search values as part of a search request to the Couchbase {product-name} Search Service. +. The Search Service performs an index scan in the FTS Vector index to find documents that match the text or geospatial portions of the query. Then it performs a vector similarity search on the results using the search vector. . The Search Service returns results to your application. diff --git a/modules/vector-index/pages/vector-index-best-practices.adoc b/modules/vector-index/pages/vector-index-best-practices.adoc index 7b85a76c4..81300bf3d 100644 --- a/modules/vector-index/pages/vector-index-best-practices.adoc +++ b/modules/vector-index/pages/vector-index-best-practices.adoc @@ -8,7 +8,7 @@ [abstract] {description} -Couchbase has performed testing to determine how index creation and query options affect the performance of Hyperscale and Composite Vector indexes. +Couchbase has tested vector indexes to determine how index creation and query settings affect the performance of Hyperscale and Composite Vector indexes. The following sections describe the results of the testing and recommendations based on these results. NOTE: Most of the tests were performed using the Hyperscale Vector index. @@ -25,29 +25,45 @@ Each has the potential to affect the performance of creating the index and the s The `nList` setting controls the number of clusters (centroids) in the index. You set the `nList` by supplying a value after the `IVF` in the `description` parameter when you create your index. This value affects the accuracy of the index and the speed of queries that use it. -The default value for this value depends on the size of your dataset. -For datasets with less than 1 million vectors, the default value is the number of vectors divided by 1000. -For datasets with more than 1 million vectors, the default value is the square root of the number of vectors. +The `nList` setting defaults to the number of vectors in the dataset divided by 1000. -Tests show that increasing `nList` beyond the default does not affect the build time of the index. + +For Composite Vector indexes, tests show that increasing `nList` beyond the default does not affect the build time of the index. However, it does improve the queries per second (QPS) that the index can handle. It also lowers the latency of queries that use the index. +Hyperscale Vector indexes tend to perform better with larger centroids (smaller `nList` values). +This performance gain has to be balanced against tyhe possibility of increased disk I/O due to centroids having more vectors associated with them. + +*Recommendation:* The best practice for the `nList` depend on your vector index type: -*Recommendation:* if you find that your query throughput and latency is not meeting your needs, you can try rebuilding the index with a larger `nList` value. +* If you find that your Composite Vector index query throughput and latency is not meeting your needs, you can try rebuilding the index with a larger `nList` value. + +* For Hyperscale Vector indexes, decrease the `nList` value if your working dataset fits into the bucket's memory quota. +You can also try decreasing the `nList` value if you have fast storage such as NVME connected to a high-speed PCIe interface. === TrainList The `TrainList` setting controls the number of vectors that Couchbase {product-name} considers when searching for centroids in the dataset. You set it using the `trainlist` key in the `WITH` clause when you create your index. -The default value is approximately 50 times the number of centroids in the index. +The default value depends on the size of the dataset: +* If there are less than 10,000 vectors, Couchbase Server samples all of the vectors. +* If there are 10,000 or more vectors, Couchbase {product-name} samples the number of vectors divided by 10 or 10 times the number of centroids, whichever is larger. +Couchbase {product-name} limits the trainlist to a maximum of 1 million vectors. Tests show that increasing the `trainlist` improves QPS and reduces latency, but slightly increases memory usage for the index. - -*Recommendation:* if you find that increasing the `nList` does not improve your query performance, you can try increasing the `trainlist` value. +*Recommendation:* if you find that increasing the `nList` does not improve your query performance, you can try increasing the `train_list` value. + +The following example demonstrates how to set the `train_list` value when creating a Hyperscale Vector index: + +[source,sqlpp] +---- +include::vector-index:example$hyperscale-idx-examples.sqlpp[tag=train-list] +---- + === Partitions @@ -81,7 +97,7 @@ Couchbase {product-name} supports two quantization methods: xref:vector-index:ve You set the quantization method using the `description` parameter in the `WITH` clause when you create your index. -Couchbase tested different quantization settings using datasets that differed in size and number of dimensions. +Couchbase tested different quantization settings using datasets that differed in size and number of dimensions. The results of these tests appear in the following table: @@ -140,7 +156,6 @@ The following list describes the parameters you can set in the function: You optionally set this value as the fourth parameter in the `APPROX_VECTOR_DISTANCE` function call in your query. The default value for this value is 1, which only searches for similar vectors in the centroid that's closest to the search vector. - Tests show that increasing `nProbes` beyond the default improves the accuracy of results non-linearly (larger values show diminishing improvements). However, it caused a linear decrease in QPS and increase in latency. @@ -175,7 +190,6 @@ Based on the results of this comparison, you can decide whether you need to adju IMPORTANT: The `VECDOR_DISTANCE` function is very expensive to run because it compares all vectors in the dataset. You should only use it on a testing system with a smaller dataset. - For example, suppose you run the following query against a Hyperscale Vector index: [source,sqlpp] @@ -208,7 +222,7 @@ include::vector-index:example$hyperscale-idx-data.json[tag=exact-query-results] You can see the results of the two queries share only a few common results. You can perform a more complex query that determines the common results between the two queries and calculates the recall rate. -The following example executes both of the previous queries as subqueries, then finsd the intersection of the results. +The following example executes both of the previous queries as subqueries, then finds the intersection of the results. It calculates the recall rate based on the 10 results the queries return (called the recall@10 due to the sample size): [source,sqlpp] @@ -244,12 +258,12 @@ include::vector-index:example$hyperscale-idx-data.json[tag=tuned-query-results] The results look more similar to the results of the exact query. To verify, you can re-run the recall rate query using the new `nProbes` value. -The following example shows the recall rate query with the `APPROX_VECTOR_DISTANCE` function call wupdated with the new `nProbes` value: +The following example shows the recall rate query with the `APPROX_VECTOR_DISTANCE` function call updated with the new `nProbes` value: [source,sqlpp] ---- include::vector-index:example$hyperscale-idx-examples.sqlpp[tag=recall-rate-tuned] ----- +---- The result of this update are: diff --git a/modules/vector-index/pages/vectors-and-indexes-overview.adoc b/modules/vector-index/pages/vectors-and-indexes-overview.adoc index f9819a069..87faf2de1 100644 --- a/modules/vector-index/pages/vectors-and-indexes-overview.adoc +++ b/modules/vector-index/pages/vectors-and-indexes-overview.adoc @@ -1,13 +1,13 @@ -= Vectors and Vector Indexes Overview += Vectors and Vector Indexes :page-topic-type: concept :page-ui-name: {ui-name} :stem: latexmath :page-product-name: {product-name} -:description: This page is a high-level overview of vectors and adding vector values to indexes. +:description: This page is a high-level overview of vectors and how they work in indexes. :page-toclevels: 3 +[abstract] {description} - Couchbase {product-name} supports several types of vector indexes. These indexes let you add similarity searches to your applications without relying on external services. This page provides an overview of vectors. @@ -45,7 +45,7 @@ They may: image::vector-space-example.svg["Three-dimensional plot showing two vectors that are close by and parallel and a third vector that's away and points in another direction"] Because the first two articles are about cats, their vectors point in a similar direction and are in a similar location in space. -The third article, despite using the word "cat" as frequently as the two other articles, has a vector that has significant differences from the other two. +The third article, despite using the word "cat" as frequently as the two other articles, has a vector that has significant differences from the other two. NOTE: Some diagrams in this document (and in other discussions available on the web) show vectors in three dimensions. These diagrams are a simplification. @@ -119,9 +119,9 @@ Each metric works best for certain applications and types of data. Couchbase {product-name} supports four metrics: [#euclidean] -=== Euclidean Distance (also known as L2) +=== Euclidean Distance -Euclidean distance calculates the geometric distance between two vectors by finding the distance between the individual dimensions in the vectors. +Euclidean Distance (also known as L2) calculates the geometric distance between two vectors by finding the distance between the individual dimensions in the vectors. This method is most sensitive to the distance between the vectors in space, rather than their alignment. It's also sensitive to the scale of the vectors, where the length of one vector verses the other affects the relationship between the vectors. Use this method when the actual distance of the vectors and their magnitudes are important. @@ -139,9 +139,10 @@ NOTE: Only Hyperscale Vector and Composite Vector indexes support this metric. FTS Vector indexes do not support it. [#euclidean-squared] -=== Euclidean Squared Distance (also known as L2 Squared or L2^2^) +=== Euclidean Squared Distance + -This method is similar to Euclidean Distance, but it does not take the square root of the sum distances between the vectors: +Euclidean Squared Distance (also known as L2 Squared or L2^2^) is similar to Euclidean Distance, but it does not take the square root of the sum distances between the vectors: Euclidean Distance Formula:: @@ -154,7 +155,7 @@ latexmath:[L2^2(x, y) = \sum_{i=1}^n (x_i - y_i)^2] Because it does not take the square root of the sums, Euclidean Squared Distance is faster to calculate than Euclidean Distance. However, it does not represent the actual distance between the vectors. -The results of a vector search using L2 Squared as a metric always returns the same rankings that an L2 search returns. +The results of a vector search using L2 Squared as a metric always returns the same rankings that an L2 search returns. In cases where the dimensions of the vectors represent real-world values, L2 is more intuitive to use because it returns the actual distance between the vectors. Use this method when you need higher performance than Euclidean Distance. @@ -190,7 +191,7 @@ For example: * Targeting ads based on a user's interests and previous interactions with the service. [#cosine] -=== Cosine Similarity:: +=== Cosine Similarity This metric is similar to the dot product. However, it normalizes the vectors (making them the same length) during comparison. @@ -407,4 +408,4 @@ After Couchbase {product-name} builds and trains the new index, you can drop the You should consider the need to retrain your indexes when choosing which quantization to use. For example, the PQ quantization requires more resources to train than SQ. -If your dataset evolves rapidly, you may choose to not use PQ because you'll need to perform more frequent retraining. +If your dataset evolves rapidly, you may choose to not use PQ because you'll need to perform more frequent retraining. diff --git a/modules/vector-index/partials/index-algorithm-settings.adoc b/modules/vector-index/partials/index-algorithm-settings.adoc index 390da620a..b61ebddd0 100644 --- a/modules/vector-index/partials/index-algorithm-settings.adoc +++ b/modules/vector-index/partials/index-algorithm-settings.adoc @@ -2,7 +2,7 @@ === Quantization and Centroid settings When creating an index that includes a vector field, you choose settings that affect how the index processes vectors. -The parameter named `description` is the primary setting that controls the quantization and the number of centroids Couchbase {product-name} to create the index. +The parameter named `description` is the primary setting that controls the quantization and the number of centroids Couchbase {product-name} to create the index. Using it, you control how the index subdivides the dataset to improve performance and how it quantizes vectors to reduce memory and processing requirements. The `description` parameter is a string in the following format: @@ -21,32 +21,53 @@ One of these algorithms, xref:vector-index:use-vector-indexes.adoc#IVF[Inverted The other algorithms that {index-name} uses do not have settings you can adjust. The key setting for IVF is the number of centroids it allocates for the index. -This number affects the performance of your index in two ways: +This setting controls how large the centroids are. +Larger centroids have more vectors associated with them. -* If the index has fewer centroids, each centroid has more vectors associated with it. +You can have Couchbase {product-name} choose a number of centroids for you by not providing a value after the `IVF` in your `description` parameter. +It sets the number of centroids to the number of vectors in the dataset divided by 1000. + +You can manually set the number of centroids for the index by adding an integer value after the `IVF` in the `description` parameter. +The number of centroids you set manually must be less than the number of vectors in the dataset. + +ifeval::['{index-name}' == 'Composite Vector index'] +The number of centroids affects the performance of your {index-name} index in two ways: + +* If the index has fewer centroids, each centroid is larger (has more vectors associated with it). In this case, a vector search has to perform more comparisons, making the search slower. -However, having fewer centroids decreases the processing required to train the index. +However, having fewer centroids decreases the processing required to train the index. * A greater number of centroids results in a greater processing cost for training. This increase is due to the training process having to search for more data cluster to identify more centroids. However, it reduces the number of vectors associated with each centroid. This reduction makes search faster by limiting the number of vector comparisons during a search. +endif::[] -You can have Couchbase {product-name} choose a number of centroids for you by not providing a value after the `IVF` in your `description` parameter. -It chooses the number of centroids based on the number of vectors in the dataset: +ifeval::['{index-name}' == 'Hyperscale Vector index'] +{index-name-plural} perform better with larger centroids (fewer centroids in the index). +They use algorithms to skip vectors that are far away from the search vector, making searches faster even with more vectors per centroid. +Having fewer centroids can also speed up the index training process because Couchbase {product-name} has to identify fewer data clusters. +However, having more vectors per centroid can result in more disk I/O during searches because each centroid has more data associated with it. -* If the number of vectors in the dataset is less than 1 million (1,000,000), Couchbase {product-name} sets the number of centroids to stem:["number of vectors" / 1000]. +When choosing the number of centroids for your index, consider the following guidelines: -* If the number of vectors in greater than 1 million, Couchbase {product-name} sets the number of centroids to stem:[sqrt("number of vectors")]. +* If the majority of your working data set fits into the bucket's memory quota, choose a smaller number of centroids for the index. +Having more of the working data set in memory reduces disk I/O during searches, making searches faster. +Another option is to have the fastest possible storage such as a fast NVME connected to a high-speed PCIe interface. -You can manually set the number of centroids for the index by adding an integer value after the `IVF` in the `description` parameter. -The number of centroids you set manually must be less than the number of vectors in the dataset. +* If your working data set is much larger than the bucket's memory quota, choose a larger number of centroids for the index. +This setting reduces the number of vectors associated with each centroid, which can reduce disk I/O during searches. + +endif::[] + +You may need to experiment with different numbers of centroids to find the best setting for your dataset and queries. -See xref:vector-index:vector-index-best-practices.adoc#nlist[nList] for guidance on choosing the number of centroids for the index. +See xref:vector-index:vector-index-best-practices.adoc#nlist[nList] for more guidance on choosing the number of centroids for the index. ==== Quantization Setting {index-name} always uses quantization to reduce the size of vectors stored in the index. +By default, it uses You must choose whether the index uses xref:vector-index:use-vector-indexes.adoc#sq[Scalar Quantization (SQ)] or xref:vector-index:use-vector-indexes.adoc#pq[Product Quantization (PQ)]. See xref:vector-index:vector-index-best-practices.adoc#quantization[Quantization] for guidance on choosing the quantization method for the index. From b97ae45fc6150af7b00fc6550f4ea844a9b8d9ed Mon Sep 17 00:00:00 2001 From: Gary Gray <137797428+ggray-cb@users.noreply.github.com> Date: Wed, 3 Sep 2025 09:33:08 -0400 Subject: [PATCH 40/41] Bit more tidying up in the text. --- .../pages/composite-vector-index.adoc | 7 +++++-- .../pages/hyperscale-vector-index.adoc | 20 +++++++++---------- .../pages/use-vector-indexes.adoc | 2 +- .../partials/index-algorithm-settings.adoc | 2 +- 4 files changed, 17 insertions(+), 14 deletions(-) diff --git a/modules/vector-index/pages/composite-vector-index.adoc b/modules/vector-index/pages/composite-vector-index.adoc index a940e138e..747974123 100644 --- a/modules/vector-index/pages/composite-vector-index.adoc +++ b/modules/vector-index/pages/composite-vector-index.adoc @@ -67,7 +67,7 @@ Creating a Composite Vector index is similar to creating a non-vector GSI index. See xref:guides:create-index.adoc[] for an overview of creating indexes. In the `CREATE INDEX` statement to create the Composite Vector index, add the `VECTOR` lead key attribute after the vector's key name to declare it as an embedded vector. -You must also use the `WITH` clause to specify some additional information for the vector column. +You must also use the xref:n1ql:n1ql-language-reference/createindex.adoc#index-with[`WITH`] clause to specify some additional information for the vector column. The format for this clause with the most commonly used parameters is: [source,sqlpp] @@ -78,6 +78,9 @@ WITH { "dimension": , }; ---- +NOTE: The `WITH` clause can contain other parameters that affect how the index processes vectors. +For a full list of these parameters, see xref:n1ql:n1ql-language-reference/createindex.adoc#index-with[WITH Clause] in the {sqlpp} for Query Reference. + * `dimensions` is an integer value that sets the number of dimensions in the vector. This value is set by the embedded model you used to embed the vectors. * `similarity-metric` is a string that sets the distance metric to use when comparing vectors during index creation. @@ -89,7 +92,7 @@ For the greatest accuracy, use the distance function you plan to use when queryi * `centroids-and-quantization` is a string containing the settings for the quantization and index algorithms. See <<#algo_settings>> in the next section for more information. -For a full list of the parameters that affect a Composite Vector index, see Composite Vector Index in the SQL++ reference. +For a full list of the parameters that affect a Composite Vector index, see xref:n1ql:n1ql-language-reference/createindex.adoc[]. include::partial$index-algorithm-settings.adoc[] diff --git a/modules/vector-index/pages/hyperscale-vector-index.adoc b/modules/vector-index/pages/hyperscale-vector-index.adoc index 761f561fa..3be81ec44 100644 --- a/modules/vector-index/pages/hyperscale-vector-index.adoc +++ b/modules/vector-index/pages/hyperscale-vector-index.adoc @@ -77,7 +77,7 @@ endif::[] Use the `CREATE VECTOR INDEX` statement to create a Hyperscale Vector Index. This statement is similar to the `CREATE INDEX` statement that you use to create Global Secondary Indexes (GSI). See xref:guides:create-index.adoc[] for an overview of creating indexes. -You must also supply a `WITH` clause to set some additional information about the vector column that the Hypsercale index needs. +You must also supply a `WITH` clause to set some additional information about the vector column that the Hyperscale index needs. The following syntax shows the minimum required parameters to create a Hyperscale Vector index: @@ -161,7 +161,7 @@ In most cases, you'll not use these settings in a production environment. == Query with a Hyperscale Vector Index To use your Hyperscale Vector index, use the `SELECT` statement with a `ORDER BY` clause containing a call to the `APPROX_VECTOR_DISTANCE` function. -This function performs the vector search using the Hyperscale Vector index. +This function uses the Hyperscale Vector index when you query the vector key the index covers. A typical query looks like this: @@ -173,11 +173,14 @@ SELECT , , , - [] + ] ) LIMIT ; ---- -The parameters in the `APPROX_VECTOR_DISTANCE` function are: +NOTE: The previous query example shows just a subset of the most common parameters for the `APPROX_VECTOR_DISTANCE` function. +See xref:n1ql:n1ql-language-reference:vectorfun.adoc#approx_vector_distance[APPROX_VECTOR_DISTANCE] for the full set of parameters available in this function. + +The `APPROX_VECTOR_DISTANCE` parameters shown in the example are: * `collection-vector-column` is the name of the key containing the vector in the collection. * `search-vector-value` is the vector value to search for in the collection column. @@ -187,11 +190,8 @@ This value should match the distance metric you used when you created the index. * `centroids-to-probe` is an optional integer value that sets the number of centroids to probe for matching vectors. By default, the vector search only probes a single centroid. -For the full syntax, see `APPROX_VECTOR_DISTANCE` in the SQL++ reference. - -// FIXME: add link when available. -NOTE: You can also call the function `VECTOR_DISTANCE` to find similar vectors. +NOTE: You can also call the function xref:n1ql:n1ql-language-reference:vectorfun.adoc#vector_distance[`VECTOR_DISTANCE`] to find similar vectors. However, this function does not use the Hyperscale Vector index to perform the vector search. Instead, it performs a brute-force search for similar vectors. It's useful to measure the recall of your Hyperscale Vector index. @@ -204,9 +204,9 @@ The query pushes the `LIMIT` clause down into the index scan so that the scan en === Hyperscale Vector Index Query Example You must supply a vector value in your query that Couchbase {product-name} can compare to the vectors in the index. -In actual use, your application generates a vector for the query value using the same embedding model it used to embed the vectors in your documents. +In actual use, your application generates a vector for the query value using the same embedding model it used to embed the vectors in your documents. -To avoid the complication of calling an embedding mopdel, this example uses embedded vectors in the `rgb_questions.json` file that's included in `color_data_2vectors.zip`. +To avoid the complication of calling an embedding model, this example uses embedded vectors in the `rgb_questions.json` file that's included in `color_data_2vectors.zip`. For this example, the contents of this file are loaded into a collection named `vector-sample.color.rgb-questions`. This collection contains a `question` attribute which is a search prompt for a particular color. The `couchbase_search_query.knn.vector` attribute contains the embedded vector for the `question` attribute. diff --git a/modules/vector-index/pages/use-vector-indexes.adoc b/modules/vector-index/pages/use-vector-indexes.adoc index e6af94783..4c408a184 100644 --- a/modules/vector-index/pages/use-vector-indexes.adoc +++ b/modules/vector-index/pages/use-vector-indexes.adoc @@ -122,7 +122,7 @@ a| | *Limitations* a| * Indexing can take longer relative to other index types a| -* Lower accuracy than Hyperscalar when when using lower quantizations (fewer bits per vector) +* Lower accuracy than Hyperscalar when using lower quantizations (fewer bits per vector) * Scalar values filter data before vector search, potentially missing relevant results (see <>) a| * Not as efficient as Composite Vector indexes if the search includes purely numeric or scalar values diff --git a/modules/vector-index/partials/index-algorithm-settings.adoc b/modules/vector-index/partials/index-algorithm-settings.adoc index b61ebddd0..3198ae3ea 100644 --- a/modules/vector-index/partials/index-algorithm-settings.adoc +++ b/modules/vector-index/partials/index-algorithm-settings.adoc @@ -144,7 +144,7 @@ The following table shows several `description` values along with an explanation | `IVF,SQ8` | Couchbase {product-name} chooses the number of centroids the IVF algorithm uses. -The index uses Scalar Quantization with an 8-bit index, meaning each dimension of the vector is broken into 256 bins. +The index uses Scalar Quantization with an 8-bit index, meaning it breaks each of the vector's dimensions into 256 bins. | `IVF1024,PQ8x8` | IVF uses 1024 centroids to divide the dataset. From ae866579350c0d8869641995b9e838868467e12b Mon Sep 17 00:00:00 2001 From: Gary Gray <137797428+ggray-cb@users.noreply.github.com> Date: Wed, 3 Sep 2025 11:18:18 -0400 Subject: [PATCH 41/41] * Moved Python code to draw base of some diagrams to a source directory, as per Simon's suggestion. * Added more links to reference. * Fixed a few stray references to Couchbase Server instead of using the product-name alias. --- .../draw-centroid-ivf-diagram.py | 0 .../draw-centroid-pq-diagram.py | 0 .../{images => source}/draw-cosine-diagram.py | 0 .../draw-dot-product-diagram.py | 0 .../draw-euclidean-distance-diagram.py | 0 .../draw-vector-space-diagram.py | 0 .../pages/hyperscale-vector-index.adoc | 3 ++- .../pages/vector-index-best-practices.adoc | 23 ++++++++----------- .../pages/vectors-and-indexes-overview.adoc | 6 ++--- 9 files changed, 15 insertions(+), 17 deletions(-) rename modules/vector-index/assets/{images => source}/draw-centroid-ivf-diagram.py (100%) rename modules/vector-index/assets/{images => source}/draw-centroid-pq-diagram.py (100%) rename modules/vector-index/assets/{images => source}/draw-cosine-diagram.py (100%) rename modules/vector-index/assets/{images => source}/draw-dot-product-diagram.py (100%) rename modules/vector-index/assets/{images => source}/draw-euclidean-distance-diagram.py (100%) rename modules/vector-index/assets/{images => source}/draw-vector-space-diagram.py (100%) diff --git a/modules/vector-index/assets/images/draw-centroid-ivf-diagram.py b/modules/vector-index/assets/source/draw-centroid-ivf-diagram.py similarity index 100% rename from modules/vector-index/assets/images/draw-centroid-ivf-diagram.py rename to modules/vector-index/assets/source/draw-centroid-ivf-diagram.py diff --git a/modules/vector-index/assets/images/draw-centroid-pq-diagram.py b/modules/vector-index/assets/source/draw-centroid-pq-diagram.py similarity index 100% rename from modules/vector-index/assets/images/draw-centroid-pq-diagram.py rename to modules/vector-index/assets/source/draw-centroid-pq-diagram.py diff --git a/modules/vector-index/assets/images/draw-cosine-diagram.py b/modules/vector-index/assets/source/draw-cosine-diagram.py similarity index 100% rename from modules/vector-index/assets/images/draw-cosine-diagram.py rename to modules/vector-index/assets/source/draw-cosine-diagram.py diff --git a/modules/vector-index/assets/images/draw-dot-product-diagram.py b/modules/vector-index/assets/source/draw-dot-product-diagram.py similarity index 100% rename from modules/vector-index/assets/images/draw-dot-product-diagram.py rename to modules/vector-index/assets/source/draw-dot-product-diagram.py diff --git a/modules/vector-index/assets/images/draw-euclidean-distance-diagram.py b/modules/vector-index/assets/source/draw-euclidean-distance-diagram.py similarity index 100% rename from modules/vector-index/assets/images/draw-euclidean-distance-diagram.py rename to modules/vector-index/assets/source/draw-euclidean-distance-diagram.py diff --git a/modules/vector-index/assets/images/draw-vector-space-diagram.py b/modules/vector-index/assets/source/draw-vector-space-diagram.py similarity index 100% rename from modules/vector-index/assets/images/draw-vector-space-diagram.py rename to modules/vector-index/assets/source/draw-vector-space-diagram.py diff --git a/modules/vector-index/pages/hyperscale-vector-index.adoc b/modules/vector-index/pages/hyperscale-vector-index.adoc index 3be81ec44..62f5f018c 100644 --- a/modules/vector-index/pages/hyperscale-vector-index.adoc +++ b/modules/vector-index/pages/hyperscale-vector-index.adoc @@ -59,7 +59,8 @@ If a vector does not meet both of these requirements, the vector index treats it The embedding model you use to embed the vectors may determine this value for you. For example, OpenAI API's `text-embedding-ada-002` embedding model creates vectors that have 1536 dimensions. -* You must decide what distance metric and quantization you want your index to use. +* You must decide whether you want to use the default distance metric and quantization for your index. +By default, a Hyperscale Vector index uses the xref:vector-index:vectors-and-indexes-overview.adoc#euclidean-squared[Euclidean distance squared] metric and xref:vector-index:vectors-and-indexes-overview.adoc#sq[Scalar Quantization (SQ)] with 8 bits per vector dimension (`SQ8`). The metrics affect how the index compares vectors. The quantization determines how much memory your index uses and the amount of processing Couchbase {product-name} must perform to train and search them. See xref:vector-index:vectors-and-indexes-overview.adoc#vector_similarity[Vector Similarity Metrics] and xref:vector-index:vectors-and-indexes-overview.adoc#quantization[Quantization] for more information. diff --git a/modules/vector-index/pages/vector-index-best-practices.adoc b/modules/vector-index/pages/vector-index-best-practices.adoc index 81300bf3d..91261975a 100644 --- a/modules/vector-index/pages/vector-index-best-practices.adoc +++ b/modules/vector-index/pages/vector-index-best-practices.adoc @@ -18,6 +18,10 @@ However, many of the results also apply to Composite Vector indexes where the tw When you create a Hyperscale Vector index, you can set the parameters in the following list. Each has the potential to affect the performance of creating the index and the speed and accuracy of queries that use the index. +For more information about these parameters: + +* For Composite Vector index, see the xref:n1ql:n1ql-language-reference/createindex.adoc#index-with[WITH Clause] in the xref:n1ql:n1ql-language-reference/createindex.adoc[] page of the {sqlpp} for Query Reference. +* For Hyperscale Vector index, see xref:n1ql:n1ql-language-reference/createvectorindex.adoc#index-with[WITH Clause] in the xref:n1ql:n1ql-language-reference/createvectorindex.adoc[] page of the {sqlpp} for Query Reference. [#nlist] === nList @@ -43,13 +47,13 @@ This performance gain has to be balanced against tyhe possibility of increased d * For Hyperscale Vector indexes, decrease the `nList` value if your working dataset fits into the bucket's memory quota. You can also try decreasing the `nList` value if you have fast storage such as NVME connected to a high-speed PCIe interface. -=== TrainList +=== train_list -The `TrainList` setting controls the number of vectors that Couchbase {product-name} considers when searching for centroids in the dataset. -You set it using the `trainlist` key in the `WITH` clause when you create your index. +The `train_list` setting controls the number of vectors that Couchbase {product-name} considers when searching for centroids in the dataset. +You set it using the `train_list` argument in the `WITH` clause when you create your index. The default value depends on the size of the dataset: -* If there are less than 10,000 vectors, Couchbase Server samples all of the vectors. +* If there are less than 10,000 vectors, Couchbase {product-name} samples all of the vectors. * If there are 10,000 or more vectors, Couchbase {product-name} samples the number of vectors divided by 10 or 10 times the number of centroids, whichever is larger. Couchbase {product-name} limits the trainlist to a maximum of 1 million vectors. @@ -64,7 +68,6 @@ The following example demonstrates how to set the `train_list` value when creati include::vector-index:example$hyperscale-idx-examples.sqlpp[tag=train-list] ---- - === Partitions The number of partitions the index controls how the index is split among logical shards. @@ -81,13 +84,10 @@ These changes do not affect the QPS or latency of queries that use the index. The number of replicas you set affects the fault tolerance, query throughput, and memory footprint of the index. You set this value using the `num_replicas` key in the `WITH` clause when you create or alter your index. - -+ Tests show that increasing the number of replicas learly increases the QPS and linerly reduces the latency of queries that use the index. However, it also linearly increased the memory footprint of the index. Adding replicas does not affect the time it takes to build the index. - *Recommendation:* if you find that your query throughput or latency is not meeting your needs, you can try increasing the number of replicas for the index if you can afford the additional memory usage. [#quantization] @@ -96,11 +96,9 @@ Vector indexes always use quantization to compress the vectors they index. Couchbase {product-name} supports two quantization methods: xref:vector-index:vectors-and-indexes-overview.adoc#sq[scalar quantization (SQ)] and xref:vector-index:vectors-and-indexes-overview.adoc#pq[product quantization (PQ)]. You set the quantization method using the `description` parameter in the `WITH` clause when you create your index. - Couchbase tested different quantization settings using datasets that differed in size and number of dimensions. The results of these tests appear in the following table: - [%autowidth, options="header"] |=== | Dataset | Index Type | Quantization Setting | Build Time | Memory Use | Recall Accuracy | QPS | Latency @@ -187,7 +185,7 @@ To do this, compare the results of running a query using the `APPROX_VECTOR_DIST The `VECTOR_DISTANCE` function performs a brute-force full vector comparison, so it returns the most accurate results. Based on the results of this comparison, you can decide whether you need to adjust your index or query settings to improve recall accuracy. -IMPORTANT: The `VECDOR_DISTANCE` function is very expensive to run because it compares all vectors in the dataset. +IMPORTANT: The `VECTOR_DISTANCE` function is expensive to run because it compares all vectors in the dataset. You should only use it on a testing system with a smaller dataset. For example, suppose you run the following query against a Hyperscale Vector index: @@ -219,8 +217,7 @@ Running the query returns the following results: include::vector-index:example$hyperscale-idx-data.json[tag=exact-query-results] ---- - -You can see the results of the two queries share only a few common results. +You can see the results of the two queries share few common results. You can perform a more complex query that determines the common results between the two queries and calculates the recall rate. The following example executes both of the previous queries as subqueries, then finds the intersection of the results. It calculates the recall rate based on the 10 results the queries return (called the recall@10 due to the sample size): diff --git a/modules/vector-index/pages/vectors-and-indexes-overview.adoc b/modules/vector-index/pages/vectors-and-indexes-overview.adoc index 87faf2de1..96cdc6ab4 100644 --- a/modules/vector-index/pages/vectors-and-indexes-overview.adoc +++ b/modules/vector-index/pages/vectors-and-indexes-overview.adoc @@ -213,9 +213,9 @@ Use this method when you're performing searches that rely on semantic meaning, s [#index-algorithms] == Index Formats -Couchbase Server supports two formats that the Vector indexes use when storing their data. +Couchbase {product-name} supports two formats that the Vector indexes use when storing their data. These formats control how the index stores the vectors. -Couchbase Server automatically chooses which algorithm to use, based on the type of the index and the size of the dataset. +Couchbase {product-name} automatically chooses which algorithm to use, based on the type of the index and the size of the dataset. However, you can set parameters when you create the index that affect how the algorithm organizes data. === Flat Index @@ -268,7 +268,7 @@ However, quantization does reduce the accuracy of a vector. It's similar to using a lossy image compression format, such as JPEG, on an picture to reduce its data size. It trades off some detail and accuracy for a smaller, more manageable data size. -Unlike the indexing algorithms, you choose the quantization method you want Couchbase Server to use when you create a Hyperscale Vector or Composite Vector index. +Unlike the indexing algorithms, you choose the quantization method you want Couchbase {product-name} to use when you create a Hyperscale Vector or Composite Vector index. Couchbase {product-name} supports two types of quantization: