From 9632b873016dd0a1fa2421dd373ca6e909a6320b Mon Sep 17 00:00:00 2001 From: Walter Date: Thu, 14 May 2026 08:03:14 +0800 Subject: [PATCH 1/2] docs: add 4.17.0 release documentation - Add 4.17.0 on-prem release notes - Add Aggregate node entry to processing node docs - Document task list metrics for replication and transformation tasks - Add Paimon soft delete CDC guidance - Simplify the spelling check CI workflow to run only manually to avoid blocking pushes and pull requests --- .github/workflows/spelling.yml | 141 +------------ .../best-practice/heart-beat-task.md | 4 +- docs/connectors/warehouses-and-lake/paimon.md | 1 + docs/data-replication/monitor-task.md | 28 ++- .../aggregate-computing-node.md | 197 ++++++++++++++++++ .../data-transformation/monitor-view-tasks.md | 28 ++- docs/data-transformation/process-node.md | 6 + docs/images/aggregate_node_config.png | Bin 0 -> 44217 bytes docs/release-notes-on-prem.md | 37 ++++ 9 files changed, 298 insertions(+), 144 deletions(-) create mode 100644 docs/data-transformation/aggregate-computing-node.md create mode 100644 docs/images/aggregate_node_config.png diff --git a/.github/workflows/spelling.yml b/.github/workflows/spelling.yml index 1196badb..abd3e084 100644 --- a/.github/workflows/spelling.yml +++ b/.github/workflows/spelling.yml @@ -1,92 +1,20 @@ name: Check Spelling -# Comment management is handled through a secondary job, for details see: -# https://github.com/check-spelling/check-spelling/wiki/Feature%3A-Restricted-Permissions -# -# `jobs.comment-push` runs when a push is made to a repository and the `jobs.spelling` job needs to make a comment -# (in odd cases, it might actually run just to collapse a comment, but that's fairly rare) -# it needs `contents: write` in order to add a comment. -# -# `jobs.comment-pr` runs when a pull_request is made to a repository and the `jobs.spelling` job needs to make a comment -# or collapse a comment (in the case where it had previously made a comment and now no longer needs to show a comment) -# it needs `pull-requests: write` in order to manipulate those comments. - -# Updating pull request branches is managed via comment handling. -# For details, see: https://github.com/check-spelling/check-spelling/wiki/Feature:-Update-expect-list -# -# These elements work together to make it happen: -# -# `on.issue_comment` -# This event listens to comments by users asking to update the metadata. -# -# `jobs.update` -# This job runs in response to an issue_comment and will push a new commit -# to update the spelling metadata. -# -# `with.experimental_apply_changes_via_bot` -# Tells the action to support and generate messages that enable it -# to make a commit to update the spelling metadata. -# -# `with.ssh_key` -# In order to trigger workflows when the commit is made, you can provide a -# secret (typically, a write-enabled github deploy key). -# -# For background, see: https://github.com/check-spelling/check-spelling/wiki/Feature:-Update-with-deploy-key - -# Sarif reporting -# -# Access to Sarif reports is generally restricted (by GitHub) to members of the repository. -# -# Requires enabling `security-events: write` -# and configuring the action with `use_sarif: 1` -# -# For information on the feature, see: https://github.com/check-spelling/check-spelling/wiki/Feature:-Sarif-output - -# Minimal workflow structure: -# -# on: -# push: -# ... -# pull_request_target: -# ... -# jobs: -# # you only want the spelling job, all others should be omitted -# spelling: -# # remove `security-events: write` and `use_sarif: 1` -# # remove `experimental_apply_changes_via_bot: 1` -# ... otherwise adjust the `with:` as you wish +# This workflow is intentionally manual-only so spelling does not block pushes +# or pull requests. on: - push: - branches: - - "**" - tags-ignore: - - "**" - pull_request_target: - branches: - - "**" - types: - - 'opened' - - 'reopened' - - 'synchronize' - issue_comment: - types: - - 'created' + workflow_dispatch: jobs: spelling: name: Check Spelling permissions: contents: read - pull-requests: read - actions: read security-events: write - outputs: - followup: ${{ steps.spelling.outputs.followup }} runs-on: ubuntu-latest - if: ${{ contains(github.event_name, 'pull_request') || github.event_name == 'push' }} concurrency: - group: spelling-${{ github.event.pull_request.number || github.ref }} + group: spelling-${{ github.ref }} # note: If you use only_check_changed_files, you do not want cancel-in-progress cancel-in-progress: true steps: @@ -94,7 +22,6 @@ jobs: id: spelling uses: check-spelling/check-spelling@main with: - suppress_push_for_open_pull_request: ${{ github.actor != 'dependabot[bot]' && 1 }} checkout: true check_file_names: 0 spell_check_this: check-spelling/spell-check-this@prerelease @@ -102,65 +29,7 @@ jobs: use_magic_file: 0 report-timing: 1 warnings: bad-regex,binary-file,deprecated-feature,large-file,limited-references,no-newline-at-eof,noisy-file,non-alpha-in-dictionary,token-is-substring,unexpected-line-ending,whitespace-in-dictionary,minified-file,unsupported-configuration,no-files-to-check - experimental_apply_changes_via_bot: 1 - use_sarif: ${{ (!github.event.pull_request || (github.event.pull_request.head.repo.full_name == github.repository)) && 1 }} + use_sarif: 1 extra_dictionary_limit: 20 extra_dictionaries: cspell:software-terms/dict/softwareTerms.txt - - comment-push: - name: Report (Push) - # If your workflow isn't running on push, you can remove this job - runs-on: ubuntu-latest - needs: spelling - permissions: - contents: write - if: (success() || failure()) && needs.spelling.outputs.followup && github.event_name == 'push' - steps: - - name: comment - uses: check-spelling/check-spelling@main - with: - checkout: true - spell_check_this: check-spelling/spell-check-this@prerelease - task: ${{ needs.spelling.outputs.followup }} - - comment-pr: - name: Report (PR) - # If you workflow isn't running on pull_request*, you can remove this job - runs-on: ubuntu-latest - needs: spelling - permissions: - contents: read - pull-requests: write - if: (success() || failure()) && needs.spelling.outputs.followup && contains(github.event_name, 'pull_request') - steps: - - name: comment - uses: check-spelling/check-spelling@main - with: - checkout: true - spell_check_this: check-spelling/spell-check-this@prerelease - task: ${{ needs.spelling.outputs.followup }} - experimental_apply_changes_via_bot: 1 - - update: - name: Update PR - permissions: - contents: write - pull-requests: write - actions: read - runs-on: ubuntu-latest - if: ${{ - github.event_name == 'issue_comment' && - github.event.issue.pull_request && - contains(github.event.comment.body, '@check-spelling-bot apply') - }} - concurrency: - group: spelling-update-${{ github.event.issue.number }} - cancel-in-progress: false - steps: - - name: apply spelling updates - uses: check-spelling/check-spelling@main - with: - experimental_apply_changes_via_bot: 1 - checkout: true - ssh_key: "${{ secrets.CHECK_SPELLING }}" diff --git a/docs/case-practices/best-practice/heart-beat-task.md b/docs/case-practices/best-practice/heart-beat-task.md index 14e59b02..bdee7d45 100644 --- a/docs/case-practices/best-practice/heart-beat-task.md +++ b/docs/case-practices/best-practice/heart-beat-task.md @@ -5,9 +5,9 @@ TapData uses heartbeat tables to write timestamp information to the source datab ## Applicable Scenarios -* If the source database often has long periods without DML operations (such as data insertion), and you need to quickly determine the status of incremental tasks through the **Incremental Checkpoint** in the **Task List** to ensure the link status and incremental log acquisition are normal. +* If the source database often has long periods without DML operations (such as data insertion), and you need to quickly determine the status of incremental tasks through the **Last Event Time** in the **Task List** to ensure the link status and incremental log acquisition are normal. - ![Incremental Checkpoint](../../images/incremental_check_point.png) + ![Last Event Time](../../images/incremental_check_point.png) * If the source database has many DML operations, it is necessary to prevent the incremental logs recorded by TapData from being archived and deleted, which would make it impossible to obtain the incremental checkpoint. diff --git a/docs/connectors/warehouses-and-lake/paimon.md b/docs/connectors/warehouses-and-lake/paimon.md index 0a2566d2..29d48db4 100644 --- a/docs/connectors/warehouses-and-lake/paimon.md +++ b/docs/connectors/warehouses-and-lake/paimon.md @@ -32,6 +32,7 @@ Add a [Type Modification Processor](../../data-transformation/process-node.md#ty - To avoid write conflicts and reduce compaction pressure, disable multi-threaded writes in the target node and set batch size to 1,000 rows and timeout to 1,000 ms. - Always define a primary key for efficient upserts and deletes; for large tables, use partitioning to speed up queries and writes. - Paimon supports primary keys only (no secondary indexes) and does not allow runtime schema evolution. +- When Paimon is used as the target and soft delete is enabled, TapData converts `DELETE` operations into `UPDATE` operations with a delete marker. Because Paimon updates require complete row data, the source `DELETE` event must provide the full before image; otherwise, fields other than the primary key may be written as `null`. If the source database is MongoDB 6.0 or later, enable **[Document Pre-image](../on-prem-databases/mongodb.md#node-advanced-features)**. For other source databases, ensure that CDC logs contain the complete row data before the `DELETE` operation. ## Connect to Paimon diff --git a/docs/data-replication/monitor-task.md b/docs/data-replication/monitor-task.md index 7825db78..69675cdc 100644 --- a/docs/data-replication/monitor-task.md +++ b/docs/data-replication/monitor-task.md @@ -1,14 +1,37 @@ # Monitor Data Replication Task -Once the data replication task is started, the page will automatically redirect to the task monitoring page. From there, you can monitor the task's operation details, such as the status of the Agent, data synchronization progress, task progress, alert settings, and other relevant information. +After you start a data replication task, TapData automatically redirects you to the task monitoring page. You can use this page to check runtime details such as Agent status, synchronization status, task progress, and alert settings. You can also review the overall task status from the task list before opening a specific task for details. + :::tip -By clicking the **monitor** button on the task list page, you can access the monitoring page as well. +You can also open the monitoring page by clicking **Monitor** on the task list page. ::: + +## Task List Metrics + +On the **Data Replication** task list page, use filters such as **Task Status**, **Sync Type**, **Task Milestone**, **Agent Name**, and **Task Name** to find tasks. You can also click **Display Settings** to adjust the columns shown in the list. The following table describes the common fields: + +| Field | Description | +| --- | --- | +| **Task Name** | The display name of the task. You can search tasks by this field. | +| **Task Status** | The current task status, such as Editing, Running, Stopped, or Failed. | +| **Sync Type** | The task synchronization type, such as full, incremental, or full + incremental. | +| **Task Milestone** | The current execution stage, which helps you determine whether the task is initializing, running full synchronization, running incremental synchronization, or processing another stage. | +| **Incremental Delay** | The time between when an event is generated at the source and when the task finishes processing it. Use this metric to identify incremental backlog. | +| **Last Event Time** | The latest source event time processed by the task. The closer this time is to the current time, the more up to date incremental processing is. | +| **Last Run Time** | The most recent time when the task was started. | +| **Create Time** | The time when the task was created. | +| **Update Time** | The most recent time when the task configuration or status was updated. | +| **Available Operation** | Operations available for the task, such as Start, Edit, Monitor, Reset, Copy, and Delete. The available operations depend on the task status. | + +To view node-level metrics, run logs, alerts, or task settings, click **Monitor** on the right side of the target task to open the task details page. + +## View Task Details + ![](../images/monitor_copy_task_overview.png) @@ -70,4 +93,3 @@ Click the ![](../images/task_setting_icon.png) icon at the top of the page, whic * Task increment start notification * Task stop alert * Task increment delay alert - diff --git a/docs/data-transformation/aggregate-computing-node.md b/docs/data-transformation/aggregate-computing-node.md new file mode 100644 index 00000000..54f88ac3 --- /dev/null +++ b/docs/data-transformation/aggregate-computing-node.md @@ -0,0 +1,197 @@ +# Aggregate Node + +The **Aggregate** node groups, summarizes, and derives values from detail or model data, then continuously writes a reusable result set, such as an ADM table, for downstream reports or APIs. This helps reduce repeated calculations, keep metric definitions consistent, and improve query performance. + +## Prerequisites + +- The Aggregate node is available in **data transformation tasks** and **Real-Time Data Hub** flows, such as FDM-to-MDM model building. +- This node is supported only when the upstream data source node is **MongoDB**. + +## Notes + +- More complex aggregation logic places higher requirements on source data quality, target database performance, and index design. +- The Aggregate node is best suited for stable result sets that are reused by downstream systems. For temporary analysis or one-time queries, validate the metric logic in an analysis tool first. +- Update and delete events affect aggregate results. Before production use, prepare sample data that covers inserts, updates, and deletes. + +## Supported Aggregate Functions and Filters + +TapData provides aggregate functions and filter conditions for common data processing scenarios. + +
+Supported aggregate functions + +| Function | Usage | +| --- | --- | +| `$sum` | Sums values, such as sales amount. It can also be used for counting. | +| `$avg` | Calculates an average, such as average order value. | +| `$min` | Returns the minimum value, such as the first order time. | +| `$max` | Returns the maximum value, such as the latest order time. | +| `$count` | Counts records. The node converts it to `$sum: 1`. | +| `$first` | Returns the specified field value from the first record in a group, such as the first order status. | +| `$last` | Returns the specified field value from the last record in a group, such as the latest processing result. | +| `$push` | Appends field values in the group to an array and keeps duplicate values. | +| `$addToSet` | Appends field values in the group to an array and removes duplicate values. | + +:::tip + +The results of `$first` and `$last` depend on the order of records entering the aggregation stage. To select the first or last record by time or another business field, use Raw Pipeline and add an explicit `$sort` stage before `$group`. + +::: + +
+ +
+Supported filter conditions + +| Operator | Description | +| --- | --- | +| `=` | Equal to. | +| `≠` | Not equal to. | +| `>` | Greater than. | +| `≥` | Greater than or equal to. | +| `<` | Less than. | +| `≤` | Less than or equal to. | +| `IN` | Matches any value in a list. Separate multiple values with commas. | +| `NOT IN` | Excludes values in a list. Separate multiple values with commas. | +| `REGEX` | Matches a regular expression. | + +
+ +## Use Case and Example + +BI reports, user profile systems, and business APIs often consume metrics rather than raw detail rows. With the **Aggregate** node, you can move frequently used calculations, such as user profile metrics or dashboard statistics, into the data processing pipeline. The result is computed once and reused by multiple downstream consumers, reducing repeated scans of large detail tables. + +The following example builds a **user order summary table**. It filters paid orders from the `order_detail` collection, groups them by user ID, calculates each user's total spend, order count, and latest order time, and writes the result to `user_order_summary` for downstream queries. + +```mermaid +flowchart LR + %% Define style classes + classDef source fill:#e1f5fe,stroke:#3b82f6,stroke-width:2px,color:#1e3a8a + classDef process fill:#fef3c7,stroke:#eab308,stroke-width:2px,color:#92400e + classDef target fill:#dcfce7,stroke:#10b981,stroke-width:2px,color:#064e3b + + A[("order_detail
(source detail table)")]:::source --> B{"Filter
status=PAID"}:::process + B --> C["Group by user
(group by userId)"]:::process + C --> D1["Sum
sum(amount)"]:::process & D2["Count
count(orderId)"]:::process & D3["Max
max(orderTime)"]:::process + D1 & D2 & D3 --> E("Merge into one summary record"):::process --> F[("user_order_summary
(target summary table)")]:::target +``` + +**Data transformation result:** + +| Stage | Example | +| --- | --- | +| **Source detail input** | Contains multiple records: `{orderId: "O1", userId: "U1", status: "PAID", amount: 120.5}`, `{orderId: "O2", userId: "U1", status: "PAID", amount: 300.0}` | +| **Aggregate output** | Produces one summary record: `{userId: "U1", totalAmount: 420.5, orderCount: 2, lastOrderTime: "2026-05-08"}` | + +:::tip + +In Visual Config mode, the group field, such as `userId`, is output as `_id` by default. To output it as a top-level field, use Raw Pipeline and adjust the structure in the `$project` stage. + +::: + +## Procedure + +1. Log in to TapData platform. +2. In the left navigation bar, click **Data Transformation**, then click **Create Task** on the right side of the page. + + :::tip + + If you use this node in **Real-Time Data Hub**, save the MDM model first, then open the model's **Task Configuration** page. You can then add the Aggregate node to the pipeline. + + ::: + +3. In the **Connections** area on the left panel, drag in a connected MongoDB data source and select the detail collection to aggregate. +4. From the **Processing Nodes** area, drag in the **Aggregate** node and connect the data source node to it. +5. Click the Aggregate node and configure the aggregation rules on the **General** tab in the right panel. + + ![Aggregate node configuration example](../images/aggregate_node_config.png) + + - **Node Name**: Enter a business-friendly name, such as **User Order Summary**. + - **Aggregate Mode**: The default mode is **Visual Config**. You can switch to **Raw Pipeline** when needed. + - **Visual Config**: Configure basic aggregation logic in the UI. In the user order summary example, only paid orders are counted, and total spend, order count, and latest order time are summarized by user for segmentation, dashboards, or user profile analysis. + - **$match Filter**: Define the data range for the calculation. Select the `status` field, set the operator to `=`, and enter `PAID` to include only paid orders. Click **Add Condition** to add more filter conditions. + - **$group Fields**: Select the aggregation dimension. In this example, select `userId` to generate one summary result per user. Click **Add Group Field** to add more grouping fields. + - **Aggregate Fields**: Configure the function, source field, and output field. Add three calculated fields: use `$sum` on `amount` and output `totalAmount`, use `$count` and output `orderCount`, and use `$max` on `orderTime` and output `lastOrderTime`. + - **Effective Update Fields**: Specify which source field changes should trigger aggregate result updates. We recommend selecting `status`, `userId`, `amount`, and `orderTime` to cover changes to payment status, grouping, amount, and order time. + - **Group Change Double Aggregation**: When the source grouping field changes, update both the old group and the new group. If `userId` can change at the source, enable this option to prevent the old user's summary from retaining the previous value. + + :::tip + + In Visual Config mode, the group field is output as `_id` by default. If downstream writes must use a top-level `userId` field as the update condition, use Raw Pipeline and adjust the output structure in the `$project` stage. + + ::: + + - **Raw Pipeline**: This mode is suitable for advanced users familiar with MongoDB. Use it when you need a custom output structure, such as outputting `_id` as top-level `userId`, or when you need more complex aggregation stages. The following pipeline keeps the same business logic as Visual Config and uses `$project` to produce a structure that is easier to update and query downstream: + + ```json + [ + { + "$match": { + "status": "PAID" + } + }, + { + "$group": { + "_id": "$userId", + "totalAmount": { + "$sum": "$amount" + }, + "orderCount": { + "$sum": 1 + }, + "lastOrderTime": { + "$max": "$orderTime" + } + } + }, + { + "$project": { + "_id": 0, + "userId": "$_id", + "totalAmount": 1, + "orderCount": 1, + "lastOrderTime": 1 + } + } + ] + ``` + +6. (Optional) On the **Advanced** tab of the Aggregate node configuration panel, tune node execution performance: + + - **Enable Concurrent Processing**: Enabled by default. When enabled, the node processes incoming data with multiple threads to improve aggregation throughput. + - **Set Concurrency**: Available after concurrent processing is enabled. The default value is 4. You can increase it, for example to 8 or 16, based on source load and compute node CPU resources. + +7. Drag a target data source from the left side of the page to store the aggregated result set, then connect the Aggregate node to the target node. +8. Click the target node, MySQL in this example, and select or enter the target table name, such as `user_order_summary`. +9. Configure update conditions based on the uniqueness requirements of the result set. In most cases, use the group key in the aggregate output as the update condition. For example, if a custom pipeline outputs `userId`, update by `userId`. If you keep the default aggregate structure, update by the actual `_id` field. +10. Verify the configuration, then click **Start**. + +After the task starts, TapData continuously maintains aggregate results based on upstream detail data. When source detail data is inserted, updated, or deleted, the result set is updated accordingly. + +## Validate the Results + +After the task starts, query the result table in the target database, MySQL in this example, to verify that the aggregate output is correct. + +Example query: + +```sql +SELECT * FROM user_order_summary LIMIT 1; +``` + +Example result: + +```text +| userId | totalAmount | orderCount | lastOrderTime | +| ------ | ----------- | ---------- | ------------------ | +| U10001 | 420.5 | 2 | 2026-05-08 20:15:00 | +``` + +If the result does not match expectations, check the filter conditions, group fields, and aggregate field configuration. Also confirm that the target table update condition matches the group key and that source change events contain the complete data needed for the calculation. + +## Best Practices + +- Start with the result structure required by downstream reports or APIs, then work backward to define the aggregate fields and group fields. +- Use stable business dimensions as group fields, such as user ID, region code, product ID, or business date. +- Create indexes on frequently queried fields in the target collection or table, such as `userId`, `region`, or `bizDate`. +- For complex metrics, validate the pipeline with a small data sample before using it in a production task. +- If an aggregation becomes too complex, prepare the detail data with model nodes first, then generate the result set with the Aggregate node. diff --git a/docs/data-transformation/monitor-view-tasks.md b/docs/data-transformation/monitor-view-tasks.md index 05769504..d4f21528 100644 --- a/docs/data-transformation/monitor-view-tasks.md +++ b/docs/data-transformation/monitor-view-tasks.md @@ -2,14 +2,37 @@ -Once the data transformation task is started, the page will automatically redirect to the task monitoring page. From there, you can monitor the task's operation details, such as the status of the Agent, data synchronization progress, task progress, alert settings, and other relevant information. +After you start a data transformation task, TapData automatically redirects you to the task monitoring page. You can use this page to check runtime details such as Agent status, synchronization status, task progress, and alert settings. You can also review the overall task status from the task list before opening a specific task for details. + :::tip -By clicking the **monitor** button on the task list page, you can access the monitoring page as well. +You can also open the monitoring page by clicking **Monitor** on the task list page. ::: + +## Task List Metrics + +On the **Data Transformation** task list page, use filters such as **Task Status**, **Sync Type**, **Task Milestone**, **Agent Name**, and **Task Name** to find tasks. You can also click **Display Settings** to adjust the columns shown in the list. The following table describes the common fields: + +| Field | Description | +| --- | --- | +| **Task Name** | The display name of the task. You can search tasks by this field. | +| **Task Status** | The current task status, such as Editing, Running, Stopped, or Failed. | +| **Sync Type** | The task synchronization type, such as full, incremental, or full + incremental. | +| **Task Milestone** | The current execution stage, which helps you determine whether the task is initializing, running full synchronization, running incremental synchronization, or processing another stage. | +| **Incremental Delay** | The time between when an event is generated at the source and when the task finishes processing it. Use this metric to identify incremental backlog. | +| **Last Event Time** | The latest source event time processed by the task. The closer this time is to the current time, the more up to date incremental processing is. | +| **Last Run Time** | The most recent time when the task was started. | +| **Create Time** | The time when the task was created. | +| **Update Time** | The most recent time when the task configuration or status was updated. | +| **Available Operation** | Operations available for the task, such as Start, Edit, Monitor, Reset, Copy, and Delete. The available operations depend on the task status. | + +To view node-level metrics, run logs, alerts, or task settings, click **Monitor** on the right side of the target task to open the task details page. + +## View Task Details + ![](../images/monitor_copy_task_overview.png) @@ -69,4 +92,3 @@ Click the ![](../images/task_setting_icon.png) icon at the top of the page, whic * Task increment start notification * Task stop alert * Task increment delay alert - diff --git a/docs/data-transformation/process-node.md b/docs/data-transformation/process-node.md index e305da3c..25b96e4d 100644 --- a/docs/data-transformation/process-node.md +++ b/docs/data-transformation/process-node.md @@ -173,6 +173,12 @@ mysql> select * from student_merge; +## Aggregate + +The **Aggregate** node groups, summarizes, and derives values from MongoDB source detail or model data. It is suitable for creating reusable result sets for user profiles, order summaries, and operational dashboards. + +For prerequisites, configuration steps, and example pipelines, see [Aggregate Node](aggregate-computing-node.md). + ## Join diff --git a/docs/images/aggregate_node_config.png b/docs/images/aggregate_node_config.png new file mode 100644 index 0000000000000000000000000000000000000000..884ce1d4ed864a724250f52ff74c5114d14d0e4d GIT binary patch literal 44217 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 P0e^B*%92&Djf4IRaA4KJ literal 0 HcmV?d00001 diff --git a/docs/release-notes-on-prem.md b/docs/release-notes-on-prem.md index a71a7fc3..40c88d21 100644 --- a/docs/release-notes-on-prem.md +++ b/docs/release-notes-on-prem.md @@ -15,6 +15,43 @@ import TabItem from '@theme/TabItem'; ``` +## 4.17.0 + +### New Features + +- Added the [Aggregate node](data-transformation/aggregate-computing-node.md), which supports **Visual Config** for grouping, summarizing, and deriving data. You can use it to precompute metrics and keep business definitions consistent across downstream consumers. + +### Enhancements + +- Improved task list metrics with metric descriptions, delay status, and additional runtime information. +- Improved Paimon target configuration by supporting import and export of custom table creation settings. +- Improved Db2 Raw Log parsing for High Availability (HA) architectures. +- Improved Kafka write logic by supporting bucket assignment based on update conditions and allowing primary key update events to be split into Delete and Insert operations. +- Enhanced custom nodes so that one processing run can return multiple data records. +- Improved connection timeout handling and HA retry strategies for the built-in MongoDB service to increase system stability. +- Added support for mocking input data in JS nodes for faster debugging. + +### Bug Fixes + +- Fixed an intermittent issue where run logs could not be displayed for data replication or transformation tasks. +- Fixed an issue where an intermediate database connection error could cause the management node (TM) to exit unexpectedly. +- Fixed an issue where Real-Time Data Hub did not correctly display row counts and storage sizes for AS400 data sources. +- Fixed an issue where the task cache page could not display cache information properly. +- Fixed a task error during cache rebuild caused by updates to the `_id` field. +- Fixed an issue where shared cache could read stale data and affect data consistency. +- Fixed an issue in master-child merge flattening scenarios where child-table association keys were not cleaned up correctly after they changed in the primary table. +- Fixed excessive invalid warning logs in master-child merge tasks. +- Fixed an incorrect recommended association key order in data validation tasks. +- Fixed an issue where restarting a task with no incremental data could incorrectly trigger an incremental delay alert. +- Fixed a null pointer exception when synchronizing specific time-type data in the incremental phase. +- Fixed JSON parsing errors in specific scenarios. +- Fixed DDL handling errors when synchronizing Dameng Database to Doris. +- Fixed an error when synchronizing negative time format values from MySQL. +- Fixed validation failures when comparing array and object values between MongoDB and MySQL. +- Fixed a task error when synchronizing PostgreSQL partitioned tables to SQL Server. +- Fixed an issue where SQL Server did not output logs correctly after Database Log was enabled. +- Fixed an issue where, if a SQL Server-to-SQL Server task stopped because of an error, the error details were not written correctly to the frontend task logs. + ## 4.16.0 ### New Features From 799c667cb2b67b1eb99fc0ff65fc9ef328d96a0c Mon Sep 17 00:00:00 2001 From: Walter Date: Thu, 14 May 2026 08:13:04 +0800 Subject: [PATCH 2/2] ci(spelling): add actions read permission Add actions: read permission to the spelling check workflow's permissions. --- .github/workflows/spelling.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/spelling.yml b/.github/workflows/spelling.yml index abd3e084..541fb07b 100644 --- a/.github/workflows/spelling.yml +++ b/.github/workflows/spelling.yml @@ -11,6 +11,7 @@ jobs: name: Check Spelling permissions: contents: read + actions: read security-events: write runs-on: ubuntu-latest concurrency: