From e2db011fbeedf84aab05e5a85fce080e69ec02b5 Mon Sep 17 00:00:00 2001 From: Fanit Kolchina Date: Tue, 26 Nov 2024 10:50:44 -0500 Subject: [PATCH 01/16] Initial commit Signed-off-by: Fanit Kolchina --- .../2024-06-07-opensearch-performance-2.17.md | 262 ++++++++++++++++++ 1 file changed, 262 insertions(+) create mode 100644 _posts/2024-06-07-opensearch-performance-2.17.md diff --git a/_posts/2024-06-07-opensearch-performance-2.17.md b/_posts/2024-06-07-opensearch-performance-2.17.md new file mode 100644 index 000000000..88e7865cb --- /dev/null +++ b/_posts/2024-06-07-opensearch-performance-2.17.md @@ -0,0 +1,262 @@ +--- +layout: post +title: "OpenSearch Project update: A look at performance progress through version 2.17" +layout: post +authors: + - sisurab + - pallp +date: 2024-11-26 +categories: + - technical-posts + - community +meta_keywords: OpenSearch performance progress 2.17, OpenSearch roadmap +meta_description: Learn more about the strategic enhancements and performance features that OpenSearch has delivered up to version 2.17. +has_science_table: true +excerpt: Learn more about the strategic enhancements and performance features that OpenSearch has delivered up to version 2.17. +featured_blog_post: false +featured_image: false +--- + +OpenSearch covers a broad range of functionality for applications involving document search, e-commerce search, log analytics, observability, and data analytics. All of these applications depend on a full-featured, scalable, reliable, and high-performance foundation. In the latest OpenSearch versions, we've added new features such as enhanced artificial intelligence and machine learning (AI/ML) semantic/vector search capabilities, neural search, hybrid search, flat objects, and zero-ETL integrations. As we continue to add new features, we are also improving scalability, reliability, and performance both for existing and for new features. These improvements allow us to support ever-growing data collections with high throughput, low latency, lower resource consumption, and, thus, lower costs. This blog post focuses on performance improvements in OpenSearch 2.12, 2.13, and 2.14. These fall into four broad categories: text querying, vector storage and querying, ingestion and indexing, and storage efficiency. + +In this post, we focus on the performance improvements seen in OpenSearch 2.17, as measured against prior releases, specifically in query types such as text querying, term aggregations, range queries, date histograms, and sorting. These advancements were evaluated using the [OpenSearch Big5 workload](https://github.com/opensearch-project/opensearch-benchmark-workloads/tree/main/big5), ensuring we target common use cases in both search and analytics applications. The key benchmarks provide an easy-to-replicate framework for measuring real-world performance enhancements. For those interested in a more detailed analysis of the performance benchmarks or wishing to conduct your own benchmark tests, see the [Appendix](#appendix---benchmarking-tests-and-results). + + + +# Performance improvements through 2.17 + +Since its inception, OpenSearch has made consistent improvements to performance, and the 2.17 release is no exception. Compared to version 1.x and recent 2.x versions, we have achieved up XX speedups, reducing query latencies across various categories. Below is a detailed breakdown of the improvements in 2.17 across the Big5 workload. + +#### Key highlights for Version 2.17 + +* **Overall Query Performance**: OpenSearch 2.17 achieves **6x better performance** compared to OS 1.x. +* **Text Queries**: Text search queries, fundamental to many OpenSearch use cases, are **57% faster** in 2.17 compared to the baseline of OS 1.0. +* **Terms Aggregation**: This critical query type for log analytics shows a **97% improvement** over OS 1.3, allowing for faster and more efficient data aggregation. +* **Date Histograms**: OpenSearch 2.17 reduces the relative latency for date histograms by **84%** compared to 1.3, showcasing major speed enhancements for time-series analysis. +* **Range Queries**: With **85%-90% performance improvement** compared to OpenSearch 1.x, range queries now execute quicker with fewer resources. + + +| | +**Query Types** |1.3.18 |2.7 |2.11 |2.12 |2.13 |2.14 |2.15 |2.16 |2.17 | +|--- |--- |--- |--- |--- |--- |--- |--- |--- |--- |--- | +| +**Big 5 Buckets** | +Text Query |59.51 |47.91 |41.05 |27.29 |27.61 |27.85 |27.39 |21.7 |21.77 | +| +Sorting |17.73 |11.24 |8.14 |7.99 |7.53 |7.47 |7.78 |7.22 |7.26 | +| +Terms Aggregation |609.43 |1351 |1316 |1228 |291 |293 |113 |112 |113 | +| +Range Queries |26.08 |23.12 |16.91 |18.71 |17.33 |17.39 |18.51 |3.17 |3.17 | +| +Date Histogram |6068 |5249 |5168 |469 |357 |146 |157 |164 |160 | +|Aggregate (geo mean) |159.04 |154.59 |130.9 |74.85 |51.84 |43.44 |37.07 |24.66 |24.63 | +|Speedup factor, compared to OS 1.3 (geo mean) |1.0 |1.03 |1.21 |2.12 |3.07 |3.66 |4.29 |6.45 |6.46 | +|Relative latency, compared to OS 1.3 (geo mean) |100% |97.20 |82.31 |47.06 |32.60 |27.31 |23.31 |15.51 |15.93 | + +## Queries + + +#### Text Queries + +Building on the advancements in OpenSearch 2.12, where the `match_only_text` field was introduced, OpenSearch 2.17 takes this further by optimizing text queries, reducing the space needed for indexes and speeding up query execution even more. Text queries are now **64% faster** than in 2.11 and **57% faster** than OpenSearch 1.x. + +#### Term and multi-term aggregations + +Term aggregations are crucial for slicing and dicing large datasets across multiple criteria. OpenSearch 2.17 has enhanced the efficiency of global term aggregations, leveraging term frequency optimizations. The results are a **97% reduction in query latency** compared to 1.3, showcasing speedups in handling large immutable collections, such as log data. Latency for Multi Term Aggregation queries have been reduced upto 20% and memory footprint for short lived objects decreased by 50-60% after removing the need for new byte array allocations for storing composite keys. + +We also added support for the["wildcard" field type](https://github.com/opensearch-project/OpenSearch/pull/13461) that supports efficient execution of wildcard, prefix, and regexp queries by matching first against trigrams (or bigrams or individual characters), then post-filtering by evaluating the original field value against the pattern. + +#### Date Histograms + +A key query type for time-based data analysis, date histograms are now executing **84% faster** in OpenSearch 2.17 compared to 1.3. This enhancement reduces the time required for time-series aggregations, especially when there are no sub-aggregations. Same optimization has been added to range aggregation also. + +Cardinality aggregation is a powerful tool for counting distinct values, used in cases like tracking unique visitors, detecting anomalies in event types, or tallying unique products. We introduce an [optimization](https://github.com/opensearch-project/OpenSearch/pull/13821) that can dynamically prune documents that contain distinct values already collected, significantly improving performance for low-cardinality requests. Even for high-cardinality requests, this can provide up to a 20% speed increase by avoiding processing of redundant documents. + +#### Range queries and numeric fields + +These queries, often used to filter data within a specific numerical or date range, have also seen improvements. With version 2.17, range queries are now **85%-90% faster** than they were in OpenSearch 1.3, thanks to [approximate range optimizations](https://github.com/opensearch-project/OpenSearch/pull/13788) in how range filters are handled. During search time we evaluate if a query matches a particular requirement for it to be rewritten from `originalQuery` to `approximateQuery`. The re-written query performs quicker utilizing fewer resources without compromising on search results in most cases. + +#### Sorting and filtering + +Sorting performance has been continuously refined in the 2.x series. With OpenSearch 2.17, sorting is more efficient offering a **59% improvement** over OS 1.3. + +We introduced a [new approach](https://github.com/opensearch-project/OpenSearch/pull/14774) to handling large filter lists by encoding filter lists as Roaring Bitmaps. This reduces the memory and network overhead required to store and transmit these filters. The bitmap-based approach excels when filter sizes are huge, such as in common use cases like filtering a product index by a customer's owned products. Users can store and join large bitmap filters with the main index at query time. Our tests show the bitmap method maintains low latency in the high-cardinality scenarios, making it a more scalable solution than traditional terms queries or lookups. + + + +## Vector Search + +**Disk Optimized vector Search:** OpenSearch vector engine continues to prioritize cost savings with its latest release, version 2.17. This release introduces disk-optimized vector search that enables customers to leverage the full potential of vector workloads, even in low-memory environments. Disk-optimized vector search is designed to provide out-of-the-box 32x compression with Binary quantization, a powerful compression technique. However, users have the flexibility to fine-tune cost, response time, and accuracy to their unique needs through configurable parameters such as compression rate, sampling, and rescoring strategies. According to internal benchmarks, OpenSearch's disk-optimized vector search can deliver cost savings of up to 70%, while maintaining impressive performance with p90 latencies around 200ms and recall over 0.9. Check [documentaion](https://opensearch.org/docs/latest/search-plugins/knn/disk-based-vector-search/) for getting started. + +Vector search capabilities in native engines(faiss, nmslib) have received a significant boost with this latest release. We have integrated the Lucene Vector field with native engines, enabling the use of KNNVectorFormat during segment creation. Further native memory footprint during indexing has been drastically reduced by introducing [incremental graph build](https://github.com/opensearch-project/k-NN/issues/1938) capability instead of loading all the dataset at once into a memory. This helps with HNSW graph builds in low memory environments. OpenSearch's 2.17 release extends OpenSearch's Byte compression technique to Faiss Engine [HSNW](https://github.com/opensearch-project/k-NN/pull/1823) and [IVF](https://github.com/opensearch-project/k-NN/pull/2002) algorithms to further reduce memory footprint up to 75% for vectors that fit into Byte range [-128., 127] . Other improvements include handling [non-existent fields](https://github.com/opensearch-project/k-NN/pull/1874) in filters, [graph merge](https://github.com/opensearch-project/k-NN/pull/1844) stats size calculation, improved [caching](https://github.com/opensearch-project/k-NN/pull/2015) and more. + +## Roadmap for 2025 + +### Core search engine + +In 2025, we're pushing the boundaries of OpenSearch's Query Engine with several key initiatives aimed at improving performance, scalability, and efficiency: + +* **Streaming Architecture**: We're moving from a request/reply model to streaming, processing and delivering data in real-time, reducing memory overhead and improving query speed. +* **Native Join Support**: We're introducing efficient JOIN operations across indexes to be supported natively, fully integrated with OpenSearch's query DSL, PPL, and SQL. +* **Native Vectorized Processing**: By leveraging modern CPU SIMD operations and native code, we're optimizing the processing of data streams to eliminate Java's garbage collection bottlenecks. +* **[Smarter Query Planning](https://github.com/opensearch-project/OpenSearch/issues/12390)**: Optimizing where and how computations run ensures we reduce unnecessary data transfer and improve performance for parallel query execution. +* **[gRPC-based Search API](https://github.com/opensearch-project/OpenSearch/issues/15190)**: We're enhancing client-server communication with Protobuf and gRPC, speeding up search by cutting down transport overhead. +* **[Query Performance Optimization](https://github.com/orgs/opensearch-project/projects/153)**: Improving performance remain our priority and several key initiatives such as docId encoding and query approximation will enhance performance on large range queries and reduce index size. +* **[Star Tree Indexing](https://github.com/opensearch-project/OpenSearch/issues/12498)**: Precomputing aggregations with star tree indexing ensures faster, more predictable performance for aggregation-heavy queries. + + + + +### Hybrid Search + +Hybrid search combines lexical and semantic vector search to get the best of both worlds. Highly specific names — like part numbers — are best found using lexical search, while broader queries are often best handled by semantic vector search. We have supported Hybrid Search since OpenSearch 2.10. We plan a variety of enhancements to it. + +By executing the lexical and the vector searches in parallel, we predict up to 25% latency improvement. + +We will support re-sorting of the results of hybrid queries. + +We will support additional algorithms for combining the query results. In particular, reciprocal rank fusion (RRF) has shown good results in some applications. + +Finally, we will return the raw scores of the sub-queries, which is useful for debugging and for relevance tuning. + +### Vector Search + +Semantic vector search is a powerful technique for finding semantic similiarities, but it can be costly, because indexing vectors to make them efficient to search is time-consuming, and the vectors themselves can consume large amounts of memory. + +We are currently working on: + +* speeding up vector indexing by 80% and reduce the memory required for indexing; +* reducing the amount of space needed to store vectors by compressing vector components from 32 bits to 16, 8, and even 1 bit. Our experiments show modest reductions in search quality (recall) with 16 and 8 bit components; we are still analyzing the 1-bit case (binary quantization). +* reducing cost with disk based approximate nearest neighbor algorithms (aNN) using external storage (SSDs, S3 etc). + +Vector techniques have also been less flexible than lexical techniques in many ways, so we are: + +* improving search relevancy by supporting re-ranking on compressed vectors; +* supporting aNN vector search for the multi-tenant case, where each tenant has their own sub-collection. This is especially valuable for customers each of whose user organizations has a large vector collection. + +### Performance benchmarking + +We will update [the Big5 workload](https://github.com/opensearch-project/opensearch-benchmark-workloads/tree/main/big5) mappings and settings — in particular, adding support for dynamic templates, configurable merge policies, match-only text, and query default query field set as “message”. + +## Conclusion + +While OpenSearch continues to expand its functionality, we are also investing in improving the performance, efficiency, and robustness of the system for every workload. In particular, vector techniques are being widely adopted both for pure semantic search and for hybrid semantic and lexical search. + +The OpenSearch team at AWS works in collaboration with the larger OpenSearch community. Without its contributions to testing, feedback, and development, OpenSearch would not be where it is today. + +Stay tuned to our blog and GitHub for continuous updates and insights into our progress and future plans. + + + +## Appendix - Benchmarking tests and results + + + +This section presents details on the performance benchmarks we use and the results we've measured. The data was collected using OpenSearch Benchmark to run the big5 workload against different distributions and configurations of OpenSearch. In particular: + +* OpenSearch Benchmark was used for testing both ES and OS, since this is our standard tool and Rally numbers might be different. +* Each test ran against a single-node cluster, to ensure better reproducibility and easier setup. +* The instance type was *c5.2xlarge*: 8 vCPU, 16 GB, a middle-of-the-road instance type. Improvements in resource usage efficiency can be masked by oversized instances. +* Big5 Index was comprised of a single shard, no replicas (i.e. run with `--workload-params="number_of_replicas:0"`). +* Ingestion during the test was run with single bulk indexing client to ensure data is ingested in chronological order. +* Tests were run in [benchmarking mode](https://opensearch.org/docs/latest/benchmark/user-guide/target-throughput/#benchmarking-mode) (i.e. target-throughput was disabled) so that the OpenSearch client sends requests to the OpenSearch cluster as fast as possible +* Indexing LSM was configured with LogByteSizeMergePolicy, since this optimization was in place last year, prior to the blog post being published. +* Corpus size of the workload: 60 GB, 70M docs. Store size after ingestion is 15 GB for the primary shard. Eliminating overhead like doc values, etc., RSS should be about 8 GB which should match the JVM heap size for the instance. Having most data resident in memory should provide a good assessment of performance improvements. +* The mapping file for Elasticsearch will be the one that Elastic used for their blog post runs. The workload will need to be modified manually to set this up. + + + +|A |Query Types |OS 1.0 |OS 2.7 |OS 2.11 |OS 2.12 |OS 2.13 |OS 2.14 | +|--- |--- |--- |--- |--- |--- |--- |--- | +|Big 5 Areas + +Mean Latency, ms |Text Query |44.34 |37.02 |36.12 |19.42 |19.41 |20.01 | +|--- |--- |--- |--- |--- |--- |--- |--- | +|Sorting |65.04 |18.58 |10.21 |6.22 |5.55 |5.53 | +|Terms Aggregation |311.78 |315.27 |316.32 |282.41 |36.27 |27.18 | +|Range Queries |4.06 |4.52 |4.32 |3.81 |3.44 |3.41 | +|Date Histogram |4812.36 |5093.01 |5057.62 |310.32 |332.41 |141.5 | +|Geo Mean | |111.93 |87.03 |76.08 |33.2 |21.38 |17.07 | +|Relative latency +(Geo Mean) | |100 |78 |68 |30 |19 |15 | +|Relative latency +(Geo Mean) | |100% |78% |68% |30% |19% |15% | +|Speedup +(Geo Mean) | |1 |1.3 |1.5 |3.3 |5.3 |6.7 | + +### 2. Query categories + +|**Buckets** |Query |Order |OS 1.0 P90 Service Time (ms) |ES 7.10 P90 Service Time RSD (%) |ES 8.8.1 P90 Service Time (ms) |ES P90 Service Time RSD (%) |OS 2.7 P90 Service Time (ms) |**OS 2.7 P90 Service Time RSD (%)** |OS 2.11.0 P90 Service Time (ms) |OS 2.11.0 P90 Service Time RSD (%) |OS 2.12.0 P90 Service Time (ms) |OS 2.13.0 P90 Service Time (ms) |OS 2.14 P90 Service Time (ms) | +|--- |--- |--- |--- |--- |--- |--- |--- |--- |--- |--- |--- |--- |--- | +|Text Querying |default |1 |2.79 |0.92 |1.4 |5.52 |2.65 |11.4 |2.41 |2.59 |2.5 |2.34 |2.27 | +|scroll |22 |448.9 |1.69 |208.29 |3.22 |228.42 |2.43 |227.36 |2.97 |222.1 |210.41 |217.82 | +|query-string-on-message |23 |180.55 |0.25 |3.33 |6.86 |173.6 |0.16 |168.29 |0.47 |8.72 |9.29 |8.22 | +|query-string-on-message-filtered |24 |174.25 |0.81 |89.22 |0.31 |125.88 |0.67 |146.62 |0.48 |102.53 |110.49 |135.98 | +|query-string-on-message-filtered-sorted-num |25 |238.14 |0.38 |194.03 |0.13 |183.62 |0.51 |180.46 |0.25 |112.39 |120.41 |139.95 | +|term |10 |0.81 |2.5 |0.87 |13.81 |1.06 |8.9 |0.91 |3.35 |0.96 |0.88 |0.83 | +|Sorting |desc_sort_timestamp |2 |13.09 |1.68 |246.83 |0.22 |159.45 |1.83 |28.39 |1.36 |20.65 |18.76 |20.4483 | +|asc_sort_timestamp |3 |993.81 |3.7 |38.5 |1.1 |61.94 |5.79 |78.91 |0.87 |39.78 |36.83 |33.79 | +|desc_sort_with_after_timestamp |4 |1123.65 |0.14 |237.67 |0.48 |163.53 |1.6 |28.93 |1.43 |19.4 |18.78 |22.492 | +|asc_sort_with_after_timestamp |5 |1475.51 |0.74 |24.84 |2.09 |42.69 |7.86 |38.55 |1.67 |6.22 |5.55 |5.14 | +|desc_sort_timestamp_can_match_shortcut |6 |15.49 |0.95 |46.47 |0.48 |31.13 |1.72 |7.64 |2.05 |7.11 |6.54 |6.88 | +|desc_sort_timestamp_no_can_match_shortcut |7 |15.29 |3.27 |46.61 |0.21 |30.95 |2.31 |7.63 |2.32 |7.17 |6.53 |6.74441 | +|asc_sort_timestamp_can_match_shortcut |8 |198.59 |0.59 |11.22 |1.6 |32.46 |2.13 |18.93 |2.59 |12.64 |9.45 |8.91 | +|asc_sort_timestamp_no_can_match_shortcut |9 |197.36 |1.15 |11.26 |1.5 |32.5 |2.08 |18.78 |2.67 |12.74 |9.02 |8.82 | +|sort_keyword_can_match_shortcut |26 |181.18 |0.34 |2.12 |4.71 |2.59 |11.11 |2.37 |0.51 |2.46 |2.18 |2.13 | +|sort_keyword_no_can_match_shortcut |27 |181.06 |0.22 |2.12 |4.48 |2.43 |2.04 |2.44 |3.02 |2.49 |2.15 |2.09 | +|sort_numeric_desc |28 |36.19 |15.15 |20.78 |1.23 |35.15 |1.48 |23.6 |1.65 |6.04 |5.83 |5.78 | +|sort_numeric_asc |29 |66.87 |3.12 |22.02 |1.07 |37.74 |1.69 |21.14 |1.21 |5.3 |5.15 |5.2 | +|sort_numeric_desc_with_match |30 |1.23 |4.45 |0.84 |11.51 |1.01 |3.13 |0.99 |9.26 |0.92 |0.85 |0.8 | +|sort_numeric_asc_with_match |31 |1.24 |1.11 |0.83 |3.93 |0.99 |0.44 |0.9 |1.65 |0.89 |0.84 |0.8 | +|Terms Aggregation |multi_terms-keyword |11 |0.92 |1.09 |0.94 |10.32 |1.1 |5.51 |1 |10.09 |1.05 |0.91 |0.89 | +|keyword-terms |12 |2126.25 |0.28 |1497.29 |0.72 |2117.22 |0.96 |2382.37 |0.68 |1906.71 |12.74 |6.96 | +|keyword-terms-low-cardinality |13 |2135.16 |0.59 |1505.32 |0.3 |2121.88 |0.42 |2338.1 |1.78 |1893.9 |10.81 |5.25 | +|composite-terms |14 |696.37 |0.61 |634.91 |0.21 |668.09 |0.28 |631.23 |0.69 |572.77 |581.24 |551.62 | +|composite_terms-keyword |15 |1012.96 |1.18 |866.91 |0.4 |943.35 |0.48 |900.66 |0.13 |827.16 |861.81 |826.18 | +|Range Queries |range |17 |203.29 |1.61 |130.57 |0.88 |170.68 |0.78 |189.77 |0.21 |115.38 |115.2 |125.99 | +|range-numeric |18 |0.81 |11.34 |0.8 |5.2 |0.96 |3.46 |0.87 |1.14 |0.9 |0.76 |0.75 | +|keyword-in-range |19 |210.69 |0.57 |138.94 |0.2 |179.18 |1.38 |200.37 |0.05 |123.59 |124.66 |134.06 | +|range_field_conjunction_big_range_big_term_query |32 |0.92 |1.73 |0.92 |1.81 |1.13 |5.35 |0.99 |3.35 |1.01 |0.91 |0.82 | +|range_field_disjunction_big_range_small_term_query |33 |0.82 |2.38 |0.91 |2.45 |1.08 |4.66 |1.04 |10.32 |1 |0.86 |0.81 | +|range_field_conjunction_small_range_small_term_query |34 |0.83 |2.13 |0.95 |8.52 |1.09 |10.28 |0.93 |1.53 |0.98 |0.85 |0.81 | +|range_field_conjunction_small_range_big_term_query |35 |0.83 |12.05 |0.8 |2.34 |0.98 |1.09 |0.88 |2.22 |0.91 |0.78 |0.78 | +|Date Histogram |date_histogram_hourly_agg |20 |3618.5 |0.24 |10.42 |2.91 |3664.45 |0.08 |3785.48 |0.13 |8.5 |9.97 |3.39 | +|date_histogram_minute_agg |21 |2854.99 |0.34 |3031.03 |0.34 |2933.76 |0.46 |2961.69 |0.12 |2518.69 |2635.16 |148.69 | +|composite-date_histogram-daily |16 |3760.5 |0.1 |4484.72 |1.6 |4016.42 |1.12 |3574.18 |0.1 |1.44 |1.51 |1.39 | +|range-auto-date-histo |36 |5267.47 |0.25 |4840.65 |0.21 |5960.21 |0.18 |6055.74 |0.39 |6784.27 |6977.05 |6129.29 | +|range-auto-date-histo-with-metrics |37 |12612.77 |0.16 |12036.19 |0.33 |13314.87 |0.11 |13637.23 |0.09 |13759.51 |14662.24 |13208.98 | +| | | |40050.08 | |30391.52 | |37446.24 | |37667.78 | |29110.78 |26579.74 |21,781.75 | From 0e6c40840c5b910e52d962ea299b62505e03286a Mon Sep 17 00:00:00 2001 From: Fanit Kolchina Date: Tue, 26 Nov 2024 19:45:25 -0500 Subject: [PATCH 02/16] Add OpenSearch performance 2.17 blog Signed-off-by: Fanit Kolchina --- .../2024-06-07-opensearch-performance-2.17.md | 262 ----------------- .../2024-11-26-opensearch-performance-2.17.md | 272 ++++++++++++++++++ .../OS-PerformanceChart-ldc@2x.png | Bin 0 -> 130437 bytes 3 files changed, 272 insertions(+), 262 deletions(-) delete mode 100644 _posts/2024-06-07-opensearch-performance-2.17.md create mode 100644 _posts/2024-11-26-opensearch-performance-2.17.md create mode 100644 assets/media/blog-images/2024-11-26-opensearch-performance-2.17/OS-PerformanceChart-ldc@2x.png diff --git a/_posts/2024-06-07-opensearch-performance-2.17.md b/_posts/2024-06-07-opensearch-performance-2.17.md deleted file mode 100644 index 88e7865cb..000000000 --- a/_posts/2024-06-07-opensearch-performance-2.17.md +++ /dev/null @@ -1,262 +0,0 @@ ---- -layout: post -title: "OpenSearch Project update: A look at performance progress through version 2.17" -layout: post -authors: - - sisurab - - pallp -date: 2024-11-26 -categories: - - technical-posts - - community -meta_keywords: OpenSearch performance progress 2.17, OpenSearch roadmap -meta_description: Learn more about the strategic enhancements and performance features that OpenSearch has delivered up to version 2.17. -has_science_table: true -excerpt: Learn more about the strategic enhancements and performance features that OpenSearch has delivered up to version 2.17. -featured_blog_post: false -featured_image: false ---- - -OpenSearch covers a broad range of functionality for applications involving document search, e-commerce search, log analytics, observability, and data analytics. All of these applications depend on a full-featured, scalable, reliable, and high-performance foundation. In the latest OpenSearch versions, we've added new features such as enhanced artificial intelligence and machine learning (AI/ML) semantic/vector search capabilities, neural search, hybrid search, flat objects, and zero-ETL integrations. As we continue to add new features, we are also improving scalability, reliability, and performance both for existing and for new features. These improvements allow us to support ever-growing data collections with high throughput, low latency, lower resource consumption, and, thus, lower costs. This blog post focuses on performance improvements in OpenSearch 2.12, 2.13, and 2.14. These fall into four broad categories: text querying, vector storage and querying, ingestion and indexing, and storage efficiency. - -In this post, we focus on the performance improvements seen in OpenSearch 2.17, as measured against prior releases, specifically in query types such as text querying, term aggregations, range queries, date histograms, and sorting. These advancements were evaluated using the [OpenSearch Big5 workload](https://github.com/opensearch-project/opensearch-benchmark-workloads/tree/main/big5), ensuring we target common use cases in both search and analytics applications. The key benchmarks provide an easy-to-replicate framework for measuring real-world performance enhancements. For those interested in a more detailed analysis of the performance benchmarks or wishing to conduct your own benchmark tests, see the [Appendix](#appendix---benchmarking-tests-and-results). - - - -# Performance improvements through 2.17 - -Since its inception, OpenSearch has made consistent improvements to performance, and the 2.17 release is no exception. Compared to version 1.x and recent 2.x versions, we have achieved up XX speedups, reducing query latencies across various categories. Below is a detailed breakdown of the improvements in 2.17 across the Big5 workload. - -#### Key highlights for Version 2.17 - -* **Overall Query Performance**: OpenSearch 2.17 achieves **6x better performance** compared to OS 1.x. -* **Text Queries**: Text search queries, fundamental to many OpenSearch use cases, are **57% faster** in 2.17 compared to the baseline of OS 1.0. -* **Terms Aggregation**: This critical query type for log analytics shows a **97% improvement** over OS 1.3, allowing for faster and more efficient data aggregation. -* **Date Histograms**: OpenSearch 2.17 reduces the relative latency for date histograms by **84%** compared to 1.3, showcasing major speed enhancements for time-series analysis. -* **Range Queries**: With **85%-90% performance improvement** compared to OpenSearch 1.x, range queries now execute quicker with fewer resources. - - -| | -**Query Types** |1.3.18 |2.7 |2.11 |2.12 |2.13 |2.14 |2.15 |2.16 |2.17 | -|--- |--- |--- |--- |--- |--- |--- |--- |--- |--- |--- | -| -**Big 5 Buckets** | -Text Query |59.51 |47.91 |41.05 |27.29 |27.61 |27.85 |27.39 |21.7 |21.77 | -| -Sorting |17.73 |11.24 |8.14 |7.99 |7.53 |7.47 |7.78 |7.22 |7.26 | -| -Terms Aggregation |609.43 |1351 |1316 |1228 |291 |293 |113 |112 |113 | -| -Range Queries |26.08 |23.12 |16.91 |18.71 |17.33 |17.39 |18.51 |3.17 |3.17 | -| -Date Histogram |6068 |5249 |5168 |469 |357 |146 |157 |164 |160 | -|Aggregate (geo mean) |159.04 |154.59 |130.9 |74.85 |51.84 |43.44 |37.07 |24.66 |24.63 | -|Speedup factor, compared to OS 1.3 (geo mean) |1.0 |1.03 |1.21 |2.12 |3.07 |3.66 |4.29 |6.45 |6.46 | -|Relative latency, compared to OS 1.3 (geo mean) |100% |97.20 |82.31 |47.06 |32.60 |27.31 |23.31 |15.51 |15.93 | - -## Queries - - -#### Text Queries - -Building on the advancements in OpenSearch 2.12, where the `match_only_text` field was introduced, OpenSearch 2.17 takes this further by optimizing text queries, reducing the space needed for indexes and speeding up query execution even more. Text queries are now **64% faster** than in 2.11 and **57% faster** than OpenSearch 1.x. - -#### Term and multi-term aggregations - -Term aggregations are crucial for slicing and dicing large datasets across multiple criteria. OpenSearch 2.17 has enhanced the efficiency of global term aggregations, leveraging term frequency optimizations. The results are a **97% reduction in query latency** compared to 1.3, showcasing speedups in handling large immutable collections, such as log data. Latency for Multi Term Aggregation queries have been reduced upto 20% and memory footprint for short lived objects decreased by 50-60% after removing the need for new byte array allocations for storing composite keys. - -We also added support for the["wildcard" field type](https://github.com/opensearch-project/OpenSearch/pull/13461) that supports efficient execution of wildcard, prefix, and regexp queries by matching first against trigrams (or bigrams or individual characters), then post-filtering by evaluating the original field value against the pattern. - -#### Date Histograms - -A key query type for time-based data analysis, date histograms are now executing **84% faster** in OpenSearch 2.17 compared to 1.3. This enhancement reduces the time required for time-series aggregations, especially when there are no sub-aggregations. Same optimization has been added to range aggregation also. - -Cardinality aggregation is a powerful tool for counting distinct values, used in cases like tracking unique visitors, detecting anomalies in event types, or tallying unique products. We introduce an [optimization](https://github.com/opensearch-project/OpenSearch/pull/13821) that can dynamically prune documents that contain distinct values already collected, significantly improving performance for low-cardinality requests. Even for high-cardinality requests, this can provide up to a 20% speed increase by avoiding processing of redundant documents. - -#### Range queries and numeric fields - -These queries, often used to filter data within a specific numerical or date range, have also seen improvements. With version 2.17, range queries are now **85%-90% faster** than they were in OpenSearch 1.3, thanks to [approximate range optimizations](https://github.com/opensearch-project/OpenSearch/pull/13788) in how range filters are handled. During search time we evaluate if a query matches a particular requirement for it to be rewritten from `originalQuery` to `approximateQuery`. The re-written query performs quicker utilizing fewer resources without compromising on search results in most cases. - -#### Sorting and filtering - -Sorting performance has been continuously refined in the 2.x series. With OpenSearch 2.17, sorting is more efficient offering a **59% improvement** over OS 1.3. - -We introduced a [new approach](https://github.com/opensearch-project/OpenSearch/pull/14774) to handling large filter lists by encoding filter lists as Roaring Bitmaps. This reduces the memory and network overhead required to store and transmit these filters. The bitmap-based approach excels when filter sizes are huge, such as in common use cases like filtering a product index by a customer's owned products. Users can store and join large bitmap filters with the main index at query time. Our tests show the bitmap method maintains low latency in the high-cardinality scenarios, making it a more scalable solution than traditional terms queries or lookups. - - - -## Vector Search - -**Disk Optimized vector Search:** OpenSearch vector engine continues to prioritize cost savings with its latest release, version 2.17. This release introduces disk-optimized vector search that enables customers to leverage the full potential of vector workloads, even in low-memory environments. Disk-optimized vector search is designed to provide out-of-the-box 32x compression with Binary quantization, a powerful compression technique. However, users have the flexibility to fine-tune cost, response time, and accuracy to their unique needs through configurable parameters such as compression rate, sampling, and rescoring strategies. According to internal benchmarks, OpenSearch's disk-optimized vector search can deliver cost savings of up to 70%, while maintaining impressive performance with p90 latencies around 200ms and recall over 0.9. Check [documentaion](https://opensearch.org/docs/latest/search-plugins/knn/disk-based-vector-search/) for getting started. - -Vector search capabilities in native engines(faiss, nmslib) have received a significant boost with this latest release. We have integrated the Lucene Vector field with native engines, enabling the use of KNNVectorFormat during segment creation. Further native memory footprint during indexing has been drastically reduced by introducing [incremental graph build](https://github.com/opensearch-project/k-NN/issues/1938) capability instead of loading all the dataset at once into a memory. This helps with HNSW graph builds in low memory environments. OpenSearch's 2.17 release extends OpenSearch's Byte compression technique to Faiss Engine [HSNW](https://github.com/opensearch-project/k-NN/pull/1823) and [IVF](https://github.com/opensearch-project/k-NN/pull/2002) algorithms to further reduce memory footprint up to 75% for vectors that fit into Byte range [-128., 127] . Other improvements include handling [non-existent fields](https://github.com/opensearch-project/k-NN/pull/1874) in filters, [graph merge](https://github.com/opensearch-project/k-NN/pull/1844) stats size calculation, improved [caching](https://github.com/opensearch-project/k-NN/pull/2015) and more. - -## Roadmap for 2025 - -### Core search engine - -In 2025, we're pushing the boundaries of OpenSearch's Query Engine with several key initiatives aimed at improving performance, scalability, and efficiency: - -* **Streaming Architecture**: We're moving from a request/reply model to streaming, processing and delivering data in real-time, reducing memory overhead and improving query speed. -* **Native Join Support**: We're introducing efficient JOIN operations across indexes to be supported natively, fully integrated with OpenSearch's query DSL, PPL, and SQL. -* **Native Vectorized Processing**: By leveraging modern CPU SIMD operations and native code, we're optimizing the processing of data streams to eliminate Java's garbage collection bottlenecks. -* **[Smarter Query Planning](https://github.com/opensearch-project/OpenSearch/issues/12390)**: Optimizing where and how computations run ensures we reduce unnecessary data transfer and improve performance for parallel query execution. -* **[gRPC-based Search API](https://github.com/opensearch-project/OpenSearch/issues/15190)**: We're enhancing client-server communication with Protobuf and gRPC, speeding up search by cutting down transport overhead. -* **[Query Performance Optimization](https://github.com/orgs/opensearch-project/projects/153)**: Improving performance remain our priority and several key initiatives such as docId encoding and query approximation will enhance performance on large range queries and reduce index size. -* **[Star Tree Indexing](https://github.com/opensearch-project/OpenSearch/issues/12498)**: Precomputing aggregations with star tree indexing ensures faster, more predictable performance for aggregation-heavy queries. - - - - -### Hybrid Search - -Hybrid search combines lexical and semantic vector search to get the best of both worlds. Highly specific names — like part numbers — are best found using lexical search, while broader queries are often best handled by semantic vector search. We have supported Hybrid Search since OpenSearch 2.10. We plan a variety of enhancements to it. - -By executing the lexical and the vector searches in parallel, we predict up to 25% latency improvement. - -We will support re-sorting of the results of hybrid queries. - -We will support additional algorithms for combining the query results. In particular, reciprocal rank fusion (RRF) has shown good results in some applications. - -Finally, we will return the raw scores of the sub-queries, which is useful for debugging and for relevance tuning. - -### Vector Search - -Semantic vector search is a powerful technique for finding semantic similiarities, but it can be costly, because indexing vectors to make them efficient to search is time-consuming, and the vectors themselves can consume large amounts of memory. - -We are currently working on: - -* speeding up vector indexing by 80% and reduce the memory required for indexing; -* reducing the amount of space needed to store vectors by compressing vector components from 32 bits to 16, 8, and even 1 bit. Our experiments show modest reductions in search quality (recall) with 16 and 8 bit components; we are still analyzing the 1-bit case (binary quantization). -* reducing cost with disk based approximate nearest neighbor algorithms (aNN) using external storage (SSDs, S3 etc). - -Vector techniques have also been less flexible than lexical techniques in many ways, so we are: - -* improving search relevancy by supporting re-ranking on compressed vectors; -* supporting aNN vector search for the multi-tenant case, where each tenant has their own sub-collection. This is especially valuable for customers each of whose user organizations has a large vector collection. - -### Performance benchmarking - -We will update [the Big5 workload](https://github.com/opensearch-project/opensearch-benchmark-workloads/tree/main/big5) mappings and settings — in particular, adding support for dynamic templates, configurable merge policies, match-only text, and query default query field set as “message”. - -## Conclusion - -While OpenSearch continues to expand its functionality, we are also investing in improving the performance, efficiency, and robustness of the system for every workload. In particular, vector techniques are being widely adopted both for pure semantic search and for hybrid semantic and lexical search. - -The OpenSearch team at AWS works in collaboration with the larger OpenSearch community. Without its contributions to testing, feedback, and development, OpenSearch would not be where it is today. - -Stay tuned to our blog and GitHub for continuous updates and insights into our progress and future plans. - - - -## Appendix - Benchmarking tests and results - - - -This section presents details on the performance benchmarks we use and the results we've measured. The data was collected using OpenSearch Benchmark to run the big5 workload against different distributions and configurations of OpenSearch. In particular: - -* OpenSearch Benchmark was used for testing both ES and OS, since this is our standard tool and Rally numbers might be different. -* Each test ran against a single-node cluster, to ensure better reproducibility and easier setup. -* The instance type was *c5.2xlarge*: 8 vCPU, 16 GB, a middle-of-the-road instance type. Improvements in resource usage efficiency can be masked by oversized instances. -* Big5 Index was comprised of a single shard, no replicas (i.e. run with `--workload-params="number_of_replicas:0"`). -* Ingestion during the test was run with single bulk indexing client to ensure data is ingested in chronological order. -* Tests were run in [benchmarking mode](https://opensearch.org/docs/latest/benchmark/user-guide/target-throughput/#benchmarking-mode) (i.e. target-throughput was disabled) so that the OpenSearch client sends requests to the OpenSearch cluster as fast as possible -* Indexing LSM was configured with LogByteSizeMergePolicy, since this optimization was in place last year, prior to the blog post being published. -* Corpus size of the workload: 60 GB, 70M docs. Store size after ingestion is 15 GB for the primary shard. Eliminating overhead like doc values, etc., RSS should be about 8 GB which should match the JVM heap size for the instance. Having most data resident in memory should provide a good assessment of performance improvements. -* The mapping file for Elasticsearch will be the one that Elastic used for their blog post runs. The workload will need to be modified manually to set this up. - - - -|A |Query Types |OS 1.0 |OS 2.7 |OS 2.11 |OS 2.12 |OS 2.13 |OS 2.14 | -|--- |--- |--- |--- |--- |--- |--- |--- | -|Big 5 Areas - -Mean Latency, ms |Text Query |44.34 |37.02 |36.12 |19.42 |19.41 |20.01 | -|--- |--- |--- |--- |--- |--- |--- |--- | -|Sorting |65.04 |18.58 |10.21 |6.22 |5.55 |5.53 | -|Terms Aggregation |311.78 |315.27 |316.32 |282.41 |36.27 |27.18 | -|Range Queries |4.06 |4.52 |4.32 |3.81 |3.44 |3.41 | -|Date Histogram |4812.36 |5093.01 |5057.62 |310.32 |332.41 |141.5 | -|Geo Mean | |111.93 |87.03 |76.08 |33.2 |21.38 |17.07 | -|Relative latency -(Geo Mean) | |100 |78 |68 |30 |19 |15 | -|Relative latency -(Geo Mean) | |100% |78% |68% |30% |19% |15% | -|Speedup -(Geo Mean) | |1 |1.3 |1.5 |3.3 |5.3 |6.7 | - -### 2. Query categories - -|**Buckets** |Query |Order |OS 1.0 P90 Service Time (ms) |ES 7.10 P90 Service Time RSD (%) |ES 8.8.1 P90 Service Time (ms) |ES P90 Service Time RSD (%) |OS 2.7 P90 Service Time (ms) |**OS 2.7 P90 Service Time RSD (%)** |OS 2.11.0 P90 Service Time (ms) |OS 2.11.0 P90 Service Time RSD (%) |OS 2.12.0 P90 Service Time (ms) |OS 2.13.0 P90 Service Time (ms) |OS 2.14 P90 Service Time (ms) | -|--- |--- |--- |--- |--- |--- |--- |--- |--- |--- |--- |--- |--- |--- | -|Text Querying |default |1 |2.79 |0.92 |1.4 |5.52 |2.65 |11.4 |2.41 |2.59 |2.5 |2.34 |2.27 | -|scroll |22 |448.9 |1.69 |208.29 |3.22 |228.42 |2.43 |227.36 |2.97 |222.1 |210.41 |217.82 | -|query-string-on-message |23 |180.55 |0.25 |3.33 |6.86 |173.6 |0.16 |168.29 |0.47 |8.72 |9.29 |8.22 | -|query-string-on-message-filtered |24 |174.25 |0.81 |89.22 |0.31 |125.88 |0.67 |146.62 |0.48 |102.53 |110.49 |135.98 | -|query-string-on-message-filtered-sorted-num |25 |238.14 |0.38 |194.03 |0.13 |183.62 |0.51 |180.46 |0.25 |112.39 |120.41 |139.95 | -|term |10 |0.81 |2.5 |0.87 |13.81 |1.06 |8.9 |0.91 |3.35 |0.96 |0.88 |0.83 | -|Sorting |desc_sort_timestamp |2 |13.09 |1.68 |246.83 |0.22 |159.45 |1.83 |28.39 |1.36 |20.65 |18.76 |20.4483 | -|asc_sort_timestamp |3 |993.81 |3.7 |38.5 |1.1 |61.94 |5.79 |78.91 |0.87 |39.78 |36.83 |33.79 | -|desc_sort_with_after_timestamp |4 |1123.65 |0.14 |237.67 |0.48 |163.53 |1.6 |28.93 |1.43 |19.4 |18.78 |22.492 | -|asc_sort_with_after_timestamp |5 |1475.51 |0.74 |24.84 |2.09 |42.69 |7.86 |38.55 |1.67 |6.22 |5.55 |5.14 | -|desc_sort_timestamp_can_match_shortcut |6 |15.49 |0.95 |46.47 |0.48 |31.13 |1.72 |7.64 |2.05 |7.11 |6.54 |6.88 | -|desc_sort_timestamp_no_can_match_shortcut |7 |15.29 |3.27 |46.61 |0.21 |30.95 |2.31 |7.63 |2.32 |7.17 |6.53 |6.74441 | -|asc_sort_timestamp_can_match_shortcut |8 |198.59 |0.59 |11.22 |1.6 |32.46 |2.13 |18.93 |2.59 |12.64 |9.45 |8.91 | -|asc_sort_timestamp_no_can_match_shortcut |9 |197.36 |1.15 |11.26 |1.5 |32.5 |2.08 |18.78 |2.67 |12.74 |9.02 |8.82 | -|sort_keyword_can_match_shortcut |26 |181.18 |0.34 |2.12 |4.71 |2.59 |11.11 |2.37 |0.51 |2.46 |2.18 |2.13 | -|sort_keyword_no_can_match_shortcut |27 |181.06 |0.22 |2.12 |4.48 |2.43 |2.04 |2.44 |3.02 |2.49 |2.15 |2.09 | -|sort_numeric_desc |28 |36.19 |15.15 |20.78 |1.23 |35.15 |1.48 |23.6 |1.65 |6.04 |5.83 |5.78 | -|sort_numeric_asc |29 |66.87 |3.12 |22.02 |1.07 |37.74 |1.69 |21.14 |1.21 |5.3 |5.15 |5.2 | -|sort_numeric_desc_with_match |30 |1.23 |4.45 |0.84 |11.51 |1.01 |3.13 |0.99 |9.26 |0.92 |0.85 |0.8 | -|sort_numeric_asc_with_match |31 |1.24 |1.11 |0.83 |3.93 |0.99 |0.44 |0.9 |1.65 |0.89 |0.84 |0.8 | -|Terms Aggregation |multi_terms-keyword |11 |0.92 |1.09 |0.94 |10.32 |1.1 |5.51 |1 |10.09 |1.05 |0.91 |0.89 | -|keyword-terms |12 |2126.25 |0.28 |1497.29 |0.72 |2117.22 |0.96 |2382.37 |0.68 |1906.71 |12.74 |6.96 | -|keyword-terms-low-cardinality |13 |2135.16 |0.59 |1505.32 |0.3 |2121.88 |0.42 |2338.1 |1.78 |1893.9 |10.81 |5.25 | -|composite-terms |14 |696.37 |0.61 |634.91 |0.21 |668.09 |0.28 |631.23 |0.69 |572.77 |581.24 |551.62 | -|composite_terms-keyword |15 |1012.96 |1.18 |866.91 |0.4 |943.35 |0.48 |900.66 |0.13 |827.16 |861.81 |826.18 | -|Range Queries |range |17 |203.29 |1.61 |130.57 |0.88 |170.68 |0.78 |189.77 |0.21 |115.38 |115.2 |125.99 | -|range-numeric |18 |0.81 |11.34 |0.8 |5.2 |0.96 |3.46 |0.87 |1.14 |0.9 |0.76 |0.75 | -|keyword-in-range |19 |210.69 |0.57 |138.94 |0.2 |179.18 |1.38 |200.37 |0.05 |123.59 |124.66 |134.06 | -|range_field_conjunction_big_range_big_term_query |32 |0.92 |1.73 |0.92 |1.81 |1.13 |5.35 |0.99 |3.35 |1.01 |0.91 |0.82 | -|range_field_disjunction_big_range_small_term_query |33 |0.82 |2.38 |0.91 |2.45 |1.08 |4.66 |1.04 |10.32 |1 |0.86 |0.81 | -|range_field_conjunction_small_range_small_term_query |34 |0.83 |2.13 |0.95 |8.52 |1.09 |10.28 |0.93 |1.53 |0.98 |0.85 |0.81 | -|range_field_conjunction_small_range_big_term_query |35 |0.83 |12.05 |0.8 |2.34 |0.98 |1.09 |0.88 |2.22 |0.91 |0.78 |0.78 | -|Date Histogram |date_histogram_hourly_agg |20 |3618.5 |0.24 |10.42 |2.91 |3664.45 |0.08 |3785.48 |0.13 |8.5 |9.97 |3.39 | -|date_histogram_minute_agg |21 |2854.99 |0.34 |3031.03 |0.34 |2933.76 |0.46 |2961.69 |0.12 |2518.69 |2635.16 |148.69 | -|composite-date_histogram-daily |16 |3760.5 |0.1 |4484.72 |1.6 |4016.42 |1.12 |3574.18 |0.1 |1.44 |1.51 |1.39 | -|range-auto-date-histo |36 |5267.47 |0.25 |4840.65 |0.21 |5960.21 |0.18 |6055.74 |0.39 |6784.27 |6977.05 |6129.29 | -|range-auto-date-histo-with-metrics |37 |12612.77 |0.16 |12036.19 |0.33 |13314.87 |0.11 |13637.23 |0.09 |13759.51 |14662.24 |13208.98 | -| | | |40050.08 | |30391.52 | |37446.24 | |37667.78 | |29110.78 |26579.74 |21,781.75 | diff --git a/_posts/2024-11-26-opensearch-performance-2.17.md b/_posts/2024-11-26-opensearch-performance-2.17.md new file mode 100644 index 000000000..2c8b3b031 --- /dev/null +++ b/_posts/2024-11-26-opensearch-performance-2.17.md @@ -0,0 +1,272 @@ +--- +layout: post +title: "OpenSearch Project update: A look at performance progress through version 2.17" +layout: post +authors: + - sisurab + - pallp + - vamshin + - macrakis + - ihoang +date: 2024-11-26 +categories: + - technical-posts + - community +meta_keywords: OpenSearch performance progress 2.17, OpenSearch roadmap +meta_description: Learn more about the strategic enhancements and performance features that OpenSearch has delivered up to version 2.17. +has_science_table: true +excerpt: Learn more about the strategic enhancements and performance features that OpenSearch has delivered up to version 2.17. +featured_blog_post: false +featured_image: false +--- + +Since its inception, OpenSearch has been dedicated to supporting a diverse range of applications, including document search, log analytics, observability, and security analytics. These critical workloads require a foundation that is not only scalable and reliable but also high-performing and cost-efficient. OpenSearch remains focused on meeting these demands while continuously evolving to address emerging challenges. With the release of version 2.17, OpenSearch achieved another milestone in its journey of optimization and innovation. This release delivers a 6x performance improvement over OpenSearch version 1.3, with gains across essential operations such as text queries, term aggregations, range queries, date histograms, and sorting. + +As OpenSearch integrates advanced capabilities like vector and hybrid search, disk-optimized storage, and improved query processing, it continues to address the growing needs for efficiency, scalability, and performance. These improvements reflect the contributions and collaboration of a dedicated community, whose insights and efforts drive OpenSearch forward. + +In this post, we'll highlight the performance improvements in OpenSearch 2.17 compared to prior releases. We'll focus on key query types, including text queries, term aggregations, range queries, date histograms, and sorting. These improvements were evaluated using the [OpenSearch Big5 workload](https://github.com/opensearch-project/opensearch-benchmark-workloads/tree/main/big5), which represents common use cases in both search and analytics applications. The benchmarks provide a repeatable framework for measuring real-world performance enhancements. For a detailed benchmark analysis or to run your own benchmarks, see the [Appendix](#appendix---benchmarking-tests-and-results). + + + +## Performance improvements through 2.17 + +Since its inception, OpenSearch has consistently improved performance, and version 2.17 continues this trend. to earlier versions, OpenSearch 2.17 delivers an improved performance, achieving a **6x speedup** over OpenSearch 1.3 and reducing query latencies across various categories. The following graph shows the relative improvements by query category as the 90th percentiile latencies, with a baseline of OpenSearch 1.3. + +OpenSearch performance improvements up to 2.17{:style="width: 100%; max-width: 800px; height: auto; text-align: center"} + +### Key highlights + +Based on our benchmarking, we've identified the following key highlights through version 2.17: + +- **Overall query performance**: OpenSearch 2.17 delivers **6x better performance** than OpenSearch 1.3. +- **Text queries**: Text search queries, fundamental to many OpenSearch use cases, are **63% faster** in 2.17 compared to the baseline of OpenSearch 1.3. +- **Terms aggregations**: This critical query type for log analytics shows a **81% improvement** compared to OpenSearch 1.3, allowing for faster and more efficient data aggregation. +- **Date histograms**: OpenSearch 2.17 performance for date histograms has **improved by 97%** compared to OpenSearch 1.3, providing major speed improvements for time-series analysis. +- **Range queries**: With **87% performance improvement** compared to OpenSearch 1.3, range queries now execute quicker using fewer resources. +- **Sorting and filtering**: OpenSearch 2.17 delivers faster sorting with **59% improvement** compared to OpenSearch 1.3, enhancing query performance for numeric and textual datasets. + +The following table summarizes performance improvements for the preceding query types. + +| | +**Query Types** |1.3.18 |2.7 |2.11 |2.12 |2.13 |2.14 |2.15 |2.16 |2.17 | +|--- |--- |--- |--- |--- |--- |--- |--- |--- |--- |--- | +| +**Big 5 areas mean latency, ms +** | +Text Query |59.51 |47.91 |41.05 |27.29 |27.61 |27.85 |27.39 |21.7 |21.77 | +| +Sorting |17.73 |11.24 |8.14 |7.99 |7.53 |7.47 |7.78 |7.22 |7.26 | +| +Terms Aggregation |1730.71 |1351 |1316 |1228 |291 |293 |113 |112 |113 | +| +Range Queries |26.08 |23.12 |16.91 |18.71 |17.33 |17.39 |18.51 |3.17 |3.17 | +| +Date Histogram |6068 |5249 |5168 |469 |357 |146 |157 |164 |160 | +|Aggregate (geo mean) |195.96 |154.59 |130.9 |74.85 |51.84 |43.44 |37.07 |24.66 |24.63 | +|Speedup factor, compared to OS 1.3 (geo mean) |1.0 |1.27 |1.50 |2.62 |3.78 |4.51 |5.29 |7.95 |7.96 | +|Relative latency, compared to OS 1.3 (geo mean) |100% |78.89 |66.80 |38.20 |26.45 |22.17 |18.92 |12.58 |15.93 | + +## Queries + +OpenSearch has made the following query improvements. + +### Text queries + +Text queries are fundamental to effective text search, especially in applications requiring fast and accurate document retrieval. OpenSearch 2.12 introduced the **match_only_text** field to address specific needs in analytics and applications prioritizing 100% recall or customized ranking strategies. This field type dramatically reduced index sizes and accelerated query execution by removing the complexity of relevance-based scoring. As a result, **text queries performed 47% faster compared to OpenSearch 2.11 and 57% faster than OpenSearch 1.3**. + +With OpenSearch 2.17, we further amplified these performance gains. Building on the foundations of the **match_only_text** field, OpenSearch 2.17 optimizes text queries, achieving **21% faster performance compared to 2.14** and an overall **63% faster performance compared to 1.3**. These improvements stem from continued enhancements to query execution and index optimization. Applications relying on text search for analytics or high-recall use cases can now achieve faster results with reduced resource usage, making OpenSearch 2.17 an even more powerful choice for modern text search workloads. + +### Term and multi-term aggregations + +Term aggregations are crucial for slicing large datasets based on multiple criteria, making them important query operations for data analytics use cases. Building on prior advancements, **OpenSearch 2.17** enhances the efficiency of global term aggregations, using term frequency optimizations to handle large immutable collections, such as log data, with unprecedented speed. + +Performance benchmarks demonstrate a **61% performance improvement when compared with OpenSearch 2.14** and an overall **81% reduction in query latency compared to OpenSearch 1.3**, while **multi-term aggregation queries exhibit up to a 20% reduction in latency**. Additionally, memory efficiency is improved dramatically, with a **50–-60% reduction in memory footprint for short-lived objects**, because new byte array allocations for storing composite keys are not needed. + +OpenSearch 2.17 also introduces support for the **[wildcard field type](https://github.com/opensearch-project/OpenSearch/pull/13461)**, enabling highly efficient execution of wildcard, prefix, and regular expression queries. This new field type uses trigrams (or bigrams and individual characters) to match patterns before applying a post-filtering step to evaluate the original field, resulting in faster and more efficient query execution. + +These advancements make OpenSearch 2.17 a powerful tool for analytics use cases, from large-scale log processing to complex query scenarios, continuing the mission of delivering speed, efficiency, and scalability to your data workflows. + +### Date Histograms + +Date histograms are fundamental for time-based data analysis, underpinning OpenSearch Dashboards visualizations such as time-series charts. In **OpenSearch 2.17**, date histogram queries now execute **55% faster when compared to OpenSearch 2.13** and **97% faster compared to OpenSearch 1.3**, significantly improving the performance of time-series aggregations. This enhancement is particularly impactful for queries without subaggregations and has also been extended to **range aggregations**, further optimizing time-based analyses. + +Additionally, **cardinality aggregation**---a critical tool for counting distinct values, such as unique visitors, event types, or products---has received a major performance boost. OpenSearch 2.17 introduces an [optimization](https://github.com/opensearch-project/OpenSearch/pull/13821) that dynamically prunes documents containing distinct values already collected, significantly reducing redundant processing. For **low-cardinality requests**, this leads to notable performance gains, while **high-cardinality requests** see improvements of up to **20%**, streamlining the handling of even the most demanding datasets. + +These enhancements make OpenSearch 2.17 an essential upgrade for managing time-based or high-volume datasets, ensuring faster and more efficient query execution for diverse analytics needs. + +### Range queries and numeric fields + +**Range queries**, commonly used to filter data within specific numerical or date ranges, have undergone significant performance improvements in OpenSearch 2.17. These queries are now **81% faster than OpenSearch 2.14** and **87% faster compared to OpenSearch 1.3**, because of the advancements and optimizations in processing range filters. + +At search time, OpenSearch evaluates whether a query can be rewritten from its *original query* to an *approximate query*, which executes faster and uses fewer resources. This [approximate range optimization](https://github.com/opensearch-project/OpenSearch/pull/13788) ensures that most queries deliver equivalent results with reduced computational overhead, maintaining accuracy while improving performance. These enhancements make OpenSearch 2.17 an excellent choice for applications requiring high-performance range filtering, such as analytics dashboards, monitoring systems, and time-series data exploration. + +### Sorting and filtering + +**Sorting performance** has been a focus throughout the OpenSearch 2.x series, with **OpenSearch 2.17** showing minor improvements when compared to OpenSearch 2.14, while being **59% faster compared to OpenSearch 1.3**. These refinements enable faster query results, particularly for datasets requiring extensive sorting by numeric or textual fields. + +Filtering has also seen a significant advancement with the introduction of **[Roaring Bitmap encoding](https://github.com/opensearch-project/OpenSearch/pull/14774)** for handling large filter lists. This approach minimizes memory and network overhead by compressing filter data into efficient bitmap structures. It is particularly effective for high-cardinality scenarios, such as filtering a product catalog by items owned by a specific customer. The bitmap-based filters can be stored and seamlessly joined with the main index at query time. Tests demonstrate that this method maintains **low latency** even with extensive filters, making it a scalable and high-performing alternative to traditional terms queries or lookup strategies. These improvements ensure that OpenSearch 2.17 delivers faster and more efficient sorting and filtering for diverse use cases, from search to large-scale analytics. + + +## Vector search + +**Disk-optimized vector search:** OpenSearch vector engine continues to prioritize cost savings with its 2.17 release. This release introduces disk-optimized vector search that allows you to use the full potential of vector workloads, even in low-memory environments. Disk-optimized vector search is designed to provide out-of-the-box **32x compression** when using binary quantization, a powerful compression technique. Additionally, you have the flexibility to fine-tune cost, response time, and accuracy to your unique needs through configurable parameters such as compression rate, sampling, and rescoring strategies. According to internal benchmarks, OpenSearch's disk-optimized vector search can deliver cost savings of up to 70%, while maintaining p90 latencies around 200 ms and recall over 0.9. For more information, see [Disk-based vector search](https://opensearch.org/docs/latest/search-plugins/knn/disk-based-vector-search/). + +**Cost improvements by reducing memory footprint:** Vector search capabilities in native engines (Faiss and NMSLIB) have received a significant boost with this latest release. The 2.17 release extends OpenSearch's byte compression technique to the Faiss Engine [HSNW](https://github.com/opensearch-project/k-NN/pull/1823) and [IVF](https://github.com/opensearch-project/k-NN/pull/2002) algorithms to further reduce memory footprint up to 75% for vectors that fit into byte range ([-128, 127]). These provide 25% additional memory footprint savings compared to OpenSearch's 2.14 version with [FP16 quantization](https://opensearch.org/blog/optimizing-opensearch-with-fp16-quantization/) and overall up to 85% savings compared to OpenSearch 1.3. + +**Vector index build improvements:** In 2024, the Vector Engine team made significant [investments](https://github.com/opensearch-project/k-NN/issues/1599) to improve the performance of the OpenSearch vector engine. This includes adding [AVX512 SIMD support](https://github.com/opensearch-project/k-NN/issues/2056), fixing [some bugs](https://github.com/opensearch-project/k-NN/issues/2277) related to segment replication with vector indexes, [transitioning to the more efficient KNNVectorsFormat](https://github.com/opensearch-project/k-NN/issues/1853), and [employing incremental graph builds during merges to reduce memory footprint](https://github.com/opensearch-project/k-NN/issues/1938). With incremental graph builds, the native memory footprint during indexing has been significantly reduced, because the full dataset is loaded into memory at once. This improvement supports HNSW graph builds in low-memory environments and reduces overall build time by approximately 30% compared to OpenSearch 1.3. + +**Exact search improvements:** In OpenSearch 2.15, [SIMD optimizations](https://opensearch.org/blog/boosting-k-nn-exact-search/) were added to the k-NN plugin's script scoring, resulting in significant performance gains for CPUs with SIMD support, such as AVX2 or AVX512 on x86 or NEON on ARM. Further improvements in OpenSearch 2.17 introduced Lucene's new vector format, which includes optimized memory-mapped file access. Together, these enhancements significantly reduce search latency for exact k-NN searches on supported hardware. + +# Roadmap for 2025 + +The following improvements are included in the OpenSearch roadmap for 2025. + +## Core search engine + +In 2025, we will push the boundaries of OpenSearch's query engine with several key initiatives aimed at improving performance, scalability, and efficiency: + +* **[Streaming architecture](https://github.com/opensearch-project/OpenSearch/issues/16679)**: We're moving from a request/response model to streaming, processing and delivering data in real time, reducing memory overhead and improving query speed. +* **[Native join support](https://github.com/opensearch-project/OpenSearch/issues/15185)**: We're introducing efficient JOIN operations across indexes to be supported natively, fully integrated with OpenSearch's query DSL, Piped Processing Language (PPL), and SQL. +* **Native vectorized processing**: By using modern CPU SIMD operations and native code, we're optimizing the processing of data streams to eliminate Java's garbage collection bottlenecks. +* **[Smarter query planning](https://github.com/opensearch-project/OpenSearch/issues/12390)**: Optimizing where and how computations run ensures we reduce unnecessary data transfer and improve performance for parallel query execution. +* **[gRPC-based Search API](https://github.com/opensearch-project/OpenSearch/issues/15190)**: We're enhancing client-server communication with Protobuf and gRPC, accelerating search by reducing overhead. +* **[Query performance optimization](https://github.com/orgs/opensearch-project/projects/153)**: Improving performance remains our priority, and several key initiatives such as docId encoding and query approximation will reduce index size and enhance performance of large-range queries. +* **[Star-Tree indexing](https://github.com/opensearch-project/OpenSearch/issues/12498)**: Precomputing aggregations using Star-Tree indexing ensures faster, more predictable performance for aggregation-heavy queries. + +### Vector search + +In 2025, we will continue to invest in the following key initiatives aimed at performance improvements and cost savings: + +* **Index build acceleration with GPUs and SIMD:** k-NN performance can be enhanced by using libraries with GPU support. Because vector distance calculations are compute-heavy, GPUs can speed up computations and enhance the performance of index build time and search queries. +* **Autotuning k-NN indexes:** OpenSearch's vector database offers a toolkit of algorithms tailored for diverse workloads. In 2025, our primary goal is to enhance the out-of-the-box experience by autotuning hyperparameters and settings based on access patterns and hardware resources. +* **Cold-warm tiering:** In version 2.18, we added support for enabling vector search on remote snapshots. We will continue focusing on decoupling index read/write operations to extend vector indexes to different storage systems in order to cut down storage and compute costs. +* **Memory footprint reduction:** We will continue to be aggressive in reducing memory footprint of vector indexes. One of the goals is the ability to partially load the HNSW indexes in native engines. This complements our disk-based-optimized search and helps further cut down the operating cost of the OpenSearch clusters. +* **Reduced disk storage with "derived source":** Currently, vector data is stored both in a doc-values-like format and in the `_source` stored field. The `_source` stored field can contribute more than 60% of the overall storage requirement for vectors. We plan to create a custom stored fields format that will inject the vector fields into the source from the doc-values-like format. In addition to saving storage, this will have secondary effects of improved indexing throughput, lighter shards, and even faster search. + +### Neural search + +Neural search uses machine learning models to understand the semantic meaning behind search queries, going beyond traditional keyword matching. **It encompasses dense vector search, sparse vector search, and hybrid approaches that combine semantic understanding with lexical search**. Since introducing neural search capabilities in OpenSearch 2.9, we've expanded the functionality to include text embedding, cross-encoder reranking, sparse encoding, and hybrid search. + +Our 2025 roadmap emphasizes optimizing performance, enhancing functionality, and simplifying adoption. Key initiatives include: + +- **Improving hybrid query performance**: Reduce latency by up to 25%. +- **Introducing explainability for hybrid queries**: Provide insights into how each subquery result contributes to the final hybrid query result, enabling better debugging and performance analysis. +- **Supporting additional algorithms for combining hybrid query results**: Support algorithms like reciprocal rank fusion (RRF), which improves hybrid search latency by avoiding costly score normalization because the scores are rank-based. +- **Enhancing neural sparse pruning strategies**: Apply techniques such as pruning by weight, by ratio with max weight, by top-k, and by alpha-mass to improve performance by 20%. +- **Optimizing inference calls during updates and re-indexing**: Reduce the number of inference calls for neural and sparse ingestion pipelines, increasing throughput by 20% for these operations. +- **Consolidating multi-field inference calls**: Combine multiple field inference calls into a single operation for dense and sparse vector semantic search, reducing inference latency by 15% for multi-field dense-vector-based semantic queries. +- **Reducing memory usage for resource-constrained systems**: Introduce a new quantization processor to decrease memory usage by 20%, improving efficiency in environments with limited resources or connectivity. + +These advancements aim to enhance query performance, streamline operations, and expand usability across diverse workloads. + +# Conclusion + +OpenSearch continues to evolve, not only by expanding its functionality but also by significantly enhancing performance, efficiency, and scalability across diverse workloads. OpenSearch 2.17 exemplifies the community's commitment, delivering improvements in query speed, resource utilization, and memory efficiency across text queries, aggregations, range queries, and time-series analytics. These advancements underscore our dedication to optimizing OpenSearch for real-world use cases. + +Key innovations like disk-optimized vector search and enhancements to term and multi-term aggregations demonstrate our focus on staying at the forefront of vector search and analytics technology. Additionally, OpenSearch 2.17's improvements to hybrid and vector search, combined with roadmap plans for streaming architecture, gRPC APIs, and smarter query planning, highlight our forward-looking strategy to meet the demands of modern workloads. + +These achievements are made possible through collaboration with the broader OpenSearch community, whose contributions in testing, feedback, and development have been invaluable. Together, we are building a robust and efficient search and analytics engine capable of addressing current and future challenges. + +Stay connected to our [_blog_](https://opensearch.org/blog) and [_GitHub_](https://github.com/opensearch-project/OpenSearch) for ongoing updates and insights as we continue this journey of innovation and share future plans. + +## Appendix: Benchmarking tests and results + +This section outlines the performance benchmarks and results achieved using OpenSearch Benchmark to evaluate the Big5 workload across various OpenSearch versions and configurations. + +### Benchmark Setup + +- **Benchmarking tool**: OpenSearch Benchmark, our standard benchmarking tool used in prior evaluations. +- **Instance type**: *c5.2xlarge* (8 vCPU, 16 GB RAM), chosen as a mid-tier option to avoid masking resource efficiency gains with oversized instances. +- **Cluster configuration**: Single-node cluster for reproducibility and ease of setup. +- **Index setup**: Big5 Index configured with one shard and no replicas (`--workload-params="number_of_replicas:0"`). +- **Corpus details**: 100 GB dataset with 116 million documents. The storage size after ingestion was 24 GB for the primary shard. After removing overheads like doc values, the RSS is expected to be around 8 GB, matching the JVM heap size for the instance. Keeping most of the data in memory ensures a more accurate evaluation of performance improvements. +- **Ingestion**: Conducted with a single bulk indexing client to ensure that data is ingested in chronological order. +- **Merge policy**: + - LogByteSizeMergePolicy for OpenSearch 2.11.0 and later. + - TieredMergePolicy for OpenSearch 1.3.18 and 2.7.0. +- **Test mode**: Tests were run in [benchmarking mode](https://opensearch.org/docs/latest/benchmark/user-guide/target-throughput/#benchmarking-mode) (`target-throughput` disabled) so that the OpenSearch client sent requests to the OpenSearch cluster as fast as possible. + +### Key notes and considerations + +- **Additional queries**: The Big5 workload was recently updated to include additional queries. These queries have been incorporated in the results of this blog. +- **`multi_terms-keyword` support**: OpenSearch 1.3.18 and 2.7.0 recorded `0` ms service time for `multi_terms-keyword`. This is because `multi_terms-keyword` was not supported until OS 2.11.0. Thus, entries in **Mean latency** account for this by excluding `multi_terms-keyword` from the geometric mean computation for OS 1.3.18 and OS 2.7. + +The following table provides benchmarking test results. + +|**Buckets** |Query |Order |OS 1.3.18 p90 service time (ms) |OS 2.7 p90 service time (ms) |OS 2.11.1 p90 service time (ms) |OS 2.12.0 p90 service time (ms) |OS 2.13.0 p90 service time (ms) |OS 2.14 p90 service time (ms) |OS 2.15 p90 service time (ms) |OS 2.16 p90 service time (ms) |OS 2.17 p90 service time (ms) | +|--- |--- |--- |--- |--- |--- |--- |--- |--- |--- |--- |--- | +|Text Query |query-string-on-message |1 |332.75 |280 |276 |78.25 |80 |77.75 |77.25 |77.75 |78 | +|query-string-on-message-filtered |2 |67.25 |47 |30.25 |46.5 |47.5 |46 |46.75 |29.5 |30 | +|query-string-on-message-filtered-sorted-num |3 |125.25 |102 |85.5 |41 |41.25 |41 |40.75 |24 |24.5 | +|term |4 |4 |3.75 |4 |4 |4 |4 |4 |4 |4 | +|Sorting |asc_sort_timestamp |5 |9.75 |15.75 |7.5 |7 |7 |7 |7 |7 |7 | +|asc_sort_timestamp_can_match_shortcut |6 |13.75 |7 |7 |6.75 |6 |6.25 |6.5 |6 |6.25 | +|asc_sort_timestamp_no_can_match_shortcut |7 |13.5 |7 |7 |6.5 |6 |6 |6.5 |6 |6.25 | +|asc_sort_with_after_timestamp |8 |35 |33.75 |238 |212 |197.5 |213.5 |204.25 |160.5 |185.25 | +|desc_sort_timestamp |9 |12.25 |39.25 |6 |7 |5.75 |5.75 |5.75 |6 |6 | +|desc_sort_timestamp_can_match_shortcut |10 |7 |120.5 |5 |5.5 |5 |4.75 |5 |5 |5 | +|desc_sort_timestamp_no_can_match_shortcut |11 |6.75 |117 |5 |5 |4.75 |4.5 |4.75 |5 |5 | +|desc_sort_with_after_timestamp |12 |487 |33.75 |325.75 |358 |361.5 |385.25 |378.25 |320.25 |329.5 | +|sort_keyword_can_match_shortcut |13 |291 |3 |3 |3.25 |3.5 |3 |3 |3 |3 | +|sort_keyword_no_can_match_shortcut |14 |290.75 |3.25 |3 |3.5 |3.25 |3 |3.75 |3 |3.25 | +|sort_numeric_asc |15 |7.5 |4.5 |4.5 |4 |4 |4 |4 |4 |4 | +|sort_numeric_asc_with_match |16 |2 |1.75 |2 |2 |2 |2 |1.75 |2 |2 | +|sort_numeric_desc |17 |8 |6 |6 |5.5 |4.75 |5 |4.75 |4.25 |4.5 | +|sort_numeric_desc_with_match |18 |2 |2 |2 |2 |2 |2 |1.75 |2 |2 | +|Terms Aggregation |cardinality-agg-high |19 |3075.75 |2432.25 |2506.25 |2246 |2284.5 |2202.25 |2323.75 |2337.25 |2408.75 | +|cardinality-agg-low |20 |2925.5 |2295.5 |2383 |2126 |2245.25 |2159 |3 |3 |3 | +|composite_terms-keyword |21 |466.75 |378.5 |407.75 |394.5 |353.5 |366 |350 |346.5 |350.25 | +|composite-terms |22 |290 |242 |263 |252 |233 |228.75 |229 |223.75 |226 | +|keyword-terms |23 |4695.25 |3478.75 |3557.5 |3220 |29.5 |26 |25.75 |26.25 |26.25 | +|keyword-terms-low-cardinality |24 |4699.5 |3383 |3477.25 |3249.75 |25 |22 |21.75 |21.75 |21.75 | +|multi_terms-keyword |25 |0* |0* |854.75 |817.25 |796.5 |748 |768.5 |746.75 |770 | +|Range Queries |keyword-in-range |26 |101.5 |100 |18 |22 |23.25 |26 |27.25 |18 |17.75 | +|range |27 |85 |77 |14.5 |18.25 |20.25 |22.75 |24.25 |13.75 |14.25 | +|range_field_conjunction_big_range_big_term_query |28 |2 |2 |2 |2 |2 |2 |2 |2 |2 | +|range_field_conjunction_small_range_big_term_query |29 |2 |1.75 |2 |2 |2 |2 |1.5 |2 |2 | +|range_field_conjunction_small_range_small_term_query |30 |2 |2 |2 |2 |2 |2 |2 |2 |2 | +|range_field_disjunction_big_range_small_term_query |31 |2 |2 |2 |2 |2 |2 |2 |2 |2.25 | +|range-agg-1 |32 |4641.25 |3810.75 |3745.75 |3578.75 |3477.5 |3328.75 |3318.75 |2 |2.25 | +|range-agg-2 |33 |4568 |3717.25 |3669.75 |3492.75 |3403.5 |3243.5 |3235 |2 |2.25 | +|range-numeric |34 |2 |2 |2 |2 |2 |2 |2 |2 |2 | +|Date Histogram |composite-date_histogram-daily |35 |4828.75 |4055.5 |4051.25 |9 |3 |2.5 |3 |2.75 |2.75 | +|date_histogram_hourly_agg |36 |4790.25 |4361 |4363.25 |12.5 |12.75 |6.25 |6 |6.25 |6.5 | +|date_histogram_minute_agg |37 |1404.5 |1340.25 |1113.75 |1001.25 |923 |36 |32.75 |35.25 |39.75 | +|range-auto-date-histo |38 |10373 |8686.75 |9940.25 |8696.75 |8199.75 |8214.75 |8278.75 |8306 |8293.75 | +|range-auto-date-histo-with-metrics |39 |22988.5 |20438 |20108.25 |20392.75 |20117.25 |19656.5 |19959.25 |20364.75 |20147.5 | +| | | |71659 |59633.5 |61501.75 |50337.25 |42943.25 |41,119.75 |39,422.00 |33,135.25 |33,048.50 | + + diff --git a/assets/media/blog-images/2024-11-26-opensearch-performance-2.17/OS-PerformanceChart-ldc@2x.png b/assets/media/blog-images/2024-11-26-opensearch-performance-2.17/OS-PerformanceChart-ldc@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..dbc978bbcdc8c35fe414417c1c364b8ec226b6cd GIT binary patch literal 130437 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
  • oJ-y67V9mXymKl5OZvu4HQ={r1wq zINBNPTmeo+^{M}}a{`C(m0BeY6ZmOJPhtqCFexX$rqU;cAO{Hc<`0`CMgP{1RL63K zO`%wJ55isYA!D}Y`{w)^O|nmQ0)I8qVQ>4p&r|)zdW(J5fYSz{sk^786GoNeEK(c-EV=S|{@k0x<&s+HhHZ$?I0?FFZ7pH|b|UD#(P6JsD}yRP(Zzq1qJW_IBfV%)Imx%DT&&t*WqCCEl2Pnjahikpq*iULN{}n757z`E zZ@qot^8+;Ch6}3v5YGdaxH!sJCg z6OowgokpmGrFN4$|Gtg^(gTAq6s}TVISvO=+JA-P0fTjW@jAk5jpQoI@lsy3$ z5nSJg7smwLXEl zhZW!sk~+P`D(3JxM`JaCjoCa_i*?*j4;4o5$ncjvMn`%%KwQl-!;2lum?t&VqGqQm zuEJ6l;>=6{x*V8nX69wF+XuM$cpx_45nZKj4%E!9Hw9jG5Mu|dMeBRN1exazSPbKV zih(7_2=s9FRQqAvfu)P!E8qr;UDR+1K<_Ak4C~IDpj^Rx<(Y}h@252WbBN~`83A(a zTOe)I5@9Co04MbbBdw|qWFr>YI%dPN*#W=zXJ+Fj8FN{tK{O^L@dyT-4NQmNzwhn* z`(9Yl^XV_gN(k#32Di;P|Fw;oLV<%D00jnc!K_TKu=bSw3P41I70!D98CL4kb4$v| zbQZ=Z2?F1+QyIbnE#-`Qh4yHIrZA25qh$>;5TD827EC^q$Ncv;8gtDA+>O2iA_CUS z3~u!dRv73W`W?&|c*dJ${Q+)ZBMRJ{C(ay+9C^Ds5Hf-3m(-0Vf>aN@YM7=TPkLF+ z2v8PX``4`h&M0XcW&KPq=1Jv?LMeq-*j_S2f+v713nHMXh1nCqp2(y=bUf8X${sNV

    T=xo{DGbubum={KPH94S+p+)xWoT`0~<~Nep4%} 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�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 Kdx*PsFaHa$0e!>( literal 0 HcmV?d00001 From c2e0b1d2c93599b205d9be42589b10c5aa44c26c Mon Sep 17 00:00:00 2001 From: Fanit Kolchina Date: Tue, 26 Nov 2024 19:53:05 -0500 Subject: [PATCH 03/16] Add rewritten intro Signed-off-by: Fanit Kolchina --- _posts/2024-11-26-opensearch-performance-2.17.md | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/_posts/2024-11-26-opensearch-performance-2.17.md b/_posts/2024-11-26-opensearch-performance-2.17.md index 2c8b3b031..a9a4c7d76 100644 --- a/_posts/2024-11-26-opensearch-performance-2.17.md +++ b/_posts/2024-11-26-opensearch-performance-2.17.md @@ -20,11 +20,13 @@ featured_blog_post: false featured_image: false --- -Since its inception, OpenSearch has been dedicated to supporting a diverse range of applications, including document search, log analytics, observability, and security analytics. These critical workloads require a foundation that is not only scalable and reliable but also high-performing and cost-efficient. OpenSearch remains focused on meeting these demands while continuously evolving to address emerging challenges. With the release of version 2.17, OpenSearch achieved another milestone in its journey of optimization and innovation. This release delivers a 6x performance improvement over OpenSearch version 1.3, with gains across essential operations such as text queries, term aggregations, range queries, date histograms, and sorting. +OpenSearch has always been committed to expanding functionality, scalability, and performance. In previous performance blogs, we discussed the major improvements we've made between OpenSearch 1.0 and first [2.11](https://opensearch.org/blog/opensearch-performance-improvements/)and then [2.14](https://opensearch.org/blog/opensearch-performance-2.14/). In this blog, we'll bring you up to date on our continuing performance improvements through OpenSearch 2.17. -As OpenSearch integrates advanced capabilities like vector and hybrid search, disk-optimized storage, and improved query processing, it continues to address the growing needs for efficiency, scalability, and performance. These improvements reflect the contributions and collaboration of a dedicated community, whose insights and efforts drive OpenSearch forward. +The wide range of applications that OpenSearch supports means that no one number can summarize the improvements you will see in your applications. That's why we're reporting on a variety of performance metrics, some mostly relevant to analytics in general and log analytics in particular, some mostly relevant to lexical search, and yet others relevant to semantic search using vector embeddings and k-NN. Under the rubric of performance, we're also including improvements in resource utilization, notably RAM and disk. -In this post, we'll highlight the performance improvements in OpenSearch 2.17 compared to prior releases. We'll focus on key query types, including text queries, term aggregations, range queries, date histograms, and sorting. These improvements were evaluated using the [OpenSearch Big5 workload](https://github.com/opensearch-project/opensearch-benchmark-workloads/tree/main/big5), which represents common use cases in both search and analytics applications. The benchmarks provide a repeatable framework for measuring real-world performance enhancements. For a detailed benchmark analysis or to run your own benchmarks, see the [Appendix](#appendix---benchmarking-tests-and-results). +Overall, OpenSearch 2.17 delivers a 6x overall performance improvement over OpenSearch 1.3, with gains across essential operations such as text queries, term aggregations, range queries, date histograms, and sorting. And that's not even counting improvements to semantic vector search, which is now highly configurable to let you choose the ideal balance of response time, accuracy, and cost for your applications. All these improvements reflect the contributions and collaboration of a dedicated community, whose insights and efforts drive OpenSearch forward. + +This post highlights the performance improvements in OpenSearch 2.17. The first section focuses on key query operations, including text queries, term aggregations, range queries, date histograms, and sorting. These improvements were evaluated using the [OpenSearch Big5 workload](https://github.com/opensearch-project/opensearch-benchmark-workloads/tree/main/big5), which represents common use cases in both search and analytics applications. The benchmarks provide a repeatable framework for measuring real-world performance enhancements. The next section reports on vector search improvements. Finally, we present our roadmap for 2025, where you'll see that we're making qualitative improvements in many areas, in addition to important incremental changes. We are improving query speed by processing data in real time. We are building a query planner which uses resources more efficiently. We are speeding up intra-cluster communications. And we're adding efficient Join operations to query DSL, Piped Processing Language (PPL), and SQL. To follow our work in more detail, and to contribute comments or code, please participate on the [OpenSearch Forum](https://forum.opensearch.org/) as well as directly in our GitHub repos.