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 引擎的状态数据只存储主键信息,可以显著提高状态访问效率,从而提升实时计算任务的性能。
相关推荐
香饽饽~、1 小时前
【第十一篇】SpringBoot缓存技术
java·开发语言·spring boot·后端·缓存·intellij-idea
程序员爱钓鱼2 小时前
Go语言实战指南 —— Go中的反射机制:reflect 包使用
后端·google·go
ℳ₯㎕ddzོꦿ࿐2 小时前
Spring Boot 集成 MinIO 实现分布式文件存储与管理
spring boot·分布式·后端
ai小鬼头7 小时前
百度秒搭发布:无代码编程如何让普通人轻松打造AI应用?
前端·后端·github
考虑考虑7 小时前
@FilterRegistration和@ServletRegistration注解
spring boot·后端·spring
一只叫煤球的猫7 小时前
🔥 同事混用@Transactional和TransactionTemplate被我怼了,三种事务管理到底怎么选?
java·spring boot·后端
你的人类朋友9 天前
(●'◡'●)从Dockerfile快速入门Docker Compose
后端
GetcharZp9 天前
「神器推荐」Rclone:轻松玩转云端存储,FTP 也能飞起来!
后端
华子w9089258599 天前
基于 SpringBoot+JSP 的医疗预约与诊断系统设计与实现
java·spring boot·后端
舒一笑9 天前
工作流会使用到Webhook是什么
后端·程序员