在上一篇文章中,我们已经获取到了业务数据的输出流,分别是dim层维度数据的输出流,及dwd层事实数据的输出流,接下来我们要做的就是把这些输出流分别再流向对应的数据介质中,dim层流向hbase中,dwd层依旧回写到kafka中。

1.分流维度表sink到hbase

上一篇的结果是维度数据在侧输出流hbaseDs,事实数据在主流filterDs中,如下:

//5.动态分流,事实表写会kafka,维度表写入hbase
OutputTag<JSONObject> hbaseTag = new OutputTag<JSONObject>(TableProcess.SINK_TYPE_HBASE){};
//创建自定义mapFunction函数
SingleOutputStreamOperator<JSONObject> kafkaTag = filterDs.process(new TableProcessFunction(hbaseTag));
DataStream<JSONObject> hbaseDs = kafkaTag.getSideOutput(hbaseTag);
filterDs.print("json str --->>");

处理流程如下:

自定义RickSinkFunction类:DimSink.java

  • 初始化phoenix连接

  • 保存数据

1.1 配置

在BaseDbTask任务中,我们已经获取到hbase的输出流,然后就可以开始hbase的一系列操作了。

添加phoenix依赖包

<!-- phoenix -->
<dependency>
   <groupId>org.apache.phoenix</groupId>
   <artifactId>phoenix-spark</artifactId>
   <version>5.0.0-HBase-2.0</version>
   <exclusions>
       <exclusion>
           <groupId>org.glassfish</groupId>
           <artifactId>javax.el</artifactId>
       </exclusion>
   </exclusions>
</dependency>

修改hbase-site.xml,因为要用单独的 schema,所以在 Idea 程序中也要加入 hbase-site.xml

为了开启 hbase 的 namespace 和 phoenix 的 schema 的映射,在程序中需要加这个配置文件,另外在 linux 服务上,也需要在 hbase 以及 phoenix 的 hbase-site.xml 配置文件中,加上以上两个配置,并使用 xsync 进行同步。

<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
<configuration>
   <property>
       <name>hbase.rootdir</name>
       <value>hdfs://hadoop101:9000/hbase</value>
   </property>
   <property>
       <name>hbase.cluster.distributed</name>
       <value>true</value>
   </property>
   <property>
       <name>hbase.zookeeper.quorum</name>
       <value>hadoop101,hadoop102,hadoop103</value>
   </property>
   <property>
       <name>hbase.table.sanity.checks</name>
       <value>false</value>
   </property>
   <property>
       <name>phoenix.schema.isNamespaceMappingEnabled</name>
       <value>true</value>
   </property>
   <property>
       <name>phoenix.schema.mapSystemTablesToNamespace</name>
       <value>true</value>
   </property>
</configuration>

1.2 创建命名空间

在phoenix中执行

create schema GMALL_REALTIME;

1.3 DimSink.java

自定义addSink类

package com.zhangbao.gmall.realtime.app.func;
import com.alibaba.fastjson.JSONObject;
import com.google.common.base.Strings;
import com.zhangbao.gmall.realtime.common.GmallConfig;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang3.StringUtils;
import org.apache.flink.configuration.Configuration;
import org.apache.flink.streaming.api.functions.sink.RichSinkFunction;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
/**
* @author: zhangbao
* @date: 2021/9/4 12:23
* @desc: 将维度表写入hbase中
**/
@Log4j2
public class DimSink extends RichSinkFunction<JSONObject> {
   private Connection conn = null;

   @Override
   public void open(Configuration parameters) throws Exception {
       log.info("建立 phoenix 连接...");
       Class.forName("org.apache.phoenix.jdbc.PhoenixDriver");
       conn = DriverManager.getConnection(GmallConfig.PHOENIX_SERVER);
       log.info("phoenix 连接成功!");
  }

   @Override
   public void invoke(JSONObject jsonObject, Context context) throws Exception {
       String sinkTable = jsonObject.getString("sink_table");
       JSONObject data = jsonObject.getJSONObject("data");
       PreparedStatement ps = null;
       if(data!=null && data.size()>0){
           try {
               //生成phoenix的upsert语句,这个包含insert和update操作
               String sql = generateUpsert(data,sinkTable.toUpperCase());
               log.info("开始执行 phoenix sql -->{}",sql);
               ps = conn.prepareStatement(sql);
               ps.executeUpdate();
               conn.commit();
               log.info("执行 phoenix sql 成功");
          } catch (SQLException throwables) {
               throwables.printStackTrace();
               throw new RuntimeException("执行 phoenix sql 失败!");
          }finally {
               if(ps!=null){
                   ps.close();
              }
          }
      }
  }

   //生成 upsert sql
   private String generateUpsert(JSONObject data, String sinkTable) {
       StringBuilder sql = new StringBuilder();
       //upsert into scheme.table(id,name) values('11','22')
       sql.append("upsert into "+GmallConfig.HBASE_SCHEMA+"."+sinkTable+"(");
       //拼接列名
       sql.append(StringUtils.join(data.keySet(),",")).append(")");
       //填充值
       sql.append("values('"+ StringUtils.join(data.values(),"','")+"')");
       return sql.toString();
  }
}

