Paimon也有聚合表了?

<1> Deduplicate--默认

当 Paimon 接收到两条或更多具有相同主键的记录时,它会将它们合并为一条记录以保持主键的唯一性

记录保留策略

  • 保留最新记录:Paimon 只会保留最新的记录,并丢弃其他具有相同主键的记录。
  • 处理 DELETE 记录:如果最新的记录是一条 DELETE 记录,则所有具有相同主键的记录都将被删除。

配置选项

  • ignore-delete :用户可以配置 ignore-delete 参数来忽略 DELETE 记录。默认情况下,DELETE 记录会导致所有具有相同主键的记录被删除,但通过设置 ignore-delete=true,可以忽略 DELETE 记录。

示例配置

sql 复制代码
CREATE TABLE my_table (
    id INT,
    name STRING,
    age INT,
    PRIMARY KEY (id) NOT ENFORCED
)
WITH (
    'merge-engine' = 'deduplicate',
    'ignore-delete' = 'true'
);

注意事项

  • 在 Flink SQL 的 TableConfig 中,将 table.exec.sink.upsert-materialize 设置为 NONE,以避免启用 upsert-materialize 可能导致的奇怪行为[[1, 4, 17]]。
  • 当输入数据无序时,建议使用序列字段(Sequence Field)来纠正乱序[[1, 4, 17]]。
  • 如果最新记录是 DELETE 记录,则所有具有相同主键的记录都将被删除,除非配置了 ignore-delete=true 来忽略 DELETE 记录。

<2> aggregation函数

对于paimon而言,实现类似Doris那种聚合模型的功能,只需要三步

  1. 指定主键
  2. 指定merge-engine为aggregation
  3. 指定聚合字段的function
sql 复制代码
CREATE TABLE my_table (
    product_id BIGINT,
    price DOUBLE,
    sales BIGINT,
    PRIMARY KEY (product_id) NOT ENFORCED
) WITH (
    'merge-engine' = 'aggregation',
    'fields.price.aggregate-function' = 'max',
    'fields.sales.aggregate-function' = 'sum'
);
<1, 23.0, 15> 
<1, 30.2, 20>
the final result will be <1, 30.2, 35>.
​
CREATE TABLE my_table (
    product_id BIGINT,
    name varchar,
    price DOUBLE,
    sales BIGINT,
    PRIMARY KEY (product_id) NOT ENFORCED
) WITH (
    'merge-engine' = 'aggregation',
    'fields.price.aggregate-function' = 'max',
    'fields.sales.aggregate-function' = 'sum'
);
<1, 张三, 23.0, 15> 
<1, 李四, 30.2, 20>
最终结果:<1, 李四, 30.2, 35>

《1》常见的聚合函数

max、min、sum、count、lastvalue、last nonnull value、firstvalue、first nonnullvalue、collect

《2》特殊的聚合函数

listagg: 将多个字符串连接成一个字符串,默认用,分隔

bool_and: 评估布尔集中的所有值是否为 true

bool_or: 检查布尔集中是否至少有一个值为 true。

rbm32: 将多个序列化的 32 位 RoaringBitmap 聚合成一个 RoaringBitmap。

rbm64: 将多个序列化的 64 位 Roaring64Bitmap 聚合成一个 Roaring64Bitmap。

nested_update: 将多行收集到一个数组中(所谓的"嵌套表")。用于指定嵌套表的主键。如果没有键,则 row 将被附加到数组中。fields.<field-name>.nested-key=pk0,pk1,... 案例如下:

sql 复制代码
-- orders table
CREATE TABLE orders (
  order_id BIGINT PRIMARY KEY NOT ENFORCED,
  user_name STRING,
  address STRING
);
​
-- sub orders that have the same order_id 
-- belongs to the same order
CREATE TABLE sub_orders (
  order_id BIGINT,
  sub_order_id INT,
  product_name STRING,
  price BIGINT,
  PRIMARY KEY (order_id, sub_order_id) NOT ENFORCED
);
​
-- wide table
CREATE TABLE order_wide (
  order_id BIGINT PRIMARY KEY NOT ENFORCED,
  user_name STRING,
  address STRING,
  sub_orders ARRAY<ROW<sub_order_id BIGINT, product_name STRING, price BIGINT>>
) WITH (
  'merge-engine' = 'aggregation',
  'fields.sub_orders.aggregate-function' = 'nested_update',
  'fields.sub_orders.nested-key' = 'sub_order_id' --这是为了将array中相同nested-key的进行覆盖,不同nested-key的进行nested_update追加
);
​
-- orders
INSERT INTO orders VALUES (1, 'Alice', 'Beijing');
-- sub_orders
INSERT INTO sub_orders VALUES (1, 1, 'iPhone', 5999);
INSERT INTO sub_orders VALUES (1, 2, 'MacBook', 12999);
​
-- widen
INSERT INTO order_wide
SELECT 
  order_id, 
  user_name,
  address, 
  CAST (NULL AS ARRAY<ROW<sub_order_id BIGINT, product_name STRING, price BIGINT>>) 
