<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0">
  <channel>
    <title><![CDATA[Mayya Sharipova - Elasticsearch Labs]]></title>
    <description><![CDATA[Articles and tutorials from the Search team at Elastic]]></description>
    <copyright><![CDATA[© 2026. Elasticsearch B.V. All Rights Reserved]]></copyright>
    <image>
      <title><![CDATA[Mayya Sharipova - Elasticsearch Labs]]></title>
      <url>https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt1121c0bf0e8a6e65/6a88da6340a1841030ef456f/search-labs-thumbnail.png</url>
      <link>https://www.elastic.co/search-labs/author/mayya-sharipova</link>
    </image>
    <link>https://www.elastic.co/search-labs/author/mayya-sharipova</link>
    <atom:link href="https://www.elastic.co/search-labs/rss/author/mayya-sharipova.xml" rel="self" type="application/rss+xml"/>
    <language><![CDATA[en]]></language>
    <lastBuildDate>Wed, 23 Sep 2026 05:24:36 GMT</lastBuildDate>
  <item>
    <title><![CDATA[One setting for production vector search: How vectordb_document mode tunes Elasticsearch automatically]]></title>
    <description><![CDATA[Benchmarks across four datasets show how one index setting applies bfloat16 vector quantization, cache preloading and parallel merges to improve vector search throughput and decrease storage.]]></description>
    <content:encoded><![CDATA[<p>We’re introducing one setting for production-ready vector search. The new <code>vectordb_document</code> index mode stores raw vectors as bfloat16 to halve their disk footprint and preloads vector data structures into the filesystem cache. It also lets segment merges run unthrottled and in parallel. In our benchmarks, it delivered up to 2× the queries per second (QPS) at high recall with <code>bbq_hnsw</code> and cut time to a search-ready index by roughly 20% with <code>bbq_disk</code>, with no tuning required. It’s available in Stateful Elasticsearch 9.5 and in Elasticsearch Serverless today.</p><p>Elasticsearch supports a diverse range of use cases, including observability metrics and logs and complex geospatial analysis. However, as vector search becomes a core component of modern architectures, the need for specialized optimization has grown. Achieving peak performance for vector-heavy workloads often requires navigating a complex space of configuration knobs. To reduce this operational toil, we wanted to provide opinionated, high-performance defaults through a single setting that simplifies performance tuning for production environments. The <a href="https://www.elastic.co/docs/reference/elasticsearch/mapping-reference/dense-vector#dense-vector-vectordb-document-mode"><code>vectordb_document</code> index mode</a> is designed specifically for optimal vector search workloads.</p><h2>How to set up vectordb_document mode</h2><p>Setup is a single setting. When you’re creating an index, define the following in the index settings:</p>PUT my-index
{
  "settings" : {
    "index" : {
      "mode" : "vectordb_document"
     }
   }
}<p><code>vectordb_document</code> mode is available on all Elasticsearch subscription tiers, including Basic.</p><p>Most indices used for vector search also support other operations, such as aggregations or geo-search. They also support hybrid search. Because vector search is typically the most computationally demanding part of these mixed workloads, we recommend using the <code>vectordb_document</code> index mode to prioritize performance for your most intensive operations. An index in <code>vectordb_document</code> mode remains highly capable, supporting almost all operations available in the default standard mode, while optimizing specifically for the resource-heavy demands of vector search.</p><p>The <code>“_document”</code> suffix represents our roadmap. We're also developing a <code>“vectordb_columnar”</code> mode as another way to optimize vector search, suited to different data and access patterns.</p><h2>Elasticsearch vector search benchmarks across four datasets</h2><p>To validate these defaults, we performed extensive benchmarking across various datasets and two index types: <code>bbq_hnsw</code> and <code>bbq_disk</code>. We ran all benchmarks on a single-node Elasticsearch instance on AWS using a <code>c8gd.2xlarge</code> instance (Graviton 4, ARM64, local NVMe SSD) with a pod limited to 8GB RAM (2GB heap) and 4 CPUs, using a single shard.</p><p>Datasets:</p><p><strong>Dataset</strong></p><p><strong>Vectors</strong></p><p><strong>Dims</strong></p><p><strong>Use case</strong></p><p><code>laion-img-emb-512-20M-cosine</code></p><p>20 million</p><p>512</p><p>Pure vector search (low dim)</p><p><code>msmarco-v2-10M-jina-v5-1024</code></p><p>10 million</p><p>1024</p><p>Pure vector search (med dim)</p><p><code>dbpedia-openai-1M-3072-angular</code></p><p>1 million</p><p>3072</p><p>Pure vector search (high dim)</p><p><code>arxiv-for-fanns-large</code></p><p>2.7 million</p><p>4096</p><p>Filtered search</p><h3>bbq_hnsw: HNSW index performance with vectordb_document</h3><h4>Query throughput and recall</h4><p>On all four datasets, <code>vectordb_document</code> produced a better QPS–recall curve, and the shape of the advantage is itself informative. On <code>dbpedia-openai-1M</code>, <code>msmarco-v2-10M</code>, and <code>arxiv-for-fanns-large</code>, the curves start close together at low recall (essentially identical on arXiv) and separate as recall rises, reaching roughly 1.4×, 2.2×, and 2× at the high-recall end. On <code>laion-img-emb-512-20M</code>, the curves are apart from the start and settle at about 2× from recall 0.80 upward.</p><p>The gap widens with recall because higher recall is bought with oversampling, and oversampling is exactly where <code>vectordb_document</code> saves. The two effects compound. bfloat16 storage halves the bytes read per rescored candidate. More importantly for hierarchical navigable small world (HNSW), the oversample factor is applied to the graph search itself;  each segment is searched for k × oversample candidates, so cost scales with oversample times segment count. Unthrottled parallel merging leaves fewer, larger graphs (14–21 segments versus 22–29), and the graph and quantized vector files are preloaded into the filesystem cache, so <code>vectordb_document</code> pays far less for each increment of oversample.</p><p>Comparing identical search settings, rather than equal recall, makes the effect explicit. With rescoring switched off, the two modes are within 1%–28% of each other; at oversample 5, <code>vectordb_document</code> is 2–4× faster; at oversample 10, up to 10×. Those high-oversample settings sit off the QPS–recall frontier, which is why the curves above top out nearer 2×, but they isolate where the saving comes from.</p><p><strong>Oversample</strong></p><p><strong>DBpedia</strong></p><p><strong>LAION</strong></p><p><strong>MS MARCO</strong></p><p><strong>arXiv</strong></p><p>off</p><p>1.23×</p><p>1.28×</p><p>1.11×</p><p>1.01×</p><p>5</p><p>4.07×</p><p>2.66×</p><p>2.66×</p><p>2.05×</p><p>10</p><p>10.5×</p><p>2.33×</p><p>2.46×</p><p>4.03×</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt7be4c804a0ed7c22/6a86d603e3ec262b84519f42/1.png" alt="Elasticsearch vector search QPS vs recall for bbq_hnsw on LAION 512-dim dataset showing 2x throughput with vectordb_document" /><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt231178fa23d0726e/6a86d61ceb4ccc9c18f20f42/2.png" alt="Elasticsearch vector search QPS vs recall for bbq_hnsw on MS MARCO 1024-dim dataset with vectordb_document mode enabled" /><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt80dfbad51b8f3bb9/6a86d63feb4ccc69c2f20f48/3.png" alt="Elasticsearch vector search QPS vs recall for bbq_hnsw on DBpedia 3072-dim dataset with vectordb_document mode enabled" /><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt85e29cf189fcc51b/6a86d65173f7435dda4861ed/4.png" alt="Elasticsearch vector search QPS vs recall for bbq_hnsw on arXiv 4096-dim filtered search with vectordb_document mode" /><h4>Indexing speed and merge behavior </h4><p>In our benchmarks, <code>vectordb_document</code> increased upload time by roughly 16%. This is expected: merges now run unthrottled and parallelized across threads, so they compete with indexing for CPU while documents are still being ingested. Measured indexing time rose 9%–26% across the four datasets. HNSW graph construction is CPU-bound, so that contention is felt directly.</p><p>The same changes make the post-upload phase much cheaper. Disabling auto-throttling removes merge rate limiting entirely (in default mode, DBpedia spent 57% of its merge time throttled), and bfloat16 halves the raw vector data, cutting total bytes merged by 42%–49%. Post-ingest merging finished 75%–86% sooner on three of the four datasets, which brings total time to a search-ready index to only about 6% above the baseline. DBpedia was the exception in the other direction: Its merge tail dominated, so total time actually fell 25%.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltaf89df79ce0e2185/6a86d6f4da6aead8bb379480/1.png" alt="Upload time comparison across four datasets for bbq_hnsw HNSW index with and without vectordb_document mode" /><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt9162cec285c4f2a1/6a86d708a8b3231735cbfbbd/2.png" alt="Total ingest time including merges for bbq_hnsw HNSW index comparing default mode to vectordb_document mode" /><h3>bbq_disk: disk-based vector search performance with vectordb_document</h3><h4>bbq_disk query throughput and recall</h4><p>For <code>bbq_disk</code> indices, <code>vectordb_document</code> mode's impact on search throughput varied by dataset. On the lower-dimensional datasets, QPS was essentially unchanged at equal recall: <code>laion-img-emb-512-20M-cosine</code> (512 dims) and <code>msmarco-v2-10M-jina-v5-1024</code> (1024 dims) track each other closely across the recall range, with <code>vectordb_document</code> ahead in the lower recall end and a few percent behind at the high-recall end. On the higher-dimensional datasets, we saw a consistent gain of roughly 20% at equal recall: <code>dbpedia-openai-1M-3072-angular</code> (3072 dims) and <code>arxiv-for-fanns-large</code> (4096 dims).</p><p>Our interpretation is that this is mainly a rescoring effect. <code>vectordb_document</code> stores vectors as bfloat16, so each rescored candidate reads 2× dims bytes instead of 4× dims. The sweep supports this directly: The advantage grows with the query-time oversample factor, which is exactly what sets how many candidates get rescored. On DBpedia, the QPS ratio rises from 1.16× at oversample 3 to 4.3× at oversample 8, and on arXiv from 1.20× to 1.56×, while on laion and MS MARCO, it stays flat or drifts just below 1. Rescoring is simply a much larger share of the query on the smaller, higher-dimensional datasets; on the 10 million and 20 million ones, scanning 1-bit posting lists dominates.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltc3dccb980e1e3a57/6a86d7ebeb4ccc0f68f20f4c/1.png" alt="Elasticsearch vector search QPS vs recall for bbq_disk on LAION 512-dim dataset with vectordb_document mode enabled" /><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltffd0c65e300e7985/6a86d80462f1e2732aafe73f/2.png" alt="Elasticsearch vector search QPS vs recall for bbq_disk on MS MARCO 1024-dim dataset with vectordb_document mode" /><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt7574001d33d755e7/6a86d81a386ac33034adef66/3.png" alt="Elasticsearch vector search QPS vs recall for bbq_disk on DBpedia 3072-dim showing 20% gain with vectordb_document" /><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt45ec0bc4e1a47504/6a86d82aa1b20b40a18701ff/4.png" alt="Elasticsearch vector search QPS vs recall for bbq_disk on DBpedia 3072-dim showing 20% gain with vectordb_document" /><h4>Indexing speed and merge behavior </h4><p>Across the four datasets, <code>vectordb_document</code> cut total time to a fully merged, search-ready index by about 20%. Every dataset improved, from 6% on <code>msmarco-v2-10M</code> to 50% on <code>dbpedia-openai-1M</code>, where the post-upload merge phase alone fell from 322 seconds to 54 seconds. Upload time on its own is less clear-cut: On the day charted below, it finished 2%–15% sooner, depending on dataset, but on the earlier run set, it was marginally slower, so we read upload as unchanged to modestly faster and treat time-to-searchable as the real result.</p><p>The gain is almost entirely in merging. In default mode, Elasticsearch rate-limits how fast merges may write, and that limiter was binding hard: 75% of all merge time on DBpedia and 73% on laion was spent paused by it. <code>vectordb_document</code> disables the limiter, so paused time is zero and merge time drops 63% on DBpedia and 42% on laion. bfloat16 helps for the same reason: The limiter meters bytes written, so halving the raw vector data means less to write under the cap. The gradient across datasets follows the throttling rather than the byte count: arXiv, at 21% of merge time throttled, saw 30% less merge time, while MS MARCO, never throttled, got 55% fewer bytes but only 11% less merge time.</p><p>The two index types respond differently on ingest because merging costs something different in each. Merging <code>bbq_hnsw</code> segments means rebuilding HNSW graphs: CPU-bound work that competes directly with the equally CPU-bound graph construction on incoming documents, and on a 4-CPU pod that contention surfaces as a slower upload. <code>bbq_disk</code> merges are dominated by writing bytes rather than by CPU, so lifting the rate limiter spends I/O bandwidth that the local NVMe has to spare, and bfloat16 means that there are fewer bytes to write in the first place. Both index types reach a fully merged index far sooner; the difference is only whether the upload phase pays for it.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt5792080b8d372fdd/6a86d85a8bbe584d8790e7cf/5.png" alt="Upload time comparison across four datasets for bbq_disk index with and without vectordb_document mode" /><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltfc61269e37f0d5f4/6a86d86b762d1efd795cb927/6.png" alt="Total ingest time for bbq_disk index showing 20% faster time to search-ready with vectordb_document mode" /><h2>What vectordb_document sets under the hood</h2><h3><code>element_type</code> (<code>dense_vector</code>)</h3><ul><li><p><strong>Value: </strong>bfloat16.</p></li><li><p><strong>Impact: </strong>Stores each dimension of the raw vector as bfloat16 instead of the default float32, halving the storage of raw vectors with negligible impact on recall.</p></li><li><p><strong>Benefit: </strong>Lower disk footprint (reduced total cost of ownership [TCO]), faster fetching of vectors for rescoring.</p></li></ul><h3>Dynamic float array mapping</h3><ul><li><p><strong>Value: </strong>Float arrays with 32 or more values are dynamically mapped as <code>dense_vector</code>. (In the default mode, this threshold is 128.)</p></li><li><p><strong>Impact:</strong> No need to explicitly declare the field as a dense vector field; the system identifies it automatically.</p></li><li><p><strong>Benefit: </strong>Configuration simplicity.</p></li></ul><h3><code>exclude_source_vectors</code></h3><ul><li><p><strong>Value: </strong>true.</p></li><li><p><strong>Impact: </strong>Vectors are stored once in the vector index and not duplicated in <code>_source</code>. They’re omitted from <code>_source</code> in responses, but they can still be retrieved on request.</p></li></ul><p><strong>Benefit: </strong>Lower disk footprint; faster queries, since large vectors are no longer shipped with every <code>_source</code> fetch.</p><h3><code>index.store.preload</code></h3><ul><li><p><strong>Value: </strong>[<code>"vex"</code>, <code>"veq"</code>, <code>"veb"</code>, <code>"cenivf"</code>].</p></li><li><p><strong>Impact: </strong>Preloads search-time vector data structures into the filesystem cache whenever new segments are opened.</p></li><li><p><strong>Benefit: </strong>Reduced query latency.</p></li></ul><h3><code>index.merge.intra_merge_parallelism_enabled</code></h3><ul><li><p><strong>Value: </strong>true.</p></li><li><p><strong>Impact: </strong>Use parallel threads for segment merging to achieve optimal segment sizes.</p></li><li><p><strong>Benefit: </strong>Faster convergence to fewer, larger segments leads to better recall, lower query latency.</p></li></ul><h3><code>index.merge.scheduler.auto_throttle</code></h3><ul><li><p><strong>Value: </strong>false.</p></li><li><p><strong>Impact: </strong>Allows merges to proceed at full speed.</p></li><li><p><strong>Benefit: </strong>Merges reach optimal segment sizes sooner, resulting in better recall, lower query latency.</p></li></ul><p>While these defaults are optimized for the majority of use cases, most can be overridden individually to suit unique hardware constraints or extreme performance requirements, with one exception: <code>exclude_source_vectors: true</code> is locked in and cannot be changed on a <code>vectordb_document</code> index.</p><h2>Summary</h2><p>The <code>vectordb_document</code> index mode is a production-ready foundation for vector search: By adopting high-performance defaults, teams can focus on building features rather than on hand-tuning merge or storage settings or on adjusting preload settings. </p><p>Across four datasets, the picture is consistently favorable, though the balance differs by index type. With <code>bbq_hnsw</code>, QPS recall improved on every dataset, from roughly on par at low recall to as much as double at the high-recall end, in exchange for a modest ingest cost of about 16% longer upload and 6% longer time to a search-ready index. With <code>bbq_disk</code>, the trade runs the other way: Total time to a search-ready index dropped by about 20%, while search improved by about 20% at equal recall on the higher-dimensional datasets (3072 and 4096 dims) and was essentially unchanged on the lower-dimensional ones. The split comes down to what merging costs in each: Rebuilding HNSW graphs is CPU work that competes with indexing; whereas <code>bbq_disk</code> merges are write-bound and simply run faster once they’re unthrottled.</p><p>In both cases, the new defaults move the system in the direction that most users want, with no per-index tuning required. And, for the settings that genuinely depend on the data itself, such as the degree of quantization, auto-calibration now derives them for you. (See <a href="https://www.elastic.co/search-labs/blog/vector-quantization-auto-calibration-elasticsearch">How Elasticsearch auto-tunes vector quantization to hit your recall target</a>.)</p><p>Try it out by creating an index with the <code>vectordb_document</code> index mode in Stateful Elasticsearch 9.5 or in Serverless.</p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/elasticsearch-vector-search-vectordb-document-mode</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/elasticsearch-vector-search-vectordb-document-mode</guid>
    <category><![CDATA[Vector Database]]></category>
    <dc:creator><![CDATA[Mayya Sharipova,Gilad Gal,Quinn Harper]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt24f9f391ea8b5d02/6a86ce55bed19d4545af9b54/unnamed.jpg" length="0" type="image/jpeg"/>
    <pubDate>Thu, 20 Aug 2026 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Up to 12x Faster Vector Indexing in Elasticsearch with NVIDIA cuVS: GPU-acceleration Chapter 2]]></title>
    <description><![CDATA[Discover how Elasticsearch achieves nearly 12x higher indexing throughput with GPU-accelerated vector indexing and NVIDIA cuVS.]]></description>
    <content:encoded><![CDATA[<p>Earlier this year, Elastic announced the <a href="https://ir.elastic.co/news/news-details/2025/Elastic-Brings-Enterprise-Data-to-NVIDIA-AI-Factories/default.aspx">collaboration</a> with NVIDIA to bring GPU acceleration to Elasticsearch, integrating with <a href="https://developer.nvidia.com/cuvs">NVIDIA cuVS</a>—as detailed in a <a href="https://www.nvidia.com/en-us/on-demand/session/gtc25-S71286/">session at NVIDIA GTC</a> and various <a href="https://www.elastic.co/search-labs/blog/gpu-accelerated-vector-search-elasticsearch-nvidia">blogs</a>. This post is an update on the co-engineering effort with the NVIDIA vector search team.</p><h2>Recap</h2><p>First, let’s bring you up to speed. Elasticsearch has established itself as a powerful vector database, offering a rich set of features and strong performance for large-scale similarity search. With capabilities such as scalar quantization, Better Binary Quantization (<a href="https://www.elastic.co/search-labs/blog/better-binary-quantization-lucene-elasticsearch">BBQ</a>), <a href="https://www.elastic.co/blog/accelerating-vector-search-simd-instructions">SIMD</a> vector operations, and more disk-efficient algorithms like <a href="https://www.elastic.co/search-labs/blog/diskbbq-elasticsearch-introduction">DiskBBQ</a>, it already provides efficient and flexible options for managing vector workloads.</p><p>By integrating NVIDIA cuVS as a callable module for vector search tasks, we aim to deliver significant gains in vector indexing performance and efficiency to better support large-scale vector workloads.</p><h2>The challenge</h2><p>One of the toughest challenges in building a high-performance vector database is constructing the vector index - the <a href="https://arxiv.org/abs/1603.09320">HNSW</a> graph. Index building quickly becomes dominated by millions or even billions of arithmetic operations as every vector is compared against many others. In addition, index lifecycle operations, such as compaction and merges, can further increase the overall compute overhead of indexing. As data volumes and associated vector embeddings grow exponentially, accelerated computing GPUs, built for massive parallelism and high-throughput math, are ideally positioned to handle these workloads.</p><h2>Enter the Elasticsearch-GPU Plugin</h2><p><a href="https://developer.nvidia.com/cuvs">NVIDIA cuVS</a> is an open-source CUDA-X library for GPU-accelerated vector search and data clustering that enables fast index building and embedding retrieval for AI and recommendation workloads.</p><p>Elasticsearch uses cuVS through <a href="https://mvnrepository.com/artifact/com.nvidia.cuvs/cuvs-java">cuvs-java</a>, an open-source library developed by the community and maintained by NVIDIA. The cuvs-java library is lightweight and builds on the <a href="https://docs.nvidia.com/cuvs/api-reference/c-api-core-c-api">cuVS C API</a> using <a href="https://openjdk.org/projects/panama/">Panama</a> Foreign Function to expose cuVS features in an idiomatic Java way, while remaining modern and performant.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltc7fd7361099da05a/6a17e920be608670af00477f/5f6daa1eb07f704a6707d9e6b7ccb81d0abaa8c9-566x419.png" alt="How Elasticsearch works with NVIDIA cuVS, CPU and GPU indexing" /><p>The cuvs-java library is integrated into a <a href="https://github.com/elastic/elasticsearch/pull/135545">new Elasticsearch plugin</a>; therefore, vector indexing on the GPU can occur on the same Elasticsearch node and process, without the need to provision any external code or hardware. During index building, if the cuVS library is installed and a GPU is present and configured, Elasticsearch will use the GPU to accelerate the vector indexing process. The vectors are given to the GPU, which constructs a <a href="https://arxiv.org/abs/2308.15136">CAGRA</a> graph. This graph is then converted to the HNSW format, making it immediately available for vector search on the CPU. The final format of the built graph is the same as what would be built on the CPU; this allows Elasticsearch to leverage GPUs for high-throughput vector indexing when the underlying hardware supports it, while freeing CPU power for other tasks (concurrent search, data processing, etc.).</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt485f55f29d6df5c4/6a17e922be6086dcf3004785/3ea255bd9bfd7983f78143c5eba999d2149d72be-671x356.png" alt="" /><h2>Index build acceleration</h2><p>As part of integrating GPU acceleration into Elasticsearch, several enhancements were made to cuvs-java, focusing on efficient data input/output and function invocation. A key enhancement is the use of <a href="https://github.com/rapidsai/cuvs/blob/2cf5fa7666d703dccbe655f8214656b0952bb69b/java/cuvs-java/src/main/java/com/nvidia/cuvs/CuVSMatrix.java">cuVSMatrix</a> to transparently model vectors, whether they reside on the Java heap, off-heap, or in GPU memory. This enables data to move efficiently between memory and the GPU, avoiding unnecessary copies of potentially billions of vectors.</p><p>Thanks to this underlying zero-copy abstraction, both transferring to GPU memory and retrieving the graph can occur directly. During indexing, vectors are first buffered in memory on the Java heap, then sent to the GPU to construct the CAGRA graph. The graph is subsequently retrieved from the GPU, converted into HNSW format, and persisted to disk.</p><p>At merge time, the vectors are already stored on disk, bypassing the Java heap entirely. Index files are memory-mapped, and data is transferred directly into GPU memory. The design also easily accommodates different bit-widths, such as float32 or int8, and naturally extends to other quantization schemes.</p><h2>Drumroll…so, how does it perform?</h2><p>Before we get into the numbers, a bit of context is helpful. Segment merging in Elasticsearch typically runs automatically in the background during indexing, which makes it difficult to benchmark in isolation. To obtain reproducible results, we used force-merge to explicitly trigger segment merging in a controlled experiment. Since force-merge performs the same underlying merge operations as background merging, its performance serves as a useful indicator of expected improvements, even though the exact gains may differ in real-world indexing workloads.</p><p>Now, let’s see the numbers.</p><p>Our initial benchmark results are very promising. We ran the benchmark on an AWS <code>g6.4xlarge</code> instance with locally attached NVMe storage. A single node of Elasticsearch was configured to use the default, optimal number of indexing threads (8 - one for each physical core), and to disable <a href="https://www.elastic.co/docs/reference/elasticsearch/index-settings/merge">merge throttling</a> (which is less applicable with fast NVMe disks).</p><p>For the dataset, we used 2.6 million vectors with 1,536 dimensions from the <a href="https://github.com/elastic/rally-tracks/blob/master/openai_vector/README.md">OpenAI Rally vector track</a>, encoded as <a href="https://github.com/elastic/elasticsearch/pull/137072">base64 strings</a>, and indexed as float32 <em>hnsw</em>. In all scenarios, the constructed graphs achieve recall levels of up to 95%. Here’s what we found:</p><ul><li><p><strong>Indexing Throughput:</strong> By moving graph construction to the GPU during in-memory buffer flushes, we increase throughput by ~12x.</p></li><li><p><strong>Force-merge:</strong> After indexing completes, the GPU continues to accelerate segment merging, speeding up the force-merge phase by ~7x.</p></li></ul><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltfea4ee13b5a3b10d/6a17e923e9ea879c6aa9c616/f60ea9ee5996e456f393ffd195ee7eada6e5a7c2-948x387.png" alt="" /><ul><li><p><strong>CPU usage:</strong> Offloading graph construction to the GPU significantly reduces both average and peak CPU utilization. The graphs below illustrate CPU usage during indexing and merging, highlighting how much lower it is when these operations run on the GPU. Lower CPU utilization during GPU indexing frees up CPU cycles that can be redirected to improve search performance.</p></li></ul><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt80ff9c53f9b6884a/6a17e925445de9ee4b4d0187/5e680a5fc41700a877f3d8b2e5ce18ebd3f37a0b-1600x562.png" alt="" /><ul><li><p><strong>Recall:</strong> Accuracy remains effectively the same between CPU and GPU runs, with the GPU-built graph reaching marginally higher recall.</p></li></ul><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt5cbe084eca27b8e4/6a17e926faa913317093c8b7/48a2b7758606bd321712b7d8378cd2640e652a4e-1384x544.png" alt="" /><h2>Comparing along another dimension: Price</h2><p>The earlier comparison intentionally used identical hardware, with the only difference being whether the GPU was used during indexing. That setup is useful for isolating raw compute effects, but we can also look at the comparison from a cost perspective.</p><p>At roughly the same hourly price as the GPU-accelerated configuration, one can provision a CPU-only setup with approximately twice the comparable CPU and memory resources: 32 vCPUs (AMD EPYC) and 64 GB of RAM, allowing to double the number of indexing threads to 16.</p><p>To keep the comparison fair and consistent, we ran this CPU-only experiment on an AWS g6.8xlarge instance, with the GPU explicitly disabled. This allowed us to hold all other hardware characteristics constant while evaluating the cost–performance trade-off of GPU acceleration versus CPU-only indexing.</p><p>The more powerful CPU instance does show improved performance compared to the benchmarks in the above section, as you would expect. However, when we compare this more powerful CPU instance against the original GPU-accelerated results, the GPU still delivers substantial performance gains: <strong>~5x</strong> improvement in indexing throughput, and <strong>~6x </strong>in force merge, all while building graphs that achieve recall levels of up to <strong>95%.</strong></p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt94b5eb6f95ba307d/6a17e928abe0f255d4dfea35/8ffa58cae3ad175ef2932a351aeef4c34a1407b9-948x394.png" alt="" /><h2>Conclusion</h2><p>In end-to-end scenarios, GPU acceleration with NVIDIA cuVS delivers nearly a 12x improvement in indexing throughput and a 7x decrease in force-merge latency, with significantly lower CPU utilization. This shows that vector indexing and merge workloads benefit significantly from GPU acceleration. On a cost-adjusted comparison, GPU acceleration continues to yield substantial performance gains, with approximately 5x higher indexing throughput and 6x faster force-merge operations.</p><p>GPU-accelerated vector indexing is currently planned for Tech Preview in Elasticsearch 9.3, which is scheduled to be released early in 2026.</p><p>Stay tuned for more.</p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/elasticsearch-gpu-accelerated-vector-indexing-nvidia</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/elasticsearch-gpu-accelerated-vector-indexing-nvidia</guid>
    <category><![CDATA[Vector Database]]></category>
    <dc:creator><![CDATA[Chris Hegarty,Hemant Malik,Corey Nolet,Manas Singh,Mithun Radhakrishnan,Mayya Sharipova,Lorenzo Dematte,Ben Frederickson]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt1248d51633bd75d9/6a17e92ae9ea8714b3a9c61a/08f7469a4daaf67b7c5999585aae179b6680c78d-896x746.png" length="0" type="image/png"/>
    <pubDate>Wed, 03 Dec 2025 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Making Elasticsearch and Lucene the best vector database: up to 8x faster and 32x efficient]]></title>
    <description><![CDATA[Discover the recent enhancements and optimizations that notably improve vector search performance in Elasticsearch &amp; Lucene vector database.]]></description>
    <content:encoded><![CDATA[<h2>Elasticsearch and Lucene report card: noteworthy speed and efficiency investments</h2><p>Our mission at Elastic is to make Apache Lucene the best vector database out there, and to continue to make Elasticsearch the best retrieval platform out there for search and RAG. Our investments into Lucene are key to ensure that every release of Elasticsearch brings increasing faster performance and scale.</p><p>Customers are already building the next generation of AI enabled search applications with Elastic’s vector database and vector search technology. <a href="https://roboflow.com/">Roboflow</a> is used by over 500,000 engineers to create datasets, train models, and deploy computer vision models to production. Roboflow uses Elastic vector database to store and search billions of vector embeddings.</p><p>In this blog we summarize recent enhancements and optimisations that significantly improve vector search performance in Elasticsearch and Apache Lucene, over and above performance gains <a href="https://www.elastic.co/search-labs/blog/apache-lucene-9.9-search-speedups">delivered with Lucene 9.9</a> and Elasticsearch 8.12.x.</p><p>The integration of vector search into Elasticsearch relies on Apache Lucene, the layer that orchestrates data storage and retrieval. <a href="https://www.elastic.co/search-labs/blog/vector-search-elasticsearch-rationale">Lucene's architecture</a> organizes data into segments, immutable units that undergo periodic merging. This structure allows for efficient management of inverted indices, essential for text search. With vector search, Lucene extends its capabilities to handle multi-dimensional points, employing the hierarchical navigable small world (HNSW) algorithm to index vectors.</p><p>This approach facilitates scalability, enabling data sets to exceed available RAM size while maintaining performance. Additionally, Lucene's segment-based approach offers lock-free search operations, supporting incremental changes and ensuring visibility consistency across various data structures. The integration however comes with its own engineering challenges. Merging segments requires recomputing HNSW graphs, incurring index-time overhead. Searches must cover multiple segments, leading to possible latency overhead. Moreover, optimal performance requires scaling RAM as data grows, which may raise resource management concerns.</p><p>Lucene's integration into Elasticsearch comes with the benefit of robust vector search capabilities. This includes aggregations, document level security, geo-spatial queries, pre-filtering, to full compatibility with various Elasticsearch features. Imagine running vector searches using a geo bounding box, this is an example usecase enabled by Elasticsearch and Lucene.</p><p>Lucene's architecture lays a solid foundation for efficient and versatile vector search within Elasticsearch. Let’s explore optimization strategies and enhancements we have implemented to integrate vector search into Lucene, which delivers a high performance and comprehensive feature-set for developers.</p><h2>Harnessing Lucene's architecture for multi-threaded search</h2><p>Lucene's segmented architecture enables the implementation of multi-threaded search capabilities. Elasticsearch’s performance gains come from efficiently searching multiple segments simultaneously. Latency of individual searches is significantly reduced by using the processing power of all available CPU cores. While it may not directly improve overall throughput, this enhancement prioritizes minimizing response times, ensuring that users receive their search results as swiftly as possible.</p><p>Furthermore, this optimization is particularly beneficial for Hierarchical Navigable Small World (HNSW) searches, as each graph is independent of the others and can be searched in parallel, maximizing efficiency and speeding up retrieval times even further.</p><p>The advantage of having multiple independent segments extends to the architectural level, especially in serverless environments. In this <a href="https://www.elastic.co/blog/elastic-serverless-architecture">new architecture,</a> the indexing tier is responsible for creating new segments, each containing its own HSNW graph. The search tier can simply replicate these segments without incurring the CPU cost of indexation. This separation allows a significant portion of compute resources to be dedicated to searches, optimizing overall system performance and responsiveness.</p><h2>Accelerating multi-graph vector search</h2><p>In spite of gains achieved with parallelization, each segment's searches would remain independent, unaware of progress made by other segment searches. So our focus shifted towards optimizing the efficiency of concurrent searches across multiple segments.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt35f29a49abcd2e22/6a17d78ae31791cd572d5682/103e9a7a97e9c219edb028e0fc675346920002cc-974x407.png" alt="" /><p>The graph shows that the number queries per second increased from 104 queries/sec to 219 queries/sec.</p><p>Recognizing the potential for further speedups, we leveraged our insights from optimizing lexical search, to enable information exchange among segment searches allowing for better coordination and efficiency in vector search.</p><p><a href="https://www.elastic.co/search-labs/blog/multi-graph-vector-search">Our strategy for accelerating multi-graph vector search</a> revolves around balancing exploration and exploitation within the proximity graph. By adjusting the size of the expanded match set, we control the trade-off between runtime and recall, crucial for achieving optimal search performance across multiple graphs.</p><p>In multi-graph search scenarios, the challenge lies in efficiently navigating individual graphs, while ensuring comprehensive exploration to avoid local minima. While searching multiple graphs independently yields higher recall, it incurs increased runtime due to redundant exploration efforts. To mitigate this, we devised a strategy to intelligently share state between searches, enabling informed traversal decisions based on global and local competitive thresholds.</p><p>This approach involves maintaining shared global and local queues of distances to closest vectors, dynamically adapting search parameters based on the competitiveness of each graph's local search. By synchronizing information exchange and adjusting search strategies accordingly, we achieve significant improvements in search latency while preserving recall rates comparable to single-graph searches.</p><p>The impact of these optimizations is evident in our benchmark results. In concurrent search and indexing scenarios, we notice up to 60% reduction in query latencies! Even for queries conducted outside of indexing operations, we observed notable speedups and a dramatic decrease in the number of vector operations required. These enhancements, integrated into Lucene 9.10 and subsequently Elasticsearch 8.13, mark significant strides towards enhancing vector database performance for search while maintaining excellent recall rates.</p><h2>Harnessing Java's latest advancements for ludicrous speed</h2><p>In the area of Java development, automatic vectorization has been a boon, optimizing scalar operations into SIMD (Single Instruction Multiple Data) instructions through the HotSpot C2 compiler. While this automatic optimization has been beneficial, it has its limitations, particularly in scenarios where explicit control over code shape yields superior performance. Enter Project Panama Vector API, a recent addition to the JDK offering an API for expressing computations reliably compiled to SIMD instructions at runtime.</p><p>Lucene's vector search implementation relies on fundamental operations like dot product, square, and cosine distance, both in floating point and binary variants. Traditionally, these operations were backed by scalar implementations, leaving performance enhancements to the JIT compiler. However, recent advancements introduce a paradigm shift, enabling developers to express these operations explicitly for optimal performance.</p><p>Consider the dot product operation, a fundamental vector computation. Traditionally implemented in Java with scalar arithmetic, recent innovations leverage the Panama Vector API to express dot product computations in a manner conducive to SIMD instructions. This revised implementation iterates over input arrays, multiplying and accumulating elements in batches, aligning with the underlying hardware capabilities.</p><p><a href="https://www.elastic.co/blog/accelerating-vector-search-simd-instructions">By harnessing Panama Vector API,</a> Java code now interfaces seamlessly with SIMD instructions, unlocking the potential for significant performance gains. The compiled code, when executed on compatible CPUs, leverages advanced vector instructions like AVX2 or AVX 512, resulting in accelerated computations. Disassembling the compiled code reveals optimized instructions tailored to the underlying hardware architecture.</p><p>Microbenchmarks comparing traditional Java implementations to those leveraging Panama Vector API illustrate dramatic performance improvements. Across various vector operations and dimension sizes, the optimized implementations outperform their predecessors by significant margins, offering a glimpse into the transformative power of SIMD instructions.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt8efb30efc7e6c157/6a17d78bfbc5f8285d49190c/d2a5f15bb0d16608b67753a82312d2f254370622-1204x120.png" alt="" /><p>Micro-benchmark comparing dot product with the new Panama API (dotProductNew) and the scalar implementation (dotProductOld).</p><p>Beyond microbenchmarks, the real-world impact of these optimizations is quite exciting to think about. Vector search benchmarks, such as <a href="https://elasticsearch-benchmarks.elastic.co/#tracks/so_vector/nightly/default/90d">SO Vector,</a> demonstrate notable enhancements in indexing throughput, merge times, and query latencies. Elasticsearch, embracing these advancements, incorporates the faster implementations by default, ensuring users reap the performance benefits seamlessly.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltdd3a97bf5f0cd24a/6a17d78d3e9e452c84ba12e6/e82a7ee152fdebfc856106bdc1f68c6eab9b5798-1349x882.png" alt="" /><p>The graph shows indexing throughput increased from about 900 documents/sec to about 1300 documents/sec.</p><p>Despite the incubating status of Panama Vector API, its quality and potential benefits are undeniable. Lucene's pragmatic approach allows for selective adoption of non-final JDK APIs, balancing the promise of performance improvements with maintenance considerations. With Lucene and Elasticsearch, users can leverage these advancements effortlessly, with performance gains translating directly to real-world workloads.</p><p>The integration of Panama Vector API into Java development yields a new era of performance optimization, particularly in vector search scenarios. By embracing hardware-accelerated SIMD instructions, developers can unlock efficiency gains, visible both in microbenchmarks and macro-level benchmarks. As Java continues to evolve, leveraging its latest features promises to propel performance to new heights, enriching user experiences across diverse applications.</p><h2>Maximizing memory efficiency with scalar quantization</h2><p>Memory consumption has long been a concern for efficient vector database operations, particularly for searching large datasets. Lucene introduces a breakthrough optimization technique - scalar quantization - aimed at significantly reducing memory requirements without sacrificing search performance.</p><p>Consider a scenario where querying millions of float32 vectors of high dimensions demands substantial memory, leading to significant costs. By embracing byte quantization, Lucene slashes memory usage by approximately 75%, offering a viable solution to the memory-intensive nature of vector search operations.</p><p>For quantizing floats to bytes, Lucene implements <a href="https://www.elastic.co/search-labs/blog/scalar-quantization-in-lucene">Scalar quantization</a> a lossy compression technique that transforms raw data into a compressed form, sacrificing some information for space efficiency. Lucene's implementation of scalar quantization achieves remarkable space savings with minimal impact on recall, making it an ideal solution for memory-constrained environments.</p><p>Lucene's architecture, consisting of nodes, shards, and segments, which facilitates efficient distribution and management of documents for search. Each segment stores raw vectors, quantized vectors, and metadata, ensuring optimized storage and retrieval mechanisms.</p><p>Lucene's vector quantization adapts dynamically over time, adjusting quantiles during segment merge operations to maintain optimal recall. By intelligently handling quantization updates and re-quantization when necessary, Lucene ensures consistent performance while accommodating changes in data distribution.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt4680278043366ea4/6a17d78e1d1b83ebd893e2d5/73fb017cce8096a108a7a7297c86cfb26866922c-1440x447.png" alt="" /><p>Example of merged quantiles where segments A and B have 1000 documents and C only has 100.</p><p>Experimental results demonstrate the efficacy of scalar quantization in reducing memory footprint while maintaining search performance. Despite minor differences in recall compared to raw vectors, Lucene's quantized vectors offer significant speed improvements and recall recovery with minimal additional vectors.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt62d403efee1b4ebb/6a17d790e317918e322d5686/aacf329d8eb54a9b73a1e4722e14f27379dd80d7-576x455.png" alt="" /><p>Recall@10 for quantized vectors vs raw vectors. The search performance of quantized vectors is significantly faster than raw, and recall is quickly recoverable by gathering just 5 more vectors; visible by quantized@15.</p><p>Lucene's scalar quantization presents a revolutionary approach to memory optimization in vector search operations. With no need for training or optimization steps, Lucene seamlessly integrates quantization into its indexing process, automatically adapting to changes in data distribution over time. As Lucene and Elasticsearch continue to evolve, widespread adoption of scalar quantization will revolutionize memory efficiency for vector database applications, paving the way for enhanced search performance at scale.</p><h2>Achieving seamless compression with minimal impact on recall</h2><p>To make compression even better, we aimed to reduce each dimension from 7 bits to just 4 bits. Our main goal was to compress data further while still keeping search results accurate. By making some improvements, we managed to compress data by a factor of 8 without making search results worse. Here's how we did it.</p><p>We focused on keeping search results accurate while making data smaller. By making sure we didn't lose important information during compression, we could still find things well even with less detailed data. To make sure we didn't lose any important information, we added a smart error correction system.</p><p>We checked our compression improvements by testing them with different types of data and real search situations. This helped us see how well our searches worked with different compression levels and what we might lose in accuracy by compressing more.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blta71070ad46fd4573/6a17d791be608665ca00459d/7c32834cfb733a6ad3deb64eb9813d4855539823-972x602.png" alt="" /><p>Comparison of int4 dot product values to the corresponding float values for a random sample of 100 documents and their 10 nearest neighbors.</p><p>These compression features were created to easily work with existing vector search systems. They help organizations and users save space without needing to change much in their setup. With this simple compression, organizations can expand their search systems without wasting resources.</p><p>In short, moving to 4 bits per dimension for scalar quantization was a big step in making compression more efficient. It lets users compress their original vectors by 8 times. By optimizing carefully, adding error correction, testing with real data, and offering scalable deployment, organizations could save a lot of storage space without making search results worse. This opens up new chances for efficient and scalable search applications.</p><h2>Paving the way for binary quantization</h2><p>The optimization to reduce each dimension to 4 bits not only delivers significant compression gains but also lays the groundwork for further advancements in compression efficiency. Specifically, future advancements like binary quantization into Lucene, a development that has the potential to revolutionize vector storage and retrieval.</p><p>In an ongoing effort to push the boundaries of compression in vector search, we are actively working on integrating binary quantization into Lucene using the same techniques and principles that underpin our existing optimization strategies. The goal is to achieve binary quantization of vector dimensions, thereby reducing the size of the vector representation by a factor of 32 compared to the original floating-point format.</p><p>Through our iterations and experiments, we want to deliver the full potential of vector search while maximizing resource utilization and scalability. Stay tuned for further updates on our progress towards integrating binary quantization into Lucene and Elasticsearch, and the transformative impact it will have on vector database storage and retrieval.</p><h2>Multi-vector integration in Lucene and Elasticsearch</h2><p>Several real world applications rely on text embedding models and large text inputs. Most embedding models have token limits, which necessitate chunking of longer text into passages. Therefore, instead of a single document, multiple passages and embeddings must be managed, potentially complicating metadata preservation.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blte7cf9100604bef40/6a17d793033c8d5c696baff7/b8a6073b44c078ef8ee5294e559cf8092bf40e38-1440x903.png" alt="" /><p>Now instead of having a single piece of metadata indicating, for example the first chapter of the book “Little Women”, you have to index that information data for every sentence.</p><p>Lucene's "join" functionality, integral to Elasticsearch's nested field type, offers a solution. This feature enables multiple nested documents within a top-level document, allowing searches across nested documents and subsequent joins with their parent documents. So, how do we deliver support for vectors in nested fields with Elasticsearch?</p><p>The key lies in how Lucene joins back to parent documents when searching child vector passages. The parallel concept here is the debate around pre-filtering versus post-filtering in kNN methods, as the timing of joining significantly impacts result quality and quantity. To address this, <a href="https://www.elastic.co/search-labs/blog/adding-passage-vector-search-to-lucene">recent enhancements to Lucene</a> enable pre-joining against parent documents while searching the HNSW graph.</p><p>Practically, pre-joining ensures that when retrieving the k nearest neighbors of a query vector, the algorithm returns the k nearest documents instead of passages. This approach diversifies results without complicating the HNSW algorithm, requiring only a minimal additional memory overhead per stored vector.</p><p>Efficiency is improved by leveraging certain restrictions, such as disjoint sets of parent and child documents and the monotonicity of document IDs. These restrictions allow for optimizations using bit sets, providing rapid identification of parent document IDs.</p><p>Searching through a vast number of documents efficiently required investing in nested fields and joins in Lucene. This work helps storage and search for dense vectors that represent passages within long texts, making document searches in Lucene more effective. Overall, these advancements represent an exciting step forward in the area of vector database retrieval within Lucene.</p><h2>Wrapping up (for now)</h2><p>We're dedicated to making Elasticsearch and Lucene the best vector database with every release. Our goal is to make it easier for people to search for things. With some of the investments we discuss in this blog, there is significant progress, but we're not done!</p><p>To say that the gen AI ecosystem is rapidly evolving is an understatement. At Elastic, we want to give developers the most flexible and open tools to keep up with all the innovation—with features available across recent releases until 8.13 and <a href="https://www.elastic.co/blog/elastic-serverless-architecture">serverless</a></p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/elasticsearch-lucene-vector-database-gains</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/elasticsearch-lucene-vector-database-gains</guid>
    <category><![CDATA[Vector Database]]></category>
    <category><![CDATA[AI]]></category>
    <dc:creator><![CDATA[Mayya Sharipova,Benjamin Trent,Jim Ferenczi]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt35f29a49abcd2e22/6a17d78ae31791cd572d5682/103e9a7a97e9c219edb028e0fc675346920002cc-974x407.png" length="0" type="image/png"/>
    <pubDate>Fri, 26 Apr 2024 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Introducing kNN Query: An expert way to do kNN search]]></title>
    <description><![CDATA[Explore how the kNN query in Elasticsearch can be used and how it differs from top-level kNN search, including examples.]]></description>
    <content:encoded><![CDATA[<h3>kNN search as a top-level section</h3><p><a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/knn-search.html">kNN search</a> in Elasticsearch is organized as a top level section of a search request. We have designed it this way so that:</p><ul><li><p>It can always return global k nearest neighbors regardless of a number of shards</p></li><li><p>These global k results are combined with a results from other queries to form a hybrid search</p></li><li><p>The global k results are passed to aggregations to form facets.</p></li></ul><p>Here is a simplified diagram how kNN search is executed internally (some phases are omitted) :</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltf9df3a17c59cedde/6a170b2aab7f08ec09db9e96/24e227a8482aead389c0ad6298779fd8610006f7-2849x1020.gif" alt="Execution for top level kNN search" /><p>Figure 1: The steps for the top level kNN search are:</p><ol><li><p>A user submits a search request</p></li><li><p>The coordinator node sends a kNN search part of the request to data nodes in the DFS phase</p></li><li><p>Each data node runs kNN search and sends back the local top-k results to the coordinator</p></li><li><p>The coordinator merges all local results to form the global top k nearest neighbors.</p></li><li><p>The coordinator sends back the global k nearest neighbors to the data nodes with any additional queries provided</p></li><li><p>Each data node runs additional queries and sends back the local <code>size</code> results to the coordinator</p></li><li><p>The coordinator merges all local results and sends a response to the user</p></li></ol><p>We first run kNN search in the DFS phase to obtain the global top k results. These global k results are then passed to other parts of the search request, such as other queries or aggregations. Even the execution looks complex, from a user’s perspective this model of running kNN search is simple, as the user can always be sure that kNN search returns the global k results.</p><h3>Introducing kNN query in Elasticsearch</h3><p>With time we realized there is also a need to represent kNN search as a query. Query is a core component of a search request in Elasticsearch, and representing kNN search as a query allows for flexibility to combine it with other queries to address more complex requests.</p><p>kNN query, unlike the top level kNN search, doesn’t have a <code>k</code> parameter. The number of results (nearest neighbors) returned is defined by the <code>size</code> parameter, as in other queries. Similar to kNN search, the <code>num_candidates</code> parameter defines how many candidates to consider on each shard while executing a kNN search.</p>GET products/_search
{
 "size" : 3,
 "query": {
   "knn": {
     "field": "embedding",
     "query_vector": [2,2,2,0],
     "num_candidates": 10
   }
 }
}

<p>kNN query is executed differently from the top level kNN search. Here is a simplified diagram that describes how a kNN query is executed internally (some phases are omitted):</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltf2768a24d52acbbd/6a170b2c7d8d6762fd70e71a/fe505bf7e95ae94c0f7605df1348ef15536134b9-2849x1020.gif" alt="Execution for kNN query" /><p>Figure 2: The steps for query based kNN search are:</p><ol><li><p>A user submits a search request</p></li><li><p>The coordinator sends to the data nodes a kNN search query with additional queries provided</p></li><li><p>Each data node runs the query and sends back the local size results to the coordinator node</p></li><li><p>The coordinator node merges all local results and sends a response to the user</p></li></ol><p>We run kNN search on a shard to get <code>num_candidates</code> results; these results are passed to other queries and aggregations on a shard to get size results from the shard. As we don’t collect the global k nearest neighbors first, in this model the number of nearest neighbors collected and visible for other queries and aggregations depend on the number of shards.</p><h3>kNN query API examples</h3><p>Let’s look at API examples that demonstrate differences between the top level kNN search and kNN query.</p><p>We create an index of products and index some documents:</p>PUT products
{
 "mappings": {
   "dynamic": "strict",
   "properties": {
     "department": {
       "type": "keyword"
     },
     "brand": {
       "type": "keyword"
     },
     "description": {
       "type": "text"
     },
     "embedding": {
       "type": "dense_vector",
       "index": true,
       "similarity": "l2_norm"
     },
     "price": {
       "type": "float"
     }
   }
 }
}
POST products/_bulk?refresh=true
{"index":{"_id":1}}
{"department":"women","brand": "Levi's", "description":"high-rise red jeans","embedding":[1,1,1,1],"price":100}
{"index":{"_id":2}}
{"department":"women","brand": "Calvin Klein","description":"high-rise beautiful jeans","embedding":[1,1,1,1],"price":250}
{"index":{"_id":3}}
{"department":"women","brand": "Gap","description":"every day jeans","embedding":[1,1,1,1],"price":50}
{"index":{"_id":4}}
{"department":"women","brand": "Levi's","description":"jeans","embedding":[2,2,2,0],"price":75}
{"index":{"_id":5}}
{"department":"women","brand": "Levi's","description":"luxury jeans","embedding":[2,2,2,0],"price":150}
{"index":{"_id":6}}
{"department":"men","brand": "Levi's", "description":"jeans","embedding":[2,2,2,0],"price":50}
{"index":{"_id":7}}
{"department":"women","brand": "Levi's", "description":"jeans 2023","embedding":[2,2,2,0],"price":150}
<p>kNN query similar to the top level kNN search, has <code>num_candidates</code> and an internal <code>filter</code> parameter that acts as a pre-filter.</p>GET products/_search
{
 "size" : 3,
 "query": {
   "knn": {
     "field": "embedding",
     "query_vector": [2,2,2,0],
     "num_candidates": 10,
     "filter" : {
       "term" : {
         "department" : "women"
       }
     }
   }
 }
} 
<p>kNN query can get more diverse results than kNN search for collapsing and aggregations. For the kNN query below, on each shard we execute kNN search to obtain 10 nearest neighbors which are then passed to collapse to get 3 top results. Thus, we will get 3 diverse hits in a response.</p>GET products/_search
{
 "size" : 3,
 "query": {
   "knn": {
     "field": "embedding",
     "query_vector": [2,2,2,0],
     "num_candidates": 10,
     "filter" : {
       "term" : {
         "department" : "women"
       }
     }
   }
 },
 "collapse": {
   "field": "brand"        
 }
}
<p>The top level kNN search first gets the global top 3 results in the DFS phase, and then passes them to collapse in the query phase. We will get only 1 hit in a response, as all the global 3 nearest neighbors happened to be from the same brand.</p>GET products/_search?size=3
{
 "knn" : {
   "field": "embedding",
     "query_vector": [2,2,2,0],
     "k" : 3,
     "num_candidates": 10,
     "filter" : {
       "term" : {
         "department" : "women"
       }
     }
 },
 "collapse": {
   "field": "brand"        
 }
}
<p>Similarly for aggregations, a kNN query allows us to get 3 distinct buckets, while kNN search only allows 1.</p>GET products/_search
{
"size": 0,
"query": {
   "knn": {
     "field": "embedding",
     "query_vector": [2,2,2,0],
     "num_candidates": 10,
     "filter" : {
       "term" : {
         "department" : "women"
       }
     }
   }
 },
 "aggs": {
   "brands": {
     "terms": {
       "field": "brand"
     }
   }
 }
}
​
GET products/_search
{
"size": 0,
"knn" : {
 "field": "embedding",
   "query_vector": [2,2,2,0],
   "k" : 3,
   "num_candidates": 10,
   "filter" : {
     "term" : {
       "department" : "women"
     }
   }
 },
 "aggs": {
   "brands": {
     "terms": {
       "field": "brand"
     }
   }
 }
}
<p>Now, let’s look at other examples that show the flexibility of the kNN query. Specifically, how it can be flexibly combined with other queries.</p><p>kNN can be a part of a <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-bool-query.html">boolean</a> query (with a caveat that all external query filters are applied as post-filters for kNN search). We can use a <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-bool-query.html#named-queries">_name</a> parameter for kNN query to enhance results with extra information that tells if the kNN query was a match and its score contribution.</p>GET products/_search?include_named_queries_score
{
 "size": 3,
 "query": {
   "bool": {
     "should": [
       {
         "knn": {
           "field": "embedding",
           "query_vector": [2,2,2,0],
           "num_candidates": 10,
           "_name": "knn_query"
         }
       },
       {
         "match": {
           "description": {
             "query": "luxury",
             "_name": "bm25query"
           }
         }
       }
     ]
   }
 }
}
<p>kNN can also be a part of complex queries, such as a <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-pinned-query.html">pinned</a> query. This is useful when we want to display the top nearest results, but also want to promote a selected number of other results.</p>GET products/_search
{
 "size": 3,
 "query": {
   "pinned": {
     "ids": [ "1", "2" ],
     "organic": {
       "knn": {
           "field": "embedding",
           "query_vector": [2,2,2,0],
           "num_candidates": 10,
           "_name": "knn_query"
         }
     }
   }
 }
}
<p>We can even make the kNN query a part of our <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-function-score-query.html">function_score</a> query. This is useful when we need to define custom scores for results returned by kNN query: ​</p>GET products/_search
{
 "size": 3,
 "query": {
   "function_score": {
     "query": {
       "knn": {
           "field": "embedding",
           "query_vector": [2,2,2,0],
           "num_candidates": 10,
           "_name": "knn_query"
         }
     },
     "functions": [
       {
         "filter": { "match": { "department": "men" } },
         "weight": 100
       },
       {
         "filter": { "match": { "department": "women" } },
         "weight": 50
       }
     ]
   }
 }
}
<p>kNN query being a part of <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-dis-max-query.html">dis_max</a> query is useful when we want to combine results from kNN search and other queries, so that a document’s score comes from the highest ranked clause with a tie breaking increment for any additional clause. ​</p>GET products/_search
{
 "size": 5,
 "query": {
   "dis_max": {
     "queries": [
       {
         "knn": {
           "field": "embedding",
           "query_vector": [2,2, 2,0],
           "num_candidates": 3,
           "_name": "knn_query"
         }
       },
       {
         "match": {
           "description": "high-rise jeans"
         }
       }
     ],
     "tie_breaker": 0.8
   }
 }
}
<p>kNN search as a query has been introduced with the 8.12 release. Please try it out, and we would appreciate any feedback.</p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/knn-query-elasticsearch</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/knn-query-elasticsearch</guid>
    <category><![CDATA[Vector Database]]></category>
    <dc:creator><![CDATA[Mayya Sharipova,Benjamin Trent]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltd528ca7843f1946f/6a170b2e2b835ff0b7f4b21b/d2c2a3cddc393d80b11e4ed93672e345d0addd7d-1024x1024.png" length="0" type="image/png"/>
    <pubDate>Thu, 07 Dec 2023 00:00:00 GMT</pubDate>
  </item>
  </channel>
</rss>