然后在主程序中加入

//6. 将维度表写入hbase中
hbaseDs.addSink(new DimSink());

1.4 测试

  • 需要启动的服务

    hdfs、zk、kafka、Maxwell、hbase,BaseDbTask.java

  • 修改配置数据:gmall2021_realtime.table_process

    INSERT INTO `gmall2021_realtime`.`table_process` (`source_table`, `operate_type`, `sink_type`, `sink_table`, `sink_columns`, `sink_pk`, `sink_extend`) VALUES ('base_trademark', 'insert', 'hbase', 'dim_base_trademark', 'id,tm_name', 'id', NULL);

    此条配置数据代表,如果表base_trademark有插入数据,就把数据同步到hbase中,自动建表,作为维度数据。

  • 修改业务库中表数据:gmall2021.base_trademark

    INSERT INTO `gmall2021`.`base_trademark` (`id`, `tm_name`, `logo_url`) VALUES ('15', '55', '55');
  • 查看phoenix数据:select * from GMALL_REALTIME.BASE_TRADEMARK;

数据已经实时同步到hbase中。

2.分流事实表sink到kafka

2.1 MyKafkaUtil定义新方法

在MyKafkaUtil中定义新的生产者方法,可动态指定topic,如果不指定则生产到默认topic:default_data

/**
    * 动态生产到不同的topic,如果不传topic,则自动生产到默认的topic
    * @param T 序列化后的数据,可指定topic
    */
   public static <T> FlinkKafkaProducer<T> getKafkaBySchema(KafkaSerializationSchema<T> T){
       Properties pros = new Properties();
       pros.setProperty(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG,KAFKA_HOST);
       return new FlinkKafkaProducer<T>(DEFAULT_TOPIC,T,pros,FlinkKafkaProducer.Semantic.EXACTLY_ONCE);
  }

在主任务BaseDbTask中使用

//7. 将事实数据写回到kafka
FlinkKafkaProducer<JSONObject> kafkaBySchema = MyKafkaUtil.getKafkaBySchema(new KafkaSerializationSchema<JSONObject>() {
   @Override
   public void open(SerializationSchema.InitializationContext context) throws Exception {
       System.out.println("kafka serialize open");
  }
   @Override
   public ProducerRecord<byte[], byte[]> serialize(JSONObject jsonObject, @Nullable Long aLong) {
       String sinkTopic = jsonObject.getString("sink_table");
       return new ProducerRecord<>(sinkTopic, jsonObject.getJSONObject("data").toString().getBytes());
  }
});
kafkaTag.addSink(kafkaBySchema);

2.2 测试

  • 需要启动的服务

    hdfs、zk、kafka、Maxwell、hbase,BaseDbTask.java

  • 修改配置信息:gmall2021_realtime.table_process

    INSERT INTO `gmall2021_realtime`.`table_process` (`source_table`, `operate_type`, `sink_type`, `sink_table`, `sink_columns`, `sink_pk`, `sink_extend`) VALUES ('order_info', 'insert', 'kafka', 'dwd_order_info', 'id,consignee,consignee_tel,total_amount,order_status,user_id,payment_way,delivery_address,order_comment,out_trade_no,trade_body,create_time,operate_time,expire_time,process_status,tracking_no,parent_order_id,img_url,province_id,activity_reduce_amount,coupon_reduce_amount,original_total_amount,feight_fee,feight_fee_reduce,refundable_time', 'id', NULL);

    表示表order_info有插入数据,就会同步到kafka中,topic为dwd_order_info。

  • 启动kafka消费者,查看是否有数据进来

    [zhangbao@hadoop101 root]$ cd /opt/module/kafka/bin/

    [zhangbao@hadoop101 bin]$ ./kafka-console-consumer.sh --bootstrap-server hadoop101:9092,hadoop102:9092,hadoop103:9092 --topic dwd_order_info

  • 最后启动业务数据生成服务:mock-db-0.0.1-SNAPSHOT.jar

    记得先修改配置文件的生成日期:2021-09-12

最后查看kafka消费者可以看到有数据产生,说明流程已经走通。

3.算子选择简介

function 可转换结构 可过滤数据 侧输出 open 可以使用状态 输出至
MapFunction Yes         下游算子
FilterFunction   Yes       下游算子
RichMapFunction Yes     Yes Yes 下游算子
RichFilterFunction   Yes   Yes Yes 下游算子
ProcessFunction Yes Yes Yes Yes Yes 下游算子
SinkFunction Yes Yes       外部
RichSinkFunction Yes Yes   Yes Yes 外部

