调用别人网站注册表单php网站开发职责

pingmian/2025/10/8 14:36:09/文章来源:
调用别人网站注册表单,php网站开发职责,有什么软件可以制作图片,公司网站需要修改前言 1、DWD 层开发 DWD层设计要点#xff1a; #xff08;1#xff09;DWD层的设计依据是维度建模理论#xff08;主体是事务型事实表#xff08;选择业务过程 - 声明粒度 - 确定维度 - 确定事实#xff09;#xff0c;另外两种周期型快照事实表和累积型…前言 1、DWD 层开发 DWD层设计要点 1DWD层的设计依据是维度建模理论主体是事务型事实表选择业务过程 - 声明粒度 - 确定维度 - 确定事实另外两种周期型快照事实表和累积型事务事实表按需求选择该层存储维度模型的事实表。 2DWD层的数据存储格式为orc列式存储snappy压缩和DIM层、DWS层都是一样的。 3DWD层表名的命名规范为dwd_数据域_表名_单分区增量全量标识inc/full划分数据域的目的是为了通过对数据分类使得从业务系统中可以快速的找到我们希望得到的数据划分数据域的标准是按照业务过程将若干个业务过程划分到一个数据域里面其实所谓的划分数据域就是在划分事实表因为一个业务过程对应一个事实表。 1.1、交易域加购事务事实表 加购指的是加入购物车这个业务过程我们按照设计事务事实表的过程来设计它的表结构 1.1.1、选择业务过程 就是加购物车这个行为 1.1.2、声明粒度 要求尽可能选择最细粒度声明粒度将来指代的是将来这张表的每一行所代表的内容。这里我们声明的粒度就是谁在什么时候把什么商品加到了购物车 1.1.3、确认维度 我们首先能想到的就是用户、时间和商品至于其它维度我们在设计事实表的时候尽可能多的考虑到避免后期一些指标无法分析。 确认了维度我们就确认了我们这张事务事实表的维度外键。 1.1.4、确认事实 确认事实就是确认事实表的度量值对于这里的加购操作度量值主要就是加购的商品件数。 1.1.5、建表语句 这里我们的表名由几部分组成dwd 代表这张表是 dwd 层的事实表trade 代表数据域是交易域cart_add 代表这张事实表的业务过程是加购操作inc 因为这张表是事务型事实表所以我们一般都是增量表。 再看字段其中 id 选取的是我们业务系统中 cart_info 的 iduser_id sku_id date_id 是我们的维度外键sku_num 是我们的度量值。剩下的 create_time 是具体的加购时间精确到秒它区别于维度外键 date_iddate_id 是日期只能精确到哪一天source_id source_type_code source_type_name 这些字段都是来自我们业务系统的我们之前说 DIM 层和 DWD 层的维度表和事实表都是业务驱动的所以它们各自表的设计字段的选择来源于我们的业务系统中表这里的加购事务事实表就是对应我们业务系统当中的 cart_info 通过查询字典表可以看到 不同的 source_type_code 代表不同类型的加购操作用户通过哪种来源类型来加购的比如用户通过广告来加购的那通过哪个广告呢所以这里我们还指定了 source_id这些字段都算是维度但是我们并没有对这些属性做一个维度表而是直接放到事实表里也就是维度退化而维度退化要求不能只有编码一般都是编码和文字描述共存的所以这里我们保留了来源类型编码和来源类型名称。 DROP TABLE IF EXISTS dwd_trade_cart_add_inc; CREATE EXTERNAL TABLE dwd_trade_cart_add_inc (id STRING COMMENT 编号,user_id STRING COMMENT 用户id,sku_id STRING COMMENT 商品id,date_id STRING COMMENT 时间id,create_time STRING COMMENT 加购时间,source_id STRING COMMENT 来源类型ID,source_type_code STRING COMMENT 来源类型编码,source_type_name STRING COMMENT 来源类型名称,sku_num BIGINT COMMENT 加购物车件数 ) COMMENT 交易域加购物车事务事实表PARTITIONED BY (dt STRING)ROW FORMAT DELIMITED FIELDS TERMINATED BY \tSTORED AS ORCLOCATION /warehouse/gmall/dwd/dwd_trade_cart_add_inc/TBLPROPERTIES (orc.compress snappy); 1.1.6、数据流向 现在我们表设计好了下一步就是数据源从哪来从 ods 层的哪些表来以及我们怎么向这张表进行装载insert select这就需要我们了解一下这张表的不同维度的数据应该来自于哪些表。 我们首先需要了解业务系统中 order_info 这张表 其实对于加购这个过程无非只有两种情况1、原本购物车没有这个商品然后进行加购这是对数据库来说是一个 insert 操作2、原本购物车就有这个商品然后加购这对数据库来说是一个 update 操作。显式的变化就是 sku_num 的值的变化。 这样我们就搞清楚了加购这个业务过程会对 order_info或者可以说是 ods_order_info_inc 产生影响产生的影响就是 sku_num 字段的值发生变化。 现在我们不仅要知道数据从张表来还得知道数据从具体哪个分区流向哪个分区 首日数据 所有的增量表都要在首日做一个全量同步这里我们的加购表当前存储的就是首日的全量数据我们需要对字段 create_time 做一个动态分区来把不同时间的加购信息放到不同的分区 每日数据 解决了首日全量数据的分区问题我们之后 ods 层每天的分区中存储的就是 Maxwell 监听的每日的增量数据所以这些都是加购信息我们直接存储当当日分区即可 1.1.7、首日装载语句 -- 动态分区需要设置非严格模式 set hive.exec.dynamic.partition.modenonstrict; insert overwrite table dwd_trade_cart_add_inc partition (dt) selectid,user_id,sku_id,date_format(create_time,yyyy-MM-dd) date_id,create_time,source_id,source_type,dic.dic_name,sku_num,date_format(create_time, yyyy-MM-dd) from (selectdata.id,data.user_id,data.sku_id,data.create_time,data.source_id,data.source_type,data.sku_numfrom ods_cart_info_incwhere dt 2020-06-14and type bootstrap-insert )ci left join (selectdic_code,dic_namefrom ods_base_dic_fullwhere dt2020-06-14and parent_code24 )dic on ci.source_typedic.dic_code; 1.1.8、每日装载语句 我们比如要装载 06-15 这一天的数据首先我们需要保证 type 为 insert 或者 update 类型的操作并且加购后的 sku_num 的值要大于旧的 sku_num 值。 insert overwrite table dwd_trade_cart_add_inc partition(dt2020-06-15) selectid,user_id,sku_id,date_id,create_time,source_id,source_type_code,source_type_name,sku_num from (selectdata.id,data.user_id,data.sku_id,date_format(from_utc_timestamp(ts*1000,GMT8),yyyy-MM-dd) date_id,date_format(from_utc_timestamp(ts*1000,GMT8),yyyy-MM-dd HH:mm:ss) create_time,data.source_id,data.source_type source_type_code,if(typeinsert,data.sku_num,data.sku_num-old[sku_num]) sku_numfrom ods_cart_info_incwhere dt2020-06-15and (typeinsertor(typeupdate and old[sku_num] is not null and data.sku_numcast(old[sku_num] as int))) )cart left join (selectdic_code,dic_name source_type_namefrom ods_base_dic_fullwhere dt2020-06-15and parent_code24 )dic on cart.source_type_codedic.dic_code; 这里在判断是否修改了 order_info 中 sku_num 值的时候我们还可以通过下面的方式来确认修改之前包含该字段 typeupdate and array_contains(map_keys(old),sku_num) 这里我们不能使用 create_time 作为加购时间因为 create_time 是我们创建这个购物车的时间而不是真正的加购时间所以我们应该用 ods_cart_info_inc 中的 ts 自动因为它代表的是订单的变动时间 对于不同的操作类型insert 或 updatesku_num 的值也是不一样的对于 insert 操作这个商品是第一次加入购物车所以 sku_num 就是加购的件数但是对于 updatesku_num 指的是加购后的件数所以实际加购的数量old[sku_num]-data.sku_num 。 所以只要我们清楚了加购这个业务过程对订单表的影响装载这张表就很简单了。  1.2、交易域下单事务事实表 同样分两步设计表结构4步编写装载语句 1.2.1、设计表结构 选择业务过程我们选择的是下单这个业务过程声明粒度要求尽可能最细粒度所以这里的粒度应该是一个订单中的一个商品项而不是一整个订单所以我们也就可以想到这张事实表对应业务系统中的 order_detail 表。确认维度关于下单操作我们能想到的维度比如时间、用户、商品、地区、活动和优惠券。以及下单方式我们之前说过如果某些维度表的维度属性很少比如支付方式表没有必要去单独创建一个维度表因为它就一个支付方式字段则可不创建该维度表而把该表的维度属性直接增加到与之相关的事实表中对于维度退化。确认维度是个灵活的过程它并不取决于我们要分析什么指标而是取决于我们业务系统能提供什么信息比如这里的 order_detail 中包含了下单地区、该订单参与的活动以及使用优惠券的信息才能支持我们确认这样的维度。确认事实也就是确认度量值这里的度量值可以是下单件数、下单原始金额、下单的最终金额、活动优惠金额和优惠券优惠金额等。 1.2.2、建表语句 同样这里的维度可以分为四部分 从业务系统表当中直接拿过来的字段比如 id、order_id 、create_time、source_id、source_type用作关联维度表的维度外键user_id、sku_id、province_id、activity_id算是退化字段因为它和activity_rule_id都在同一张表但是activity_rule_id的粒度更细、activity_rule_id 、coupo_id、date_id等度量指标字段比如 sku_num、split_xxx ...维度退化字段比如 activity_id、source_type_code、source_id、source_type_name 等 DROP TABLE IF EXISTS dwd_trade_order_detail_inc; CREATE EXTERNAL TABLE dwd_trade_order_detail_inc (id STRING COMMENT 编号,order_id STRING COMMENT 订单id,user_id STRING COMMENT 用户id,sku_id STRING COMMENT 商品id,province_id STRING COMMENT 省份id,activity_id STRING COMMENT 参与活动规则id,activity_rule_id STRING COMMENT 参与活动规则id,coupon_id STRING COMMENT 使用优惠券id,date_id STRING COMMENT 下单日期id,create_time STRING COMMENT 下单时间,source_id STRING COMMENT 来源编号,source_type_code STRING COMMENT 来源类型编码,source_type_name STRING COMMENT 来源类型名称,sku_num BIGINT COMMENT 商品数量,split_original_amount DECIMAL(16, 2) COMMENT 原始价格,split_activity_amount DECIMAL(16, 2) COMMENT 活动优惠分摊,split_coupon_amount DECIMAL(16, 2) COMMENT 优惠券优惠分摊,split_total_amount DECIMAL(16, 2) COMMENT 最终价格分摊 ) COMMENT 交易域下单明细事务事实表PARTITIONED BY (dt STRING)ROW FORMAT DELIMITED FIELDS TERMINATED BY \tSTORED AS ORCLOCATION /warehouse/gmall/dwd/dwd_trade_order_detail_inc/TBLPROPERTIES (orc.compress snappy); 1.2.3、数据流向 在数据装载之前我们同样需要了解数据的流向下单这个业务过程会对哪些表产生影响我们就从哪个表去获取数据。 这里的下单这个操作会影响到 order_info会插入一条订单数据、order_detail会插入多条数据取决于订单的中的商品数量、order_detail_coupon用户使用优惠券就会在这张表中插入数据和 order_detail_activity用户参与活动就会往这张表插入数据。 相比较上面的加购操作这里的下单操作虽然涉及到的表更多但是它都是插入insert操作所以事实上装载的逻辑要比加购简单。同时我们依然要区分首日和每日的数据。 1.2.4、首日数据装载 逻辑还是比较简单的就是把 order_detail 作为主表不断进行 left join set hive.exec.dynamic.partition.modenonstrict; insert overwrite table dwd_trade_order_detail_inc partition (dt) selectod.id,order_id,user_id,sku_id,province_id,activity_id,activity_rule_id,coupon_id,date_format(create_time, yyyy-MM-dd) date_id,create_time,source_id,source_type,dic_name,sku_num,split_original_amount,split_activity_amount,split_coupon_amount,split_total_amount,date_format(create_time,yyyy-MM-dd) from (selectdata.id,data.order_id,data.sku_id,data.create_time,data.source_id,data.source_type,data.sku_num,data.sku_num * data.order_price split_original_amount,data.split_total_amount,data.split_activity_amount,data.split_coupon_amountfrom ods_order_detail_incwhere dt 2020-06-14and type bootstrap-insert ) od left join (selectdata.id,data.user_id,data.province_idfrom ods_order_info_incwhere dt 2020-06-14and type bootstrap-insert ) oi on od.order_id oi.id left join (selectdata.order_detail_id,data.activity_id,data.activity_rule_idfrom ods_order_detail_activity_incwhere dt 2020-06-14and type bootstrap-insert ) act on od.id act.order_detail_id left join (selectdata.order_detail_id,data.coupon_idfrom ods_order_detail_coupon_incwhere dt 2020-06-14and type bootstrap-insert ) cou on od.id cou.order_detail_id left join (selectdic_code,dic_namefrom ods_base_dic_fullwhere dt2020-06-14and parent_code24 )dic on od.source_typedic.dic_code; 1.2.5、每日装载语句  对于之后的每日装载我们只需要确保每张表的 type 为 insert、dt 当天即可。 insert overwrite table dwd_trade_order_detail_inc partition (dt2020-06-15) selectod.id,order_id,user_id,sku_id,province_id,activity_id,activity_rule_id,coupon_id,date_id,create_time,source_id,source_type,dic_name,sku_num,split_original_amount,split_activity_amount,split_coupon_amount,split_total_amount from (selectdata.id,data.order_id,data.sku_id,date_format(data.create_time, yyyy-MM-dd) date_id,data.create_time,data.source_id,data.source_type,data.sku_num,data.sku_num * data.order_price split_original_amount,data.split_total_amount,data.split_activity_amount,data.split_coupon_amountfrom ods_order_detail_incwhere dt 2020-06-15and type insert ) od left join (selectdata.id,data.user_id,data.province_idfrom ods_order_info_incwhere dt 2020-06-15and type insert ) oi on od.order_id oi.id left join (selectdata.order_detail_id,data.activity_id,data.activity_rule_idfrom ods_order_detail_activity_incwhere dt 2020-06-15and type insert ) act on od.id act.order_detail_id left join (selectdata.order_detail_id,data.coupon_idfrom ods_order_detail_coupon_incwhere dt 2020-06-15and type insert ) cou on od.id cou.order_detail_id left join (selectdic_code,dic_namefrom ods_base_dic_fullwhere dt2020-06-15and parent_code24 )dic on od.source_typedic.dic_code; 1.3、交易域取消订单事务事实表 注意是取消订单不是退单还没完成支付呢。 1.3.1、设计表结构 依然是那4个步骤 选择业务过程取消订单声明粒度谁在什么时候取消了哪个商品确认维度时间、用户、商品、地区、活动、优惠券确认事实取消的商品件数、取消的金额、下单的原始金额、最终下单金额、活动优惠金额、优惠券金额 可以看到取消订单表的大部分维度和下单表是一致的只是语义不一样而已。 1.3.2、建表语句 DROP TABLE IF EXISTS dwd_trade_cancel_detail_inc; CREATE EXTERNAL TABLE dwd_trade_cancel_detail_inc (id STRING COMMENT 编号,order_id STRING COMMENT 订单id,user_id STRING COMMENT 用户id,sku_id STRING COMMENT 商品id,province_id STRING COMMENT 省份id,activity_id STRING COMMENT 参与活动规则id,activity_rule_id STRING COMMENT 参与活动规则id,coupon_id STRING COMMENT 使用优惠券id,date_id STRING COMMENT 取消订单日期id,cancel_time STRING COMMENT 取消订单时间,source_id STRING COMMENT 来源编号,source_type_code STRING COMMENT 来源类型编码,source_type_name STRING COMMENT 来源类型名称,sku_num BIGINT COMMENT 商品数量,split_original_amount DECIMAL(16, 2) COMMENT 原始价格,split_activity_amount DECIMAL(16, 2) COMMENT 活动优惠分摊,split_coupon_amount DECIMAL(16, 2) COMMENT 优惠券优惠分摊,split_total_amount DECIMAL(16, 2) COMMENT 最终价格分摊 ) COMMENT 交易域取消订单明细事务事实表PARTITIONED BY (dt STRING)ROW FORMAT DELIMITED FIELDS TERMINATED BY \tSTORED AS ORCLOCATION /warehouse/gmall/dwd/dwd_trade_cancel_detail_inc/TBLPROPERTIES (orc.compress snappy); 1.3.3、 数据流向 我们需要知道取消订单会对哪些表产生影响事实上只会对 order_info 产生影响改变 order_info 的 order_status 字段 同样我们的首日数据存在 ods_order_info_inc 当中当中也存在一些取消订单的数据需要我们进行分区处理。 不同 order_status 对应的状态 这里需要注意的是对于已取消、已完成、退款完成这些操作表示的都是最终的操作这些订单的状态不会再发生变化但是对于未支付、已支付、退款中这些订单状态都还可能会发送变化。所以当我们在找支付成功的订单时不仅要考虑订单状态是已支付状态还有退款完成、已支付这些状态也经历过已支付状态。 1.3.4、首日数据装载 set hive.exec.dynamic.partition.modenonstrict; insert overwrite table dwd_trade_cancel_detail_inc partition (dt) selectod.id,order_id,user_id,sku_id,province_id,activity_id,activity_rule_id,coupon_id,date_format(canel_time,yyyy-MM-dd) date_id,canel_time,source_id,source_type,dic_name,sku_num,split_original_amount,split_activity_amount,split_coupon_amount,split_total_amount,date_format(canel_time,yyyy-MM-dd) from (selectdata.id,data.order_id,data.sku_id,data.source_id,data.source_type,data.sku_num,data.sku_num * data.order_price split_original_amount,data.split_total_amount,data.split_activity_amount,data.split_coupon_amountfrom ods_order_detail_incwhere dt 2020-06-14and type bootstrap-insert ) od join (selectdata.id,data.user_id,data.province_id,data.operate_time canel_timefrom ods_order_info_incwhere dt 2020-06-14and type bootstrap-insertand data.order_status1003 ) oi on od.order_id oi.id left join (selectdata.order_detail_id,data.activity_id,data.activity_rule_idfrom ods_order_detail_activity_incwhere dt 2020-06-14and type bootstrap-insert ) act on od.id act.order_detail_id left join (selectdata.order_detail_id,data.coupon_idfrom ods_order_detail_coupon_incwhere dt 2020-06-14and type bootstrap-insert ) cou on od.id cou.order_detail_id left join (selectdic_code,dic_namefrom ods_base_dic_fullwhere dt2020-06-14and parent_code24 )dic on od.source_typedic.dic_code; 1.3.5、每日数据装载 这里需要注意我们取消的订单可能是前一天下的所以我们从当天的 ods_order_detail_inc 中是查不到的所以我们查询的时候还需要从当天的前一天订单明细中也查一份而且为了和 order_detail 进行 join 关联防止关联不上我们的其它表也需要查询前一天的数据。 insert overwrite table dwd_trade_cancel_detail_inc partition (dt2020-06-15) selectod.id,order_id,user_id,sku_id,province_id,activity_id,activity_rule_id,coupon_id,date_format(canel_time,yyyy-MM-dd) date_id,canel_time,source_id,source_type,dic_name,sku_num,split_original_amount,split_activity_amount,split_coupon_amount,split_total_amount from (selectdata.id,data.order_id,data.sku_id,data.source_id,data.source_type,data.sku_num,data.sku_num * data.order_price split_original_amount,data.split_total_amount,data.split_activity_amount,data.split_coupon_amountfrom ods_order_detail_inc -- 取消订单不会影响订单明细表where (dt2020-06-15 or dtdate_add(2020-06-15,-1))and (type insert or type bootstrap-insert) -- 过了第2天就可以不写bootstrap-insert ) od join (selectdata.id,data.user_id,data.province_id,data.operate_time canel_timefrom ods_order_info_incwhere dt 2020-06-15and type updateand data.order_status1003and array_contains(map_keys(old),order_status) ) oi on order_id oi.id left join (selectdata.order_detail_id,data.activity_id,data.activity_rule_idfrom ods_order_detail_activity_incwhere (dt2020-06-15 or dtdate_add(2020-06-15,-1))and (type insert or type bootstrap-insert) ) act on od.id act.order_detail_id left join (selectdata.order_detail_id,data.coupon_idfrom ods_order_detail_coupon_incwhere (dt2020-06-15 or dtdate_add(2020-06-15,-1))and (type insert or type bootstrap-insert) ) cou on od.id cou.order_detail_id left join (selectdic_code,dic_namefrom ods_base_dic_fullwhere dt2020-06-15and parent_code24 )dic on od.source_typedic.dic_code; 1.4、交易域支付成功事务事实表 我们要求事实表对应的业务过程必须是原子操作的也就是不可再切分的所以这里说的是支付成功这个业务过程而不是支付这个行为因为支付可能成功、可能失败。 1.4.1、设计表结构 选择业务过程支付成功声明粒度谁什么时候成功支付了哪个商品确认维度时间、用户、商品、地区、活动、优惠券、支付方式维度退化确认事实支付件数、支付金额、最终支付金额、活动优惠金额、优惠券金额 1.4.2、建表语句 同样是维度外键度量值退化字段 DROP TABLE IF EXISTS dwd_trade_pay_detail_suc_inc; CREATE EXTERNAL TABLE dwd_trade_pay_detail_suc_inc (id STRING COMMENT 编号,order_id STRING COMMENT 订单id,user_id STRING COMMENT 用户id,sku_id STRING COMMENT 商品id,province_id STRING COMMENT 省份id,activity_id STRING COMMENT 参与活动规则id,activity_rule_id STRING COMMENT 参与活动规则id,coupon_id STRING COMMENT 使用优惠券id,payment_type_code STRING COMMENT 支付类型编码,payment_type_name STRING COMMENT 支付类型名称,date_id STRING COMMENT 支付日期id,callback_time STRING COMMENT 支付成功时间,source_id STRING COMMENT 来源编号,source_type_code STRING COMMENT 来源类型编码,source_type_name STRING COMMENT 来源类型名称,sku_num BIGINT COMMENT 商品数量,split_original_amount DECIMAL(16, 2) COMMENT 应支付原始金额,split_activity_amount DECIMAL(16, 2) COMMENT 支付活动优惠分摊,split_coupon_amount DECIMAL(16, 2) COMMENT 支付优惠券优惠分摊,split_payment_amount DECIMAL(16, 2) COMMENT 支付金额 ) COMMENT 交易域成功支付事务事实表PARTITIONED BY (dt STRING)ROW FORMAT DELIMITED FIELDS TERMINATED BY \tSTORED AS ORCLOCATION /warehouse/gmall/dwd/dwd_trade_pay_detail_suc_inc/TBLPROPERTIES (orc.compress snappy); 1.4.3、数据流向 支付成功会影响哪些表其实只会影响一张表当支付成功后 order_info 的 order_status 字段就会变成 1002payment_info 的 order_status 字段会变成 1602 。 事实表要求我们的粒度是最小的所以我们需要找到支付成功的订单明细而不是订单信息。所以我们需要先从 order_info 中找到支付成功的订单然后去和 order_detail 关联得到该订单的所有商品 ... 尽管支付成功后 order_info 的 order_status 字段会变成 1002但是我们并不能把它当做过滤条件因为它并不是一个最终状态我们应该去 payment_info 去找更合适。 当我们点击支付按钮的时候payment_info 中就会插入一条数据此时的 payment_status 值为 1601 待支付状态create_time 也会插入当前时间但是 callback_time 字段为空callback_content 字段同样为空。当支付成功的时候 payment_status 值变为 1602 支付成功状态 callback_time 字段为支付成功的时间callback_content 字段为回调内容。 所以当我们每日装载数据的时候就需要从 ods_payment_info_inc 的当日分区中过滤 type 为 update 的数据首日装载另做判断因为首日装载都是 bootstrap-insert 我们需要判断支 payment_status 。 1.4.4、首日装载语句 insert overwrite table dwd_trade_pay_detail_suc_inc partition (dt) selectod.id,od.order_id,user_id,sku_id,province_id,activity_id,activity_rule_id,coupon_id,payment_type,pay_dic.dic_name,date_format(callback_time,yyyy-MM-dd) date_id,callback_time,source_id,source_type,src_dic.dic_name,sku_num,split_original_amount,split_activity_amount,split_coupon_amount,split_total_amount,date_format(callback_time,yyyy-MM-dd) from (selectdata.id,data.order_id,data.sku_id,data.source_id,data.source_type,data.sku_num,data.sku_num * data.order_price split_original_amount,data.split_total_amount,data.split_activity_amount,data.split_coupon_amountfrom ods_order_detail_incwhere dt 2020-06-14and type bootstrap-insert ) od join (selectdata.user_id,data.order_id,data.payment_type,data.callback_timefrom ods_payment_info_incwhere dt2020-06-14and typebootstrap-insertand data.payment_status1602 ) pi on od.order_idpi.order_id left join (selectdata.id,data.province_idfrom ods_order_info_incwhere dt 2020-06-14and type bootstrap-insert ) oi on od.order_id oi.id left join (selectdata.order_detail_id,data.activity_id,data.activity_rule_idfrom ods_order_detail_activity_incwhere dt 2020-06-14and type bootstrap-insert ) act on od.id act.order_detail_id left join (selectdata.order_detail_id,data.coupon_idfrom ods_order_detail_coupon_incwhere dt 2020-06-14and type bootstrap-insert ) cou on od.id cou.order_detail_id left join (selectdic_code,dic_namefrom ods_base_dic_fullwhere dt2020-06-14and parent_code11 ) pay_dic on pi.payment_typepay_dic.dic_code left join (selectdic_code,dic_namefrom ods_base_dic_fullwhere dt2020-06-14and parent_code24 )src_dic on od.source_typesrc_dic.dic_code; 1.4.5、每日装载语句 直接从 payment_info 中过滤出 typeupdate 的记录然后在关联 oder_detail  的时候需要考虑不只是获取当日分区的订单明细因为可能今天的支付成功订单是昨天创建的所以需要从两个分区当日和前一天获取订单明细数据。在关联 order_info 的时候不需要获取前一天的分区数据因为只要 payment_info 发生变化order_info 的 order_status 也会发生变化所以只需要过滤出 ods_order_info_inc 中的 typeupdate 的数据。 insert overwrite table dwd_trade_pay_detail_suc_inc partition (dt2020-06-15) selectod.id,od.order_id,user_id,sku_id,province_id,activity_id,activity_rule_id,coupon_id,payment_type,pay_dic.dic_name,date_format(callback_time,yyyy-MM-dd) date_id,callback_time,source_id,source_type,src_dic.dic_name,sku_num,split_original_amount,split_activity_amount,split_coupon_amount,split_total_amount from (selectdata.id,data.order_id,data.sku_id,data.source_id,data.source_type,data.sku_num,data.sku_num * data.order_price split_original_amount,data.split_total_amount,data.split_activity_amount,data.split_coupon_amountfrom ods_order_detail_incwhere (dt 2020-06-15 or dt date_add(2020-06-15,-1))and (type insert or type bootstrap-insert) ) od join (selectdata.user_id,data.order_id,data.payment_type,data.callback_timefrom ods_payment_info_incwhere dt2020-06-15and typeupdateand array_contains(map_keys(old),payment_status)and data.payment_status1602 ) pi on od.order_idpi.order_id left join (selectdata.id,data.province_idfrom ods_order_info_incwhere (dt 2020-06-15)and (type update)and array_contains(map_keys(old),order_status)and order_status1002 ) oi on od.order_id oi.id left join (selectdata.order_detail_id,data.activity_id,data.activity_rule_idfrom ods_order_detail_activity_incwhere (dt 2020-06-15 or dt date_add(2020-06-15,-1))and (type insert or type bootstrap-insert) ) act on od.id act.order_detail_id left join (selectdata.order_detail_id,data.coupon_idfrom ods_order_detail_coupon_incwhere (dt 2020-06-15 or dt date_add(2020-06-15,-1))and (type insert or type bootstrap-insert) ) cou on od.id cou.order_detail_id left join (selectdic_code,dic_namefrom ods_base_dic_fullwhere dt2020-06-15and parent_code11 ) pay_dic on pi.payment_typepay_dic.dic_code left join (selectdic_code,dic_namefrom ods_base_dic_fullwhere dt2020-06-15and parent_code24 )src_dic on od.source_typesrc_dic.dic_code; 1.5、交易域退单事务事实表 我们这里只考虑申请退单不考虑申请退单后卖家怎么处理退单状态怎么变化。 1.5.1、设计表结构 选择业务过程退单声明粒度谁什么时候退了哪件商品确认维度时间、用户、商品、退单类型、退单原因类型确认事实退单件数、退单金额 1.5.2、建表语句 DROP TABLE IF EXISTS dwd_trade_order_refund_inc; CREATE EXTERNAL TABLE dwd_trade_order_refund_inc (id STRING COMMENT 编号,user_id STRING COMMENT 用户ID,order_id STRING COMMENT 订单ID,sku_id STRING COMMENT 商品ID,province_id STRING COMMENT 地区ID,date_id STRING COMMENT 日期ID,create_time STRING COMMENT 退单时间,refund_type_code STRING COMMENT 退单类型编码,refund_type_name STRING COMMENT 退单类型名称,refund_reason_type_code STRING COMMENT 退单原因类型编码,refund_reason_type_name STRING COMMENT 退单原因类型名称,refund_reason_txt STRING COMMENT 退单原因描述,refund_num BIGINT COMMENT 退单件数,refund_amount DECIMAL(16, 2) COMMENT 退单金额 ) COMMENT 交易域退单事务事实表PARTITIONED BY (dt STRING)STORED AS ORCLOCATION /warehouse/gmall/dwd/dwd_trade_order_refund_inc/TBLPROPERTIES (orc.compress snappy); 1.5.3、数据流向 同样需要分析退单这个业务过程会对哪些表产生影响order_info 的 order_status 字段会发生变化变为 1005 退款中order_refund_info 表中会插入一条数据。 1.5.4、首日装载 insert overwrite table dwd_trade_order_refund_inc partition(dt) selectri.id,user_id,order_id,sku_id,province_id,date_format(create_time,yyyy-MM-dd) date_id,create_time,refund_type,type_dic.dic_name,refund_reason_type,reason_dic.dic_name,refund_reason_txt,refund_num,refund_amount,date_format(create_time,yyyy-MM-dd) from (selectdata.id,data.user_id,data.order_id,data.sku_id,data.refund_type,data.refund_num,data.refund_amount,data.refund_reason_type,data.refund_reason_txt,data.create_timefrom ods_order_refund_info_incwhere dt2020-06-14and typebootstrap-insert )ri left join (selectdata.id,data.province_idfrom ods_order_info_inc --为了拿到 province_idwhere dt2020-06-14and typebootstrap-insert )oi on ri.order_idoi.id left join (selectdic_code,dic_namefrom ods_base_dic_fullwhere dt2020-06-14and parent_code 15 )type_dic on ri.refund_typetype_dic.dic_code left join (selectdic_code,dic_namefrom ods_base_dic_fullwhere dt2020-06-14and parent_code 13 )reason_dic on ri.refund_reason_typereason_dic.dic_code; 1.5.5、每日装载语句 insert overwrite table dwd_trade_order_refund_inc partition(dt2020-06-15) selectri.id,user_id,order_id,sku_id,province_id,date_format(create_time,yyyy-MM-dd) date_id,create_time,refund_type,type_dic.dic_name,refund_reason_type,reason_dic.dic_name,refund_reason_txt,refund_num,refund_amount from (selectdata.id,data.user_id,data.order_id,data.sku_id,data.refund_type,data.refund_num,data.refund_amount,data.refund_reason_type,data.refund_reason_txt,data.create_timefrom ods_order_refund_info_incwhere dt2020-06-15and typeinsert )ri left join (selectdata.id,data.province_idfrom ods_order_info_inc where dt2020-06-15and typeupdateand array_contains(map_keys(old),old_status)and order_status1005 )oi on ri.order_idoi.id left join (selectdic_code,dic_namefrom ods_base_dic_fullwhere dt2020-06-15and parent_code 15 )type_dic on ri.refund_typetype_dic.dic_code left join (selectdic_code,dic_namefrom ods_base_dic_fullwhere dt2020-06-15and parent_code 13 )reason_dic on ri.refund_reason_typereason_dic.dic_code; 1.6、交易域退款成功事务事实表 1.6.1、设计表结构 选择业务过程退款成功声明粒度谁什么时候哪件商品退款成功确认维度用户、地区、时间、商品、退款方式确认事实退款件数、退款金额 1.6.2、建表语句 DROP TABLE IF EXISTS dwd_trade_refund_pay_suc_inc; CREATE EXTERNAL TABLE dwd_trade_refund_pay_suc_inc (id STRING COMMENT 编号,user_id STRING COMMENT 用户ID,order_id STRING COMMENT 订单编号,sku_id STRING COMMENT SKU编号,province_id STRING COMMENT 地区ID,payment_type_code STRING COMMENT 支付类型编码,payment_type_name STRING COMMENT 支付类型名称,date_id STRING COMMENT 日期ID,callback_time STRING COMMENT 支付成功时间,refund_num DECIMAL(16, 2) COMMENT 退款件数,refund_amount DECIMAL(16, 2) COMMENT 退款金额 ) COMMENT 交易域提交退款成功事务事实表PARTITIONED BY (dt STRING)STORED AS ORCLOCATION /warehouse/gmall/dwd/dwd_trade_refund_pay_suc_inc/TBLPROPERTIES (orc.compress snappy); 1.6.3、数据流向 用户退款会对哪些表产生影响order_info 的 order_status 字段会发生变化1006refund_payment 的 redund_status 也会发生变化。 和上面的退单一样我们都需要精确到商品因为退单可能是退订单中的一件或多件商品。 1.6.4、首日装载 insert overwrite table dwd_trade_refund_pay_suc_inc partition(dt) selectrp.id,user_id,rp.order_id,rp.sku_id,province_id,payment_type,dic_name,date_format(callback_time,yyyy-MM-dd) date_id,callback_time,refund_num,total_amount,date_format(callback_time,yyyy-MM-dd) from (selectdata.id,data.order_id,data.sku_id,data.payment_type,data.callback_time,data.total_amountfrom ods_refund_payment_incwhere dt2020-06-14and type bootstrap-insertand data.refund_status1602 )rp left join (selectdata.id,data.user_id,data.province_idfrom ods_order_info_incwhere dt2020-06-14and typebootstrap-insert )oi on rp.order_idoi.id left join (selectdata.order_id,data.sku_id,data.refund_numfrom ods_order_refund_info_incwhere dt2020-06-14and typebootstrap-insert )ri on rp.order_idri.order_id and rp.sku_idri.sku_id --必须保证同一订单同一商品 left join (selectdic_code,dic_namefrom ods_base_dic_fullwhere dt2020-06-14and parent_code11 )dic on rp.payment_typedic.dic_code; 1.6.5、每日装载 insert overwrite table dwd_trade_refund_pay_suc_inc partition(dt2020-06-15) selectrp.id,user_id,rp.order_id,rp.sku_id,province_id,payment_type,dic_name,date_format(callback_time,yyyy-MM-dd) date_id,callback_time,refund_num,total_amount from (selectdata.id,data.order_id,data.sku_id,data.payment_type,data.callback_time,data.total_amountfrom ods_refund_payment_incwhere dt2020-06-15and type updateand array_contains(map_keys(old),refund_status)and data.refund_status1602 )rp left join (selectdata.id,data.user_id,data.province_idfrom ods_order_info_incwhere dt2020-06-15and typeupdateand array_contains(map_keys(old),order_status)and data.order_status1006 )oi on rp.order_idoi.id left join (selectdata.order_id,data.sku_id,data.refund_numfrom ods_order_refund_info_incwhere dt2020-06-15and typeupdateand array_contains(map_keys(old),refund_status)and data.refund_status0705 )ri on rp.order_idri.order_id and rp.sku_idri.sku_id left join (selectdic_code,dic_namefrom ods_base_dic_fullwhere dt2020-06-15and parent_code11 )dic on rp.payment_typedic.dic_code; 1.7、交易域购物车周期快照表 所谓周期快照表区别于我们前面的事务事实表周期快照表是全量表一般用来解决存量型指标比如库存、余额等这是事务事实表的不足。 1.7.1、设计表结构 对于事务型事实表通常都是一张事实表对应一个业务过程对于累积快照事实表一张表对应多个业务过程。对于这里的周期快照表并没有讨论的意义。因为无法确定它对应几个业务过程。 DROP TABLE IF EXISTS dwd_trade_cart_full; CREATE EXTERNAL TABLE dwd_trade_cart_full (id STRING COMMENT 编号,user_id STRING COMMENT 用户id,sku_id STRING COMMENT 商品id,sku_name STRING COMMENT 商品名称,sku_num BIGINT COMMENT 加购物车件数 ) COMMENT 交易域购物车周期快照事实表PARTITIONED BY (dt STRING)ROW FORMAT DELIMITED FIELDS TERMINATED BY \tSTORED AS ORCLOCATION /warehouse/gmall/dwd/dwd_trade_cart_full/TBLPROPERTIES (orc.compress snappy); 1.7.2、装载语句 对于购物车表我们在 ODS 层建了两张表增量和全量这里我们选择全量表作为数据来源 insert overwrite table dwd_trade_cart_full partition(dt2020-06-14) selectid,user_id,sku_id,sku_name,sku_num from ods_cart_info_full where dt2020-06-14 and is_ordered0; 这里的 is_ordered 是一个删除标记当它的值为 1 的时候代表用户已下单也就意味着从购物车删除了该商品。所以我们每日装载的时候需要注意筛选出 is_ordered 0 的数据。 1.8、工具域优惠券领取事务事实表 有关优惠券的业务过程领券、使用券下单、使用券支付。它们都会对表 coupon_use 产生影响领券后表 coupon_use 会插入一条新的记录使用券下单时会对字段 order_id、coupon_status、using_time 都会发生变化使用券支付时会对字段 coupon_status、used_time 发生变化。 1.8.1、建表语句 需要注意对于优惠券事实表它并没有一个明显的度量值。虽然我们说事实表是由维度外键和度量值组成的但规矩也不是死的这里的度量值是隐含的也就是一行代表一个优惠券的记录。 DROP TABLE IF EXISTS dwd_tool_coupon_get_inc; CREATE EXTERNAL TABLE dwd_tool_coupon_get_inc (id STRING COMMENT 编号,coupon_id STRING COMMENT 优惠券ID,user_id STRING COMMENT userid,date_id STRING COMMENT 日期ID,get_time STRING COMMENT 领取时间 ) COMMENT 优惠券领取事务事实表PARTITIONED BY (dt STRING)STORED AS ORCLOCATION /warehouse/gmall/dwd/dwd_tool_coupon_get_inc/TBLPROPERTIES (orc.compress snappy); 1.8.2、首日装载  insert overwrite table dwd_tool_coupon_get_inc partition(dt) selectdata.id,data.coupon_id,data.user_id,date_format(data.get_time,yyyy-MM-dd) date_id,data.get_time,date_format(data.get_time,yyyy-MM-dd) from ods_coupon_use_inc where dt2020-06-14 and typebootstrap-insert; 1.8.3、每日装载  只要是 insert 就一定是领券操作只要是 update 就是使用券操作。 insert overwrite table dwd_tool_coupon_get_inc partition (dt2020-06-15) selectdata.id,data.coupon_id,data.user_id,date_format(data.get_time,yyyy-MM-dd) date_id,data.get_time from ods_coupon_use_inc where dt2020-06-15 and typeinsert; 1.9、工具域优惠券使用(下单)事务事实表 1.9.1、建表语句 DROP TABLE IF EXISTS dwd_tool_coupon_order_inc; CREATE EXTERNAL TABLE dwd_tool_coupon_order_inc (id STRING COMMENT 编号,coupon_id STRING COMMENT 优惠券ID,user_id STRING COMMENT user_id,order_id STRING COMMENT order_id,date_id STRING COMMENT 日期ID,order_time STRING COMMENT 使用下单时间 ) COMMENT 优惠券使用下单事务事实表PARTITIONED BY (dt STRING)STORED AS ORCLOCATION /warehouse/gmall/dwd/dwd_tool_coupon_order_inc/TBLPROPERTIES (orc.compress snappy); 1.9.2、首日装载 根据 used_time 是否为空或者 coupon_status 是否等于 1402 都是可以的。 insert overwrite table dwd_tool_coupon_order_inc partition(dt) selectdata.id,data.coupon_id,data.user_id,data.order_id,date_format(data.using_time,yyyy-MM-dd) date_id,data.using_time,date_format(data.using_time,yyyy-MM-dd) from ods_coupon_use_inc where dt2020-06-14 and typebootstrap-insert and data.using_time is not null; 1.9.3、每日装载 insert overwrite table dwd_tool_coupon_order_inc partition(dt2020-06-15) selectdata.id,data.coupon_id,data.user_id,data.order_id,date_format(data.using_time,yyyy-MM-dd) date_id,data.using_time from ods_coupon_use_inc where dt2020-06-15 and typeupdate and array_contains(map_keys(old),using_time); 1.10、工具域优惠券使用(支付)事务事实表 1.10.1、建表语句 DROP TABLE IF EXISTS dwd_tool_coupon_pay_inc; CREATE EXTERNAL TABLE dwd_tool_coupon_pay_inc (id STRING COMMENT 编号,coupon_id STRING COMMENT 优惠券ID,user_id STRING COMMENT user_id,order_id STRING COMMENT order_id,date_id STRING COMMENT 日期ID,payment_time STRING COMMENT 使用下单时间 ) COMMENT 优惠券使用支付事务事实表PARTITIONED BY (dt STRING)STORED AS ORCLOCATION /warehouse/gmall/dwd/dwd_tool_coupon_pay_inc/TBLPROPERTIES (orc.compress snappy); 1.10.2、首日装载 根据 used_time 是否为空或者 coupon_status 是否等于 1403 都是可以的。 insert overwrite table dwd_tool_coupon_pay_inc partition(dt) selectdata.id,data.coupon_id,data.user_id,data.order_id,date_format(data.used_time,yyyy-MM-dd) date_id,data.used_time,date_format(data.used_time,yyyy-MM-dd) from ods_coupon_use_inc where dt2020-06-14 and typebootstrap-insert and data.used_time is not null; 1.10.3、每日装载 insert overwrite table dwd_tool_coupon_pay_inc partition(dt2020-06-15) selectdata.id,data.coupon_id,data.user_id,data.order_id,date_format(data.used_time,yyyy-MM-dd) date_id,data.used_time from ods_coupon_use_inc where dt2020-06-15 and typeupdate and array_contains(map_keys(old),used_time); 1.11、互动域收藏商品事务事实表 1.11.1、建表语句 对于商品收藏同样没有度量字段因为一行就相当于一个隐含的度量值——一个商品收藏。 DROP TABLE IF EXISTS dwd_interaction_favor_add_inc; CREATE EXTERNAL TABLE dwd_interaction_favor_add_inc (id STRING COMMENT 编号,user_id STRING COMMENT 用户id,sku_id STRING COMMENT sku_id,date_id STRING COMMENT 日期id,create_time STRING COMMENT 收藏时间 ) COMMENT 收藏事实表PARTITIONED BY (dt STRING)STORED AS ORCLOCATION /warehouse/gmall/dwd/dwd_interaction_favor_add_inc/TBLPROPERTIES (orc.compress snappy); 1.11.2、首日装载 同样我们需要分析收藏这个行为会对哪些表产生影响事实上只会对 favor_info 产生影响 当用户收藏商品的时候favor_info 中会插入一条数据当用户取消收藏时favor_info 中的 is_cancal 字段修改为为 1 同时 cancal_time 设置为当前时间。所以只要 typeinsert 就是商品收藏操作只要是 typeupdate 并且 is_cancal1 并且 cancal_time is not null 那么就是取消收藏操作但是我们这里并没有建立取消收藏事实表。 set hive.exec.dynamic.partition.modenonstrict; insert overwrite table dwd_interaction_favor_add_inc partition(dt) selectdata.id,data.user_id,data.sku_id,date_format(data.create_time,yyyy-MM-dd) date_id,data.create_time,date_format(data.create_time,yyyy-MM-dd) from ods_favor_info_inc where dt2020-06-14 and type bootstrap-insert; 1.11.3、每日装载 insert overwrite table dwd_interaction_favor_add_inc partition(dt2020-06-15) selectdata.id,data.user_id,data.sku_id,date_format(data.create_time,yyyy-MM-dd) date_id,data.create_time from ods_favor_info_inc where dt2020-06-15 and type insert; 1.12、互动域评价事务事实表 1.12.1、建表语句 我们的这张表的粒度应该是 谁什么时候哪个订单哪个商品评论相关的维度属性/度量比如好评还是差评可以算是一个维度被用在 SQL 的 where 过滤条件当中也可以算是度量值被用在聚合函数当中具体看使用场景 DROP TABLE IF EXISTS dwd_interaction_comment_inc; CREATE EXTERNAL TABLE dwd_interaction_comment_inc (id STRING COMMENT 编号,user_id STRING COMMENT 用户ID,sku_id STRING COMMENT sku_id,order_id STRING COMMENT 订单ID,date_id STRING COMMENT 日期ID,create_time STRING COMMENT 评价时间,appraise_code STRING COMMENT 评价编码,appraise_name STRING COMMENT 评价名称(好评/中评/差评/自动) ) COMMENT 评价事务事实表PARTITIONED BY (dt STRING)STORED AS ORCLOCATION /warehouse/gmall/dwd/dwd_interaction_comment_inc/TBLPROPERTIES (orc.compress snappy); 1.12.2、首日装载 insert overwrite table dwd_interaction_comment_inc partition(dt) selectid,user_id,sku_id,order_id,date_format(create_time,yyyy-MM-dd) date_id,create_time,appraise,dic_name,date_format(create_time,yyyy-MM-dd) from (selectdata.id,data.user_id,data.sku_id,data.order_id,data.create_time,data.appraisefrom ods_comment_info_incwhere dt2020-06-14and typebootstrap-insert )ci left join (selectdic_code,dic_namefrom ods_base_dic_fullwhere dt2020-06-14and parent_code12 )dic on ci.appraisedic.dic_code; 1.12.3、每日装载 insert overwrite table dwd_interaction_comment_inc partition(dt2020-06-15) selectid,user_id,sku_id,order_id,date_format(create_time,yyyy-MM-dd) date_id,create_time,appraise,dic_name from (selectdata.id,data.user_id,data.sku_id,data.order_id,data.create_time,data.appraisefrom ods_comment_info_incwhere dt2020-06-15and typeinsert )ci left join (selectdic_code,dic_namefrom ods_base_dic_fullwhere dt2020-06-15and parent_code12 )dic on ci.appraisedic.dic_code; 1.13、流量域页面浏览事务事实表 流量域里面的业务过程一般都来自用户行为日志因为我们一个网页的访问量、一个按钮的点击量不会存到数据库一般都是前端埋点写到日志里面。 1.13.1、建表语句 这里我们的业务过程页面浏览的粒度是 谁这里指的主要是设备id因为很多时候并不需要登录才能浏览 什么时候 浏览了哪个页面 DROP TABLE IF EXISTS dwd_traffic_page_view_inc; CREATE EXTERNAL TABLE dwd_traffic_page_view_inc (province_id STRING COMMENT 省份id,brand STRING COMMENT 手机品牌,channel STRING COMMENT 渠道,is_new STRING COMMENT 是否首次启动,model STRING COMMENT 手机型号,mid_id STRING COMMENT 设备id,operate_system STRING COMMENT 操作系统,user_id STRING COMMENT 会员id,version_code STRING COMMENT app版本号,page_item STRING COMMENT 目标id ,page_item_type STRING COMMENT 目标类型,last_page_id STRING COMMENT 上页类型,page_id STRING COMMENT 页面ID ,source_type STRING COMMENT 来源类型,date_id STRING COMMENT 日期id,view_time STRING COMMENT 跳入时间,session_id STRING COMMENT 所属会话id,during_time BIGINT COMMENT 持续时间毫秒 ) COMMENT 页面日志表PARTITIONED BY (dt STRING)STORED AS ORCLOCATION /warehouse/gmall/dwd/dwd_traffic_page_view_incTBLPROPERTIES (orc.compress snappy); 这里从 province_id 到 version_code 字段都是从日志中退化到事实表的字段它们存在于日志数据中的 common 属性里面都是环境信息。这里退化的原因是我们的数据源是日志而日志中既包含了环境这些维度信息又包含了业务过程信息如果把它们单独分开分别创建多张维度表和事实表的话当我们需要从日志中读取再装载的时候又需要把它们 join 起来。所以反正它们本来就在一起还不如直接放一起做一个维度退化免得分开还得 join。 这张表几乎所有字段都来组我们的日志数据除了 province_id 需要通过关联 area_code 来间接得到、session_id 需要加工得到。 1.13.2、数据装载 我们需要通过判断 page 属性是否为空来判断当前日志是不是页面日志page 为空是启动日志不为空则为页面日志。 关于页面浏览表的分区因为我们的页面浏览是没有历史数据的所以我们并不需要首日、每日装载的区分。 set hive.cbo.enablefalse; insert overwrite table dwd_traffic_page_view_inc partition (dt2020-06-14) selectprovince_id,brand,channel,is_new,model,mid_id,operate_system,user_id,version_code,page_item,page_item_type,last_page_id,page_id,source_type,date_format(from_utc_timestamp(ts,GMT8),yyyy-MM-dd) date_id,date_format(from_utc_timestamp(ts,GMT8),yyyy-MM-dd HH:mm:ss) view_time,concat(mid_id,-,last_value(session_start_point,true) over (partition by mid_id order by ts)) session_id,during_time from (selectcommon.ar area_code,common.ba brand,common.ch channel,common.is_new is_new,common.md model,common.mid mid_id,common.os operate_system,common.uid user_id,common.vc version_code,page.during_time,page.item page_item,page.item_type page_item_type,page.last_page_id,page.page_id,page.source_type,ts,if(page.last_page_id is null,ts,null) session_start_pointfrom ods_log_incwhere dt2020-06-14and page is not null )log left join (selectid province_id,area_codefrom ods_base_province_fullwhere dt2020-06-14 )bp on log.area_codebp.area_code; Bug - struct is not null 描述 例如struct是一个结构体它有一些字段比如user_idpage_id等等在Hive3.x版本中使用struct is not null时没有把结构体为null的数据筛选掉。 原因 这是Hive3.x中的一个bug在语句的执行计划中这个判断结构体是否为空的过滤条件直接被忽略了。         在数据库中有RBO基于规则的优化策略和CBO基于代价的优化策略两种优化策略。实际上就是因为CBO这个优化策略导致的Hive中默认使用了CBO优化策略。 解决方案 1方案一已知了结构体struct里的字段名称直接判断结构体里的字段是否为null即可 2方案二在Hive4.0版本中修复了此bug因此使用Hive4.0版本即可或者根据Hive4.0修复这部分的代码在自己所用的Hive版本中修改对应的代码 3方案三在Hive中禁用CBO优化set hive.cbo.enablefalse; 1.14、流量域启动事务事实表 对于启动这个操作而言只有移动端的应用才有这个操作PC 端并没有。 1.14.1、建表语句 DROP TABLE IF EXISTS dwd_traffic_start_inc; CREATE EXTERNAL TABLE dwd_traffic_start_inc (province_id STRING COMMENT 省份id,brand STRING COMMENT 手机品牌,channel STRING COMMENT 渠道,is_new STRING COMMENT 是否首次启动,model STRING COMMENT 手机型号,mid_id STRING COMMENT 设备id,operate_system STRING COMMENT 操作系统,user_id STRING COMMENT 会员id,version_code STRING COMMENT app版本号,entry STRING COMMENT icon手机图标 notice 通知,open_ad_id STRING COMMENT 广告页ID ,date_id STRING COMMENT 日期id,start_time STRING COMMENT 启动时间,loading_time_ms BIGINT COMMENT 启动加载时间,open_ad_ms BIGINT COMMENT 广告总共播放时间,open_ad_skip_ms BIGINT COMMENT 用户跳过广告时点 ) COMMENT 启动日志表PARTITIONED BY (dt STRING)STORED AS ORCLOCATION /warehouse/gmall/dwd/dwd_traffic_start_incTBLPROPERTIES (orc.compress snappy); 1.14.2、数据装载 同样为了防止结构体字段 is not null 不生效这里需要关闭 CBO set hive.cbo.enablefalse; insert overwrite table dwd_traffic_start_inc partition(dt2020-06-14) selectprovince_id,brand,channel,is_new,model,mid_id,operate_system,user_id,version_code,entry,open_ad_id,date_format(from_utc_timestamp(ts,GMT8),yyyy-MM-dd) date_id,date_format(from_utc_timestamp(ts,GMT8),yyyy-MM-dd HH:mm:ss) action_time,loading_time,open_ad_ms,open_ad_skip_ms from (selectcommon.ar area_code,common.ba brand,common.ch channel,common.is_new,common.md model,common.mid mid_id,common.os operate_system,common.uid user_id,common.vc version_code,start.entry,start.loading_time,start.open_ad_id,start.open_ad_ms,start.open_ad_skip_ms,tsfrom ods_log_incwhere dt2020-06-14and start is not null )log left join (selectid province_id,area_codefrom ods_base_province_fullwhere dt2020-06-14 )bp on log.area_codebp.area_code; 注意 我们这里的 start 是 hive 中的关键字所以需要使用反引号但是这个命令将来会被写到 shell 脚本里而在 shell 脚本中反引号是执行反引号中的 shell 命令的意思所以到时候我们还需要通过 \ 来转义。 1.15、流量域动作事务事实表 这里的动作主要采集的是用户的领券、加购、收藏这些动作。 1.15.1、建表语句 DROP TABLE IF EXISTS dwd_traffic_action_inc; CREATE EXTERNAL TABLE dwd_traffic_action_inc (province_id STRING COMMENT 省份id,brand STRING COMMENT 手机品牌,channel STRING COMMENT 渠道,is_new STRING COMMENT 是否首次启动,model STRING COMMENT 手机型号,mid_id STRING COMMENT 设备id,operate_system STRING COMMENT 操作系统,user_id STRING COMMENT 会员id,version_code STRING COMMENT app版本号,during_time BIGINT COMMENT 持续时间毫秒,page_item STRING COMMENT 目标id ,page_item_type STRING COMMENT 目标类型,last_page_id STRING COMMENT 上页类型,page_id STRING COMMENT 页面id ,source_type STRING COMMENT 来源类型,action_id STRING COMMENT 动作id,action_item STRING COMMENT 目标id ,action_item_type STRING COMMENT 目标类型,date_id STRING COMMENT 日期id,action_time STRING COMMENT 动作发生时间 ) COMMENT 动作日志表PARTITIONED BY (dt STRING)STORED AS ORCLOCATION /warehouse/gmall/dwd/dwd_traffic_action_incTBLPROPERTIES (orc.compress snappy); 1.15.2、装载语句 set hive.cbo.enablefalse; insert overwrite table dwd_traffic_action_inc partition(dt2020-06-14) selectprovince_id,brand,channel,is_new,model,mid_id,operate_system,user_id,version_code,during_time,page_item,page_item_type,last_page_id,page_id,source_type,action_id,action_item,action_item_type,date_format(from_utc_timestamp(ts,GMT8),yyyy-MM-dd) date_id,date_format(from_utc_timestamp(ts,GMT8),yyyy-MM-dd HH:mm:ss) action_time from (selectcommon.ar area_code,common.ba brand,common.ch channel,common.is_new,common.md model,common.mid mid_id,common.os operate_system,common.uid user_id,common.vc version_code,page.during_time,page.item page_item,page.item_type page_item_type,page.last_page_id,page.page_id,page.source_type,action.action_id,action.item action_item,action.item_type action_item_type,action.tsfrom ods_log_inc lateral view explode(actions) tmp as actionwhere dt2020-06-14and actions is not null )log left join (selectid province_id,area_codefrom ods_base_province_fullwhere dt2020-06-14 )bp on log.area_codebp.area_code; 注意这里用到了炸裂函数关于炸裂函数的使用仅仅这里写一遍是远远不够的还是得下去多练 1.16、流量域曝光事务事实表 这里的曝光指的是系统给我们推送内容的曝光行为比如广告、轮播图、推荐。 1.16.1、建表语句 DROP TABLE IF EXISTS dwd_traffic_display_inc; CREATE EXTERNAL TABLE dwd_traffic_display_inc (province_id STRING COMMENT 省份id,brand STRING COMMENT 手机品牌,channel STRING COMMENT 渠道,is_new STRING COMMENT 是否首次启动,model STRING COMMENT 手机型号,mid_id STRING COMMENT 设备id,operate_system STRING COMMENT 操作系统,user_id STRING COMMENT 会员id,version_code STRING COMMENT app版本号,during_time BIGINT COMMENT app版本号,page_item STRING COMMENT 目标id ,page_item_type STRING COMMENT 目标类型,last_page_id STRING COMMENT 上页类型,page_id STRING COMMENT 页面ID ,source_type STRING COMMENT 来源类型,date_id STRING COMMENT 日期id,display_time STRING COMMENT 曝光时间,display_type STRING COMMENT 曝光类型,display_item STRING COMMENT 曝光对象id ,display_item_type STRING COMMENT app版本号,display_order BIGINT COMMENT 曝光顺序,display_pos_id BIGINT COMMENT 曝光位置 ) COMMENT 曝光日志表PARTITIONED BY (dt STRING)STORED AS ORCLOCATION /warehouse/gmall/dwd/dwd_traffic_display_incTBLPROPERTIES (orc.compress snappy); 这里我们的曝光时间 直接取的进入页面的时间因为我们模拟的前端埋点并没有添加曝光时间属性。 1.16.2、装载语句 set hive.cbo.enablefalse; insert overwrite table dwd_traffic_display_inc partition(dt2020-06-14) selectprovince_id,brand,channel,is_new,model,mid_id,operate_system,user_id,version_code,during_time,page_item,page_item_type,last_page_id,page_id,source_type,date_format(from_utc_timestamp(ts,GMT8),yyyy-MM-dd) date_id,date_format(from_utc_timestamp(ts,GMT8),yyyy-MM-dd HH:mm:ss) display_time,display_type,display_item,display_item_type,display_order,display_pos_id from (selectcommon.ar area_code,common.ba brand,common.ch channel,common.is_new,common.md model,common.mid mid_id,common.os operate_system,common.uid user_id,common.vc version_code,page.during_time,page.item page_item,page.item_type page_item_type,page.last_page_id,page.page_id,page.source_type,display.display_type,display.item display_item,display.item_type display_item_type,display.order display_order,display.pos_id display_pos_id,tsfrom ods_log_inc lateral view explode(displays) tmp as displaywhere dt2020-06-14and displays is not null )log left join (selectid province_id,area_codefrom ods_base_province_fullwhere dt2020-06-14 )bp on log.area_codebp.area_code; 1.17、流量域错误事务事实表 错误日志有可能是来自于页面日志也有可能是来自启动日志。 1.17.1、建表语句 DROP TABLE IF EXISTS dwd_traffic_error_inc; CREATE EXTERNAL TABLE dwd_traffic_error_inc (province_id STRING COMMENT 地区编码,brand STRING COMMENT 手机品牌,channel STRING COMMENT 渠道,is_new STRING COMMENT 是否首次启动,model STRING COMMENT 手机型号,mid_id STRING COMMENT 设备id,operate_system STRING COMMENT 操作系统,user_id STRING COMMENT 会员id,version_code STRING COMMENT app版本号,page_item STRING COMMENT 目标id ,page_item_type STRING COMMENT 目标类型,last_page_id STRING COMMENT 上页类型,page_id STRING COMMENT 页面ID ,source_type STRING COMMENT 来源类型,entry STRING COMMENT icon手机图标 notice 通知,loading_time STRING COMMENT 启动加载时间,open_ad_id STRING COMMENT 广告页ID ,open_ad_ms STRING COMMENT 广告总共播放时间,open_ad_skip_ms STRING COMMENT 用户跳过广告时点,actions ARRAYSTRUCTaction_id:STRING,item:STRING,item_type:STRING,ts:BIGINT COMMENT 动作信息,displays ARRAYSTRUCTdisplay_type :STRING,item :STRING,item_type :STRING,order :STRING,pos_id:STRING COMMENT 曝光信息,date_id STRING COMMENT 日期id,error_time STRING COMMENT 错误时间,error_code STRING COMMENT 错误码,error_msg STRING COMMENT 错误信息 ) COMMENT 错误日志表PARTITIONED BY (dt STRING)STORED AS ORCLOCATION /warehouse/gmall/dwd/dwd_traffic_error_incTBLPROPERTIES (orc.compress snappy); 这里的 actions 和 displays 字段并没有使用炸裂函数因为这样会破坏我们的粒度如果将来需要用到这个数据的时候就需要炸裂函数了。  1.17.2、装载语句 set hive.cbo.enablefalse; set hive.execution.enginemr; insert overwrite table dwd_traffic_error_inc partition(dt2020-06-14) selectprovince_id,brand,channel,is_new,model,mid_id,operate_system,user_id,version_code,page_item,page_item_type,last_page_id,page_id,source_type,entry,loading_time,open_ad_id,open_ad_ms,open_ad_skip_ms,actions,displays,date_format(from_utc_timestamp(ts,GMT8),yyyy-MM-dd) date_id,date_format(from_utc_timestamp(ts,GMT8),yyyy-MM-dd HH:mm:ss) error_time,error_code,error_msg from (selectcommon.ar area_code,common.ba brand,common.ch channel,common.is_new,common.md model,common.mid mid_id,common.os operate_system,common.uid user_id,common.vc version_code,page.during_time,page.item page_item,page.item_type page_item_type,page.last_page_id,page.page_id,page.source_type,start.entry,start.loading_time,start.open_ad_id,start.open_ad_ms,start.open_ad_skip_ms,actions,displays,err.error_code,err.msg error_msg,tsfrom ods_log_incwhere dt2020-06-14and err is not null )log join (selectid province_id,area_codefrom ods_base_province_fullwhere dt2020-06-14 )bp on log.area_codebp.area_code; set hive.execution.enginespark; 注意这里的 actions、displays 对应到 Java 中是 List 类型在 Hive On Spark 中报错 不期望的类型的列这是 Hive On Spark 的一个 bug我们需要通过切换 Hvie 引擎来解决。 1.18、用户域用户注册事务事实表 1.18.1、建表语句 DROP TABLE IF EXISTS dwd_user_register_inc; CREATE EXTERNAL TABLE dwd_user_register_inc (user_id STRING COMMENT 用户ID,date_id STRING COMMENT 日期ID,create_time STRING COMMENT 注册时间,channel STRING COMMENT 应用下载渠道,province_id STRING COMMENT 省份id,version_code STRING COMMENT 应用版本,mid_id STRING COMMENT 设备id,brand STRING COMMENT 设备品牌,model STRING COMMENT 设备型号,operate_system STRING COMMENT 设备操作系统 ) COMMENT 用户域用户注册事务事实表PARTITIONED BY (dt STRING)STORED AS ORCLOCATION /warehouse/gmall/dwd/dwd_user_register_inc/TBLPROPERTIES (orc.compress snappy); 1.18.2、首日装载 注册成功会影响哪些表显然用户信息表会插入一条记录日志中会多一条页面为注册页面并且带有用户id的记日志录。 但是如果只用 user_info 去设计这张注册事实表维度信息太少了只有用户和时间维度我们希望尽可能丰富维度属性所以这里我们会从地区表、日志表去获取更多的维度信息。 这里我们的表当然是以表为主而不是以日志为主因为业务数据更加靠谱比如业务数据库有事务保证比如涉及到金额的操作我们绝不会用日志去传输 set hive.exec.dynamic.partition.modenonstrict; insert overwrite table dwd_user_register_inc partition(dt) selectui.user_id,date_format(create_time,yyyy-MM-dd) date_id,create_time,channel,province_id,version_code,mid_id,brand,model,operate_system,date_format(create_time,yyyy-MM-dd) from (selectdata.id user_id,data.create_timefrom ods_user_info_incwhere dt2020-06-14and typebootstrap-insert )ui left join (selectcommon.ar area_code,common.ba brand,common.ch channel,common.md model,common.mid mid_id,common.os operate_system,common.uid user_id,common.vc version_codefrom ods_log_incwhere dt2020-06-14and page.page_idregisterand common.uid is not null )log on ui.user_idlog.user_id left join (selectid province_id,area_codefrom ods_base_province_fullwhere dt2020-06-14 )bp on log.area_codebp.area_code; 1.18.3、每日装载 insert overwrite table dwd_user_register_inc partition(dt2020-06-15) selectui.user_id,date_format(create_time,yyyy-MM-dd) date_id,create_time,channel,province_id,version_code,mid_id,brand,model,operate_system from (selectdata.id user_id,data.create_timefrom ods_user_info_incwhere dt2020-06-15and typeinsert )ui left join (selectcommon.ar area_code,common.ba brand,common.ch channel,common.md model,common.mid mid_id,common.os operate_system,common.uid user_id,common.vc version_codefrom ods_log_incwhere dt2020-06-15and page.page_idregisterand common.uid is not null )log on ui.user_idlog.user_id left join (selectid province_id,area_codefrom ods_base_province_fullwhere dt2020-06-15 )bp on log.area_codebp.area_code; 1.19、用户域用户登录事务事实表 1.19.1、建表语句 DROP TABLE IF EXISTS dwd_user_login_inc; CREATE EXTERNAL TABLE dwd_user_login_inc (user_id STRING COMMENT 用户ID,date_id STRING COMMENT 日期ID,login_time STRING COMMENT 登录时间,channel STRING COMMENT 应用下载渠道,province_id STRING COMMENT 省份id,version_code STRING COMMENT 应用版本,mid_id STRING COMMENT 设备id,brand STRING COMMENT 设备品牌,model STRING COMMENT 设备型号,operate_system STRING COMMENT 设备操作系统 ) COMMENT 用户域用户登录事务事实表PARTITIONED BY (dt STRING)STORED AS ORCLOCATION /warehouse/gmall/dwd/dwd_user_login_inc/TBLPROPERTIES (orc.compress snappy); 1.19.2、数据装载 首先数据来自于日志日志没有历史数据所以我们并不需要区分首日次日。 我们的登录场景根据日志中有没有 user_id 可以大致分我三类从始至终没有登录、浏览到一半登录打开网页时后台自动登录。 insert overwrite table dwd_user_login_inc partition(dt2020-06-14) selectuser_id,date_format(from_utc_timestamp(ts,GMT8),yyyy-MM-dd) date_id,date_format(from_utc_timestamp(ts,GMT8),yyyy-MM-dd HH:mm:ss) login_time,channel,province_id,version_code,mid_id,brand,model,operate_system from (selectuser_id,channel,area_code,version_code,mid_id,brand,model,operate_system,tsfrom(selectuser_id,channel,area_code,version_code,mid_id,brand,model,operate_system,ts,row_number() over (partition by session_id order by ts) rnfrom(selectuser_id,channel,area_code,version_code,mid_id,brand,model,operate_system,ts,concat(mid_id,-,last_value(session_start_point,true) over(partition by mid_id order by ts)) session_idfrom(selectcommon.uid user_id,common.ch channel,common.ar area_code,common.vc version_code,common.mid mid_id,common.ba brand,common.md model,common.os operate_system,ts,if(page.last_page_id is null,ts,null) session_start_pointfrom ods_log_incwhere dt2020-06-14and page is not null)t1)t2where user_id is not null)t3where rn1 )t4 left join (selectid province_id,area_codefrom ods_base_province_fullwhere dt2020-06-14 )bp on t4.area_codebp.area_code; 脚本省略注意严格模式最好直接配到配置文件里去 propertynamehive.exec.dynamic.partition.mode/namevaluenonstrict/value /property 总结 至此DWD 层搭建完毕DWD 层一般都是和 DIM 层配置使用的一个负责提供业务过程相关行为信息一个负责提供该业务过程的维度信息。 距离 DIM 层开发过去了整整两周这两部分内容太重要了所以学的很慢但还是要回头慢慢再消化消化。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/89250.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

