From 2b72642c8c408b71ddd60ab1fdb2e1dfe2f58a99 Mon Sep 17 00:00:00 2001 From: Simon Dew Date: Tue, 4 Nov 2025 18:15:01 +0000 Subject: [PATCH 01/10] Update syntax --- modules/n1ql/partials/grammar/ddl.ebnf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/n1ql/partials/grammar/ddl.ebnf b/modules/n1ql/partials/grammar/ddl.ebnf index 07a6795c8..c59d0931f 100644 --- a/modules/n1ql/partials/grammar/ddl.ebnf +++ b/modules/n1ql/partials/grammar/ddl.ebnf @@ -79,7 +79,7 @@ drop-collection ::= 'DROP' 'COLLECTION' ( ( namespace ':' )? bucket '.' scope '. /* tag::create-primary-index[] */ create-primary-index ::= 'CREATE' 'PRIMARY' 'INDEX' ( index-name? ( 'IF' 'NOT' 'EXISTS' )? | 'IF' 'NOT' 'EXISTS' index-name ) - 'ON' keyspace-ref index-using? index-with? + 'ON' keyspace-ref index-partition? index-using? index-with? /* end::create-primary-index[] */ /* tag::index-using[] */ From 47f0e350ffc8e578791c918a53da09b3a038fd84 Mon Sep 17 00:00:00 2001 From: Simon Dew Date: Tue, 4 Nov 2025 18:16:47 +0000 Subject: [PATCH 02/10] Update syntax diagram --- .../create-primary-index.png | Bin 20813 -> 21775 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/modules/n1ql/assets/images/n1ql-language-reference/create-primary-index.png b/modules/n1ql/assets/images/n1ql-language-reference/create-primary-index.png index 924efc01f6ab596c7ecbb1dbe218a29cd27d5e6f..02c24c2ce7f854143071399f6167d888315aab53 100644 GIT binary patch literal 21775 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

uqa)T#iK2u7d;< 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 L_0+0VpN0GfqtRJS literal 20813 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 Date: Tue, 4 Nov 2025 23:02:33 +0000 Subject: [PATCH 03/10] Add PARTITION BY HASH to CREATE PRIMARY INDEX --- .../createprimaryindex.adoc | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/modules/n1ql/pages/n1ql-language-reference/createprimaryindex.adoc b/modules/n1ql/pages/n1ql-language-reference/createprimaryindex.adoc index 86f92d7ea..c29a2da22 100644 --- a/modules/n1ql/pages/n1ql-language-reference/createprimaryindex.adoc +++ b/modules/n1ql/pages/n1ql-language-reference/createprimaryindex.adoc @@ -13,6 +13,7 @@ Primary indexes contain a full set of keys in a given keyspace. :logical-hierarchy: xref:n1ql-intro/queriesandresults.adoc#logical-hierarchy :querying-indexes: xref:n1ql-intro/sysinfo.adoc#querying-indexes :index-replication: xref:indexes:index-replication.adoc#index-replication +:index-partitioning: xref:n1ql-language-reference/index-partitioning.adoc :query-settings: xref:manage:manage-settings/query-settings.adoc // TEMP @@ -72,6 +73,9 @@ When querying, if the index name contains a `#` or `_` character, you keyspace-ref:: [Required] Specifies the keyspace where the index is created. See <>. +index-partition:: (Optional) Specifies index partitions. +See <>. + index-using:: (Optional) Specifies the index type. See <>. @@ -161,6 +165,13 @@ collection:: For example, `airline` indicates the `airline` collection, assuming the query context is set. ==== +[[index-partition]] +=== PARTITION BY HASH Clause + +Used to partition the index. +Index partitioning helps increase the query performance by dividing and spreading a large index of documents across multiple nodes, horizontally scaling out an index as needed. +For details, see {index-partitioning}[Index Partitioning]. + [[index-using]] === USING Clause @@ -253,6 +264,9 @@ If the value of this property is not less than the number of index nodes in the |Integer |=== +Partitioned indexes support further options. +See {index-partitioning}[]. + == Usage // Nothing From 64c897808a9b4b355423d8b1bb01220d0485569e Mon Sep 17 00:00:00 2001 From: Simon Dew Date: Tue, 4 Nov 2025 23:12:35 +0000 Subject: [PATCH 04/10] Index partitioning: apply Vale style rules --- .../index-partitioning.adoc | 59 ++++++++++--------- 1 file changed, 31 insertions(+), 28 deletions(-) diff --git a/modules/n1ql/pages/n1ql-language-reference/index-partitioning.adoc b/modules/n1ql/pages/n1ql-language-reference/index-partitioning.adoc index 222ebef72..56a82b83e 100644 --- a/modules/n1ql/pages/n1ql-language-reference/index-partitioning.adoc +++ b/modules/n1ql/pages/n1ql-language-reference/index-partitioning.adoc @@ -10,7 +10,7 @@ :rebalancing-the-index-service: xref:learn:clusters-and-availability/rebalance.adoc#rebalancing-the-index-service {description} -The system partitions the index across a number of index nodes using a hash partitioning strategy in a way that is transparent to queries. +The system partitions the index across a number of index nodes using a hash partitioning strategy in a way that's transparent to queries. [#idx-partition-intro] -- @@ -26,14 +26,14 @@ Partitioned indexes are displayed in the Couchbase Web Console with a `partition image::manage:manage-indexes/index-indicators.png[] -For further details, refer to xref:manage:manage-indexes/manage-indexes.adoc[Manage Indexes]. +For more information, see xref:manage:manage-indexes/manage-indexes.adoc[Manage Indexes]. == Syntax To create a partitioned index, the overall syntax is the same as for a global secondary index. The distinguishing feature is the use of the PARTITION BY HASH clause to specify the partitions. -Refer to the {createindex}[CREATE INDEX] statement for details of the syntax. +See the {createindex}[CREATE INDEX] statement for details of the syntax. [[index-partition,index-partition]] @@ -44,11 +44,12 @@ Refer to the {createindex}[CREATE INDEX] statement for details of the syntax. include::partial$grammar/ddl.ebnf[tag=index-partition] ---- -image::n1ql-language-reference/index-partition.png["Syntax diagram: refer to source code listing", align=left] +image::n1ql-language-reference/index-partition.png["Syntax diagram: see source code listing", align=left] -_partition-key-expr_:: +[horizontal.compact] +partition-key-expr:: A field or an expression over a field representing a partition key. -For details and examples, refer to <>. +For details and examples, see <>. [[index-with,index-with]] === WITH Clause @@ -58,7 +59,7 @@ For details and examples, refer to <>. include::partial$grammar/ddl.ebnf[tag=index-with] ---- -image::n1ql-language-reference/index-with.png["Syntax diagram: refer to source code listing", align=left] +image::n1ql-language-reference/index-with.png["Syntax diagram: see source code listing", align=left] When creating a partitioned index, you can use the WITH clause to specify additional options for the partitions. @@ -68,43 +69,43 @@ An object with the following properties: num_partition;; [Optional] An integer that defines the number of partitions to divide into. The default value is 8. -For more details and examples, refer to <>. +For more information and examples, see <>. nodes;; [Optional] An array of strings, specifying a list of nodes. The node list to restrict the set of nodes available for placement. -Refer to the {index-with}[CREATE INDEX] statement for details of the syntax. -For more details and examples, refer to <>. +See the {index-with}[CREATE INDEX] statement for details of the syntax. +For more information and examples, see <>. defer_build;; [Optional] Boolean. When set to true, the index creation operation queues the task for building the index, but immediately pauses the building of the index. -Refer to the {index-with}[CREATE INDEX] statement for more details. +See the {index-with}[CREATE INDEX] statement for more details. num_replica;; [Optional] An integer specifying the number of replicas of the partitioned index to create. If this integer is greater than or equal to the number of index nodes in the cluster, then the index creation will fail. -Refer to the {index-with}[CREATE INDEX] statement for more details. +See the {index-with}[CREATE INDEX] statement for more details. secKeySize;; [Optional] An integer, specifying the average length of the combined index keys. -For more details and examples, refer to <>. +For more information and examples, see <>. docKeySize;; [Optional] An integer, specifying the average length of the document key. -For more details and examples, refer to <>. +For more information and examples, see <>. arrSize;; [Optional] An integer, specifying the average length of the array fields. -For more details and examples, refer to <>. +For more information and examples, see <>. numDoc;; [Optional] An integer, specifying the number of documents in the index. -For more details and examples, refer to <>. +For more information and examples, see <>. residentRatio;; [Optional] An integer, specifying the resident ratio of the index. -For more details and examples, refer to <>. +For more information and examples, see <>. [[partition-keys]] == Partition Keys @@ -113,13 +114,13 @@ Partition keys are made up of one or more terms, with each term being the docume The partition keys are hashed to generate a partition ID for each document. The partition ID is then used to identify the partition in which the document's index keys would reside. -The partition keys should be immutable, that is, its values shouldn't change once the document is created. +The partition keys should be immutable: its values should not change once the document is created. For example, in the `landmark` keyspace, the field named `activity` almost never changes, and is therefore a good candidate for partition key. If the partition keys have changed, then the corresponding document should be deleted and recreated with the new partition keys. Each term in the partition keys can be any JSON data type: number, string, boolean, array, object, or NULL. If a term in the partition keys is missing in the document, the term will have a {sqlpp} MISSING value. -Partition keys do not support {sqlpp} array expressions, e.g. `ARRAY` \... `FOR` \... `IN`. +Partition keys do not support {sqlpp} array expressions, such as `ARRAY` \... `FOR` \... `IN`. The following table lists some examples of partition keys. @@ -298,7 +299,7 @@ ORDER BY airline ==== As with equality predicate in the previous examples, the query engine can select qualifying partitions using an IN clause with matching partitioned keys. -The following example scans at most three partitions with `sourceairport "SFO"`, `"SJC"`, or `"OAK"`. +The following example scans at most 3 partitions with `sourceairport "SFO"`, `"SJC"`, or `"OAK"`. .Create a partitioned index with partition keys matching query IN clause ==== @@ -401,9 +402,9 @@ It tries to even out resource utilization across the index service nodes by movi == Choosing Partition Keys for Aggregate Query As with a range query, when an index is partitioned by document key, an aggregate query can gather the qualifying index keys from all the partitions before performing aggregation in the query engine. -Whenever aggregate pushdown optimization is allowed, the query engine will push down "partial aggregate" calculation to each partition. +Whenever aggregate pushdown optimization is allowed, the query engine will push down partial aggregate calculation to each partition. The query engine then computes the final aggregate result from the partial aggregates across all the partitions. -For more details on aggregate query optimization, refer to {gbap}[Group By and Aggregate Performance]. +For more information on aggregate query optimization, see {gbap}[Group By and Aggregate Performance]. [.server] include::ROOT:partial$query-context.adoc[tag=section] @@ -425,7 +426,7 @@ GROUP BY sourceairport, destinationairport; ---- ==== -The choice of partition keys can also improve aggregate query performance when the query engine can push down the "full aggregate" calculation to the index node. +The choice of partition keys can also improve aggregate query performance when the query engine can push down the full aggregate calculation to the index node. In this case, the query engine does not have to recompute the final aggregate result from the index nodes. In addition, certain pushdown optimizations can only be enabled when a full aggregate result is expected from the index node. To enable a full aggregate computation, the index must be created with the following requirements: @@ -591,15 +592,15 @@ At the time of rebalancing, the rebalance operation gathers statistics from each These statistics are fed to an optimization algorithm to determine the possible placement of each partition in order to minimize the variation of resource consumption across index nodes. The rebalancer will only attempt to balance resource consumption on a best try basis. -There are situations where the resource consumption cannot be fully balanced. +In some situations, the resource consumption cannot be fully balanced. For example: * The index service will not try to move the index if the cost to move an index across nodes is too high. * A cluster has a mix of non-partitioned indexes and partitioned indexes. -* There is data skew in the partitions. +* The partitions contain skewed data. -In Couchbase Server 7.0 and later, the [def]_index redistribution_ setting enables you to specify how Couchbase Server redistributes indexes on rebalance. -For further details, refer to {rebalancing-the-index-service}[Rebalancing the Index Service]. +In Couchbase Server 7.0 and later, the index redistribution setting enables you to specify how Couchbase Server redistributes indexes on rebalance. +For further details, see {rebalancing-the-index-service}[Rebalancing the Index Service]. == Repairing Failed Partitions @@ -613,12 +614,14 @@ The lost partitions cannot be repaired when the number of remaining nodes is les == Performance Considerations +// Nothing + === Max Parallelism Along with aggregate pushdown optimization, an application can further enhance the aggregate query performance by computing aggregation in parallel for each partition in the index service. This can be controlled by specifying the parameter `max_parallelism` when issuing a query. Starting with Couchbase Server 6.5, `max_parallelism` is set by default to match the number of partitions of the index. -Note that when `max_parallelism` is set to the default value, the index service uses more CPU and memory since the query traffic is increased. +When `max_parallelism` is set to the default value, the index service uses more CPU and memory since the query traffic is increased. **** [.edition]#{community}# From 9ef9c9051c2fa26fe6eeda2dcac034f5c2faa11c Mon Sep 17 00:00:00 2001 From: Simon Dew Date: Wed, 5 Nov 2025 00:08:25 +0000 Subject: [PATCH 05/10] Add primary indexes and vector indexes to Index partitioning --- .../n1ql-language-reference/index-partitioning.adoc | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/modules/n1ql/pages/n1ql-language-reference/index-partitioning.adoc b/modules/n1ql/pages/n1ql-language-reference/index-partitioning.adoc index 56a82b83e..e17c7b016 100644 --- a/modules/n1ql/pages/n1ql-language-reference/index-partitioning.adoc +++ b/modules/n1ql/pages/n1ql-language-reference/index-partitioning.adoc @@ -5,8 +5,12 @@ :page-topic-type: reference :createindex: xref:n1ql-language-reference/createindex.adoc +:createprimaryindex: xref:n1ql-language-reference/createprimaryindex.adoc +:createvectorindex: xref:n1ql-language-reference/createvectorindex.adoc :gbap: xref:n1ql-language-reference/groupby-aggregate-performance.adoc :index-with: {createindex}#index-with +:primary-index-with: {createprimaryindex}#primary-index-with +:vector-index-with: {createvectorindex}#vector-index-with :rebalancing-the-index-service: xref:learn:clusters-and-availability/rebalance.adoc#rebalancing-the-index-service {description} @@ -30,11 +34,10 @@ For more information, see xref:manage:manage-indexes/manage-indexes.adoc[Manage == Syntax -To create a partitioned index, the overall syntax is the same as for a global secondary index. +To create a partitioned index, the overall syntax is the same as for a primary index or global secondary index. The distinguishing feature is the use of the PARTITION BY HASH clause to specify the partitions. -See the {createindex}[CREATE INDEX] statement for details of the syntax. - +For more information, see {createprimaryindex}[], {createindex}[], or {createvectorindex}[]. [[index-partition,index-partition]] === PARTITION BY HASH Clause From 3241c044d327b1b3a1e5136b5f96a7bd83d7588d Mon Sep 17 00:00:00 2001 From: Simon Dew Date: Wed, 5 Nov 2025 00:08:44 +0000 Subject: [PATCH 06/10] Reformat index partitioning --- .../index-partitioning.adoc | 148 ++++++++++-------- 1 file changed, 81 insertions(+), 67 deletions(-) diff --git a/modules/n1ql/pages/n1ql-language-reference/index-partitioning.adoc b/modules/n1ql/pages/n1ql-language-reference/index-partitioning.adoc index e17c7b016..9b2d55950 100644 --- a/modules/n1ql/pages/n1ql-language-reference/index-partitioning.adoc +++ b/modules/n1ql/pages/n1ql-language-reference/index-partitioning.adoc @@ -1,7 +1,7 @@ = Index Partitioning :page-edition: Enterprise Edition :imagesdir: ../../assets/images -:description: Index Partitioning enables you to increase aggregate query performance by dividing and spreading a large index of documents across multiple nodes, horizontally scaling out an index as needed. +:description: Index partitioning enables you to increase aggregate query performance by dividing and spreading a large index of documents across multiple nodes, horizontally scaling out an index as needed. :page-topic-type: reference :createindex: xref:n1ql-language-reference/createindex.adoc @@ -28,7 +28,7 @@ Benefits of a partitioned index include: Partitioned indexes are displayed in the Couchbase Web Console with a `partitioned` indicator: -image::manage:manage-indexes/index-indicators.png[] +image::manage:manage-indexes/index-indicators.png["The Couchbase Web Console, with partitioned indexes marked."] For more information, see xref:manage:manage-indexes/manage-indexes.adoc[Manage Indexes]. @@ -49,7 +49,7 @@ include::partial$grammar/ddl.ebnf[tag=index-partition] image::n1ql-language-reference/index-partition.png["Syntax diagram: see source code listing", align=left] -[horizontal.compact] +[horizontal] partition-key-expr:: A field or an expression over a field representing a partition key. For details and examples, see <>. @@ -66,49 +66,92 @@ image::n1ql-language-reference/index-with.png["Syntax diagram: see source code l When creating a partitioned index, you can use the WITH clause to specify additional options for the partitions. -_expr_:: -An object with the following properties: +[horizontal#index-with-args] +expr:: +An object with the following properties. -num_partition;; -[Optional] An integer that defines the number of partitions to divide into. -The default value is 8. -For more information and examples, see <>. +[options="header", cols="1a,4a,1a"] +|=== +| Name | Description | Schema + +| **num_partition** + +__optional__ +| The number of partitions to divide the index into. +For more information, see <>. + +**Default:** `8` +| Integer + +| **nodes** + +__optional__ +| A list of nodes to restrict the set of nodes available for placement. +For more information, see <>. -nodes;; -[Optional] An array of strings, specifying a list of nodes. -The node list to restrict the set of nodes available for placement. -See the {index-with}[CREATE INDEX] statement for details of the syntax. -For more information and examples, see <>. +For details of the syntax, see {primary-index-with}[CREATE PRIMARY INDEX], {index-with}[CREATE INDEX], or {vector-index-with}[CREATE VECTOR INDEX]. +| String array -defer_build;; -[Optional] Boolean. -When set to true, the index creation operation queues the task for building the index, but immediately pauses the building of the index. -See the {index-with}[CREATE INDEX] statement for more details. +| **defer_build** + +__optional__ +| When set to true, the index creation operation queues the task for building the index, but immediately pauses the building of the index. -num_replica;; -[Optional] An integer specifying the number of replicas of the partitioned index to create. +For more information, see {primary-index-with}[CREATE PRIMARY INDEX], {index-with}[CREATE INDEX], or {vector-index-with}[CREATE VECTOR INDEX]. +| Boolean + +| **num_replica** + +__optional__ +| The number of replicas of the partitioned index to create. If this integer is greater than or equal to the number of index nodes in the cluster, then the index creation will fail. -See the {index-with}[CREATE INDEX] statement for more details. -secKeySize;; -[Optional] An integer, specifying the average length of the combined index keys. -For more information and examples, see <>. +For more information, see {primary-index-with}[CREATE PRIMARY INDEX], {index-with}[CREATE INDEX], or {vector-index-with}[CREATE VECTOR INDEX]. +| Integer + +| **secKeySize** + +__optional__ +| A sizing hint, specifying the average length of the combined index keys. +For more information, see <>. -docKeySize;; -[Optional] An integer, specifying the average length of the document key. -For more information and examples, see <>. +**Example:** `20` +| Integer -arrSize;; -[Optional] An integer, specifying the average length of the array fields. -For more information and examples, see <>. +| **docKeySize** + +__optional__ +| A sizing hint, specifying the average length of the document key `meta().id`. +For more information, see <>. -numDoc;; -[Optional] An integer, specifying the number of documents in the index. -For more information and examples, see <>. +**Example:** `20` +|Integer -residentRatio;; -[Optional] An integer, specifying the resident ratio of the index. -For more information and examples, see <>. +| **arrSize** + +__optional__ +| A sizing hint, specifying the average length of the array fields. +Non-array fields will be ignored. +For more information, see <>. + +**Example:** `10` +| Integer + +| **numDoc** + +__optional__ +| A sizing hint, specifying the number of documents in the index. +For more information, see <>. + +**Example:** `7303` +| Integer + +| **residentRatio** + +__optional__ +| A sizing hint, specifying the resident ratio of the index. +The resident ratio is the memory usage of the index, as a percentage of its estimated data size. +For more information, see <>. + +Couchbase recommends setting this property to `10` or higher, to avoid index build failures and other issues. + +**Example:** `50` +| Integer +|=== + +Composite Vector indexes and Hyperscale Vector indexes support further options. +See {index-with}[CREATE INDEX] or {vector-index-with}[CREATE VECTOR INDEX]. [[partition-keys]] == Partition Keys @@ -505,40 +548,11 @@ NOTE: To avoid any downtime, before removing the partitioned index, first create [[sizing-hints]] === Sizing Hints -You can optionally provide sizing hints too. +You can optionally provide sizing hints to help place the partitions. Given the sizing hints, the planner uses a formula to estimate the memory and CPU usage of the index. Based on the estimated memory and CPU usage, the planner tries to place the partitions according to the free resources available to each index node. -.Sizing Hints -[cols="2,5,2"] -|=== -| Optional Sizing Hint | Description | Example - -| *secKeySize* -| The average length of the combined index keys. -| `20` - -| *docKeySize* -| The average length of the document key `meta().id`. -| `20` - -| *arrSize* -| The average length of the array field. -Non-array fields will be ignored. -| `10` - -| *numDoc* -| The number of documents in the index. -| `7303` - -| *residentRatio* -| The memory usage of the index, as a percentage of its estimated data size. -| `50` -|=== - -NOTE: Couchbase recommends setting the residentRatio property value over 10 to avoid issues, for example, index build failures. - -To provide sizing estimation, you can use a command similar to the following examples. +For a list of sizing hints and example values, see <>. [.server] include::ROOT:partial$query-context.adoc[tag=section] From 214000379eef35ea78a9f7ff6be6a06daff10711 Mon Sep 17 00:00:00 2001 From: Simon Dew Date: Wed, 5 Nov 2025 00:42:14 +0000 Subject: [PATCH 07/10] Titles as actions --- .../n1ql-language-reference/index-partitioning.adoc | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/modules/n1ql/pages/n1ql-language-reference/index-partitioning.adoc b/modules/n1ql/pages/n1ql-language-reference/index-partitioning.adoc index 9b2d55950..162dce375 100644 --- a/modules/n1ql/pages/n1ql-language-reference/index-partitioning.adoc +++ b/modules/n1ql/pages/n1ql-language-reference/index-partitioning.adoc @@ -245,7 +245,7 @@ CREATE INDEX idx ON route // * NULL value [#doc-keys-as-partition-key] -== Using Document Keys as Partition Key +== Use Document Keys as Partition Key The simplest way to create a partitioned index is to use the document key as the partition key. @@ -270,7 +270,7 @@ With [.cmd]`meta().id` as the partition key, the index keys are evenly distribut Every query will gather the qualifying index keys from all the partitions. [#partition-keys-range-query] -== Choosing Partition Keys for Range Query +== Choose Partition Keys for Range Query An application has the option to choose the partition key that can minimize latency on a range query for a partitioned index. For example, let's say a query has an equality predicate based on the field `sourceairport` and `destinationairport`. @@ -445,7 +445,7 @@ CREATE INDEX idx ON route During index rebalancing, the rebalancer takes into account the data skew among the partitions using runtime statistics. It tries to even out resource utilization across the index service nodes by moving the partitions across the nodes when possible. -== Choosing Partition Keys for Aggregate Query +== Choose Partition Keys for Aggregate Query As with a range query, when an index is partitioned by document key, an aggregate query can gather the qualifying index keys from all the partitions before performing aggregation in the query engine. Whenever aggregate pushdown optimization is allowed, the query engine will push down partial aggregate calculation to each partition. @@ -602,7 +602,7 @@ When an index node fails, any in-flight query requests (serviced by the failed n Any new query requests requiring the lost partition are then serviced by the partitions in the replica. [[rebalancing]] -== Rebalancing +== Rebalance When new index nodes are added or removed from the cluster, the rebalance operation attempts to move the index partitions across available index nodes in order to balance resource consumptions. At the time of rebalancing, the rebalance operation gathers statistics from each index. @@ -619,7 +619,8 @@ For example: In Couchbase Server 7.0 and later, the index redistribution setting enables you to specify how Couchbase Server redistributes indexes on rebalance. For further details, see {rebalancing-the-index-service}[Rebalancing the Index Service]. -== Repairing Failed Partitions +[[repairing-failed-partitions]] +== Repair Failed Partitions When an index node fails, the index partitions on that node will be lost. The lost partitions can be recovered or repaired when: From 084ea7b7e89e42a1eb82dcd9ce87262092a23832 Mon Sep 17 00:00:00 2001 From: Simon Dew Date: Wed, 5 Nov 2025 11:01:01 +0000 Subject: [PATCH 08/10] Increase ToC depth --- .../n1ql/pages/n1ql-language-reference/index-partitioning.adoc | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/n1ql/pages/n1ql-language-reference/index-partitioning.adoc b/modules/n1ql/pages/n1ql-language-reference/index-partitioning.adoc index 162dce375..34c77fa5e 100644 --- a/modules/n1ql/pages/n1ql-language-reference/index-partitioning.adoc +++ b/modules/n1ql/pages/n1ql-language-reference/index-partitioning.adoc @@ -3,6 +3,7 @@ :imagesdir: ../../assets/images :description: Index partitioning enables you to increase aggregate query performance by dividing and spreading a large index of documents across multiple nodes, horizontally scaling out an index as needed. :page-topic-type: reference +:page-toclevels: 2 :createindex: xref:n1ql-language-reference/createindex.adoc :createprimaryindex: xref:n1ql-language-reference/createprimaryindex.adoc From a467a9caeced6e4baf38a0caa5f2a595d5fdc51b Mon Sep 17 00:00:00 2001 From: Simon Dew <39966290+simon-dew@users.noreply.github.com> Date: Thu, 6 Nov 2025 14:14:44 +0000 Subject: [PATCH 09/10] Apply suggestions from code review Co-authored-by: rakhi-prathap --- .../pages/n1ql-language-reference/createprimaryindex.adoc | 2 +- .../pages/n1ql-language-reference/index-partitioning.adoc | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/n1ql/pages/n1ql-language-reference/createprimaryindex.adoc b/modules/n1ql/pages/n1ql-language-reference/createprimaryindex.adoc index c29a2da22..ec91b81d8 100644 --- a/modules/n1ql/pages/n1ql-language-reference/createprimaryindex.adoc +++ b/modules/n1ql/pages/n1ql-language-reference/createprimaryindex.adoc @@ -170,7 +170,7 @@ For example, `airline` indicates the `airline` collection, assuming the query co Used to partition the index. Index partitioning helps increase the query performance by dividing and spreading a large index of documents across multiple nodes, horizontally scaling out an index as needed. -For details, see {index-partitioning}[Index Partitioning]. +For more information, see {index-partitioning}[Index Partitioning]. [[index-using]] === USING Clause diff --git a/modules/n1ql/pages/n1ql-language-reference/index-partitioning.adoc b/modules/n1ql/pages/n1ql-language-reference/index-partitioning.adoc index 34c77fa5e..5600b621c 100644 --- a/modules/n1ql/pages/n1ql-language-reference/index-partitioning.adoc +++ b/modules/n1ql/pages/n1ql-language-reference/index-partitioning.adoc @@ -161,7 +161,7 @@ Partition keys are made up of one or more terms, with each term being the docume The partition keys are hashed to generate a partition ID for each document. The partition ID is then used to identify the partition in which the document's index keys would reside. -The partition keys should be immutable: its values should not change once the document is created. +The partition keys should be immutable: their values should not change once the document is created. For example, in the `landmark` keyspace, the field named `activity` almost never changes, and is therefore a good candidate for partition key. If the partition keys have changed, then the corresponding document should be deleted and recreated with the new partition keys. @@ -473,7 +473,7 @@ GROUP BY sourceairport, destinationairport; ---- ==== -The choice of partition keys can also improve aggregate query performance when the query engine can push down the full aggregate calculation to the index node. +The choice of partition keys can also improve aggregate query performance by enabling the query engine to push down the full aggregate calculation to the index node. In this case, the query engine does not have to recompute the final aggregate result from the index nodes. In addition, certain pushdown optimizations can only be enabled when a full aggregate result is expected from the index node. To enable a full aggregate computation, the index must be created with the following requirements: From c51be0fe164b54ab468e44c0e5980e97daf99200 Mon Sep 17 00:00:00 2001 From: Simon Dew Date: Thu, 6 Nov 2025 14:19:33 +0000 Subject: [PATCH 10/10] Mark PARTITION BY HASH as Enterprise-only --- modules/n1ql/pages/n1ql-language-reference/createindex.adoc | 2 ++ .../n1ql/pages/n1ql-language-reference/createprimaryindex.adoc | 2 ++ 2 files changed, 4 insertions(+) diff --git a/modules/n1ql/pages/n1ql-language-reference/createindex.adoc b/modules/n1ql/pages/n1ql-language-reference/createindex.adoc index a552e0cf5..92c1ca79d 100644 --- a/modules/n1ql/pages/n1ql-language-reference/createindex.adoc +++ b/modules/n1ql/pages/n1ql-language-reference/createindex.adoc @@ -336,6 +336,8 @@ Indicates that the index key is a vector field. [[index-partition]] === PARTITION BY HASH Clause +[.edition]#{enterprise}# + Used to partition the index. Index partitioning helps increase the query performance by dividing and spreading a large index of documents across multiple nodes, horizontally scaling out an index as needed. For details, see {index-partitioning}[Index Partitioning]. diff --git a/modules/n1ql/pages/n1ql-language-reference/createprimaryindex.adoc b/modules/n1ql/pages/n1ql-language-reference/createprimaryindex.adoc index ec91b81d8..9d9b9aff1 100644 --- a/modules/n1ql/pages/n1ql-language-reference/createprimaryindex.adoc +++ b/modules/n1ql/pages/n1ql-language-reference/createprimaryindex.adoc @@ -168,6 +168,8 @@ For example, `airline` indicates the `airline` collection, assuming the query co [[index-partition]] === PARTITION BY HASH Clause +[.edition]#{enterprise}# + Used to partition the index. Index partitioning helps increase the query performance by dividing and spreading a large index of documents across multiple nodes, horizontally scaling out an index as needed. For more information, see {index-partitioning}[Index Partitioning].