6.Flink实时项目之业务数据分流的更多相关文章

  1. 5.Flink实时项目之业务数据准备

    1. 流程介绍 在上一篇文章中,我们已经把客户端的页面日志,启动日志,曝光日志分别发送到kafka对应的主题中.在本文中,我们将把业务数据也发送到对应的kafka主题中. 通过maxwell采集业务数 ...

  2. 3.Flink实时项目之流程分析及环境搭建

    1. 流程分析 前面已经将日志数据(ods_base_log)及业务数据(ods_base_db_m)发送到kafka,作为ods层,接下来要做的就是通过flink消费kafka 的ods数据,进行简 ...

  3. 7.Flink实时项目之独立访客开发

    1.架构说明 在上6节当中,我们已经完成了从ods层到dwd层的转换,包括日志数据和业务数据,下面我们开始做dwm层的任务. DWM 层主要服务 DWS,因为部分需求直接从 DWD 层到DWS 层中间 ...

  4. 10.Flink实时项目之订单维度表关联

    1. 维度查询 在上一篇中,我们已经把订单和订单明细表join完,本文将关联订单的其他维度数据,维度关联实际上就是在流中查询存储在 hbase 中的数据表.但是即使通过主键的方式查询,hbase 速度 ...

  5. 4.Flink实时项目之数据拆分

    1. 摘要 我们前面采集的日志数据已经保存到 Kafka 中,作为日志数据的 ODS 层,从 kafka 的ODS 层读取的日志数据分为 3 类, 页面日志.启动日志和曝光日志.这三类数据虽然都是用户 ...

  6. 9.Flink实时项目之订单宽表

    1.需求分析 订单是统计分析的重要的对象,围绕订单有很多的维度统计需求,比如用户.地区.商品.品类.品牌等等.为了之后统计计算更加方便,减少大表之间的关联,所以在实时计算过程中将围绕订单的相关数据整合 ...

  7. 1.Flink实时项目前期准备

    1.日志生成项目 日志生成机器:hadoop101 jar包:mock-log-0.0.1-SNAPSHOT.jar gmall_mock ​ |----mock_common ​ |----mock ...

  8. 11.Flink实时项目之支付宽表

    支付宽表 支付宽表的目的,最主要的原因是支付表没有到订单明细,支付金额没有细分到商品上, 没有办法统计商品级的支付状况. 所以本次宽表的核心就是要把支付表的信息与订单明细关联上. 解决方案有两个 一个 ...

  9. 8.Flink实时项目之CEP计算访客跳出

    1.访客跳出明细介绍 首先要识别哪些是跳出行为,要把这些跳出的访客最后一个访问的页面识别出来.那么就要抓住几个特征: 该页面是用户近期访问的第一个页面,这个可以通过该页面是否有上一个页面(last_p ...

随机推荐

  1. Visaul Studio 2015 MFC 应用程序工程创建

    近一段时间开始接触到MFC桌面开发程序,忙完了一段时间的项目开发之后,来整理整理Visaul Studio 2015开发MFC桌面程序的基本功能. 首先从创建软件工程项目开始,Visaul Studi ...

  2. 01-JS中字面量与变量

    01-JS中字面量与变量 一.直接量(字面量) 字面量:英语叫做literals,也做直接量,看见什么,它就是什么. (一)数字的字面量 数字的字面量,就是这个数字自己,并不需要任何的符号来界定这个数 ...

  3. 《剑指offer》面试题34. 二叉树中和为某一值的路径

    问题描述 输入一棵二叉树和一个整数,打印出二叉树中节点值的和为输入整数的所有路径.从树的根节点开始往下一直到叶节点所经过的节点形成一条路径. 示例: 给定如下二叉树,以及目标和 sum = 22, 5 ...

  4. 个人作业2-6.4-Python爬取顶会信息

    1.个人作业2 数据爬取阶段 import requestsfrom lxml import etreeimport pymysqldef getdata(url): # 请求CVPR主页 page_ ...

  5. golang中浮点型底层存储原理和decimal使用方法

    var price float32 = 39.29 float64和float32类似,只是用于表示各部分的位数不同而已,其中:sign=1位,exponent=11位,fraction=52位,也就 ...

  6. golang中int、float、string数据类型之间的转换

    package main import ( "fmt" "strconv" ) func main() { var num1 int = 88 var num2 ...

  7. gin中的路由参数

    package main import ( "fmt" "github.com/gin-gonic/gin" ) func main() { router := ...

  8. Python 安装MySQL 错误处理

    正常情况下如果使用python 连接数据库需要安装 python-MySQL 类库 #pip install python-MySQL 等待安装完成即可 使用时 import MySQLdb ==== ...

  9. 执行df hang住

    突然有一天发现df执行卡住了,一直不显示结果. $ df -h Filesystem Size Used Avail Use% Mounted on /dev/sda3 221G 100G 121G ...

  10. 业务驱动的全景监控体系在阿里的应用 | 阿里巴巴DevOps实践指南

    编者按:本文源自阿里云云效团队出品的<阿里巴巴DevOps实践指南>,扫描上方二维码或前往:https://developer.aliyun.com/topic/devops,下载完整版电 ...