This is an automated email from the ASF dual-hosted git repository.

kfaraz pushed a commit to branch 25.0.0
in repository https://gitbox.apache.org/repos/asf/druid.git


The following commit(s) were added to refs/heads/25.0.0 by this push:
     new 348c9f64f9 [Backport] backport ux bug fixes to 25 (#13533)
348c9f64f9 is described below

commit 348c9f64f9ca12803b8dcefe596d1f9e58db41ca
Author: Vadim Ogievetsky <[email protected]>
AuthorDate: Fri Dec 9 19:03:55 2022 -0800

    [Backport] backport ux bug fixes to 25 (#13533)
    
    * Web console: add arrayOfDoublesSketch and other small fixes (#13486)
    * add padding and keywords
    * add arrayOfDoubles
    * Update docs/development/extensions-core/datasketches-tuple.md
    Co-authored-by: Charles Smith <[email protected]>
    * Update docs/development/extensions-core/datasketches-tuple.md
    Co-authored-by: Charles Smith <[email protected]>
    * Update docs/development/extensions-core/datasketches-tuple.md
    Co-authored-by: Charles Smith <[email protected]>
    * Update docs/development/extensions-core/datasketches-tuple.md
    Co-authored-by: Charles Smith <[email protected]>
    * Update docs/development/extensions-core/datasketches-tuple.md
    Co-authored-by: Charles Smith <[email protected]>
    * partiton int
    * fix docs
    Co-authored-by: Charles Smith <[email protected]>
    * Web console: improve compaction status display (#13523)
    * improve compaction status display
    * even more accurate
    * fix snapshot
    * MSQ: Improve TooManyBuckets error message, improve error docs. (#13525)
    1) Edited the TooManyBuckets error message to mention PARTITIONED BY
       instead of segmentGranularity.
    2) Added error-code-specific anchors in the docs.
    3) Add information to various error codes in the docs about common
       causes and solutions.
    * update error anchors (#13527)
    * update snapshot
    Co-authored-by: Charles Smith <[email protected]>
    Co-authored-by: Gian Merlino <[email protected]>
---
 .../extensions-core/datasketches-tuple.md          |  43 +++++-
 docs/multi-stage-query/concepts.md                 |   3 +-
 docs/multi-stage-query/known-issues.md             |   8 +-
 docs/multi-stage-query/reference.md                |  70 +++++-----
 .../msq/indexing/error/TooManyBucketsFault.java    |   2 +-
 web-console/lib/keywords.js                        |   3 +
 web-console/script/create-sql-docs.js              |   4 +-
 web-console/src/bootstrap/react-table-defaults.tsx |   4 +-
 .../segment-timeline/segment-timeline.tsx          |   2 +-
 .../compaction-dialog/compaction-dialog.scss       |   5 +
 .../compaction-dialog/compaction-dialog.tsx        |  27 +++-
 .../compaction-config/compaction-config.tsx        |  29 +++-
 .../compaction-status/compaction-status.spec.ts    | 146 +++++++++++++++------
 .../compaction-status/compaction-status.ts         |  23 +++-
 .../ingest-query-pattern/ingest-query-pattern.ts   |   3 +-
 .../src/druid-models/metric-spec/metric-spec.tsx   |  43 ++++++
 .../workbench-query/workbench-query.ts             |   8 +-
 .../src/helpers/execution/sql-task-execution.ts    |   9 +-
 web-console/src/links.ts                           |   2 +-
 web-console/src/react-table/react-table-extra.scss |   4 +
 .../__snapshots__/datasources-view.spec.tsx.snap   |   2 +-
 .../views/datasources-view/datasources-view.tsx    |   2 +-
 .../sql-data-loader-view/sql-data-loader-view.tsx  |   2 +
 .../connect-external-data-dialog.tsx               |  18 ++-
 .../execution-error-pane.spec.tsx.snap             |   2 +-
 .../execution-error-pane/execution-error-pane.tsx  |   4 +-
 .../input-source-step/example-inputs.ts            |   3 +
 .../input-source-step/input-source-step.tsx        |  12 +-
 .../src/views/workbench-view/workbench-view.tsx    |   9 +-
 29 files changed, 372 insertions(+), 120 deletions(-)

diff --git a/docs/development/extensions-core/datasketches-tuple.md 
b/docs/development/extensions-core/datasketches-tuple.md
index fc4f74d5c8..c9a05b5ab1 100644
--- a/docs/development/extensions-core/datasketches-tuple.md
+++ b/docs/development/extensions-core/datasketches-tuple.md
@@ -39,19 +39,52 @@ druid.extensions.loadList=["druid-datasketches"]
   "name" : <output_name>,
   "fieldName" : <metric_name>,
   "nominalEntries": <number>,
-  "numberOfValues" : <number>,
-  "metricColumns" : <array of strings>
+  "metricColumns" : <array of strings>,
+  "numberOfValues" : <number>
  }
 ```
 
 |property|description|required?|
 |--------|-----------|---------|
 |type|This String should always be "arrayOfDoublesSketch"|yes|
-|name|A String for the output (result) name of the calculation.|yes|
+|name|String representing the output column to store sketch values.|yes|
 |fieldName|A String for the name of the input field.|yes|
 |nominalEntries|Parameter that determines the accuracy and size of the sketch. 
Higher k means higher accuracy but more space to store sketches. Must be a 
power of 2. See the [Theta sketch 
accuracy](https://datasketches.apache.org/docs/Theta/ThetaErrorTable) for 
details. |no, defaults to 16384|
-|numberOfValues|Number of values associated with each distinct key. |no, 
defaults to 1|
-|metricColumns|If building sketches from raw data, an array of names of the 
input columns containing numeric values to be associated with each distinct 
key.|no, defaults to empty array|
+|metricColumns|When building sketches from raw data, an array input column 
that contain numeric values to associate with each distinct key. If not 
provided, assumes `fieldName` is an `arrayOfDoublesSketch`|no, if not provided 
`fieldName` is assumed to be an arrayOfDoublesSketch|
+|numberOfValues|Number of values associated with each distinct key. |no, 
defaults to the length of `metricColumns` if provided and 1 otherwise|
+
+You can use the `arrayOfDoublesSketch` aggregator to:
+
+- Build a sketch from raw data. In this case, set `metricColumns` to an array.
+- Build a sketch from an existing `ArrayOfDoubles` sketch . In this case, 
leave `metricColumns` unset and set the `fieldName` to an `ArrayOfDoubles` 
sketch with `numberOfValues` doubles. At ingestion time, you must base64 encode 
`ArrayOfDoubles`  sketches at ingestion time.
+
+#### Example on top of raw data
+
+Compute a theta of unique users. For each user store the `added` and `deleted` 
scores. The new sketch column will be called `users_theta`.
+
+```json
+{
+  "type": "arrayOfDoublesSketch",
+  "name": "users_theta",
+  "fieldName": "user",
+  "nominalEntries": 16384,
+  "metricColumns": ["added", "deleted"],
+}
+```
+
+#### Example ingesting a precomputed sketch column
+
+Ingest a sketch column called `user_sketches` that has a base64 encoded value 
of two doubles in its array and store it in a column called `users_theta`.
+
+```json
+{
+  "type": "arrayOfDoublesSketch",
+  "name": "users_theta",
+  "fieldName": "user_sketches",
+  "nominalEntries": 16384,
+  "numberOfValues": 2,
+}
+```
 
 ### Post Aggregators
 
diff --git a/docs/multi-stage-query/concepts.md 
b/docs/multi-stage-query/concepts.md
index 44e5ea43d4..da0e774152 100644
--- a/docs/multi-stage-query/concepts.md
+++ b/docs/multi-stage-query/concepts.md
@@ -233,7 +233,8 @@ happens:
 The [`maxNumTasks`](./reference.md#context-parameters) query parameter 
determines the maximum number of tasks your
 query will use, including the one `query_controller` task. Generally, queries 
perform better with more workers. The
 lowest possible value of `maxNumTasks` is two (one worker and one controller). 
Do not set this higher than the number of
-free slots available in your cluster; doing so will result in a 
[TaskStartTimeout](reference.md#error-codes) error.
+free slots available in your cluster; doing so will result in a 
[TaskStartTimeout](reference.md#error_TaskStartTimeout)
+error.
 
 When [reading external data](#extern), EXTERN can read multiple files in 
parallel across
 different worker tasks. However, EXTERN does not split individual files across 
multiple worker tasks. If you have a
diff --git a/docs/multi-stage-query/known-issues.md 
b/docs/multi-stage-query/known-issues.md
index c76ab57aa7..648d3c297b 100644
--- a/docs/multi-stage-query/known-issues.md
+++ b/docs/multi-stage-query/known-issues.md
@@ -33,16 +33,18 @@ sidebar_label: Known issues
 
 - Worker task stage outputs are stored in the working directory given by 
`druid.indexer.task.baseDir`. Stages that
 generate a large amount of output data may exhaust all available disk space. 
In this case, the query fails with
-an [UnknownError](./reference.md#error-codes) with a message including "No 
space left on device".
+an [UnknownError](./reference.md#error_UnknownError) with a message including 
"No space left on device".
 
 ## SELECT
 
 - SELECT from a Druid datasource does not include unpublished real-time data.
 
 - GROUPING SETS and UNION ALL are not implemented. Queries using these 
features return a
-  [QueryNotSupported](reference.md#error-codes) error. 
+  [QueryNotSupported](reference.md#error_QueryNotSupported) error.
 
-- For some COUNT DISTINCT queries, you'll encounter a 
[QueryNotSupported](reference.md#error-codes) error that includes `Must not 
have 'subtotalsSpec'` as one of its causes. This is caused by the planner 
attempting to use GROUPING SETs, which are not implemented.
+- For some COUNT DISTINCT queries, you'll encounter a 
[QueryNotSupported](reference.md#error_QueryNotSupported) error
+  that includes `Must not have 'subtotalsSpec'` as one of its causes. This is 
caused by the planner attempting to use
+  GROUPING SETs, which are not implemented.
 
 - The numeric varieties of the EARLIEST and LATEST aggregators do not work 
properly. Attempting to use the numeric
   varieties of these aggregators lead to an error like
diff --git a/docs/multi-stage-query/reference.md 
b/docs/multi-stage-query/reference.md
index a4bcbfc27b..ae9bc106ca 100644
--- a/docs/multi-stage-query/reference.md
+++ b/docs/multi-stage-query/reference.md
@@ -249,14 +249,14 @@ The following table lists query limits:
 
 | Limit | Value | Error if exceeded |
 |---|---|---|
-| Size of an individual row written to a frame. Row size when written to a 
frame may differ from the original row size. | 1 MB | `RowTooLarge` |
-| Number of segment-granular time chunks encountered during ingestion. | 5,000 
| `TooManyBuckets` |
-| Number of input files/segments per worker. | 10,000 | `TooManyInputFiles` |
-| Number of output partitions for any one stage. Number of segments generated 
during ingestion. |25,000 | `TooManyPartitions` |
-| Number of output columns for any one stage. | 2,000 | `TooManyColumns` |
-| Number of cluster by columns that can appear in a stage | 1,500 | 
`TooManyClusteredByColumns` |
-| Number of workers for any one stage. | Hard limit is 1,000. Memory-dependent 
soft limit may be lower. | `TooManyWorkers` |
-| Maximum memory occupied by broadcasted tables. | 30% of each [processor 
memory bundle](concepts.md#memory-usage). | `BroadcastTablesTooLarge` |
+| Size of an individual row written to a frame. Row size when written to a 
frame may differ from the original row size. | 1 MB | 
[`RowTooLarge`](#error_RowTooLarge) |
+| Number of segment-granular time chunks encountered during ingestion. | 5,000 
| [`TooManyBuckets`](#error_TooManyBuckets) |
+| Number of input files/segments per worker. | 10,000 | 
[`TooManyInputFiles`](#error_TooManyInputFiles) |
+| Number of output partitions for any one stage. Number of segments generated 
during ingestion. |25,000 | [`TooManyPartitions`](#error_TooManyPartitions) |
+| Number of output columns for any one stage. | 2,000 | 
[`TooManyColumns`](#error_TooManyColumns) |
+| Number of cluster by columns that can appear in a stage | 1,500 | 
[`TooManyClusteredByColumns`](#error_TooManyClusteredByColumns) |
+| Number of workers for any one stage. | Hard limit is 1,000. Memory-dependent 
soft limit may be lower. | [`TooManyWorkers`](#error_TooManyWorkers) |
+| Maximum memory occupied by broadcasted tables. | 30% of each [processor 
memory bundle](concepts.md#memory-usage). | 
[`BroadcastTablesTooLarge`](#error_BroadcastTablesTooLarge) |
 
 <a name="errors"></a>
 
@@ -266,30 +266,30 @@ The following table describes error codes you may 
encounter in the `multiStageQu
 
 | Code | Meaning | Additional fields |
 |---|---|---|
-| `BroadcastTablesTooLarge` | The size of the broadcast tables used in the 
right hand side of the join exceeded the memory reserved for them in a worker 
task.<br /><br />Try increasing the peon memory or reducing the size of the 
broadcast tables. | `maxBroadcastTablesSize`: Memory reserved for the broadcast 
tables, measured in bytes. |
-| `Canceled` | The query was canceled. Common reasons for cancellation:<br 
/><br /><ul><li>User-initiated shutdown of the controller task via the 
`/druid/indexer/v1/task/{taskId}/shutdown` API.</li><li>Restart or failure of 
the server process that was running the controller task.</li></ul>| |
-| `CannotParseExternalData` | A worker task could not parse data from an 
external datasource. | `errorMessage`: More details on why parsing failed. |
-| `ColumnNameRestricted` | The query uses a restricted column name. | 
`columnName`: The restricted column name. |
-| `ColumnTypeNotSupported` | The column type is not supported. This can be 
because:<br /> <br /><ul><li>Support for writing or reading from a particular 
column type is not supported.</li><li>The query attempted to use a column type 
that is not supported by the frame format. This occurs with ARRAY types, which 
are not yet implemented for frames.</li></ul> | `columnName`: The column name 
with an unsupported type.<br /> <br />`columnType`: The unknown column type. |
-| `InsertCannotAllocateSegment` | The controller task could not allocate a new 
segment ID due to conflict with existing segments or pending segments. Common 
reasons for such conflicts:<br /> <br /><ul><li>Attempting to mix different 
granularities in the same intervals of the same datasource.</li><li>Prior 
ingestions that used non-extendable shard specs.</li></ul>| `dataSource`<br /> 
<br />`interval`: The interval for the attempted new segment allocation. |
-| `InsertCannotBeEmpty` | An INSERT or REPLACE query did not generate any 
output rows in a situation where output rows are required for success. This can 
happen for INSERT or REPLACE queries with `PARTITIONED BY` set to something 
other than `ALL` or `ALL TIME`. | `dataSource` |
-| `InsertCannotOrderByDescending` | An INSERT query contained a `CLUSTERED BY` 
expression in descending order. Druid's segment generation code only supports 
ascending order. | `columnName` |
-| `InsertCannotReplaceExistingSegment` | A REPLACE query cannot proceed 
because an existing segment partially overlaps those bounds, and the portion 
within the bounds is not fully overshadowed by query results. <br /> <br 
/>There are two ways to address this without modifying your 
query:<ul><li>Shrink the OVERLAP filter to match the query 
results.</li><li>Expand the OVERLAP filter to fully contain the existing 
segment.</li></ul>| `segmentId`: The existing segment <br />
-| `InsertLockPreempted` | An INSERT or REPLACE query was canceled by a 
higher-priority ingestion job, such as a real-time ingestion task. | |
-| `InsertTimeNull` | An INSERT or REPLACE query encountered a null timestamp 
in the `__time` field.<br /><br />This can happen due to using an expression 
like `TIME_PARSE(timestamp) AS __time` with a timestamp that cannot be parsed. 
(TIME_PARSE returns null when it cannot parse a timestamp.) In this case, try 
parsing your timestamps using a different function or pattern.<br /><br />If 
your timestamps may genuinely be null, consider using COALESCE to provide a 
default value. One option is [...]
-| `InsertTimeOutOfBounds` | A REPLACE query generated a timestamp outside the 
bounds of the TIMESTAMP parameter for your OVERWRITE WHERE clause.<br /> <br 
/>To avoid this error, verify that the you specified is valid. | `interval`: 
time chunk interval corresponding to the out-of-bounds timestamp |
-| `InvalidNullByte` | A string column included a null byte. Null bytes in 
strings are not permitted. | `column`: The column that included the null byte |
-| `QueryNotSupported` | QueryKit could not translate the provided native query 
to a multi-stage query.<br /> <br />This can happen if the query uses features 
that aren't supported, like GROUPING SETS. | |
-| `RowTooLarge` | The query tried to process a row that was too large to write 
to a single frame. See the [Limits](#limits) table for the specific limit on 
frame size. Note that the effective maximum row size is smaller than the 
maximum frame size due to alignment considerations during frame writing. | 
`maxFrameSize`: The limit on the frame size. |
-| `TaskStartTimeout` | Unable to launch all the worker tasks in time. <br /> 
<br />There might be insufficient available slots to start all the worker tasks 
simultaneously.<br /> <br /> Try splitting up the query into smaller chunks 
with lesser `maxNumTasks` number. Another option is to increase capacity. | 
`numTasks`: The number of tasks attempted to launch. |
-| `TooManyBuckets` | Exceeded the number of partition buckets for a stage. 
Partition buckets are only used for `segmentGranularity` during INSERT queries. 
The most common reason for this error is that your `segmentGranularity` is too 
narrow relative to the data. See the [Limits](#limits) table for the specific 
limit. | `maxBuckets`: The limit on buckets. |
-| `TooManyInputFiles` | Exceeded the number of input files/segments per 
worker. See the [Limits](#limits) table for the specific limit. | 
`numInputFiles`: The total number of input files/segments for the stage.<br 
/><br />`maxInputFiles`: The maximum number of input files/segments per worker 
per stage.<br /><br />`minNumWorker`: The minimum number of workers required 
for a successful run. |
-| `TooManyPartitions` | Exceeded the number of partitions for a stage. The 
most common reason for this is that the final stage of an INSERT or REPLACE 
query generated too many segments. See the [Limits](#limits) table for the 
specific limit. | `maxPartitions`: The limit on partitions which was exceeded |
-|  `TooManyClusteredByColumns`  | Exceeded the number of cluster by columns 
for a stage. See the [Limits](#limits) table for the specific limit. | 
`numColumns`: The number of columns requested.<br /><br />`maxColumns`: The 
limit on columns which was exceeded.`stage`: The stage number exceeding the 
limit<br /><br /> |
-| `TooManyColumns` | Exceeded the number of columns for a stage. See the 
[Limits](#limits) table for the specific limit. | `numColumns`: The number of 
columns requested.<br /><br />`maxColumns`: The limit on columns which was 
exceeded. |
-| `TooManyWarnings` | Exceeded the allowed number of warnings of a particular 
type. | `rootErrorCode`: The error code corresponding to the exception that 
exceeded the required limit. <br /><br />`maxWarnings`: Maximum number of 
warnings that are allowed for the corresponding `rootErrorCode`. |
-| `TooManyWorkers` | Exceeded the supported number of workers running 
simultaneously. See the [Limits](#limits) table for the specific limit. | 
`workers`: The number of simultaneously running workers that exceeded a hard or 
soft limit. This may be larger than the number of workers in any one stage if 
multiple stages are running simultaneously. <br /><br />`maxWorkers`: The hard 
or soft limit on workers that was exceeded. |
-| `NotEnoughMemory` | Insufficient memory to launch a stage. | `serverMemory`: 
The amount of memory available to a single process.<br /><br />`serverWorkers`: 
The number of workers running in a single process.<br /><br />`serverThreads`: 
The number of threads in a single process. |
-| `WorkerFailed` | A worker task failed unexpectedly. | `errorMsg`<br /><br 
/>`workerTaskId`: The ID of the worker task. |
-| `WorkerRpcFailed` | A remote procedure call to a worker task failed and 
could not recover. | `workerTaskId`: the id of the worker task |
-| `UnknownError` | All other errors. | `message` |
+| <a name="error_BroadcastTablesTooLarge">`BroadcastTablesTooLarge`</a> | The 
size of the broadcast tables used in the right hand side of the join exceeded 
the memory reserved for them in a worker task.<br /><br />Try increasing the 
peon memory or reducing the size of the broadcast tables. | 
`maxBroadcastTablesSize`: Memory reserved for the broadcast tables, measured in 
bytes. |
+| <a name="error_Canceled">`Canceled`</a> | The query was canceled. Common 
reasons for cancellation:<br /><br /><ul><li>User-initiated shutdown of the 
controller task via the `/druid/indexer/v1/task/{taskId}/shutdown` 
API.</li><li>Restart or failure of the server process that was running the 
controller task.</li></ul>| |
+| <a name="error_CannotParseExternalData">`CannotParseExternalData`</a> | A 
worker task could not parse data from an external datasource. | `errorMessage`: 
More details on why parsing failed. |
+| <a name="error_ColumnNameRestricted">`ColumnNameRestricted`</a> | The query 
uses a restricted column name. | `columnName`: The restricted column name. |
+| <a name="error_ColumnTypeNotSupported">`ColumnTypeNotSupported`</a> | The 
column type is not supported. This can be because:<br /> <br /><ul><li>Support 
for writing or reading from a particular column type is not 
supported.</li><li>The query attempted to use a column type that is not 
supported by the frame format. This occurs with ARRAY types, which are not yet 
implemented for frames.</li></ul> | `columnName`: The column name with an 
unsupported type.<br /> <br />`columnType`: The unkn [...]
+| <a 
name="error_InsertCannotAllocateSegment">`InsertCannotAllocateSegment`</a> | 
The controller task could not allocate a new segment ID due to conflict with 
existing segments or pending segments. Common reasons for such conflicts:<br /> 
<br /><ul><li>Attempting to mix different granularities in the same intervals 
of the same datasource.</li><li>Prior ingestions that used non-extendable shard 
specs.</li></ul>| `dataSource`<br /> <br />`interval`: The interval for the 
attempted new segme [...]
+| <a name="error_InsertCannotBeEmpty">`InsertCannotBeEmpty`</a> | An INSERT or 
REPLACE query did not generate any output rows in a situation where output rows 
are required for success. This can happen for INSERT or REPLACE queries with 
`PARTITIONED BY` set to something other than `ALL` or `ALL TIME`. | 
`dataSource` |
+| <a 
name="error_InsertCannotOrderByDescending">`InsertCannotOrderByDescending`</a> 
| An INSERT query contained a `CLUSTERED BY` expression in descending order. 
Druid's segment generation code only supports ascending order. | `columnName` |
+| <a 
name="error_InsertCannotReplaceExistingSegment">`InsertCannotReplaceExistingSegment`</a>
 | A REPLACE query cannot proceed because an existing segment partially 
overlaps those bounds, and the portion within the bounds is not fully 
overshadowed by query results. <br /> <br />There are two ways to address this 
without modifying your query:<ul><li>Shrink the OVERLAP filter to match the 
query results.</li><li>Expand the OVERLAP filter to fully contain the existing 
segment.</li></ul>| `se [...]
+| <a name="error_InsertLockPreempted">`InsertLockPreempted`</a> | An INSERT or 
REPLACE query was canceled by a higher-priority ingestion job, such as a 
real-time ingestion task. | |
+| <a name="error_InsertTimeNull">`InsertTimeNull`</a> | An INSERT or REPLACE 
query encountered a null timestamp in the `__time` field.<br /><br />This can 
happen due to using an expression like `TIME_PARSE(timestamp) AS __time` with a 
timestamp that cannot be parsed. (TIME_PARSE returns null when it cannot parse 
a timestamp.) In this case, try parsing your timestamps using a different 
function or pattern.<br /><br />If your timestamps may genuinely be null, 
consider using COALESCE to pro [...]
+| <a name="error_InsertTimeOutOfBounds">`InsertTimeOutOfBounds`</a> | A 
REPLACE query generated a timestamp outside the bounds of the TIMESTAMP 
parameter for your OVERWRITE WHERE clause.<br /> <br />To avoid this error, 
verify that the you specified is valid. | `interval`: time chunk interval 
corresponding to the out-of-bounds timestamp |
+| <a name="error_InvalidNullByte">`InvalidNullByte`</a> | A string column 
included a null byte. Null bytes in strings are not permitted. | `column`: The 
column that included the null byte |
+| <a name="error_QueryNotSupported">`QueryNotSupported`</a> | QueryKit could 
not translate the provided native query to a multi-stage query.<br /> <br 
/>This can happen if the query uses features that aren't supported, like 
GROUPING SETS. | |
+| <a name="error_RowTooLarge">`RowTooLarge`</a> | The query tried to process a 
row that was too large to write to a single frame. See the [Limits](#limits) 
table for specific limits on frame size. Note that the effective maximum row 
size is smaller than the maximum frame size due to alignment considerations 
during frame writing. | `maxFrameSize`: The limit on the frame size. |
+| <a name="error_TaskStartTimeout">`TaskStartTimeout`</a> | Unable to launch 
all the worker tasks in time. <br /> <br />There might be insufficient 
available slots to start all the worker tasks simultaneously.<br /> <br /> Try 
splitting up the query into smaller chunks with lesser `maxNumTasks` number. 
Another option is to increase capacity. | `numTasks`: The number of tasks 
attempted to launch. |
+| <a name="error_TooManyBuckets">`TooManyBuckets`</a> | Exceeded the maximum 
number of partition buckets for a stage (5,000 partition buckets).<br />< br 
/>Partition buckets are created for each [`PARTITIONED BY`](#partitioned-by) 
time chunk for INSERT and REPLACE queries. The most common reason for this 
error is that your `PARTITIONED BY` is too narrow relative to your data. | 
`maxBuckets`: The limit on partition buckets. |
+| <a name="error_TooManyInputFiles">`TooManyInputFiles`</a> | Exceeded the 
maximum number of input files or segments per worker (10,000 files or 
segments).<br /><br />If you encounter this limit, consider adding more 
workers, or breaking up your query into smaller queries that process fewer 
files or segments per query. | `numInputFiles`: The total number of input 
files/segments for the stage.<br /><br />`maxInputFiles`: The maximum number of 
input files/segments per worker per stage.<br  [...]
+| <a name="error_TooManyPartitions">`TooManyPartitions`</a> | Exceeded the 
maximum number of partitions for a stage (25,000 partitions).<br /><br />This 
can occur with INSERT or REPLACE statements that generate large numbers of 
segments, since each segment is associated with a partition. If you encounter 
this limit, consider breaking up your INSERT or REPLACE statement into smaller 
statements that process less data per statement. | `maxPartitions`: The limit 
on partitions which was exceeded |
+| <a name="error_TooManyClusteredByColumns">`TooManyClusteredByColumns`</a>  | 
Exceeded the maximum number of clustering columns for a stage (1,500 
columns).<br /><br />This can occur with `CLUSTERED BY`, `ORDER BY`, or `GROUP 
BY` with a large number of columns. | `numColumns`: The number of columns 
requested.<br /><br />`maxColumns`: The limit on columns which was 
exceeded.`stage`: The stage number exceeding the limit<br /><br /> |
+| <a name="error_TooManyColumns">`TooManyColumns`</a> | Exceeded the maximum 
number of columns for a stage (2,000 columns). | `numColumns`: The number of 
columns requested.<br /><br />`maxColumns`: The limit on columns which was 
exceeded. |
+| <a name="error_TooManyWarnings">`TooManyWarnings`</a> | Exceeded the maximum 
allowed number of warnings of a particular type. | `rootErrorCode`: The error 
code corresponding to the exception that exceeded the required limit. <br /><br 
/>`maxWarnings`: Maximum number of warnings that are allowed for the 
corresponding `rootErrorCode`. |
+| <a name="error_TooManyWorkers">`TooManyWorkers`</a> | Exceeded the maximum 
number of simultaneously-running workers. See the [Limits](#limits) table for 
more details. | `workers`: The number of simultaneously running workers that 
exceeded a hard or soft limit. This may be larger than the number of workers in 
any one stage if multiple stages are running simultaneously. <br /><br 
/>`maxWorkers`: The hard or soft limit on workers that was exceeded. If this is 
lower than the hard limit (1, [...]
+| <a name="error_NotEnoughMemory">`NotEnoughMemory`</a> | Insufficient memory 
to launch a stage. | `serverMemory`: The amount of memory available to a single 
process.<br /><br />`serverWorkers`: The number of workers running in a single 
process.<br /><br />`serverThreads`: The number of threads in a single process. 
|
+| <a name="error_WorkerFailed">`WorkerFailed`</a> | A worker task failed 
unexpectedly. | `errorMsg`<br /><br />`workerTaskId`: The ID of the worker 
task. |
+| <a name="error_WorkerRpcFailed">`WorkerRpcFailed`</a> | A remote procedure 
call to a worker task failed and could not recover. | `workerTaskId`: the id of 
the worker task |
+| <a name="error_UnknownError">`UnknownError`</a> | All other errors. | 
`message` |
diff --git 
a/extensions-core/multi-stage-query/src/main/java/org/apache/druid/msq/indexing/error/TooManyBucketsFault.java
 
b/extensions-core/multi-stage-query/src/main/java/org/apache/druid/msq/indexing/error/TooManyBucketsFault.java
index 8af20d0919..fdad421e64 100644
--- 
a/extensions-core/multi-stage-query/src/main/java/org/apache/druid/msq/indexing/error/TooManyBucketsFault.java
+++ 
b/extensions-core/multi-stage-query/src/main/java/org/apache/druid/msq/indexing/error/TooManyBucketsFault.java
@@ -41,7 +41,7 @@ public class TooManyBucketsFault extends BaseMSQFault
     super(
         CODE,
         "Too many partition buckets (max = %,d); try breaking your query up 
into smaller queries or "
-        + "using a wider segmentGranularity",
+        + "using a wider PARTITIONED BY",
         maxBuckets
     );
     this.maxBuckets = maxBuckets;
diff --git a/web-console/lib/keywords.js b/web-console/lib/keywords.js
index e34b2daf45..bc81153dd7 100644
--- a/web-console/lib/keywords.js
+++ b/web-console/lib/keywords.js
@@ -61,6 +61,9 @@ exports.SQL_KEYWORDS = [
   'REPLACE INTO',
   'OVERWRITE',
   'RETURNING',
+  'OVER',
+  'PARTITION BY',
+  'WINDOW',
 ];
 
 exports.SQL_EXPRESSION_PARTS = [
diff --git a/web-console/script/create-sql-docs.js 
b/web-console/script/create-sql-docs.js
index 6af65006f8..13ed438915 100755
--- a/web-console/script/create-sql-docs.js
+++ b/web-console/script/create-sql-docs.js
@@ -52,9 +52,7 @@ function convertMarkdownToHtml(markdown) {
   // Concert to markdown
   markdown = snarkdown(markdown);
 
-  return markdown
-    .replace(/<br \/>/g, '<br /><br />') // Double up the <br>s
-    .replace(/<a[^>]*>(.*?)<\/a>/g, '$1'); // Remove links
+  return markdown.replace(/<a[^>]*>(.*?)<\/a>/g, '$1'); // Remove links
 }
 
 const readDoc = async () => {
diff --git a/web-console/src/bootstrap/react-table-defaults.tsx 
b/web-console/src/bootstrap/react-table-defaults.tsx
index 4c31928064..139a13bcd5 100644
--- a/web-console/src/bootstrap/react-table-defaults.tsx
+++ b/web-console/src/bootstrap/react-table-defaults.tsx
@@ -53,12 +53,12 @@ export function bootstrapReactTable() {
         .map((row: any) => row[column.id]);
       const previewCount = countBy(previewValues);
       return (
-        <span>
+        <div className="default-aggregated">
           {Object.keys(previewCount)
             .sort()
             .map(v => `${v} (${previewCount[v]})`)
             .join(', ')}
-        </span>
+        </div>
       );
     },
     defaultPageSize: 20,
diff --git a/web-console/src/components/segment-timeline/segment-timeline.tsx 
b/web-console/src/components/segment-timeline/segment-timeline.tsx
index c138e82dff..f8cef06189 100644
--- a/web-console/src/components/segment-timeline/segment-timeline.tsx
+++ b/web-console/src/components/segment-timeline/segment-timeline.tsx
@@ -278,7 +278,7 @@ ORDER BY "start" DESC`;
             intervals = await queryDruidSql({
               query: SegmentTimeline.getSqlQuery(startDate, endDate),
             });
-            datasources = uniq(intervals.map(r => r.datasource));
+            datasources = uniq(intervals.map(r => r.datasource).sort());
           } else if (capabilities.hasCoordinatorAccess()) {
             const startIso = startDate.toISOString();
 
diff --git a/web-console/src/dialogs/compaction-dialog/compaction-dialog.scss 
b/web-console/src/dialogs/compaction-dialog/compaction-dialog.scss
index e3ca37b14e..499df985c9 100644
--- a/web-console/src/dialogs/compaction-dialog/compaction-dialog.scss
+++ b/web-console/src/dialogs/compaction-dialog/compaction-dialog.scss
@@ -23,6 +23,11 @@
     height: 80vh;
   }
 
+  .legacy-callout {
+    width: auto;
+    margin: 10px 15px 0;
+  }
+
   .form-json-selector {
     margin: 15px;
   }
diff --git a/web-console/src/dialogs/compaction-dialog/compaction-dialog.tsx 
b/web-console/src/dialogs/compaction-dialog/compaction-dialog.tsx
index d63501b1b0..3b5456e7d0 100644
--- a/web-console/src/dialogs/compaction-dialog/compaction-dialog.tsx
+++ b/web-console/src/dialogs/compaction-dialog/compaction-dialog.tsx
@@ -16,11 +16,16 @@
  * limitations under the License.
  */
 
-import { Button, Classes, Dialog, Intent } from '@blueprintjs/core';
+import { Button, Callout, Classes, Code, Dialog, Intent } from 
'@blueprintjs/core';
 import React, { useState } from 'react';
 
 import { AutoForm, FormJsonSelector, FormJsonTabs, JsonInput } from 
'../../components';
-import { COMPACTION_CONFIG_FIELDS, CompactionConfig } from 
'../../druid-models';
+import {
+  COMPACTION_CONFIG_FIELDS,
+  CompactionConfig,
+  compactionConfigHasLegacyInputSegmentSizeBytesSet,
+} from '../../druid-models';
+import { deepDelete, formatBytesCompact } from '../../utils';
 
 import './compaction-dialog.scss';
 
@@ -55,13 +60,29 @@ export const CompactionDialog = React.memo(function 
CompactionDialog(props: Comp
       canOutsideClickClose={false}
       title={`Compaction config: ${datasource}`}
     >
+      {compactionConfigHasLegacyInputSegmentSizeBytesSet(currentConfig) && (
+        <Callout className="legacy-callout" intent={Intent.WARNING}>
+          <p>
+            You current config sets the legacy 
<Code>inputSegmentSizeBytes</Code> to{' '}
+            
<Code>{formatBytesCompact(currentConfig.inputSegmentSizeBytes!)}</Code> it is
+            recommended to unset this property.
+          </p>
+          <p>
+            <Button
+              intent={Intent.WARNING}
+              text="Remove legacy setting"
+              onClick={() => setCurrentConfig(deepDelete(currentConfig, 
'inputSegmentSizeBytes'))}
+            />
+          </p>
+        </Callout>
+      )}
       <FormJsonSelector tab={currentTab} onChange={setCurrentTab} />
       <div className="content">
         {currentTab === 'form' ? (
           <AutoForm
             fields={COMPACTION_CONFIG_FIELDS}
             model={currentConfig}
-            onChange={m => setCurrentConfig(m)}
+            onChange={m => setCurrentConfig(m as CompactionConfig)}
           />
         ) : (
           <JsonInput
diff --git 
a/web-console/src/druid-models/compaction-config/compaction-config.tsx 
b/web-console/src/druid-models/compaction-config/compaction-config.tsx
index 1958f2b263..b03b66ea0e 100644
--- a/web-console/src/druid-models/compaction-config/compaction-config.tsx
+++ b/web-console/src/druid-models/compaction-config/compaction-config.tsx
@@ -22,7 +22,26 @@ import React from 'react';
 import { Field } from '../../components';
 import { deepGet, deepSet, oneOf } from '../../utils';
 
-export type CompactionConfig = Record<string, any>;
+export interface CompactionConfig {
+  dataSource: string;
+  skipOffsetFromLatest?: string;
+  tuningConfig?: any;
+  [key: string]: any;
+
+  // Deprecated:
+  inputSegmentSizeBytes?: number;
+}
+
+export const NOOP_INPUT_SEGMENT_SIZE_BYTES = 100000000000000;
+
+export function compactionConfigHasLegacyInputSegmentSizeBytesSet(
+  config: CompactionConfig,
+): boolean {
+  return (
+    typeof config.inputSegmentSizeBytes === 'number' &&
+    config.inputSegmentSizeBytes < NOOP_INPUT_SEGMENT_SIZE_BYTES
+  );
+}
 
 export const COMPACTION_CONFIG_FIELDS: Field<CompactionConfig>[] = [
   {
@@ -182,7 +201,7 @@ export const COMPACTION_CONFIG_FIELDS: 
Field<CompactionConfig>[] = [
     defined: t =>
       oneOf(deepGet(t, 'tuningConfig.partitionsSpec.type'), 'single_dim', 
'range') &&
       !deepGet(t, 'tuningConfig.partitionsSpec.maxRowsPerSegment'),
-    required: (t: CompactionConfig) =>
+    required: t =>
       !deepGet(t, 'tuningConfig.partitionsSpec.targetRowsPerSegment') &&
       !deepGet(t, 'tuningConfig.partitionsSpec.maxRowsPerSegment'),
     info: (
@@ -205,7 +224,7 @@ export const COMPACTION_CONFIG_FIELDS: 
Field<CompactionConfig>[] = [
     defined: t =>
       oneOf(deepGet(t, 'tuningConfig.partitionsSpec.type'), 'single_dim', 
'range') &&
       !deepGet(t, 'tuningConfig.partitionsSpec.targetRowsPerSegment'),
-    required: (t: CompactionConfig) =>
+    required: t =>
       !deepGet(t, 'tuningConfig.partitionsSpec.targetRowsPerSegment') &&
       !deepGet(t, 'tuningConfig.partitionsSpec.maxRowsPerSegment'),
     info: (
@@ -277,7 +296,7 @@ export const COMPACTION_CONFIG_FIELDS: 
Field<CompactionConfig>[] = [
     defaultValue: 1073741824,
     min: 1000000,
     hideInMore: true,
-    adjustment: (t: CompactionConfig) => deepSet(t, 
'tuningConfig.splitHintSpec.type', 'maxSize'),
+    adjustment: t => deepSet(t, 'tuningConfig.splitHintSpec.type', 'maxSize'),
     info: (
       <>
         Maximum number of bytes of input segments to process in a single task. 
If a single segment
@@ -293,7 +312,7 @@ export const COMPACTION_CONFIG_FIELDS: 
Field<CompactionConfig>[] = [
     defaultValue: 1000,
     min: 1,
     hideInMore: true,
-    adjustment: (t: CompactionConfig) => deepSet(t, 
'tuningConfig.splitHintSpec.type', 'maxSize'),
+    adjustment: t => deepSet(t, 'tuningConfig.splitHintSpec.type', 'maxSize'),
     info: (
       <>
         Maximum number of input segments to process in a single subtask. This 
limit is to avoid task
diff --git 
a/web-console/src/druid-models/compaction-status/compaction-status.spec.ts 
b/web-console/src/druid-models/compaction-status/compaction-status.spec.ts
index 9d1254090b..abe660e5c2 100644
--- a/web-console/src/druid-models/compaction-status/compaction-status.spec.ts
+++ b/web-console/src/druid-models/compaction-status/compaction-status.spec.ts
@@ -21,7 +21,13 @@ import { CompactionConfig } from 
'../compaction-config/compaction-config';
 import { CompactionStatus, formatCompactionInfo, zeroCompactionStatus } from 
'./compaction-status';
 
 describe('compaction status', () => {
-  const BASIC_CONFIG: CompactionConfig = {};
+  const BASIC_CONFIG: CompactionConfig = {
+    dataSource: 'tbl',
+  };
+  const LEGACY_CONFIG: CompactionConfig = {
+    dataSource: 'tbl',
+    inputSegmentSizeBytes: 1e6,
+  };
   const ZERO_STATUS: CompactionStatus = {
     dataSource: 'tbl',
     scheduleStatus: 'RUNNING',
@@ -36,52 +42,112 @@ describe('compaction status', () => {
     intervalCountSkipped: 0,
   };
 
-  it('zeroCompactionStatus', () => {
-    expect(zeroCompactionStatus(ZERO_STATUS)).toEqual(true);
-
-    expect(
-      zeroCompactionStatus({
-        dataSource: 'tbl',
-        scheduleStatus: 'RUNNING',
-        bytesAwaitingCompaction: 1,
-        bytesCompacted: 0,
-        bytesSkipped: 0,
-        segmentCountAwaitingCompaction: 0,
-        segmentCountCompacted: 0,
-        segmentCountSkipped: 0,
-        intervalCountAwaitingCompaction: 0,
-        intervalCountCompacted: 0,
-        intervalCountSkipped: 0,
-      }),
-    ).toEqual(false);
-  });
-
-  it('formatCompactionConfigAndStatus', () => {
-    expect(formatCompactionInfo({})).toEqual('Not enabled');
-
-    expect(formatCompactionInfo({ config: BASIC_CONFIG })).toEqual('Awaiting 
first run');
-
-    expect(formatCompactionInfo({ status: ZERO_STATUS })).toEqual('Not 
enabled');
+  describe('zeroCompactionStatus', () => {
+    it('works with zero', () => {
+      expect(zeroCompactionStatus(ZERO_STATUS)).toEqual(true);
+    });
 
-    expect(formatCompactionInfo({ config: BASIC_CONFIG, status: ZERO_STATUS 
})).toEqual('Running');
-
-    expect(
-      formatCompactionInfo({
-        config: BASIC_CONFIG,
-        status: {
+    it('works with non-zero', () => {
+      expect(
+        zeroCompactionStatus({
           dataSource: 'tbl',
           scheduleStatus: 'RUNNING',
-          bytesAwaitingCompaction: 0,
-          bytesCompacted: 100,
+          bytesAwaitingCompaction: 1,
+          bytesCompacted: 0,
           bytesSkipped: 0,
           segmentCountAwaitingCompaction: 0,
-          segmentCountCompacted: 10,
+          segmentCountCompacted: 0,
           segmentCountSkipped: 0,
           intervalCountAwaitingCompaction: 0,
-          intervalCountCompacted: 10,
+          intervalCountCompacted: 0,
           intervalCountSkipped: 0,
-        },
-      }),
-    ).toEqual('Fully compacted');
+        }),
+      ).toEqual(false);
+    });
+  });
+
+  describe('formatCompactionConfigAndStatus', () => {
+    it('works with nothing', () => {
+      expect(formatCompactionInfo({})).toEqual('Not enabled');
+    });
+
+    it('works when there is no status', () => {
+      expect(formatCompactionInfo({ config: BASIC_CONFIG })).toEqual('Awaiting 
first run');
+    });
+
+    it('works when here is no config', () => {
+      expect(formatCompactionInfo({ status: ZERO_STATUS })).toEqual('Not 
enabled');
+    });
+
+    it('works with config and zero status', () => {
+      expect(formatCompactionInfo({ config: BASIC_CONFIG, status: ZERO_STATUS 
})).toEqual(
+        'Running',
+      );
+    });
+
+    it('works when fully compacted', () => {
+      expect(
+        formatCompactionInfo({
+          config: BASIC_CONFIG,
+          status: {
+            dataSource: 'tbl',
+            scheduleStatus: 'RUNNING',
+            bytesAwaitingCompaction: 0,
+            bytesCompacted: 100,
+            bytesSkipped: 0,
+            segmentCountAwaitingCompaction: 0,
+            segmentCountCompacted: 10,
+            segmentCountSkipped: 0,
+            intervalCountAwaitingCompaction: 0,
+            intervalCountCompacted: 10,
+            intervalCountSkipped: 0,
+          },
+        }),
+      ).toEqual('Fully compacted');
+    });
+
+    it('works when fully compacted and some segments skipped', () => {
+      expect(
+        formatCompactionInfo({
+          config: BASIC_CONFIG,
+          status: {
+            dataSource: 'tbl',
+            scheduleStatus: 'RUNNING',
+            bytesAwaitingCompaction: 0,
+            bytesCompacted: 0,
+            bytesSkipped: 3776979,
+            segmentCountAwaitingCompaction: 0,
+            segmentCountCompacted: 0,
+            segmentCountSkipped: 24,
+            intervalCountAwaitingCompaction: 0,
+            intervalCountCompacted: 0,
+            intervalCountSkipped: 24,
+          },
+        }),
+      ).toEqual('Fully compacted (except the last P1D of data, 24 segments 
skipped)');
+    });
+
+    it('works when fully compacted and some segments skipped (with legacy 
config)', () => {
+      expect(
+        formatCompactionInfo({
+          config: LEGACY_CONFIG,
+          status: {
+            dataSource: 'tbl',
+            scheduleStatus: 'RUNNING',
+            bytesAwaitingCompaction: 0,
+            bytesCompacted: 0,
+            bytesSkipped: 3776979,
+            segmentCountAwaitingCompaction: 0,
+            segmentCountCompacted: 0,
+            segmentCountSkipped: 24,
+            intervalCountAwaitingCompaction: 0,
+            intervalCountCompacted: 0,
+            intervalCountSkipped: 24,
+          },
+        }),
+      ).toEqual(
+        'Fully compacted (except the last P1D of data and segments larger than 
1.00MB, 24 segments skipped)',
+      );
+    });
   });
 });
diff --git 
a/web-console/src/druid-models/compaction-status/compaction-status.ts 
b/web-console/src/druid-models/compaction-status/compaction-status.ts
index d17f2c44fd..c19cb26b6c 100644
--- a/web-console/src/druid-models/compaction-status/compaction-status.ts
+++ b/web-console/src/druid-models/compaction-status/compaction-status.ts
@@ -16,7 +16,11 @@
  * limitations under the License.
  */
 
-import { CompactionConfig } from '../compaction-config/compaction-config';
+import { formatBytesCompact, pluralIfNeeded } from '../../utils';
+import {
+  CompactionConfig,
+  compactionConfigHasLegacyInputSegmentSizeBytesSet,
+} from '../compaction-config/compaction-config';
 
 function capitalizeFirst(str: string): string {
   return str.slice(0, 1).toUpperCase() + str.slice(1).toLowerCase();
@@ -59,8 +63,21 @@ export function formatCompactionInfo(compaction: 
CompactionInfo) {
   const { config, status } = compaction;
   if (config) {
     if (status) {
-      if (status.bytesAwaitingCompaction === 0 && 
!zeroCompactionStatus(status)) {
-        return 'Fully compacted';
+      if (
+        status.bytesAwaitingCompaction === 0 &&
+        status.segmentCountAwaitingCompaction === 0 &&
+        status.intervalCountAwaitingCompaction === 0 &&
+        !zeroCompactionStatus(status)
+      ) {
+        if (status.segmentCountSkipped) {
+          return `Fully compacted (except the last 
${config.skipOffsetFromLatest || 'P1D'} of data${
+            compactionConfigHasLegacyInputSegmentSizeBytesSet(config)
+              ? ` and segments larger than 
${formatBytesCompact(config.inputSegmentSizeBytes!)}`
+              : ''
+          }, ${pluralIfNeeded(status.segmentCountSkipped, 'segment')} 
skipped)`;
+        } else {
+          return 'Fully compacted';
+        }
       } else {
         return capitalizeFirst(status.scheduleStatus);
       }
diff --git 
a/web-console/src/druid-models/ingest-query-pattern/ingest-query-pattern.ts 
b/web-console/src/druid-models/ingest-query-pattern/ingest-query-pattern.ts
index f4dee926b6..7bdcaae50a 100644
--- a/web-console/src/druid-models/ingest-query-pattern/ingest-query-pattern.ts
+++ b/web-console/src/druid-models/ingest-query-pattern/ingest-query-pattern.ts
@@ -63,6 +63,7 @@ export function externalConfigToIngestQueryPattern(
   config: ExternalConfig,
   isArrays: boolean[],
   timeExpression: SqlExpression | undefined,
+  partitionedByHint: string | undefined,
 ): IngestQueryPattern {
   return {
     destinationTableName: 
guessDataSourceNameFromInputSource(config.inputSource) || 'data',
@@ -71,7 +72,7 @@ export function externalConfigToIngestQueryPattern(
     mainExternalConfig: config,
     filters: [],
     dimensions: externalConfigToInitDimensions(config, isArrays, 
timeExpression),
-    partitionedBy: timeExpression ? 'day' : 'all',
+    partitionedBy: partitionedByHint || (timeExpression ? 'day' : 'all'),
     clusteredBy: [],
   };
 }
diff --git a/web-console/src/druid-models/metric-spec/metric-spec.tsx 
b/web-console/src/druid-models/metric-spec/metric-spec.tsx
index 6b3290272e..4295310486 100644
--- a/web-console/src/druid-models/metric-spec/metric-spec.tsx
+++ b/web-console/src/druid-models/metric-spec/metric-spec.tsx
@@ -78,6 +78,7 @@ export const METRIC_SPEC_FIELDS: Field<MetricSpec>[] = [
       // Should the first / last aggregators become usable at ingestion time, 
reverse the changes made in:
       // https://github.com/apache/druid/pull/10794
       'thetaSketch',
+      'arrayOfDoublesSketch',
       {
         group: 'HLLSketch',
         suggestions: ['HLLSketchBuild', 'HLLSketchMerge'],
@@ -104,6 +105,7 @@ export const METRIC_SPEC_FIELDS: Field<MetricSpec>[] = [
       'doubleMax',
       'floatMax',
       'thetaSketch',
+      'arrayOfDoublesSketch',
       'HLLSketchBuild',
       'HLLSketchMerge',
       'quantilesDoublesSketch',
@@ -178,6 +180,47 @@ export const METRIC_SPEC_FIELDS: Field<MetricSpec>[] = [
       </>
     ),
   },
+  // arrayOfDoublesSketch
+  {
+    name: 'nominalEntries',
+    type: 'number',
+    defined: typeIs('arrayOfDoublesSketch'),
+    defaultValue: 16384,
+    info: (
+      <>
+        <p>
+          Parameter that determines the accuracy and size of the sketch. 
Higher k means higher
+          accuracy but more space to store sketches.
+        </p>
+        <p>Must be a power of 2.</p>
+        <p>
+          See the{' '}
+          <ExternalLink 
href="https://datasketches.apache.org/docs/Theta/ThetaErrorTable";>
+            Theta sketch accuracy
+          </ExternalLink>{' '}
+          for details.
+        </p>
+      </>
+    ),
+  },
+  {
+    name: 'metricColumns',
+    type: 'string-array',
+    defined: typeIs('arrayOfDoublesSketch'),
+    info: (
+      <>
+        If building sketches from raw data, an array of names of the input 
columns containing
+        numeric values to be associated with each distinct key.
+      </>
+    ),
+  },
+  {
+    name: 'numberOfValues',
+    type: 'number',
+    defined: typeIs('arrayOfDoublesSketch'),
+    placeholder: 'metricColumns length or 1',
+    info: <>Number of values associated with each distinct key.</>,
+  },
   // HLLSketchBuild & HLLSketchMerge
   {
     name: 'lgK',
diff --git a/web-console/src/druid-models/workbench-query/workbench-query.ts 
b/web-console/src/druid-models/workbench-query/workbench-query.ts
index 36c71cb07a..b6a1f74aa1 100644
--- a/web-console/src/druid-models/workbench-query/workbench-query.ts
+++ b/web-console/src/druid-models/workbench-query/workbench-query.ts
@@ -82,13 +82,19 @@ export class WorkbenchQuery {
     externalConfig: ExternalConfig,
     isArrays: boolean[],
     timeExpression: SqlExpression | undefined,
+    partitionedByHint: string | undefined,
   ): WorkbenchQuery {
     return new WorkbenchQuery({
       queryContext: {},
       queryParts: [
         WorkbenchQueryPart.fromQueryString(
           ingestQueryPatternToQuery(
-            externalConfigToIngestQueryPattern(externalConfig, isArrays, 
timeExpression),
+            externalConfigToIngestQueryPattern(
+              externalConfig,
+              isArrays,
+              timeExpression,
+              partitionedByHint,
+            ),
           ).toString(),
         ),
       ],
diff --git a/web-console/src/helpers/execution/sql-task-execution.ts 
b/web-console/src/helpers/execution/sql-task-execution.ts
index e7f7250c53..358eee25c5 100644
--- a/web-console/src/helpers/execution/sql-task-execution.ts
+++ b/web-console/src/helpers/execution/sql-task-execution.ts
@@ -124,9 +124,14 @@ export async function reattachTaskExecution(
   option: ReattachTaskQueryOptions,
 ): Promise<Execution | IntermediateQueryState<Execution>> {
   const { id, cancelToken, preserveOnTermination } = option;
-  let execution = await getTaskExecution(id, undefined, cancelToken);
+  let execution: Execution;
 
-  execution = await updateExecutionWithDatasourceExistsIfNeeded(execution, 
cancelToken);
+  try {
+    execution = await getTaskExecution(id, undefined, cancelToken);
+    execution = await updateExecutionWithDatasourceExistsIfNeeded(execution, 
cancelToken);
+  } catch (e) {
+    throw new Error(`Reattaching to query failed due to: ${e.message}`);
+  }
 
   if (execution.isFullyComplete()) return execution;
 
diff --git a/web-console/src/links.ts b/web-console/src/links.ts
index 5c391d838e..6f61c29d05 100644
--- a/web-console/src/links.ts
+++ b/web-console/src/links.ts
@@ -84,7 +84,7 @@ export function getLink(linkName: LinkNames): string {
     case 'DOCS_API':
       return `${links.docsHref}/operations/api-reference.html`;
     case 'DOCS_MSQ_ERROR':
-      return `${links.docsHref}/multi-stage-query/concepts.html#error-codes`;
+      return `${links.docsHref}/multi-stage-query/reference.html`;
     case 'COMMUNITY':
       return links.communityHref;
     case 'SLACK':
diff --git a/web-console/src/react-table/react-table-extra.scss 
b/web-console/src/react-table/react-table-extra.scss
index d87c25c84d..bdeecf5e96 100644
--- a/web-console/src/react-table/react-table-extra.scss
+++ b/web-console/src/react-table/react-table-extra.scss
@@ -45,4 +45,8 @@
       }
     }
   }
+
+  .default-aggregated {
+    padding: 10px 5px;
+  }
 }
diff --git 
a/web-console/src/views/datasources-view/__snapshots__/datasources-view.spec.tsx.snap
 
b/web-console/src/views/datasources-view/__snapshots__/datasources-view.spec.tsx.snap
index c48713eff2..9bb9c16fef 100644
--- 
a/web-console/src/views/datasources-view/__snapshots__/datasources-view.spec.tsx.snap
+++ 
b/web-console/src/views/datasources-view/__snapshots__/datasources-view.spec.tsx.snap
@@ -283,7 +283,7 @@ exports[`DatasourcesView matches snapshot 1`] = `
           "filterable": false,
           "id": "compactionStatus",
           "show": true,
-          "width": 150,
+          "width": 180,
         },
         Object {
           "Cell": [Function],
diff --git a/web-console/src/views/datasources-view/datasources-view.tsx 
b/web-console/src/views/datasources-view/datasources-view.tsx
index c38a42b639..38b85388d2 100644
--- a/web-console/src/views/datasources-view/datasources-view.tsx
+++ b/web-console/src/views/datasources-view/datasources-view.tsx
@@ -1324,7 +1324,7 @@ ORDER BY 1`;
             id: 'compactionStatus',
             accessor: row => Boolean(row.compaction?.status),
             filterable: false,
-            width: 150,
+            width: 180,
             Cell: ({ original }) => {
               const { datasource, compaction } = original as Datasource;
               return (
diff --git 
a/web-console/src/views/sql-data-loader-view/sql-data-loader-view.tsx 
b/web-console/src/views/sql-data-loader-view/sql-data-loader-view.tsx
index 23c81d02d2..2b3126372a 100644
--- a/web-console/src/views/sql-data-loader-view/sql-data-loader-view.tsx
+++ b/web-console/src/views/sql-data-loader-view/sql-data-loader-view.tsx
@@ -151,6 +151,7 @@ export const SqlDataLoaderView = React.memo(function 
SqlDataLoaderView(
                     { inputSource, inputFormat, signature },
                     isArrays,
                     timeExpression,
+                    undefined,
                   ),
                 ).toString(),
                 queryContext: {
@@ -167,6 +168,7 @@ export const SqlDataLoaderView = React.memo(function 
SqlDataLoaderView(
                     { inputSource, inputFormat, signature },
                     isArrays,
                     timeExpression,
+                    undefined,
                   ),
                 ).toString(),
               });
diff --git 
a/web-console/src/views/workbench-view/connect-external-data-dialog/connect-external-data-dialog.tsx
 
b/web-console/src/views/workbench-view/connect-external-data-dialog/connect-external-data-dialog.tsx
index d857d37dbf..e043cf1340 100644
--- 
a/web-console/src/views/workbench-view/connect-external-data-dialog/connect-external-data-dialog.tsx
+++ 
b/web-console/src/views/workbench-view/connect-external-data-dialog/connect-external-data-dialog.tsx
@@ -20,7 +20,7 @@ import { Classes, Dialog } from '@blueprintjs/core';
 import { SqlExpression } from 'druid-query-toolkit';
 import React, { useState } from 'react';
 
-import { ExternalConfig } from '../../../druid-models';
+import { ExternalConfig, InputFormat, InputSource } from 
'../../../druid-models';
 import { InputFormatStep } from '../input-format-step/input-format-step';
 import { InputSourceStep } from '../input-source-step/input-source-step';
 
@@ -32,20 +32,27 @@ export interface ConnectExternalDataDialogProps {
     config: ExternalConfig,
     isArrays: boolean[],
     timeExpression: SqlExpression | undefined,
+    partitionedByHint: string | undefined,
   ): void;
   onClose(): void;
 }
 
+interface ExternalConfigStep {
+  inputSource?: InputSource;
+  inputFormat?: InputFormat;
+  partitionedByHint?: string;
+}
+
 export const ConnectExternalDataDialog = React.memo(function 
ConnectExternalDataDialog(
   props: ConnectExternalDataDialogProps,
 ) {
   const { initExternalConfig, onClose, onSetExternalConfig } = props;
 
-  const [externalConfigStep, setExternalConfigStep] = 
useState<Partial<ExternalConfig>>(
+  const [externalConfigStep, setExternalConfigStep] = 
useState<ExternalConfigStep>(
     initExternalConfig || {},
   );
 
-  const { inputSource, inputFormat } = externalConfigStep;
+  const { inputSource, inputFormat, partitionedByHint } = externalConfigStep;
 
   return (
     <Dialog
@@ -65,6 +72,7 @@ export const ConnectExternalDataDialog = React.memo(function 
ConnectExternalData
                 { inputSource, inputFormat, signature },
                 isArrays,
                 timeExpression,
+                partitionedByHint,
               );
               onClose();
             }}
@@ -76,8 +84,8 @@ export const ConnectExternalDataDialog = React.memo(function 
ConnectExternalData
           <InputSourceStep
             initInputSource={inputSource}
             mode="sampler"
-            onSet={(inputSource, inputFormat) => {
-              setExternalConfigStep({ inputSource, inputFormat });
+            onSet={(inputSource, inputFormat, partitionedByHint) => {
+              setExternalConfigStep({ inputSource, inputFormat, 
partitionedByHint });
             }}
           />
         )}
diff --git 
a/web-console/src/views/workbench-view/execution-error-pane/__snapshots__/execution-error-pane.spec.tsx.snap
 
b/web-console/src/views/workbench-view/execution-error-pane/__snapshots__/execution-error-pane.spec.tsx.snap
index 24573eea25..ecd700f396 100644
--- 
a/web-console/src/views/workbench-view/execution-error-pane/__snapshots__/execution-error-pane.spec.tsx.snap
+++ 
b/web-console/src/views/workbench-view/execution-error-pane/__snapshots__/execution-error-pane.spec.tsx.snap
@@ -9,7 +9,7 @@ exports[`ExecutionErrorPane matches snapshot 1`] = `
     className="error-message-text"
   >
     <Memo(ExternalLink)
-      
href="https://druid.apache.org/docs/25.0.0/multi-stage-query/concepts.html#error-codes";
+      
href="https://druid.apache.org/docs/25.0.0/multi-stage-query/reference.html#error_TooManyWarnings";
     >
       TooManyWarnings
     </Memo(ExternalLink)>
diff --git 
a/web-console/src/views/workbench-view/execution-error-pane/execution-error-pane.tsx
 
b/web-console/src/views/workbench-view/execution-error-pane/execution-error-pane.tsx
index b0368534cc..967cea3b0e 100644
--- 
a/web-console/src/views/workbench-view/execution-error-pane/execution-error-pane.tsx
+++ 
b/web-console/src/views/workbench-view/execution-error-pane/execution-error-pane.tsx
@@ -46,7 +46,9 @@ export const ExecutionErrorPane = React.memo(function 
ExecutionErrorPane(
       <p className="error-message-text">
         {error.errorCode && (
           <>
-            <ExternalLink 
href={getLink('DOCS_MSQ_ERROR')}>{error.errorCode}</ExternalLink>
+            <ExternalLink 
href={`${getLink('DOCS_MSQ_ERROR')}#error_${error.errorCode}`}>
+              {error.errorCode}
+            </ExternalLink>
             {': '}
           </>
         )}
diff --git 
a/web-console/src/views/workbench-view/input-source-step/example-inputs.ts 
b/web-console/src/views/workbench-view/input-source-step/example-inputs.ts
index a74f1754b1..a6ad104c7f 100644
--- a/web-console/src/views/workbench-view/input-source-step/example-inputs.ts
+++ b/web-console/src/views/workbench-view/input-source-step/example-inputs.ts
@@ -23,6 +23,7 @@ export interface ExampleInput {
   description: string;
   inputSource: InputSource;
   inputFormat?: InputFormat;
+  partitionedByHint?: string;
 }
 
 const TRIPS_INPUT_FORMAT: InputFormat = {
@@ -122,6 +123,7 @@ export const EXAMPLE_INPUTS: ExampleInput[] = [
       ],
     },
     inputFormat: TRIPS_INPUT_FORMAT,
+    partitionedByHint: 'month',
   },
   {
     name: 'NYC Taxi cabs (all files)',
@@ -206,6 +208,7 @@ export const EXAMPLE_INPUTS: ExampleInput[] = [
       ],
     },
     inputFormat: TRIPS_INPUT_FORMAT,
+    partitionedByHint: 'month',
   },
   {
     name: 'FlightCarrierOnTime (1 month)',
diff --git 
a/web-console/src/views/workbench-view/input-source-step/input-source-step.tsx 
b/web-console/src/views/workbench-view/input-source-step/input-source-step.tsx
index f144e8f975..9ea55fd0d1 100644
--- 
a/web-console/src/views/workbench-view/input-source-step/input-source-step.tsx
+++ 
b/web-console/src/views/workbench-view/input-source-step/input-source-step.tsx
@@ -71,7 +71,11 @@ const ROWS_TO_SAMPLE = 50;
 export interface InputSourceStepProps {
   initInputSource: Partial<InputSource> | undefined;
   mode: 'sampler' | 'msq';
-  onSet(inputSource: InputSource, inputFormat: InputFormat): void;
+  onSet(
+    inputSource: InputSource,
+    inputFormat: InputFormat,
+    partitionedByHint: string | undefined,
+  ): void;
 }
 
 export const InputSourceStep = React.memo(function InputSourceStep(props: 
InputSourceStepProps) {
@@ -169,7 +173,11 @@ export const InputSourceStep = React.memo(function 
InputSourceStep(props: InputS
   useEffect(() => {
     const guessedInputFormat = guessedInputFormatState.data;
     if (!guessedInputFormat) return;
-    onSet(exampleInput?.inputSource || (inputSource as any), 
guessedInputFormat);
+    onSet(
+      exampleInput?.inputSource || (inputSource as any),
+      guessedInputFormat,
+      exampleInput?.partitionedByHint,
+    );
     // eslint-disable-next-line react-hooks/exhaustive-deps
   }, [guessedInputFormatState]);
 
diff --git a/web-console/src/views/workbench-view/workbench-view.tsx 
b/web-console/src/views/workbench-view/workbench-view.tsx
index 5d601d2fb6..56af602e43 100644
--- a/web-console/src/views/workbench-view/workbench-view.tsx
+++ b/web-console/src/views/workbench-view/workbench-view.tsx
@@ -324,9 +324,14 @@ export class WorkbenchView extends 
React.PureComponent<WorkbenchViewProps, Workb
 
     return (
       <ConnectExternalDataDialog
-        onSetExternalConfig={(externalConfig, isArrays, timeExpression) => {
+        onSetExternalConfig={(externalConfig, isArrays, timeExpression, 
partitionedByHint) => {
           this.handleNewTab(
-            WorkbenchQuery.fromInitExternalConfig(externalConfig, isArrays, 
timeExpression),
+            WorkbenchQuery.fromInitExternalConfig(
+              externalConfig,
+              isArrays,
+              timeExpression,
+              partitionedByHint,
+            ),
             'Ext ' + 
guessDataSourceNameFromInputSource(externalConfig.inputSource),
           );
         }}


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to