
# Iceberg隐式分区和分区演进介绍
Iceberg表通过配置一个分区规范来定义如何从一条记录生成分区值元组。一个分区规范包含一个字段列表，每个字段由以下部分组成：
- 源列ID：来自表模式的一个源列ID或一个源列ID列表。
- 分区字段ID：用于标识分区字段，且在一个分区规范内是唯一的。在v2表元数据中，该ID在所有分区规范中都是唯一的。
- 转换方式：应用于源列以生成分区值的转换函数。
- 分区名称：分区字段的名称。
通过ID所选的源列必须是原始类型，不能包含在映射或列表中，但可以嵌套在结构体内。
分区规范捕获了从表数据到分区值的转换规则，除了用于转换数据值之外，还用于将谓词转换为分区谓词，以从表数据的列谓词推导出分区谓词，用于将逻辑查询与物理存储分离；即使分区方式发生变化，正确的分区过滤器也可以从列谓词中推导出来。简化了查询，即用户无需同时提供逻辑谓词和分区谓词。
#### 隐式分区转换规则
隐式分区转换规则请参见[表1]，其中：
- 所有转换对于null输入值都必须返回null。
- void转换可用于替换现有分区字段中的转换，以便在v1表中有效地删除该字段，详细说明请参见[分区演进]。

- bucket\[N\]：用于对源值应用哈希函数（通常是Iceberg的特定实现），然后对N取模，得到一个介于0到N-1之间的桶号。 不同的数据类型（例如int和string）即使逻辑值相同（例如34和"34"），也会产生不同的哈希值，因此不能直接进行类型升级。
  
- truncate\[W\]
  - 对于数字类型（int、long、decimal）：将值截断为最接近的W的倍数。例如，truncate\[10\]会将17转换为10。
  
  - 对于字符串和二进制类型：截断到前W个字符/字节。例如，truncate\[3\]会将**"iceberg"** 转换为**"ice"**。
  
  
  具体的操作SQL请参考[Iceberg DDL语法说明](https://support.huaweicloud.com/cmpntguide-lts-mrs/mrs_01_300768.html#mrs_01_300768)。
  
 表1隐式分区转换规则 
| 转换名称          | 说明                                     | 源类型                                                                                                   | 转换结果类型  |
|:---|:---|:---|:---|
| identity      | 源值，未经修改。                               | 除geometry、geography、variant外的任何类型。                                                                    | 源类型     |
| bucket\[N\]   | 值的哈希值，对N取模（详见下文）。                      | int、long、decimal、date、time、timestamp、timestamptz、timestamp_ns、timestamptz_ns、string、uuid、fixed、binary | int     |
| truncate\[W\] | 值被截断到宽度W（详见下文）。                        | int、long、decimal、string、binary                                                                        | 源类型     |
| year          | 提取日期或时间戳的年份，表示为从1970年开始的年数。            | date、timestamp、timestamptz、timestamp_ns、timestamptz_ns                                                | int     |
| month         | 提取日期或时间戳的月份，表示为从1970-01-01开始的月数。       | date、timestamp、timestamptz、timestamp_ns、timestamptz_ns                                                | int     |
| day           | 提取日期或时间戳的日期，表示为从1970-01-01开始的天数。       | date、timestamp、timestamptz、timestamp_ns、timestamptz_ns                                                | int     |
| hour          | 提取时间戳的小时，表示从1970-01-01 00:00:00开始的小时数。 | timestamp、timestamptz、timestamp_ns、timestamptz_ns                                                     | int     |
| void          | 总是产生null。                              | 任何数据类型                                                                                                | 源类型或int |
   
 #### 分区演进
表分区可以通过添加、删除、重命名或重新排序分区规范字段来进行演化。
更改分区规范会产生一个新的规范，该规范由一个唯一的规范ID标识。新规范会被添加到表的分区规范列表中，并且可以被设置为表的默认规范。
演进规则：
- 保持字段ID稳定：在演化规范时，更改不应导致分区字段ID发生变化。分区字段ID在清单文件中被用作分区元组的字段 ID。
- v2表：在v2中，必须为每个分区字段显式跟踪其分区字段ID。新的ID根据表元数据中最后分配的分区ID来分配。
- v1表（兼容性）：在v1中，分区字段ID没有被显式跟踪，但在参考实现中是按顺序从1000开始分配的。由于具有相同ID的分区字段可能包含不同的数据类型，这种分配方式在基于来自多个规范的清单文件读取元数据表时会产生问题。为了与旧版本兼容，建议v1表的分区演化遵循以下规则：
  - 不要重新排序分区字段。
  
  - 不要删除分区字段，应使用void转换替换该字段的转换方式来"软删除"。
  
  - 只能在先前分区规范的末尾添加新的分区字段。
  
  
  具体的操作SQL请参考[Iceberg DDL语法说明](https://support.huaweicloud.com/cmpntguide-lts-mrs/mrs_01_300768.html#mrs_01_300768)。
  
 