FROM orders -- 1, 'Alice', 'Beijing', null
​
UNION ALL 
  
SELECT 
  order_id, 
  CAST (NULL AS STRING), 
  CAST (NULL AS STRING), 
  ARRAY[ROW(sub_order_id, product_name, price)] 
FROM sub_orders;-- 1, null, null, [{"sub_order_id":1,"product_name":"iphone","price":5999},
{"sub_order_id":2,"product_name":"MacBook","price":12999}]
​
-- query using UNNEST
SELECT order_id, user_name, address, sub_order_id, product_name, price 
FROM order_wide, UNNEST(sub_orders) AS so(sub_order_id, product_name, price)

补充:select。。。unnest(sub_orders)
作用:
将宽表中的嵌套数组(sub_orders)展开成扁平结构,便于查询。
效果:
类似于 SQL JOIN,但更高效(因为数据已经预聚合)。
最终order_wide数据如下:
{
   "order_id":1,
   "user_name":"Alice",
   "address":"Beijing",
   "sub_orders":[
      {"sub_order_id":1,"product_name":"iPhone","price":5999},
      {"sub_order_id":2,"product_name":"MacBook","price":12999}
   ]
}
查询的结果如下
order_id    user_name   address sub_order_id    product_name    price
1               Alice   Beijing     1               iPhone      5999
1               Alice   Beijing     2               MacBook     12999

**mergemap: **mergemap 函数 merge input maps。它仅支持 MAP 类型。

<3> first row

  1. 功能概述

通过指定 'merge-engine' = 'first-row',用户可以保留同一主键的第一行数据。这与 deduplicate 合并引擎不同,first-row 引擎只会生成插入类型的更改日志。

  1. 使用限制
  • Changelog Producer : first-row 合并引擎必须与 lookup changelog producer 一起使用。
  • Sequence Field : 不能指定 sequence.field
  • 消息类型 : 不接受 DELETEUPDATE_BEFORE 消息。可以通过配置 first-row.ignore-delete 来忽略这两种记录。
  1. 可见性保证
  • 文件级别为0的文件只有在完成合并后才会可见。默认情况下,合并是同步的,如果开启异步合并,可能会有数据延迟。
  1. 应用场景

first-row 合并引擎在流计算中非常有用,可以替代日志去重功能。

  1. 配置示例

以下是一个使用 first-row 合并引擎的表创建示例:

sql 复制代码
CREATE TABLE test (
    key INT,
    field_a INT,
    field_b INT,
    field_c INT,
    field_d INT,
    PRIMARY KEY (key) NOT ENFORCED
) WITH (
    'merge-engine' = 'first-row',
    'changelog-producer' = 'lookup'
);

注意事项

  • 删除向量 : 合并引擎不能是 first-row,因为 first-row 引擎的读取已经没有合并,不需要删除向量。
  • 性能优化 : 由于 first-row 引擎的状态数据只存储主键信息,可以显著提高状态访问效率,从而提升实时计算任务的性能。
相关推荐
Brookty40 分钟前
Java线程安全与中断机制详解
java·开发语言·后端·学习·java-ee
你的人类朋友1 小时前
❤️‍🔥BFF架构版的hello world
前端·后端·架构
孟婆来包棒棒糖~1 小时前
SpringCloude快速入门
分布式·后端·spring cloud·微服务·wpf
雾林小妖2 小时前
springboot集成deepseek
java·spring boot·后端
知识浅谈3 小时前
基于Dify构建本地化知识库智能体:从0到1的实践指南
后端
网络安全打工人3 小时前
CentOS7 安装 rust 1.82.0
开发语言·后端·rust
梦兮林夕3 小时前
04 gRPC 元数据(Metadata)深入解析
后端·go·grpc
pe7er3 小时前
RESTful API 的规范性和接口安全性如何取舍
前端·后端
山风呼呼4 小时前
golang--通道和锁
开发语言·后端·golang
Ice__Cai4 小时前
Django + Celery 详细解析:构建高效的异步任务队列
分布式·后端·python·django