威海高区建设局网站服务态度 专业的网站建设

目录 一.map映射1.简介2.包含头文件及其初始化3.基本操作4.用迭代器正反遍历5.添加元素的四种方式6.元素的访问7.对比unordered_map,multimap 二.set集合1.简介2.包含头文件及其初始化3.基本操作4.元素的访问5.set,multiset,unordered_set&am…

慈溪市规划建设网站wordpress安装上传文件

本篇文章借鉴于此处,如果只需显示树形组件,可以直接访问该博主文章。我这里对他的组件做了扩展,增加了点击展开和关闭操作,话不多说上代码。 1.数据结构 const data {label: 根目录,children: [{label: 目录A,children: [// 叶…

赛事竞猜网站开发百度上的网站怎么做

社区网站类场景下静态资源处理 场景描述 解决的问题 本实践通过搭建WordPress博客系统,向用户展示如何l 静态资源(图片、视频等)CDN访问加速和刷新 将图片、附件等静态资源上传到阿里云OSS,并通过阿里l OSS对象跨国际区域进行复…

镇江房产网站建设做网店网站

Nginx学习:代理模块(四)响应头与SSL 响应头相关的配置也和我们之前在 FastCGI 系列学过的响应头配置是类似的,这一块也比较简单。而另一部分则是 Proxy 模块另一个特有的功能,SSL 相关的配置。不过这一块吧&#xff0c…

做网站有意思吗广州网站设计成功刻

目录 引言 统一异常处理 异常全部监测 引言 将异常处理逻辑集中到一个地方,可以避免在每个控制器或业务逻辑中都编写相似的异常处理代码,这降低了代码的冗余,提高了代码的可维护性统一的异常处理使得调试和维护变得更加容易,通…

中小学图书馆网站建设做网站电话

我只是一个搬运工 更改密码远程连接

湖北省建设厅官方网站石家庄网站推广专家

ares-sdk初始开发测试使用的是oracle数据库,由于宁波通商的特殊需要,必须把数据库环境从oracle转向mysql。 现对转换过程中出现的问题及经验总结如下:主键生成策略创建一个专门记录序列的表sequence,记录有当前序列号,序列的间隔如1创建记录当…

企业为什么要建站台呢整站seo服务

二叉树层序遍历 题目链接:102. 二叉树的层序遍历 思路:利用队列来存储遍历的节点,同时要定义size来保存当前层的节点个数。 时间复杂度O(n) 层序遍历的一般写法,通过一个 while 循环控制从上向下一层层遍历,for 循…

网站和微信公众号建设海南教育学会网站建设

目录 前言 1.下载Gitlab 2.安装Gitlab 3.启动Gitlab 4.安装cpolar 5. 创建隧道配置访问地址 6.固定GitLab访问地址 7. 配置二级子域名 8. 测试访问二级子域名 前言 GitLab 是一个用于仓库管理系统的开源项目,使用Git作为代码管理工具,并在此基…

小额贷网站建设wordpress顶部工具栏修改logo

个人主页:兜里有颗棉花糖 欢迎 点赞👍 收藏✨ 留言✉ 加关注💓本文由 兜里有颗棉花糖 原创 收录于专栏【手撕算法系列专栏】【LeetCode】 🍔本专栏旨在提高自己算法能力的同时,记录一下自己的学习过程,希望…

海口智能建站详情wordpress 后台很慢

目录 (1)背包问题 (2)最长公共子串 (3)小结 本章内容: 学习动态规划,它将问题分成小问题,并先着手解决这些小问题。学习如何设计问题的动态规划解决方案。 &#xff…

农业推广网站建设软文营销的技巧有哪些?

1、CPU 中央处理器,简称 CPU(Central Processing Unit),中央处理器主要包括两个部分,即控制器、运算器,其中还包括高速缓冲存储器及实现它们之间联系的数据、控制的总线。 电子计算机三大核心部件就是CPU…

南宁建设银行缴费网站临沂网站建设培训班

论文地址;[1512.09300] Autoencoding beyond pixels using a learned similarity metric (arxiv.org) / 一、Introduction 主要讲了深度学习中生成模型存在的问题,即常用的相似度度量方式(使用元素误差度量)对于学习良好的生成模型存在一定…

构建html5博客网站惠州做网站首选惠州邦

道可云元宇宙每日简报(2024年4月8日)讯,今日元宇宙新鲜事有: 六部门:支持内蒙古人工智能产业建设 国家发展改革委等六部门发布《关于支持内蒙古绿色低碳高质量发展若干政策措施的通知》。其中提出,加快推…

西安新能源网站建设服装设计网站有哪些

在stm32裸机工程中的Middlewares目录添加freeRtos源码 在裸机工程中的main中调用freertos接口

平板上做网站的软件上海做网站哪里好

这里讲一下,如何使用vue控制多行文字展开收起(也叫控制文字展开隐藏)。效果:这里设置了控制三行,如果超过三行会展示,“显示更多” 超出文字显示省略号。点击“显示更多”会展开所有文案,按钮变成“收起”(未超出三行的…

称心的常州网站建设互联网推广渠道

在模拟器上运行 ios 项目的时候,图片显示不出来。真机可以显示 原因:ios默认启用 impeller(新渲染引擎),不知道为什么项目不能使用。 禁用掉即可, 原因以及解决都在下面的链接里面了 Impeller rendering …

品牌网站建设的作用广州公司注册流程详解

文章目录 0 前言2 开发简介3 数据集4 实现技术4.1 系统架构4.2 开发环境4.3 疫情地图4.3.1 填充图(Choropleth maps)4.3.2 气泡图 4.4 全国疫情实时追踪4.6 其他页面 5 关键代码最后 0 前言 🔥 优质竞赛项目系列,今天要分享的是 🚩 大数据疫…

电子商务网站建设商城网站深圳家具定制

一、说明 变形金刚是一种深度学习架构,为人工智能的发展做出了杰出贡献。这是人工智能和整个技术领域的一个重要阶段,但也有点复杂。截至今天,变形金刚上有很多很好的资源,那么为什么要再制作一个呢?两个原因&#xff…