{"id":7680,"date":"2019-09-20T12:55:31","date_gmt":"2019-09-20T19:55:31","guid":{"rendered":"https:\/\/www.couchbase.com\/blog\/?p=7680"},"modified":"2025-06-13T17:21:53","modified_gmt":"2025-06-14T00:21:53","slug":"deep-dive-window-functions-in-couchbase-analytics","status":"publish","type":"post","link":"https:\/\/www.couchbase.com\/blog\/deep-dive-window-functions-in-couchbase-analytics\/","title":{"rendered":"Deep Dive: Window functions in Couchbase Analytics"},"content":{"rendered":"<p><span style=\"font-weight: 400\">Couchbase Server 6.5 brings a host of <\/span><a href=\"https:\/\/www.couchbase.com\/blog\/announcing-couchbase-server-6-5-0-beta-whats-new-and-improved\/\"><span style=\"font-weight: 400\">new features<\/span><\/a><span style=\"font-weight: 400\"> [<a href=\"#ref1\">1<\/a>] to the leading NoSQL database. <\/span><span style=\"font-weight: 400\">One of the key additions to the N1QL query language is support for window functions.\u00a0<\/span><span style=\"font-weight: 400\">These functions were originally introduced in the SQL:2003 standard and provide a performant way of answering many complex business queries. Window functions were previously discussed in the series of <\/span><a href=\"https:\/\/www.couchbase.com\/blog\/tag\/analytical-functions\/\"><span style=\"font-weight: 400\">posts<\/span><\/a><span style=\"font-weight: 400\"> [<a href=\"#ref2\">2<\/a>], [<a href=\"#ref3\">3<\/a>], [<a href=\"#ref4\">4<\/a>], and in this installment we&#8217;ll deep dive into their implementation in Couchbase Analytics.<\/span><\/p>\n<p><span style=\"font-weight: 400\">The <\/span><a href=\"https:\/\/www.couchbase.com\/blog\/announcing-couchbase-6-0\/\"><span style=\"font-weight: 400\">Couchbase Analytics service<\/span><\/a><span style=\"font-weight: 400\"> [<a href=\"#ref5\">5<\/a>] is designed to handle complex ad-hoc queries in the Couchbase data platform. Its key component is the MPP query engine that runs on a separate set of nodes in the cluster to guarantee workload isolation for the operational data nodes. Data is ingested into Analytics using the <\/span><a href=\"https:\/\/www.couchbase.com\/blog\/couchbases-history-everything-dcp\/\"><span style=\"font-weight: 400\">DCP change protocol<\/span><\/a><span style=\"font-weight: 400\"> [<a href=\"#ref6\">6<\/a>] and is hash-partitioned among all available Analytics nodes. The MPP query processor divides a single query into subtasks and schedules those to run in parallel on all nodes, repartitioning data if necessary. More information on the overall service architecture is available in our recent <\/span><a href=\"https:\/\/www.vldb.org\/pvldb\/vol12\/p2275-hubail.pdf\"><span style=\"font-weight: 400\">VLDB 2019 paper<\/span><\/a><span style=\"font-weight: 400\"> [<a href=\"#ref7\">7<\/a>] and on our <\/span><a href=\"https:\/\/www.youtube.com\/watch?v=1dN11TUj58c\"><span style=\"font-weight: 400\">video channel<\/span><\/a><span style=\"font-weight: 400\"> [<a href=\"#ref8\">8<\/a>].<\/span><\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"size-full wp-image-7681 aligncenter\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2019\/09\/HTAP.png\" alt=\"Figure 1: Couchbase Analytics Service\" width=\"729\" height=\"422\" srcset=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2019\/09\/HTAP.png 729w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2019\/09\/HTAP-300x174.png 300w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2019\/09\/HTAP-20x12.png 20w\" sizes=\"auto, (max-width: 729px) 100vw, 729px\" \/><\/p>\n<p style=\"text-align: center\"><strong>Figure 1: Couchbase Analytics Service<\/strong><\/p>\n<p><span style=\"font-weight: 400\">Window functions are also evaluated in a distributed, partition-parallel fashion by the Analytics query engine. The query compiler creates an execution plan that contains several operators working together to compute the result of the window function call. This execution plan is then sent to all Analytics nodes in the cluster where each operator works on a partition of the input data. The execution engine coordinates operator execution and delivers the query result to the client. For example, consider the following query which ranks employees in each department by their salaries.<\/span><\/p>\n<pre class=\"top-margin:24 bottom-margin:24 whitespace-before:1 whitespace-after:1 lang:plsql decode:true\">SELECT RANK() OVER (PARTITION BY department_id ORDER BY salary DESC) AS rank, \r\n       employee_id, department_id, salary\r\nFROM employee<\/pre>\n<p><span style=\"font-weight: 400\">The query processor evaluates this function in three steps as illustrated by Figure 2.<\/span><\/p>\n<p style=\"text-align: center\">\u00a0<img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-7682 size-full\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2019\/09\/CBASDeepDiveWinFunFigure2.png\" alt=\"Figure 2: Distributed, parallel query execution of window functions\" width=\"880\" height=\"416\" srcset=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2019\/09\/CBASDeepDiveWinFunFigure2.png 880w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2019\/09\/CBASDeepDiveWinFunFigure2-300x142.png 300w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2019\/09\/CBASDeepDiveWinFunFigure2-768x363.png 768w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2019\/09\/CBASDeepDiveWinFunFigure2-20x9.png 20w\" sizes=\"auto, (max-width: 880px) 100vw, 880px\" \/><\/p>\n<p style=\"text-align: center\"><strong>Figure 2: Distributed, parallel query execution of window functions<\/strong><\/p>\n<ol>\n<li><span style=\"font-weight: 400\">After the data is selected from the employee dataset it is repartitioned according to the PARTITION BY subclause of the OVER clause. The initial data layout might have each of the department records scattered across different storage partitions on several Analytics nodes. After the repartitioning step all employee records from a single department arrive into the same computation partition. The repartitioning step is executed in parallel on all nodes\/partitions in the cluster. In the most common Analytics configuration there is a one to one relationship between the number of data partitions and the number of CPU cores available in the cluster.<\/span><\/li>\n<li><span style=\"font-weight: 400\">Records within each department are sorted according to the ORDER BY subclause of the OVER clause. Once each department&#8217;s records have arrived at their corresponding computation partitions, the query processor starts sorting the data. This sorting step is also performed in parallel on all Analytics nodes.<\/span><\/li>\n<li><span style=\"font-weight: 400\">The RANK() function is then computed on sorted records within each department. This particular function only needs to look at the current record and compare it with the previous one, so it can be evaluated in a streaming fashion without requiring any additional data materialization.<\/span><\/li>\n<\/ol>\n<p><span style=\"font-weight: 400\">Executing these steps in parallel across all available nodes enables Analytics to utilize all computational resources of the cluster. This allows Analytics to achieve linear scalability as more nodes are added to meet the required performance targets.<\/span><\/p>\n<p><span style=\"font-weight: 400\">Let&#8217;s see how the above stages can be identified within a query execution plan. The Analytics explain plan feature was described in a <\/span><a href=\"https:\/\/www.couchbase.com\/blog\/analytics-explain-plan-part-1\/\"><span style=\"font-weight: 400\">previous post<\/span><\/a><span style=\"font-weight: 400\"> [<a href=\"#ref9\">9<\/a>], so here we only focus on the plan fragment related to the window function evaluation. (Recall that Analytics query plans are to be read bottom up.)<\/span><\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-7687 size-full\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2019\/09\/CBASDeepDiveWinFunFigure3v2-e1569011246976.png\" alt=\"Figure 3: Fragment of the query execution plan\" width=\"861\" height=\"826\" srcset=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2019\/09\/CBASDeepDiveWinFunFigure3v2-e1569011246976.png 861w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2019\/09\/CBASDeepDiveWinFunFigure3v2-e1569011246976-300x288.png 300w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2019\/09\/CBASDeepDiveWinFunFigure3v2-e1569011246976-768x737.png 768w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2019\/09\/CBASDeepDiveWinFunFigure3v2-e1569011246976-20x20.png 20w\" sizes=\"auto, (max-width: 861px) 100vw, 861px\" \/><\/p>\n<p style=\"text-align: center\"><strong>Figure 3: Fragment of the query execution plan<\/strong><\/p>\n<p><span style=\"font-weight: 400\">Data is read from the employee dataset by the &#8220;data-scan&#8221; operator and is passed to the &#8220;exchange&#8221; operator which is responsible for data repartitioning. The repartitioning field is &#8220;department_id&#8221; as requested by the PARTITION BY subclause. The &#8220;order&#8221; operator then sorts the data according to the ORDER BY subclause. Finally, the &#8220;window-aggregate&#8221; operator computes the RANK() function. Notice how the &#8220;physical-operator&#8221; value for this operator is set to &#8220;WINDOW_STREAM&#8221;, which means that the operator works in a streaming manner and does not require any additional data materialization. The &#8220;execution-mode&#8221; field is set to &#8220;PARTITIONED&#8221; for all operators, so they will all be executed on all available computation partitions in the cluster.<\/span><\/p>\n<p><span style=\"font-weight: 400\">Evaluation of some window functions might require information pertaining to a whole logical partition (its total number of tuples for NTILE() and PERCENTILE_RANK() functions, for example) or multiple iterations over the whole partition (when computing window frames for aggregate functions). Such functions are processed by non-streaming window operators. A non-streaming window operator is identified by &#8220;physical-operator&#8221; value of &#8220;WINDOW&#8221; in the query execution plan. The operator materializes one logical partition at a time, then starts the window function computation for each tuple in that partition. In order to handle arbitrary amounts of incoming data the operator follows the memory management model of the Analytics execution engine. The query planner assigns a memory budget to each operator. This budget cannot be exceeded during query execution. Operational data beyond the budget is spilled to disk by each operator and read back later when memory becomes available. A query usually consists of multiple operators and therefore has a global memory budget that cannot be exceeded at runtime. The Analytics query processor implements resource-based load control for incoming queries, only admitting those that can be executed within the available memory across all nodes.<\/span><\/p>\n<p><span style=\"font-weight: 400\">N1QL for Analytics also places fewer restrictions on the syntactic context of window function calls. Unlike SQL, queries in N1QL for Analytics permit window functions in WHERE and HAVING clauses as well as in N1QL-specific LET clauses.<\/span><\/p>\n<p><span style=\"font-weight: 400\">Our original query, for example, can be easily modified to return only the top-ranked employee in each department:<\/span><\/p>\n<pre class=\"whitespace-before:1 whitespace-after:1 lang:plsql decode:true\">SELECT employee_id, department_id, salary\r\nFROM employee\r\nWHERE RANK() OVER (PARTITION BY department_id ORDER BY salary DESC) = 1<\/pre>\n<p><span style=\"font-weight: 400\">To conclude, window functions in Analytics provide a powerful mechanism for parallel data analysis and reporting. The Couchbase N1QL query language allows users to easily evaluate those functions directly on their application&#8217;s JSON data, thereby avoiding complex ETL processing.<br \/>\n<\/span><\/p>\n<p><a href=\"https:\/\/couchbase.com\/downloads?family=server&amp;product=couchbase-server-developer\"><span style=\"font-weight: 400\">Download Couchbase Server 6.5<\/span><\/a><span style=\"font-weight: 400\"> today and contact us on the <\/span><a href=\"https:\/\/www.couchbase.com\/forums\/c\/analytics\/\"><span style=\"font-weight: 400\">Forums<\/span><\/a><span style=\"font-weight: 400\"> for any questions or comments.<\/span><\/p>\n<h4><span style=\"font-weight: 400\">References<\/span><\/h4>\n<p><span style=\"font-weight: 400\"><a id=\"ref1\"><\/a>[1] Announcing Couchbase Server 6.5 GA \u2013 What\u2019s New and Improved<\/span><span style=\"font-weight: 400\"><br \/>\n<\/span><a href=\"https:\/\/www.couchbase.com\/blog\/announcing-couchbase-server-6-5-0-beta-whats-new-and-improved\/\"><span style=\"font-weight: 400\">https:\/\/www.couchbase.com\/blog\/announcing-couchbase-server-6-5-0-whats-new-and-improved\/<\/span><\/a><br \/>\n<span style=\"font-weight: 400\"><a id=\"ref2\"><\/a>[2] On Par with Window Functions<\/span><br \/>\n<a href=\"https:\/\/www.couchbase.com\/blog\/on-par-with-window-functions-in-n1ql\/\"><span style=\"font-weight: 400\">https:\/\/www.couchbase.com\/blog\/on-par-with-window-functions-in-n1ql\/<\/span><\/a><br \/>\n<span style=\"font-weight: 400\"><a id=\"ref3\"><\/a>[3] Get a Bigger Picture with N1QL Window Functions and CTE<\/span><br \/>\n<a href=\"https:\/\/www.couchbase.com\/blog\/get-a-bigger-picture-with-n1ql-window-functions-and-cte\/\"><span style=\"font-weight: 400\">https:\/\/www.couchbase.com\/blog\/get-a-bigger-picture-with-n1ql-window-functions-and-cte\/<\/span><\/a><br \/>\n<span style=\"font-weight: 400\"><a id=\"ref4\"><\/a>[4] Window functions in Couchbase Analytics<\/span><br \/>\n<a href=\"https:\/\/www.couchbase.com\/blog\/window-functions-in-couchbase-analytics\/\"><span style=\"font-weight: 400\">https:\/\/www.couchbase.com\/blog\/window-functions-in-couchbase-analytics\/<\/span><\/a><br \/>\n<span style=\"font-weight: 400\"><a id=\"ref5\"><\/a>[5] Announcing Couchbase Server 6.0 with Analytics<br \/>\n<\/span><a href=\"https:\/\/www.couchbase.com\/blog\/announcing-couchbase-6-0\/\"><span style=\"font-weight: 400\">https:\/\/www.couchbase.com\/blog\/announcing-couchbase-6-0\/<\/span><\/a><br \/>\n<span style=\"font-weight: 400\"><a id=\"ref6\"><\/a>[6] Couchbase\u2019s History of Everything: DCP<br \/>\n<\/span><a href=\"https:\/\/www.couchbase.com\/blog\/couchbases-history-everything-dcp\/\"><span style=\"font-weight: 400\">https:\/\/www.couchbase.com\/blog\/couchbases-history-everything-dcp\/<\/span><\/a><br \/>\n<span style=\"font-weight: 400\"><a id=\"ref7\"><\/a>[7] Murtadha Al Hubail, Ali Alsuliman, Michael Blow, Michael Carey, Dmitry Lychagin, Ian Maxon, and Till Westmann. Couchbase Analytics: NoETL for Scalable NoSQL Data Analysis. PVLDB, 12(12): 2275-2286, 2019<\/span><span style=\"font-weight: 400\"><br \/>\n<\/span><a href=\"https:\/\/www.vldb.org\/pvldb\/vol12\/p2275-hubail.pdf\"><span style=\"font-weight: 400\">https:\/\/www.vldb.org\/pvldb\/vol12\/p2275-hubail.pdf<\/span><\/a><br \/>\n<span style=\"font-weight: 400\"><a id=\"ref8\"><\/a>[8] Couchbase Analytics: Under the Hood \u2013 Connect Silicon Valley 2018<br \/>\n<\/span><a href=\"https:\/\/www.youtube.com\/watch?v=1dN11TUj58c\"><span style=\"font-weight: 400\">https:\/\/www.youtube.com\/watch?v=1dN11TUj58c<\/span><\/a><br \/>\n<span style=\"font-weight: 400\"><a id=\"ref9\"><\/a>[9]\u00a0Analytics Explain Plan \u2013 Part 1<br \/>\n<\/span><a href=\"https:\/\/www.couchbase.com\/blog\/analytics-explain-plan-part-1\/\"><span style=\"font-weight: 400\">https:\/\/www.couchbase.com\/blog\/analytics-explain-plan-part-1\/<\/span><\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Couchbase Server 6.5 brings a host of new features [1] to the leading NoSQL database. One of the key additions to the N1QL query language is support for window functions.\u00a0These functions were originally introduced in the SQL:2003 standard and provide [&hellip;]<\/p>\n","protected":false},"author":45683,"featured_media":7111,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"inline_featured_image":false,"footnotes":""},"categories":[2294,1816,1812],"tags":[2378,2306,2304],"ppma_author":[9094],"class_list":["post-7680","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-analytics","category-couchbase-server","category-n1ql-query","tag-6-5","tag-analytical-functions","tag-reporting"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v25.8 (Yoast SEO v25.8) - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Deep Dive: Window functions in Couchbase Analytics - The Couchbase Blog<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.couchbase.com\/blog\/deep-dive-window-functions-in-couchbase-analytics\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Deep Dive: Window functions in Couchbase Analytics\" \/>\n<meta property=\"og:description\" content=\"Couchbase Server 6.5 brings a host of new features [1] to the leading NoSQL database. One of the key additions to the N1QL query language is support for window functions.\u00a0These functions were originally introduced in the SQL:2003 standard and provide [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.couchbase.com\/blog\/deep-dive-window-functions-in-couchbase-analytics\/\" \/>\n<meta property=\"og:site_name\" content=\"The Couchbase Blog\" \/>\n<meta property=\"article:published_time\" content=\"2019-09-20T19:55:31+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2025-06-14T00:21:53+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2019\/06\/Couchbase-Flora-Blog-Image-1024x295.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1024\" \/>\n\t<meta property=\"og:image:height\" content=\"295\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Dmitry Lychagin, Principal Engineer, Couchbase\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Dmitry Lychagin, Principal Engineer, Couchbase\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"6 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/deep-dive-window-functions-in-couchbase-analytics\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/deep-dive-window-functions-in-couchbase-analytics\/\"},\"author\":{\"name\":\"Dmitry Lychagin, Principal Engineer, Couchbase\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/2610a4782c51bbd9b2a2f30e08b9dfc3\"},\"headline\":\"Deep Dive: Window functions in Couchbase Analytics\",\"datePublished\":\"2019-09-20T19:55:31+00:00\",\"dateModified\":\"2025-06-14T00:21:53+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/deep-dive-window-functions-in-couchbase-analytics\/\"},\"wordCount\":1153,\"commentCount\":1,\"publisher\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/deep-dive-window-functions-in-couchbase-analytics\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2019\/06\/Couchbase-Flora-Blog-Image.png\",\"keywords\":[\"6.5\",\"analytical functions\",\"reporting\"],\"articleSection\":[\"Couchbase Analytics\",\"Couchbase Server\",\"SQL++ \/ N1QL Query\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/www.couchbase.com\/blog\/deep-dive-window-functions-in-couchbase-analytics\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/deep-dive-window-functions-in-couchbase-analytics\/\",\"url\":\"https:\/\/www.couchbase.com\/blog\/deep-dive-window-functions-in-couchbase-analytics\/\",\"name\":\"Deep Dive: Window functions in Couchbase Analytics - The Couchbase Blog\",\"isPartOf\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/deep-dive-window-functions-in-couchbase-analytics\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/deep-dive-window-functions-in-couchbase-analytics\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2019\/06\/Couchbase-Flora-Blog-Image.png\",\"datePublished\":\"2019-09-20T19:55:31+00:00\",\"dateModified\":\"2025-06-14T00:21:53+00:00\",\"breadcrumb\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/deep-dive-window-functions-in-couchbase-analytics\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.couchbase.com\/blog\/deep-dive-window-functions-in-couchbase-analytics\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/deep-dive-window-functions-in-couchbase-analytics\/#primaryimage\",\"url\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2019\/06\/Couchbase-Flora-Blog-Image.png\",\"contentUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2019\/06\/Couchbase-Flora-Blog-Image.png\",\"width\":2048,\"height\":589},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/deep-dive-window-functions-in-couchbase-analytics\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.couchbase.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Deep Dive: Window functions in Couchbase Analytics\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#website\",\"url\":\"https:\/\/www.couchbase.com\/blog\/\",\"name\":\"The Couchbase Blog\",\"description\":\"Couchbase, the NoSQL Database\",\"publisher\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.couchbase.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\",\"name\":\"The Couchbase Blog\",\"url\":\"https:\/\/www.couchbase.com\/blog\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png\",\"contentUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png\",\"width\":218,\"height\":34,\"caption\":\"The Couchbase Blog\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/\"}},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/2610a4782c51bbd9b2a2f30e08b9dfc3\",\"name\":\"Dmitry Lychagin, Principal Engineer, Couchbase\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/image\/1845089d3a8b23cae89dcb7e90a31686\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/ee7b03111d3aa598e468501586d3008fcebe423cddf3f065f94acd0213ac8057?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/ee7b03111d3aa598e468501586d3008fcebe423cddf3f065f94acd0213ac8057?s=96&d=mm&r=g\",\"caption\":\"Dmitry Lychagin, Principal Engineer, Couchbase\"},\"description\":\"Dmitry is a Principal Engineer working on Couchbase Analytics, focusing on its query compiler and the execution engine. He has more than 15 years of experience building enterprise software at Oracle, BEA Systems, and early-stage startups.\",\"sameAs\":[\"https:\/\/www.linkedin.com\/in\/dmitrylychagin\/\"],\"url\":\"https:\/\/www.couchbase.com\/blog\/author\/dmitry-lychagin\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Deep Dive: Window functions in Couchbase Analytics - The Couchbase Blog","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.couchbase.com\/blog\/deep-dive-window-functions-in-couchbase-analytics\/","og_locale":"en_US","og_type":"article","og_title":"Deep Dive: Window functions in Couchbase Analytics","og_description":"Couchbase Server 6.5 brings a host of new features [1] to the leading NoSQL database. One of the key additions to the N1QL query language is support for window functions.\u00a0These functions were originally introduced in the SQL:2003 standard and provide [&hellip;]","og_url":"https:\/\/www.couchbase.com\/blog\/deep-dive-window-functions-in-couchbase-analytics\/","og_site_name":"The Couchbase Blog","article_published_time":"2019-09-20T19:55:31+00:00","article_modified_time":"2025-06-14T00:21:53+00:00","og_image":[{"width":1024,"height":295,"url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2019\/06\/Couchbase-Flora-Blog-Image-1024x295.png","type":"image\/png"}],"author":"Dmitry Lychagin, Principal Engineer, Couchbase","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Dmitry Lychagin, Principal Engineer, Couchbase","Est. reading time":"6 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.couchbase.com\/blog\/deep-dive-window-functions-in-couchbase-analytics\/#article","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/deep-dive-window-functions-in-couchbase-analytics\/"},"author":{"name":"Dmitry Lychagin, Principal Engineer, Couchbase","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/2610a4782c51bbd9b2a2f30e08b9dfc3"},"headline":"Deep Dive: Window functions in Couchbase Analytics","datePublished":"2019-09-20T19:55:31+00:00","dateModified":"2025-06-14T00:21:53+00:00","mainEntityOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/deep-dive-window-functions-in-couchbase-analytics\/"},"wordCount":1153,"commentCount":1,"publisher":{"@id":"https:\/\/www.couchbase.com\/blog\/#organization"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/deep-dive-window-functions-in-couchbase-analytics\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2019\/06\/Couchbase-Flora-Blog-Image.png","keywords":["6.5","analytical functions","reporting"],"articleSection":["Couchbase Analytics","Couchbase Server","SQL++ \/ N1QL Query"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.couchbase.com\/blog\/deep-dive-window-functions-in-couchbase-analytics\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.couchbase.com\/blog\/deep-dive-window-functions-in-couchbase-analytics\/","url":"https:\/\/www.couchbase.com\/blog\/deep-dive-window-functions-in-couchbase-analytics\/","name":"Deep Dive: Window functions in Couchbase Analytics - The Couchbase Blog","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/deep-dive-window-functions-in-couchbase-analytics\/#primaryimage"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/deep-dive-window-functions-in-couchbase-analytics\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2019\/06\/Couchbase-Flora-Blog-Image.png","datePublished":"2019-09-20T19:55:31+00:00","dateModified":"2025-06-14T00:21:53+00:00","breadcrumb":{"@id":"https:\/\/www.couchbase.com\/blog\/deep-dive-window-functions-in-couchbase-analytics\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.couchbase.com\/blog\/deep-dive-window-functions-in-couchbase-analytics\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.couchbase.com\/blog\/deep-dive-window-functions-in-couchbase-analytics\/#primaryimage","url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2019\/06\/Couchbase-Flora-Blog-Image.png","contentUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2019\/06\/Couchbase-Flora-Blog-Image.png","width":2048,"height":589},{"@type":"BreadcrumbList","@id":"https:\/\/www.couchbase.com\/blog\/deep-dive-window-functions-in-couchbase-analytics\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.couchbase.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Deep Dive: Window functions in Couchbase Analytics"}]},{"@type":"WebSite","@id":"https:\/\/www.couchbase.com\/blog\/#website","url":"https:\/\/www.couchbase.com\/blog\/","name":"The Couchbase Blog","description":"Couchbase, the NoSQL Database","publisher":{"@id":"https:\/\/www.couchbase.com\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.couchbase.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/www.couchbase.com\/blog\/#organization","name":"The Couchbase Blog","url":"https:\/\/www.couchbase.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png","contentUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png","width":218,"height":34,"caption":"The Couchbase Blog"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/2610a4782c51bbd9b2a2f30e08b9dfc3","name":"Dmitry Lychagin, Principal Engineer, Couchbase","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/image\/1845089d3a8b23cae89dcb7e90a31686","url":"https:\/\/secure.gravatar.com\/avatar\/ee7b03111d3aa598e468501586d3008fcebe423cddf3f065f94acd0213ac8057?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/ee7b03111d3aa598e468501586d3008fcebe423cddf3f065f94acd0213ac8057?s=96&d=mm&r=g","caption":"Dmitry Lychagin, Principal Engineer, Couchbase"},"description":"Dmitry is a Principal Engineer working on Couchbase Analytics, focusing on its query compiler and the execution engine. He has more than 15 years of experience building enterprise software at Oracle, BEA Systems, and early-stage startups.","sameAs":["https:\/\/www.linkedin.com\/in\/dmitrylychagin\/"],"url":"https:\/\/www.couchbase.com\/blog\/author\/dmitry-lychagin\/"}]}},"authors":[{"term_id":9094,"user_id":45683,"is_guest":0,"slug":"dmitry-lychagin","display_name":"Dmitry Lychagin, Principal Engineer, Couchbase","avatar_url":"https:\/\/secure.gravatar.com\/avatar\/ee7b03111d3aa598e468501586d3008fcebe423cddf3f065f94acd0213ac8057?s=96&d=mm&r=g","author_category":"","last_name":"Lychagin, Principal Engineer, Couchbase","first_name":"Dmitry","job_title":"","user_url":"","description":"Dmitry is a Principal Engineer working on Couchbase Analytics, focusing on its query compiler and the execution engine. \r\nHe has more than 15 years of experience building enterprise software at Oracle, BEA Systems, and early-stage startups."}],"_links":{"self":[{"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/posts\/7680","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/users\/45683"}],"replies":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/comments?post=7680"}],"version-history":[{"count":0,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/posts\/7680\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/media\/7111"}],"wp:attachment":[{"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/media?parent=7680"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/categories?post=7680"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/tags?post=7680"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/ppma_author?post=7680"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}