使用dw-etl完美替代kettle

相信用过kettle的人都对这个工具既爱又恨,爱的是它功能很多,界面操作很丰富,一副无所不能的样子。然而,真要用它解决一些棘手的问题,它又显得无能为力。

例如这样的标准场景,数据仓库从ods层迁移数据到dw层时,ods层表格很可能类似于exam这个表的样子:

java替换kettle作业中的ktr_数据仓库


数据仓ods层一个单表通常包含有事实字段和维度字段。

而数据仓dw层则需要把表拆成事实表+维度表的星型结构,或者雪花型结构

java替换kettle作业中的ktr_java_02


面对这样的问题kettle无法优雅地解决,并且现实是我们通常还要应对全量、增量数据同步,还有维度数据的缓慢变化。

dw-etl专门为解决数据维度拆分转换设计,通过一个json配置文件,完成事实表和维度表的建模描述,到数据转换运行时,把源数据表数据逐行传给dw-etl转换引擎,则会自动完成拆分入库目标事实表和维度表。

话不多说贴上json配置文件源码供鉴赏:

{
  "project_name": "期末考试分数事实表",
  "fact_table": {
    "table_name": "fact_exam",
    "etl_columns": [
      {
        "col": "id",
        "src_col": "id",
        "data_type": "INT(11)",
        "is_auto_id": false
      },
      {
        "col": "course_agent_id",
        "data_type": "int(11)",
        "is_auto_id": false,
        "dim_id_from": "dim_course.agent_id"
      },
      {
        "col": "teacher_agent_id",
        "data_type": "int(11)",
        "is_auto_id": false,
        "dim_id_from": "dim_teacher.agent_id"
      },
      {
        "col": "student_agent_id",
        "data_type": "int(11)",
        "is_auto_id": false,
        "dim_id_from": "dim_student.agent_id"
      },
      {
        "col": "score",
        "src_col": "score",
        "data_type": "INT(11)",
        "is_auto_id": false
      },
      {
        "col": "sync_time",
        "src_col": "sync_time",
        "data_type": "datetime",
        "is_auto_id": false
      },
      {
        "col": "agent_id",
        "src_col": "",
        "data_type": "int(11)",
        "is_auto_id": true
      }
    ]
  },
  "dim_tables": [
    {
      "table_name": "dim_course",
      "etl_columns": [
        {
          "col": "course_name",
          "src_col": "course_name",
          "data_type": "VARCHAR(255)",
          "is_auto_id": false
        },
        {
          "col": "agent_id",
          "src_col": "",
          "data_type": "int(11)",
          "is_auto_id": true
        },
        {
          "col": "sync_time",
          "src_col": "sync_time",
          "data_type": "datetime",
          "is_auto_id": false
        }
      ],
      "unique_check": {
        "unique_key_columns": [
          "course_name"
        ],
        "unique_key_date_column": "sync_time",
        "uncheck_columns": [
          "course_name",
          "sync_time"
        ],
        "if_exists_skip": true
      }
    },
    {
      "table_name": "dim_teacher",
      "etl_columns": [
        {
          "col": "teach_years",
          "src_col": "teach_years",
          "data_type": "INT(11)",
          "is_auto_id": false
        },
        {
          "col": "teacher_name",
          "src_col": "teacher_name",
          "data_type": "VARCHAR(255)",
          "is_auto_id": false
        },
        {
          "col": "teacher_number",
          "src_col": "teacher_number",
          "data_type": "INT(11)",
          "is_auto_id": false
        },
        {
          "col": "agent_id",
          "src_col": "",
          "data_type": "int(11)",
          "is_auto_id": true
        },
        {
          "col": "course_agent_id",
          "data_type": "int(11)",
          "is_auto_id": false,
          "dim_id_from": "dim_course.agent_id"
        },
        {
          "col": "sync_time",
          "src_col": "sync_time",
          "data_type": "datetime",
          "is_auto_id": false
        }
      ],
      "unique_check": {
        "unique_key_columns": [
          "teacher_number"
        ],
        "unique_key_date_column": "sync_time",
        "uncheck_columns": [
          "teacher_number",
          "sync_time"
        ],
        "if_exists_skip": true
      }
    },
    {
      "table_name": "dim_student",
      "etl_columns": [
        {
          "col": "student_name",
          "src_col": "student_name",
          "data_type": "VARCHAR(255)",
          "is_auto_id": false
        },
        {
          "col": "student_number",
          "src_col": "student_number",
          "data_type": "VARCHAR(255)",
          "is_auto_id": false
        },
        {
          "col": "agent_id",
          "src_col": "",
          "data_type": "int(11)",
          "is_auto_id": true
        },
        {
          "col": "sync_time",
          "src_col": "sync_time",
          "data_type": "datetime",
          "is_auto_id": false
        }
      ],
      "unique_check": {
        "unique_key_columns": [
          "student_number"
        ],
        "unique_key_date_column": "sync_time",
        "uncheck_columns": [
          "student_number",
          "sync_time"
        ],
        "if_exists_skip": true
      }
    }
  ]
}

可见配置文件脉络非常清晰,一个事实表(fact_exam)放在fact_table对象里,多个维度表(dim_course、dim_teacher、dim_student)放在dim_tables数组对象里,然后各个表都有来源字段和目标字段、字段类型配置。为了应对缓慢变化维,事实表和维度表都加了agent_id自增id作为代理id,is_auto_id: true则表示自增主键。

维度表配置复杂一些,多了个unique_check对象配置,unique_key_columns是维度表用于唯一定位一行数据的列集合,例如学生的学号、老师的工号。如果学生学号还要加上年级班号才能唯一定位学生呢?那就把学生学号和班号id都放在unique_key_columns数组就是了。unique_key_date_column放入同步数据日期列,全量增量数据通常会有这个日期字段。uncheck_columns是排除一些与维度表缓慢变化维不相关的字段。if_exists_skip保留是true就对了,不然存在相同的维度数据还继续插入维度表则是多余的。

搞清楚配置文件格式后,其他就基本是模板化操作了,下载dw-etl及example,按照使用说明跑通example工程,就能掌握dw-etl开发了。