
# Hudi表模型设计规范
#### 规则
- Hudi表必须设置合理的主键。 Hudi表提供了数据更新和幂等写入能力，该能力要求Hudi表必须设置主键，主键设置不合理会导致数据重复。主键可以为单一主键也可以为复合主键，两种主键类型均要求主键不能有null值和空值，可以参考以下示例设置主键：
  SparkSQL：
  ```
  // 通过primaryKey指定主键，如果是复合主键需要用逗号分隔
  create table hudi_table (
  id1 int,
  id2 int,
  name string,
  price double
  ) using hudi
  options (
  primaryKey = 'id1,id2',
  preCombineField = 'price'
  );
  ```
  SparkDatasource：
  ```
  // 通过hoodie.datasource.write.recordkey.field指定主键
  df.write.format("hudi").
  option("hoodie.datasource.write.table.type", COPY_ON_WRITE).
  option("hoodie.datasource.write.precombine.field", "price").
  option("hoodie.datasource.write.recordkey.field", "id1,id2").
  ```
  FlinkSQL：
  ```
  // 通过hoodie.datasource.write.recordkey.field指定主键
  create table hudi_table(
  id1 int,
  id2 int,
  name string,
  price double
  ) partitioned by (name) with (
  'connector' = 'hudi',
  'hoodie.datasource.write.recordkey.field' = 'id1,id2',
  'write.precombine.field' = 'price')
  ```
  
- Hudi表必须配置precombine字段。 在数据同步过程中不可避免会出现数据重复写入、数据乱序问题，例如：异常数据恢复、写入程序异常重启等场景。通过设置合理precombine字段值可以保证数据的准确性，老数据不会覆盖新数据，也就是幂等写入能力。该字段可用选择的类型包括：业务表中更新时间戳、数据库的提交时间戳等。precombine字段不能有null值和空值，可以参考以下示例设置precombine字段：
  SparkSQL:
  ```
  //通过preCombineField指定precombine字段
  create table hudi_table (
  id1 int,
  id2 int,
  name string,
  price double
  ) using hudi
  options (
  primaryKey = 'id1,id2',
  preCombineField = 'price'
  );
  ```
  SparkDatasource:
  ```
  //通过hoodie.datasource.write.precombine.field指定precombine字段
  df.write.format("hudi").
  option("hoodie.datasource.write.table.type", COPY_ON_WRITE).
  option("hoodie.datasource.write.precombine.field", "price").
  option("hoodie.datasource.write.recordkey.field", "id1,id2").
  ```
  Flink:
  ```
  //通过write.precombine.field指定precombine字段
  create table hudi_table(
  id1 int,
  id2 int,
  name string,
  price double
  ) partitioned by (name) with (
  'connector' = 'hudi',
  'hoodie.datasource.write.recordkey.field' = 'id1,id2',
  'write.precombine.field' = 'price')
  ```
  
- 流式计算采用MOR表。 流式计算为低时延的实时计算，需要高性能的流式读写能力，在Hudi表中存在的MOR和COW两种模型中，MOR表的流式读写性能相对较好，因此在流式计算场景下采用MOR表模型。关于MOR表在读写性能的对比关系如下：
  
  | 对比维度 | MOR表 | COW表 |
  |:---|:---|:---|
  | 流式写  | 高    | 低    |
  | 流式读  | 高    | 低    |
  | 批量写  | 高    | 低    |
  | 批量读  | 低    | 高    |
     
  
- 实时入湖，表模型采用MOR表。 实时入湖一般的性能要求都在分钟内或者分钟级，结合Hudi两种表模型的对比，因此在实时入湖场景中需要选择MOR表模型。
  
- Hudi表名以及列名采用小写字母。 多引擎读写同一张Hudi表时，为了规避引擎之间大小写的支持不同，统一采用小写字母。
  
 
#### 建议
- Spark批处理场景，对写入时延要求不高的场景，采用COW表。 COW表模型中，写入数据存在写放大问题，因此写入速度较慢；但COW具有非常好的读取性能力。而且批量计算对写入时延不是很敏感，因此可以采用COW表。
  
- Hudi表的写任务要开启Hive元数据同步功能。 SparkSQL天然与Hive集成，无需考虑元数据问题。该条建议针对的是通过Spark Datasource API或者Flink写Hudi表的场景，通过这两种方式写Hudi时需要增加向Hive同步元数据的配置项；该配置的目的是将Hudi表的元数据统一托管到Hive元数据服务中，为后续的跨引擎操作数据以及数据管理提供便利。
  
 
