Flink开发入门简单案例--统计实时流订单

Flink开发入门简单案例

0.简介

本案例通过一个简单的订单数据生成器生成随机订单数据,基于这个生成器运用Flink DataStream API开发程序统计订单数量和金额,模拟交易看板数据。

环境:IDEA作为IDE,Flink 1.13.2,Scala 2.12,Java 1.8

1.订单数据生成器

利用 Flink 提供的自定义 Source 来实现一个自定义的实时数据生成器

在IDEA中新建工程(new Project),选择"Maven Archetype",catalog选最基础的类型,如下图所示:

1.2 在pom.xml中引入Flink依赖包

分别引入flink-java, flink-streaming-java, flink-client三个包,配置如下:

复制代码
  <properties>
    <flink.version>1.13.2</flink.version>
    <scala.binary.version>2.12</scala.binary.version>
    <slf4j.version>1.7.30</slf4j.version>
    <mysql-connector.version>8.0.23</mysql-connector.version>
  </properties>

  <dependencies>
    <dependency>
      <groupId>org.apache.flink</groupId>
      <artifactId>flink-java</artifactId>
      <version>${flink.version}</version>
    </dependency>
    <dependency>
      <groupId>org.apache.flink</groupId>
      <artifactId>flink-streaming-java_${scala.binary.version}</artifactId>
      <version>${flink.version}</version>
    </dependency>
    <dependency>
      <groupId>org.apache.flink</groupId>
      <artifactId>flink-clients_${scala.binary.version}</artifactId>
      <version>${flink.version}</version>
    </dependency>
  </dependencies>

上面的版本均采用变量定义,可以根据实际情况进行替换。

1.3 订单数据生成类

主要用到三个类,订单类,生成订单数据流类,测试类

+订单类(Item)

普通Java类,代码如下:

复制代码
public class Item {
    private String name;
    private Integer id;

    Item() {}
    public String getName() {
        return name;
    }
    void setName(String name) {
        this.name = name;
    }
    private Integer getId() {
        return this.id;
    }
    void setId(int id) {
        this.id = id;
    }
    public String toString() {
        return "Item { " +
                "name='" + name + "\'" +
                ", id=" + id + "}";
    }
}

+订单生成数据流类

用于生成订单类的数据流,代码如下:

复制代码
import org.apache.flink.streaming.api.functions.source.SourceFunction;

import java.util.Random;

public class MyStreamingSource implements SourceFunction<Item> {
    private boolean isRunning = true;
    @Override
    public void run(SourceContext<Item> sourceContext) throws Exception {
        while(isRunning) {
            Item item = generateItem();
            sourceContext.collect(item);
            Thread.sleep(1000);
        }
    }

    private Item generateItem() {
        int i = new Random().nextInt(1000);
        Item item = new Item();
        item.setId(i);
        item.setCount((i % 4) + 1);
        item.setSum(item.getCount() * (new Random().nextFloat() * 50));
        return item;
    }

    @Override
    public void cancel() {
        isRunning = false;
    }

}

+测试订单生成类

用于测试上述生成类,也是程序的主函数,代码如下

复制代码
import org.apache.flink.api.common.functions.MapFunction;
import org.apache.flink.streaming.api.datastream.DataStream;
import org.apache.flink.streaming.api.datastream.DataStreamSource;
import org.apache.flink.streaming.api.datastream.SingleOutputStreamOperator;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;

public class StreamingDemo {
    public static void main(String[] args) throws Exception {
        StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
        DataStreamSource<Item> text = env.addSource(new MyStreamingSource()).setParallelism(1);
        DataStream<Item> item = text.map((MapFunction<Item, Item>) value-> value);
        item.print().setParallelism(1);
        String jobName = "user defined streaming source";
        env.execute(jobName);
    }
}

运行StreamingDemo的main函数,可以看到如下的输出结果:

2.订单统计

接下来,编写Flink算子,以窗口的方式统计一段时间内(5秒为例)订单的数量。

2.1 仅统计订单中商品的件数

思路如下:先读入订单数据源,将读到的订单Item对象映射为一个三元组Tuple3,再按5秒钟的窗口对订单中商品数量(count)进行求和(sum),核心代码如下:

复制代码
DataStreamSource<Item> order = env.addSource(new MyStreamingSource()).setParallelism(1);
DataStream<Tuple3<Integer, Integer, Float>> mappedStream =
    order.map(new MapFunction<Item, Tuple3<Integer, Integer, Float>>() {
       @Override
        public Tuple3<Integer, Integer, Float> map(Item item) throws Exception {
            return new Tuple3<>(item.getId(), item.getCount(), item.getSum());
        }
    });
    //定义窗口,每5秒一个
    DataStream<Tuple3<Integer, Integer, Float>> windowedStream = mappedStream
            .keyBy((item)->0)  // 此处的分组方式未使用任何分组,所以使用了一个常量0
            .window(TumblingProcessingTimeWindows.of(Time.seconds(5)))
            .sum(1); // 统计三元组中序号为1(即count属性)的和
    windowedStream.print();

运行后的结果如下:

可以看到,控制台中的输出,每一条数据前是5条数据,也就是5秒钟的窗口收集到5条(每秒产生1条),第2列为商品数量的和,实现了累加。

2.2 同时统计商品数量和金额

上述示例中,对windowedStream使用了sum进行统计求和,这种方式只能对一个字段进行,如果需要同时统计数量和金额,就必须采用另外一种方式,reduce进行统计。

reduce方法也是windowedStream提供的方法,代码如下:

复制代码
DataStream<Tuple3<Integer, Integer, Float>> windowedStream = mappedStream
    .keyBy((item)->0)
    .window(TumblingProcessingTimeWindows.of(Time.seconds(5)))
    .reduce(new ReduceFunction<Tuple3<Integer, Integer, Float>>() {
        @Override
        public Tuple3<Integer, Integer, Float> reduce(Tuple3<Integer, Integer, Float> t1, Tuple3<Integer, Integer, Float> t2) throws Exception {
            return new Tuple3<>(0, t1.f1 + t2.f1, t1.f2 + t2.f2);
        }
    });

这样,即可实现同时统计数量和金额,运行后效果如下:

可以看到,第2列是count的和,第3列也是sum的和,实现了同时统计。(第1列是在程序中直接映射为了0,因为id字段统计无意义)

本文章的部分案例借鉴自以下文章:Flink 常用的 DataSet 和 DataStream API,有需要的可以自行查看。

相关推荐
涤生大数据8 小时前
带你玩转 Flink TumblingWindow:从理论到代码的深度探索
flink·理论·代码·tumblingwindow
Apache Flink19 小时前
网易游戏 Flink 云原生实践
游戏·云原生·flink
SunTecTec2 天前
SQL Server To Paimon Demo by Flink standalone cluster mode
java·大数据·flink
工作中的程序员3 天前
flink监控指标
flink
小马爱打代码3 天前
SpringBoot整合Kafka、Flink实现流式处理
spring boot·flink·kafka
代码匠心5 天前
从零开始学Flink:开启实时计算的魔法之旅
java·大数据·flink
方二华5 天前
Apache Flink的架构设计与运行流程说明
大数据·flink·apache
方二华6 天前
Flink Table API与SQL技术详解
大数据·sql·flink
方二华7 天前
Flink流式计算核心:DataStream API与时间语义深度解析
大数据·flink