{"id":17830,"date":"2026-01-20T03:00:01","date_gmt":"2026-01-20T11:00:01","guid":{"rendered":"https:\/\/www.couchbase.com\/blog\/?p=17830"},"modified":"2026-03-31T16:25:08","modified_gmt":"2026-03-31T23:25:08","slug":"filtered-ann-search-with-composite-vector-indexes-2","status":"publish","type":"post","link":"https:\/\/www.couchbase.com\/blog\/ko\/filtered-ann-search-with-composite-vector-indexes-2\/","title":{"rendered":"\ubcf5\ud569 \ubca1\ud130 \uc778\ub371\uc2a4\ub97c \uc0ac\uc6a9\ud55c \ud544\ud130\ub9c1\ub41c ANN \uac80\uc0c9(2\ubd80)"},"content":{"rendered":"<p><span style=\"font-weight: 400\">This is the second blog post of a multi-part series exploring composite vector indexing in Couchbase, check out the first post <\/span><a href=\"https:\/\/www.couchbase.com\/blog\/filtered-ann-search-with-composite-vector-indexes\/\"><span style=\"font-weight: 400\">here<\/span><\/a><span style=\"font-weight: 400\">.\u00a0<\/span><\/p>\n<p><span style=\"font-weight: 400\">The series will cover:<\/span><\/p>\n<ol>\n<li style=\"font-weight: 400\"><a href=\"https:\/\/www.couchbase.com\/blog\/filtered-ann-search-with-composite-vector-indexes\/\"><span style=\"font-weight: 400\">Why composite vector indexes matter, including concepts, terminology, and developer motivation. A Smart Grocery Recommendation System will be used as a running example.<\/span><\/a><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">How composite vector indexes are implemented inside the Couchbase Indexing Service.<\/span><\/li>\n<li style=\"font-weight: 400\"><a href=\"https:\/\/www.couchbase.com\/blog\/filtered-ann-search-with-ive-composite-vector-indexes\/\"><span style=\"font-weight: 400\">How ORDER BY pushdown works for composite vector queries.<\/span><\/a><\/li>\n<li style=\"font-weight: 400\"><a href=\"https:\/\/www.couchbase.com\/blog\/filtered-ann-search-with-composite-vector-indexes-part-4\/\"><span style=\"font-weight: 400\">Real-world performance behavior and benchmarking results.<\/span><\/a><\/li>\n<\/ol>\n<h2><span style=\"font-weight: 400\">Implementation of Composite Vector Indexes<\/span><\/h2>\n<p><span style=\"font-weight: 400\">GSI uses the FAISS index factory under the hood. An index string like the one shown below will be constructed from the description field given in the DDL.<\/span><\/p>\n<pre class=\"lang:default decode:true\">  IVF{nlist}_HNSW,{PQ{M}x{N}|SQ{n} \r\n<\/pre>\n<p><span style=\"font-weight: 400\">Example: With a description string like \u201cIVF10000,PQ32x8\u201d, an FAISS index factory string like \u201cIVF10000_HNSW,PQ32x8\u201d will be constructed.<\/span><\/p>\n<p><span style=\"font-weight: 400\">However, this factory string is used only as a building block during index training and configuration. GSI does not rely on FAISS as a monolithic in-memory index over the full dataset. Instead, FAISS is applied selectively on sampled data to learn centroids and quantization codebooks, while the full index layout, storage, mutation handling, and query execution are managed by Couchbase. This allows Couchbase to scale vector search efficiently, integrate scalar filtering and query semantics, and support continuous updates <\/span><span style=\"font-weight: 400\">\u2013 <\/span><span style=\"font-weight: 400\">capabilities that extend well beyond invoking a standalone FAISS index.<\/span><\/p>\n<h3><span style=\"font-weight: 400\">Embeddings<\/span><\/h3>\n<p><span style=\"font-weight: 400\">The embedding layer takes the relevant text fields, sends them through a transformer model, and produces semantic vectors that represent each product. These vectors power the ANN search. The application must store these embeddings alongside the product data so the vector index can use them and ensure the stored embeddings match the vector index definition (for example, fixed dimension and numeric type) expected by Couchbase.<\/span><\/p>\n<pre class=\"lang:default decode:true\">{\r\n  \"product_name\": \"almond butter\",\r\n  \"sugar_100g\": 15,\r\n  \"proteins_100g\": 20,\r\n  \"description\": \"almond butter with chocolate chips\",\r\n  \"text_vector\": [0.12, -0.04, 0.33, 0.25, ...]\r\n...\r\n}\r\n<\/pre>\n<h3><span style=\"font-weight: 400\">Index Creation and Build<\/span><\/h3>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-17831\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2026\/01\/Screenshot-2026-01-20-at-12.41.23-PM.png\" alt=\"\" width=\"1288\" height=\"702\" srcset=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2026\/01\/Screenshot-2026-01-20-at-12.41.23-PM.png 1288w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2026\/01\/Screenshot-2026-01-20-at-12.41.23-PM-300x164.png 300w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2026\/01\/Screenshot-2026-01-20-at-12.41.23-PM-1024x558.png 1024w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2026\/01\/Screenshot-2026-01-20-at-12.41.23-PM-768x419.png 768w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2026\/01\/Screenshot-2026-01-20-at-12.41.23-PM-18x10.png 18w\" sizes=\"auto, (max-width: 1288px) 100vw, 1288px\" \/><\/p>\n<pre class=\"lang:default decode:true\">CREATE INDEX idx_vec_food\r\nON food (\r\n  text_vector VECTOR,\r\n  sugars_100g,\r\n  proteins_100g,\r\n  product_name\r\n)\r\nWITH {\r\n  \"dimension\": 384,\r\n  \"similarity\": \"L2\",\r\n  \"description\": \"IVF,SQ8\"\r\n};\r\n<\/pre>\n<h3><span style=\"font-weight: 400\">Create and Build Flow<\/span><\/h3>\n<ul>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">Given the user has a sufficient number of vectors stored, GSI randomly samples data to create a representative dataset.<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">This representative dataset is used to train the FAISS index. After training, GSI persists the codebook which includes an IVF inverted list, PQ codebooks:<\/span>\n<ul>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">IVF splits the vector space in nlist partitions and each partition is represented by a centroid<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">PQ or SQ quantization is used per partition to compress the vectors<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">The HNSW graph of the centroids is created; it is useful when number of centroids is very large<\/span><\/li>\n<\/ul>\n<\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">Data is streamed from the Data Service using the DCP protocol and for each document\u00a0 received.<\/span>\n<ul>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">The document is assigned to the partition whose centroid is nearest to the vector, i.e., the centroid is C1<\/span><\/li>\n<\/ul>\n<\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">During indexing, each document\u2019s vector is assigned to its nearest centroid, stored in a compact encoded form optimized for fast distance computation, and tracked efficiently so future updates only reprocess the vector if it actually changes.<\/span><\/li>\n<\/ul>\n<h5><span style=\"font-weight: 400\">Note<\/span><\/h5>\n<p><span style=\"font-weight: 400\">If the underlying vector distribution changes significantly, the index must be rebuilt to retrain the index. This can happen due to:<\/span><\/p>\n<ul>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">A change in the embedding model (e.g., switching models or dimensions)<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">Major shifts in the data distribution (new product categories, language changes, or domain drift)<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">Re-embedding existing documents with updated embeddings<\/span><\/li>\n<\/ul>\n<h5><span style=\"font-weight: 400\">How Many Documents Are Needed to Train a Vector Index?<\/span><\/h5>\n<p><span style=\"font-weight: 400\">When building a vector index, Couchbase automatically samples vector data to train the index for efficient and accurate ANN search.<\/span><\/p>\n<p><span style=\"font-weight: 400\">In general, the collection must contain at least as many documents as the number of centroids (nlist) configured for the index, since each centroid requires training data.<\/span><\/p>\n<p><span style=\"font-weight: 400\">When product quantization (PQ) is used, this minimum becomes max(nlist, 2^nbits) to ensure sufficient data for quantizer training where nbits is N from PQ{M}x{N}.<\/span><\/p>\n<p><span style=\"font-weight: 400\">Couchbase handles training as follows:<\/span><\/p>\n<ul>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">Small datasets (up to ~10,000 documents):<\/span>\n<ul>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">All vectors are used for training, no sampling is required.<\/span><\/li>\n<\/ul>\n<\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">Larger datasets:<\/span>\n<ul>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">By default, Couchbase selects a training set by taking the larger of the following, while capping the final sample size at 1 million vectors:<\/span>\n<ul>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">10% of the dataset, and<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">10x the number of centroids (nlist)<\/span><\/li>\n<\/ul>\n<\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">This approach balances training quality with index build time<\/span><\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p><b>Best practice:<\/b><span style=\"font-weight: 400\"> For stable, high-quality training, aim for at least 10 vectors per centroid, which allows the index to learn the underlying vector distribution effectively.<\/span><\/p>\n<p><b>Advanced control:<\/b><span style=\"font-weight: 400\"> If needed, you can explicitly control the number of training vectors by specifying the train_list parameter when creating the index.<\/span><\/p>\n<p><span style=\"font-weight: 400\">Couchbase manages the sampling and training process automatically. As a user, the key requirement is to ensure that a sufficient number of embedded documents exist before building the index.<\/span><\/p>\n<h3><span style=\"font-weight: 400\">Index Scan<\/span><\/h3>\n<pre class=\"lang:default decode:true\">SELECT product_name\r\nFROM food\r\nWHERE sugars_100g &lt; 20 AND proteins_100g &gt; 10\r\nORDER BY APPROX_VECTOR_DISTANCE(text_vector, [query_embedding], 'L2')\r\nLIMIT 10;\r\n<\/pre>\n<h5><span style=\"font-weight: 400\">Scan Flow<\/span><\/h5>\n<p><span style=\"font-weight: 400\">When a query containing a vector search arrives, Couchbase follows a well-defined sequence to route it through the right components and prepare the scan.<\/span><\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-17832\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2026\/01\/Screenshot-2026-01-20-at-12.43.19-PM.png\" alt=\"\" width=\"1296\" height=\"656\" srcset=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2026\/01\/Screenshot-2026-01-20-at-12.43.19-PM.png 1296w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2026\/01\/Screenshot-2026-01-20-at-12.43.19-PM-300x152.png 300w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2026\/01\/Screenshot-2026-01-20-at-12.43.19-PM-1024x518.png 1024w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2026\/01\/Screenshot-2026-01-20-at-12.43.19-PM-768x389.png 768w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2026\/01\/Screenshot-2026-01-20-at-12.43.19-PM-18x9.png 18w\" sizes=\"auto, (max-width: 1296px) 100vw, 1296px\" \/><\/p>\n<p><span style=\"font-weight: 400\">If sargable vector indexes were created and are active, the Query Service can use them to serve the Filtered ANN queries faster<\/span><\/p>\n<p><span style=\"font-weight: 400\">The scan coordinator in the indexer process receives the below mentioned inputs along with index name and consistency parameters:<\/span><\/p>\n<ul>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">Scalar filters on indexed fields<\/span>\n<ul>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">Equality or range predicates like sugars_100g &lt; 20<\/span><\/li>\n<\/ul>\n<\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">The query vector<\/span>\n<ul>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">Embedding of the user\u2019s search intent<\/span><\/li>\n<\/ul>\n<\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">The result size k<\/span>\n<ul>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">How many similar items the user wants back\u00a0<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">This is given in the LIMIT<\/span><\/li>\n<\/ul>\n<\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">The number of nearest centroids n<\/span>\n<ul>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">How much of the vector space we want to search<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">nprobes value n is parameter to <\/span><span style=\"font-weight: 400\">APPROX_VECTOR_DISTANCE<\/span><\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p><span style=\"font-weight: 400\">After getting the above information, a scan request is formed, which goes through the following steps:<\/span><\/p>\n<ol>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">Index snapshot is fetched based on the consistency parameters given.<\/span>\n<ul>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">If the user needs session consistency, the indexer fetches the latest timestamp from the Data Service and waits for the indexer to catch up and generate consistent snapshots that can serve the query.<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">If the user is fine with any consistency, the indexer uses the snapshot that it has cached without waiting.<\/span><\/li>\n<\/ul>\n<\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">The indexer waits for the storage readers needed to serve the query.\u00a0<\/span>\n<ul>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">As the indexer\u2019s resources are limited it is configured with the max number of readers that can be run; hence, if a system is busy, scans must wait for the readers to become free.<\/span><\/li>\n<\/ul>\n<\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">The indexer fetches the codebooks for the partitions that are getting scanned for the given query.<\/span>\n<ul>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">Note that the codebook (IVF Inverted list and PQ codebooks) does not change after the initial training phase, hence there are no snapshots for codebook.<\/span><\/li>\n<\/ul>\n<\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">Using the codebooks fetched above, the nearest <\/span><i><span style=\"font-weight: 400\">nprobe<\/span><\/i><span style=\"font-weight: 400\"> centroids of the query vector in every partition needed are fetched for a given query vector.<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">For a given index partition, scalar filters and nearest centroids are combined to form non-overlapping scan ranges to read data from the index.<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">Now the indexer sets up a dedicated scan pipeline. Think of this pipeline as a small, short-lived assembly line built specifically for that query. The pipeline stages (Read, Accumulate, and Write) run in parallel to accelerate the query process.<\/span><\/li>\n<\/ol>\n<h5><span style=\"font-weight: 400\">Scan Pipeline<\/span><\/h5>\n<p><span style=\"font-weight: 400\">The scan pipeline itself has three stages: read, aggregate, and write. Like any pipeline, each stage runs in parallel and streams its output into the next.<\/span><\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-17833\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2026\/01\/Screenshot-2026-01-20-at-12.43.59-PM.png\" alt=\"\" width=\"1326\" height=\"224\" srcset=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2026\/01\/Screenshot-2026-01-20-at-12.43.59-PM.png 1326w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2026\/01\/Screenshot-2026-01-20-at-12.43.59-PM-300x51.png 300w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2026\/01\/Screenshot-2026-01-20-at-12.43.59-PM-1024x173.png 1024w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2026\/01\/Screenshot-2026-01-20-at-12.43.59-PM-768x130.png 768w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2026\/01\/Screenshot-2026-01-20-at-12.43.59-PM-18x3.png 18w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2026\/01\/Screenshot-2026-01-20-at-12.43.59-PM-1320x223.png 1320w\" sizes=\"auto, (max-width: 1326px) 100vw, 1326px\" \/><\/p>\n<ol>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">Read Stage =&gt; Parallel Scanning + Scalar Filtering<\/span>\n<ul>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">The read stage fans out across multiple scan workers.<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">Each worker:<\/span>\n<ul>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">Scans and reads its assigned index range.<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">Applies scalar filters early to prune out irrelevant items.<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">Forwards only the qualifying documents to the next stage.<\/span><\/li>\n<\/ul>\n<\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">This early pruning is crucial; it prevents unnecessary vector distance calculations later.<\/span><\/li>\n<\/ul>\n<\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">Aggregate Stage =&gt; Ordering + Vector Distance Computation<\/span>\n<ul>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">The aggregate stage collects results from all workers and performs the \u201cheavy lifting.\u201d<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">It merges and orders items if required.<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">It substitutes centroid-based approximate distances with actual computed distances.<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">It maintains a top-k heap to track the best candidates so far.<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">This stage is where ANN logic meets scalar filtering.<\/span><\/li>\n<\/ul>\n<\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">Write Stage =&gt; Streaming Results Back to the GSI Client in Query Service<\/span>\n<ul>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">Finally, the write stage streams the aggregated results to the Query Service.<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">If the index is distributed across multiple indexer nodes, results from each node are merged.<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">From there, the query processor may perform additional operations such as:<\/span>\n<ul>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">Coarse-grained filtering<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">JOINs<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">Projections or final sorting<\/span><\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n<p><span style=\"font-weight: 400\">The user ultimately receives a clean, ordered list of the nearest neighbors that satisfy all scalar conditions.<\/span><\/p>\n<h3><span style=\"font-weight: 400\">Advanced Query Behavior in Composite Vector Index Scans<\/span><\/h3>\n<p><span style=\"font-weight: 400\">Once you understand how a vector scan pipeline works, there are several deeper concepts that influence how efficiently your queries run. These behaviors are tied to how the index is defined and how scalar predicates interact with vector partitions.<\/span><\/p>\n<h5><span style=\"font-weight: 400\">Scan Parallelism<\/span><\/h5>\n<p><span style=\"font-weight: 400\">Each query has a natural limit on how much parallelism it can exploit. This inherent parallelism comes from how many non-overlapping index ranges can be generated from the scalar predicates and nprobes. More disjoint ranges means more opportunities to scan in parallel.<\/span><\/p>\n<p><span style=\"font-weight: 400\">But scalar constraints aren\u2019t the only factor. The actual number of workers the system uses is the minimum of:<\/span><\/p>\n<ul>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">How much inherent parallelism the query can expose<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">How many centroids the query needs to search<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">How many centroids the index contains<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">The configured maximum workers per scan per partition<\/span><\/li>\n<\/ul>\n<p><span style=\"font-weight: 400\">This prevents the system from oversubscribing CPU or creating unnecessary threads when there is no additional parallel work to do.<\/span><\/p>\n<h5><span style=\"font-weight: 400\">Leading Key Predicates <\/span><span style=\"font-weight: 400\">\u2013<\/span><span style=\"font-weight: 400\"> Where Parallelism Begins<\/span><\/h5>\n<p><span style=\"font-weight: 400\">The predicates on the leading index keys (the first fields listed in the composite index definition) determine how much parallelism your query can exploit.<\/span><\/p>\n<p><span style=\"font-weight: 400\">If a leading scalar key has multiple equality predicates, each becomes an independent scan range, allowing the system to fan out and execute them in parallel.<\/span><\/p>\n<p><span style=\"font-weight: 400\">If the leading key uses a range predicate, the entire query collapses into one large scan range, which reduces parallelism.<\/span><\/p>\n<p><span style=\"font-weight: 400\">In short:<\/span><\/p>\n<ul>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">Equality on leading keys \u2192 maximum parallelism<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">Range on leading keys \u2192 one big sequential scan<\/span><\/li>\n<\/ul>\n<p><span style=\"font-weight: 400\">Choosing the right leading keys in the index definition has a direct impact on latency.<\/span><\/p>\n<p><span style=\"font-weight: 400\">Vector predicates effectively behave like equality filters on centroid IDs, selecting a fixed set of clusters to scan.<\/span><\/p>\n<h5><span style=\"font-weight: 400\">Scalar Selectivity <\/span><span style=\"font-weight: 400\">\u2013<\/span><span style=\"font-weight: 400\"> How Much Work You Don\u2019t Have to Do<\/span><\/h5>\n<p><span style=\"font-weight: 400\">Scalar selectivity measures how many data points can be eliminated by a scalar filter.<\/span><\/p>\n<p><span style=\"font-weight: 400\">A highly selective filter removes a large portion of the dataset before vector distance calculations even begin.<\/span><\/p>\n<p><span style=\"font-weight: 400\">For example:<\/span><\/p>\n<ul>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">sugars_100g &lt; 20 may eliminate 70% of items<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">proteins_100g &gt; 10 may eliminate 90% of items<\/span><\/li>\n<\/ul>\n<p><span style=\"font-weight: 400\">The more selective the scalar, the fewer vectors the index must compare.<\/span><\/p>\n<p><span style=\"font-weight: 400\">Composite vector index scan throughput increases proportionally with scalar selectivity, because the pipeline spends less time reading documents and computing distances.<\/span><\/p>\n<h5><span style=\"font-weight: 400\">Pagination <\/span><span style=\"font-weight: 400\">\u2013<\/span><span style=\"font-weight: 400\"> Ordered Vector Results<\/span><\/h5>\n<p><span style=\"font-weight: 400\">Composite vector index scans produce a global order for the result set.<\/span><\/p>\n<p><span style=\"font-weight: 400\">This happens because the index substitutes centroid IDs with actual vector distances, giving each candidate a precise distance metric.<\/span><\/p>\n<p><span style=\"font-weight: 400\">You can use LIMIT and OFFSET to paginate through results as long as enough qualifying items exist within the selected n centroids.<\/span><\/p>\n<p><span style=\"font-weight: 400\">This makes composite vector indexes suitable for UIs that require infinite scroll or page-by-page product browsing.<\/span><\/p>\n<h5><span style=\"font-weight: 400\">Flexibility in Index Definition <\/span><span style=\"font-weight: 400\">\u2013<\/span><span style=\"font-weight: 400\"> Tailor the Index to the Workload<\/span><\/h5>\n<p><span style=\"font-weight: 400\">Composite vector index DDL gives you full control over the ordering of index keys.<\/span><\/p>\n<p><span style=\"font-weight: 400\">This order directly affects how filtering is performed, which in turn impacts query performance.<\/span><\/p>\n<p><span style=\"font-weight: 400\">This flexibility enables multiple pruning strategies:<\/span><\/p>\n<ul>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">Vector-centric pruning<\/span>\n<ul>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">Start the index with the vector key, followed by scalars:<\/span>\n<ul>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">CREATE INDEX idx ON food(text_vector, sugars_100g, proteins_100g)<\/span><\/li>\n<\/ul>\n<\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">Good for workloads driven primarily by vector similarity.<\/span><\/li>\n<\/ul>\n<\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">Scalar-centric pruning<\/span>\n<ul>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">Place highly selective scalar fields first, then the vector key:<\/span>\n<ul>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">CREATE INDEX idx ON food(sugars_100g, proteins_100g, text_vector)<\/span><\/li>\n<\/ul>\n<\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">This is the most common and most efficient pattern because selective scalars prune aggressively before vector evaluation begins.<\/span><\/li>\n<\/ul>\n<\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">Vector-only pruning<\/span>\n<ul>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">Create an index only on the vector key:<\/span>\n<ul>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">CREATE INDEX idx ON food(text_vector)<\/span><\/li>\n<\/ul>\n<\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">This is useful when scalar fields have poor selectivity and won\u2019t help prune the search space.<\/span><\/li>\n<\/ul>\n<\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">Scalar-only pruning<\/span>\n<ul>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">Create a traditional non-vector index for queries that don\u2019t use vector similarity.<\/span><\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<h5><span style=\"font-weight: 400\">Scalar-Only Query Support and Covering Scans<\/span><\/h5>\n<p><span style=\"font-weight: 400\">When the scalar predicates in a query are sargable against the scalar keys of a composite vector index, the index can be used to serve purely scalar queries <\/span><span style=\"font-weight: 400\">\u2013 <\/span><span style=\"font-weight: 400\">even when no vector similarity condition is present. In such cases, the composite vector index behaves like a traditional secondary index and can act as a covering index, allowing the query to be satisfied entirely from the index without fetching documents from the Data Service.<\/span><\/p>\n<p><span style=\"font-weight: 400\">The scalar-only query:<\/span><\/p>\n<pre class=\"lang:default decode:true\">SELECT product_name\r\nFROM food\r\nWHERE sugars_100g &lt; 20 AND proteins_100g &gt; 10;\r\n<\/pre>\n<p><span style=\"font-weight: 400\">Is sargable for:\u00a0<\/span><\/p>\n<pre class=\"lang:default decode:true\">CREATE INDEX idx_vec_food\r\nON food(sugars_100g, proteins_100g, text_vector VECTOR, product_name);\r\n<\/pre>\n<p><span style=\"font-weight: 400\">And not for:<\/span><\/p>\n<pre class=\"lang:default decode:true\">CREATE INDEX idx_bad\r\nON food(text_vector VECTOR, sugars_100g, proteins_100g);\r\n<\/pre>\n<p><span style=\"font-weight: 400\">This is because:\u00a0<\/span><\/p>\n<ul>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">The leading key is a vector<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">GSI cannot seek or range-scan on it<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">The index cannot be used efficiently for scalar predicates<\/span><\/li>\n<\/ul>\n<p><span style=\"font-weight: 400\">Up to this point, we\u2019ve seen how composite vector indexes combine scalar pruning with vector similarity efficiently. But similarity alone is rarely sufficient in real applications. What happens when you want results that are both semantically close to a query and ordered according to application-specific signals such as nutrition, price, or freshness, without pulling large result sets back to the query layer?<\/span><\/p>\n<p><span style=\"font-weight: 400\">In the next part of this series, we\u2019ll dive into <\/span><i><span style=\"font-weight: 400\">Filtered ANN Search With Composite Vector Indexes<\/span><\/i><span style=\"font-weight: 400\"> and show how Couchbase pushes complex ORDER BY and LIMIT semantics directly into the indexer, allowing distance-based similarity and scalar ordering to be evaluated together in a single, efficient execution path.<\/span><\/p>\n","protected":false},"excerpt":{"rendered":"<p>This is the second blog post of a multi-part series exploring composite vector indexing in Couchbase, check out the first post here.\u00a0 The series will cover: Why composite vector indexes matter, including concepts, terminology, and developer motivation. A Smart Grocery [&hellip;]<\/p>\n","protected":false},"author":85690,"featured_media":17835,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"inline_featured_image":false,"footnotes":""},"categories":[9937],"tags":[],"ppma_author":[10168],"class_list":["post-17830","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-vector-search"],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v27.3 (Yoast SEO v27.3) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>Filtered ANN Search With Composite Vector Indexes (Part 2) - The Couchbase Blog<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.couchbase.com\/blog\/ko\/filtered-ann-search-with-composite-vector-indexes-2\/\" \/>\n<meta property=\"og:locale\" content=\"ko_KR\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Filtered ANN Search With Composite Vector Indexes (Part 2)\" \/>\n<meta property=\"og:description\" content=\"This is the second blog post of a multi-part series exploring composite vector indexing in Couchbase, check out the first post here.\u00a0 The series will cover: Why composite vector indexes matter, including concepts, terminology, and developer motivation. A Smart Grocery [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.couchbase.com\/blog\/ko\/filtered-ann-search-with-composite-vector-indexes-2\/\" \/>\n<meta property=\"og:site_name\" content=\"The Couchbase Blog\" \/>\n<meta property=\"article:published_time\" content=\"2026-01-20T11:00:01+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2026-03-31T23:25:08+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2026\/01\/Filtered-ANN-Search-with-Composite-Vector-Indexes-1.png\" \/>\n\t<meta property=\"og:image:width\" content=\"2400\" \/>\n\t<meta property=\"og:image:height\" content=\"1256\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Sai Kommaraju, Senior Software Engineer\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Sai Kommaraju, Senior Software Engineer\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"11\ubd84\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/filtered-ann-search-with-composite-vector-indexes-2\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/filtered-ann-search-with-composite-vector-indexes-2\\\/\"},\"author\":{\"name\":\"Sai Kommaraju, Senior Software Engineer\",\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/#\\\/schema\\\/person\\\/8fb575d74280ff3d0f044904277a8076\"},\"headline\":\"Filtered ANN Search With Composite Vector Indexes (Part 2)\",\"datePublished\":\"2026-01-20T11:00:01+00:00\",\"dateModified\":\"2026-03-31T23:25:08+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/filtered-ann-search-with-composite-vector-indexes-2\\\/\"},\"wordCount\":2183,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/#organization\"},\"image\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/filtered-ann-search-with-composite-vector-indexes-2\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/wp-content\\\/uploads\\\/sites\\\/1\\\/2026\\\/01\\\/Filtered-ANN-Search-with-Composite-Vector-Indexes-1.png\",\"articleSection\":[\"Vector Search\"],\"inLanguage\":\"ko-KR\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/filtered-ann-search-with-composite-vector-indexes-2\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/filtered-ann-search-with-composite-vector-indexes-2\\\/\",\"url\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/filtered-ann-search-with-composite-vector-indexes-2\\\/\",\"name\":\"Filtered ANN Search With Composite Vector Indexes (Part 2) - The Couchbase Blog\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/filtered-ann-search-with-composite-vector-indexes-2\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/filtered-ann-search-with-composite-vector-indexes-2\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/wp-content\\\/uploads\\\/sites\\\/1\\\/2026\\\/01\\\/Filtered-ANN-Search-with-Composite-Vector-Indexes-1.png\",\"datePublished\":\"2026-01-20T11:00:01+00:00\",\"dateModified\":\"2026-03-31T23:25:08+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/filtered-ann-search-with-composite-vector-indexes-2\\\/#breadcrumb\"},\"inLanguage\":\"ko-KR\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/filtered-ann-search-with-composite-vector-indexes-2\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"ko-KR\",\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/filtered-ann-search-with-composite-vector-indexes-2\\\/#primaryimage\",\"url\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/wp-content\\\/uploads\\\/sites\\\/1\\\/2026\\\/01\\\/Filtered-ANN-Search-with-Composite-Vector-Indexes-1.png\",\"contentUrl\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/wp-content\\\/uploads\\\/sites\\\/1\\\/2026\\\/01\\\/Filtered-ANN-Search-with-Composite-Vector-Indexes-1.png\",\"width\":2400,\"height\":1256},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/filtered-ann-search-with-composite-vector-indexes-2\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Filtered ANN Search With Composite Vector Indexes (Part 2)\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/#website\",\"url\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/\",\"name\":\"The Couchbase Blog\",\"description\":\"Couchbase, the NoSQL Database\",\"publisher\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"ko-KR\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/#organization\",\"name\":\"The Couchbase Blog\",\"url\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"ko-KR\",\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/wp-content\\\/uploads\\\/2023\\\/04\\\/admin-logo.png\",\"contentUrl\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/wp-content\\\/uploads\\\/2023\\\/04\\\/admin-logo.png\",\"width\":218,\"height\":34,\"caption\":\"The Couchbase Blog\"},\"image\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/#\\\/schema\\\/logo\\\/image\\\/\"}},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/#\\\/schema\\\/person\\\/8fb575d74280ff3d0f044904277a8076\",\"name\":\"Sai Kommaraju, Senior Software Engineer\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"ko-KR\",\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/wp-content\\\/uploads\\\/sites\\\/1\\\/2026\\\/01\\\/Sai-Kommaraju.jpega2ca26c70968f44d876aa239d293a709\",\"url\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/wp-content\\\/uploads\\\/sites\\\/1\\\/2026\\\/01\\\/Sai-Kommaraju.jpeg\",\"contentUrl\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/wp-content\\\/uploads\\\/sites\\\/1\\\/2026\\\/01\\\/Sai-Kommaraju.jpeg\",\"caption\":\"Sai Kommaraju, Senior Software Engineer\"},\"url\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/ko\\\/author\\\/saikommaraju\\\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Filtered ANN Search With Composite Vector Indexes (Part 2) - The Couchbase Blog","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.couchbase.com\/blog\/ko\/filtered-ann-search-with-composite-vector-indexes-2\/","og_locale":"ko_KR","og_type":"article","og_title":"Filtered ANN Search With Composite Vector Indexes (Part 2)","og_description":"This is the second blog post of a multi-part series exploring composite vector indexing in Couchbase, check out the first post here.\u00a0 The series will cover: Why composite vector indexes matter, including concepts, terminology, and developer motivation. A Smart Grocery [&hellip;]","og_url":"https:\/\/www.couchbase.com\/blog\/ko\/filtered-ann-search-with-composite-vector-indexes-2\/","og_site_name":"The Couchbase Blog","article_published_time":"2026-01-20T11:00:01+00:00","article_modified_time":"2026-03-31T23:25:08+00:00","og_image":[{"width":2400,"height":1256,"url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2026\/01\/Filtered-ANN-Search-with-Composite-Vector-Indexes-1.png","type":"image\/png"}],"author":"Sai Kommaraju, Senior Software Engineer","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Sai Kommaraju, Senior Software Engineer","Est. reading time":"11\ubd84"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.couchbase.com\/blog\/filtered-ann-search-with-composite-vector-indexes-2\/#article","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/filtered-ann-search-with-composite-vector-indexes-2\/"},"author":{"name":"Sai Kommaraju, Senior Software Engineer","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/8fb575d74280ff3d0f044904277a8076"},"headline":"Filtered ANN Search With Composite Vector Indexes (Part 2)","datePublished":"2026-01-20T11:00:01+00:00","dateModified":"2026-03-31T23:25:08+00:00","mainEntityOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/filtered-ann-search-with-composite-vector-indexes-2\/"},"wordCount":2183,"commentCount":0,"publisher":{"@id":"https:\/\/www.couchbase.com\/blog\/#organization"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/filtered-ann-search-with-composite-vector-indexes-2\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2026\/01\/Filtered-ANN-Search-with-Composite-Vector-Indexes-1.png","articleSection":["Vector Search"],"inLanguage":"ko-KR","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.couchbase.com\/blog\/filtered-ann-search-with-composite-vector-indexes-2\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.couchbase.com\/blog\/filtered-ann-search-with-composite-vector-indexes-2\/","url":"https:\/\/www.couchbase.com\/blog\/filtered-ann-search-with-composite-vector-indexes-2\/","name":"Filtered ANN Search With Composite Vector Indexes (Part 2) - The Couchbase Blog","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/filtered-ann-search-with-composite-vector-indexes-2\/#primaryimage"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/filtered-ann-search-with-composite-vector-indexes-2\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2026\/01\/Filtered-ANN-Search-with-Composite-Vector-Indexes-1.png","datePublished":"2026-01-20T11:00:01+00:00","dateModified":"2026-03-31T23:25:08+00:00","breadcrumb":{"@id":"https:\/\/www.couchbase.com\/blog\/filtered-ann-search-with-composite-vector-indexes-2\/#breadcrumb"},"inLanguage":"ko-KR","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.couchbase.com\/blog\/filtered-ann-search-with-composite-vector-indexes-2\/"]}]},{"@type":"ImageObject","inLanguage":"ko-KR","@id":"https:\/\/www.couchbase.com\/blog\/filtered-ann-search-with-composite-vector-indexes-2\/#primaryimage","url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2026\/01\/Filtered-ANN-Search-with-Composite-Vector-Indexes-1.png","contentUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2026\/01\/Filtered-ANN-Search-with-Composite-Vector-Indexes-1.png","width":2400,"height":1256},{"@type":"BreadcrumbList","@id":"https:\/\/www.couchbase.com\/blog\/filtered-ann-search-with-composite-vector-indexes-2\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.couchbase.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Filtered ANN Search With Composite Vector Indexes (Part 2)"}]},{"@type":"WebSite","@id":"https:\/\/www.couchbase.com\/blog\/#website","url":"https:\/\/www.couchbase.com\/blog\/","name":"\uce74\uc6b0\uce58\ubca0\uc774\uc2a4 \ube14\ub85c\uadf8","description":"NoSQL \ub370\uc774\ud130\ubca0\uc774\uc2a4, Couchbase","publisher":{"@id":"https:\/\/www.couchbase.com\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.couchbase.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"ko-KR"},{"@type":"Organization","@id":"https:\/\/www.couchbase.com\/blog\/#organization","name":"\uce74\uc6b0\uce58\ubca0\uc774\uc2a4 \ube14\ub85c\uadf8","url":"https:\/\/www.couchbase.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"ko-KR","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png","contentUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png","width":218,"height":34,"caption":"The Couchbase Blog"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/8fb575d74280ff3d0f044904277a8076","name":"\uc0ac\uc774 \ucf54\ub9c8\ub77c\uc8fc, \uc218\uc11d \uc18c\ud504\ud2b8\uc6e8\uc5b4 \uc5d4\uc9c0\ub2c8\uc5b4","image":{"@type":"ImageObject","inLanguage":"ko-KR","@id":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2026\/01\/Sai-Kommaraju.jpega2ca26c70968f44d876aa239d293a709","url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2026\/01\/Sai-Kommaraju.jpeg","contentUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2026\/01\/Sai-Kommaraju.jpeg","caption":"Sai Kommaraju, Senior Software Engineer"},"url":"https:\/\/www.couchbase.com\/blog\/ko\/author\/saikommaraju\/"}]}},"acf":[],"authors":[{"term_id":10168,"user_id":85690,"is_guest":0,"slug":"saikommaraju","display_name":"Sai Kommaraju, Senior Software Engineer","avatar_url":{"url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2026\/01\/Sai-Kommaraju.jpeg","url2x":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2026\/01\/Sai-Kommaraju.jpeg"},"0":null,"1":"","2":"","3":"","4":"","5":"","6":"","7":"","8":""}],"_links":{"self":[{"href":"https:\/\/www.couchbase.com\/blog\/ko\/wp-json\/wp\/v2\/posts\/17830","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.couchbase.com\/blog\/ko\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.couchbase.com\/blog\/ko\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/ko\/wp-json\/wp\/v2\/users\/85690"}],"replies":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/ko\/wp-json\/wp\/v2\/comments?post=17830"}],"version-history":[{"count":0,"href":"https:\/\/www.couchbase.com\/blog\/ko\/wp-json\/wp\/v2\/posts\/17830\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/ko\/wp-json\/wp\/v2\/media\/17835"}],"wp:attachment":[{"href":"https:\/\/www.couchbase.com\/blog\/ko\/wp-json\/wp\/v2\/media?parent=17830"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/ko\/wp-json\/wp\/v2\/categories?post=17830"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/ko\/wp-json\/wp\/v2\/tags?post=17830"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/ko\/wp-json\/wp\/v2\/ppma_author?post=17830"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}