Flink示例

Flink SQL

简单订单统计

假设有以下两个订单流数据,数据字段分别为用户ID、购买的商品名称、商品数量。

数据流A:

1L,"尺子",3

1L,"铅笔",4

3L,"橡皮",2

数据流B:

2L,"手表",3

2L,"笔记本",3

4L,"计算器",1

目标:合并两个流的数据,并筛选出商品数量大于2的订单数据。

import org.apache.flink.streaming.api.scala.StreamExecutionEnvironment
import org.apache.flink.table.api.{$,EnvironmentSettings}
import org.apache.flink.table.api.bridge.scala.StreamTableEnvironment
import org.apache.flink.streaming.api.scala._
import org.apache.flink.table.api_

/**
* Flink SQL统计订单流数据
* 知识点:DataStream转为Table、视图,Table转为DataStream
*/
object FlinkSQLDemo{
    def main(args:Array[String]):Unit={
        //创建流执行环境
        val env=StreamExecutionEnvironment.getExecutionEnvironment
        //创建EnvironmentSettings实例并设置参数
        val settings=EnvironmentSettings
            .newInstance() //创建一个用于创建EnvironmentSettings实例的构建器
            .useBlinkPlanner() //将Blink计划器设置为所需的模块(默认)
            .inStreamingMode() //设置组件以流模式工作,默认启用
            .build() //创建一个不可变的EnvironmentSettings实例

        //构建流式表执行环境StreamTableEnvironment
        val tableEnv: StreamTableEnvironment=StreamTableEnvironment.create(env,settings)

        //构建订单数据流A
        val orderStreamA:DataStream[Order]=env.fromCollection(
            List(Order(1L,"尺子",3),
                Order(1L,"铅笔",4),
                Order(3L,"橡皮",2)
            )
        )

        //构建订单数据流B
        val orderStreamA:DataStream[Order]=env.fromCollection(
            List(Order(2L,"手表",3),
                Order(2L,"笔记本",3),
                Order(4L,"计算器",1)
            )
        )

        //将DataStream转为Table,并指定Table的所有字段
        val tableA: Table=tableEnv.fromDataStream(orderStreamA,$"user",$"product",$"amount")

        //将Table的schema以摘要格式打印到控制台
        tableA.printSchema()
        //(
        // 'user' BIGINT,
        // 'product' STRING,
        // 'user' INT,
        //)
        //将DataStream转为视图,视图名称为tableB,并指定视图的所有字段
        tableEnv.createTemporaryView("tableB",orderStreamB,$("user"),$("product"),$("amount"))

        //执行SQL查询,合并查询结果
        println("tableA默认表名:"+tableA.toString)
        val resultTable:Table=tableEnv.sqlQuery(
            "SELECT * FROM " + tableA + " WHERE amount>2" +
            "UNION ALL "+
            "SELECT * FROM tableB WHERE amount > 2"
        )

        //将结果Table转为仅追加流
        val dataStreamResult=tableEnv.toAppendStream[Order](resultTable)
        //将流打印到控制台
        dataStreamResult.print()
        //触发程序执行
        env.execute()
    }
}

//创建订单样例
case class Order(user:Long,product:String,amount:Int)

在IDEA本地执行上述代码,控制台输出结果如下:

1> Order(1,铅笔,4)

11> Order(2,笔记本,3)

10> Order(2,手表,3)

12> Order(1,尺子,3)

计算产品类别销售额TopN

假设有一个存储产品类别销售额数据的文件sales.csv。

字段分别为日期、产品类别、销售额。

使用Flink SQL统计每一个产品类别销售额的前三名(分组求TopN)

在Maven项目中的pom.xml中添加支持读取CSV文件的Flink依赖:http://t.csdnimg.cn/bWIBB

Table API

Table API适用于Scala, Java和Python。

  • Scala Table API利用了Scala表达式
  • Java Table API既支持表达式DSL,也支持解析和转换为等效表达式的字符串
  • Python Table API目前只支持解析和转换为等效表达式的字符串

Table API聚合查询代码示例:

//获得表环境TableEnvironment
val tableEnv: TableEnvironment=...

//注册一个Order表

//扫描(读取)已注册的Orders表,返回结果Table(相当于将已注册的表转为Table,便于后续操作)
val orders: Table=tableEnv.from("Orders")
//计算来自法国的所有客户的收入
val revenue:Table=Orders
    .filter($"cCountry"==="FRANCE")
    .groupby($"cID",$"cName")
    .select($"cID",$"cName",$"revenue".sum AS "revSum")

    //Table转DataStream
    //执行查询

其中,读表语句val orders: Table=tableEnv.from("Orders")需注意:

从默认的Catalog和数据库中读取名称为tableName的表(或视图)
Table tab=tableEnv.from("tableName")
从指定的Catalog中读取名称为tableName的表
Table tab=tableEnv.from("catalogName.dbName.tableName")
使用转义从指定的Catalog中读取表(例如,数据库名称中的点必须转义)
Table tab=tableEnv.from("catalogName.`db.Name`.tableName")

订单分组计数

假设有一个名为Orders的已注册表具有属性a,b,c,rowtime。

下面分别使用Scala和Java Table API在批环境中对Order表进行处理。

扫描Orders表,按照字段a分组,并计算每组的数据行数。

Java Table API
// Java Table API需要导出的包
import org.apache.flink.table.api.*;
// 对于表达式DSL,需要导入静态包
import static org.apache.flink.table.api.Expressions.*;

// 环境配置
EnvironmentSettings settings=EnvironmentSettings
    .newInstance()
    .inStreamingMode()
    .build();
TableEnvironment tEnv=TableEnvironment.create(settings);

// 向表环境注册一个Orders表
// ...

// 读取已注册的Orders表,返回结果Table(相当于将已注册的表转化为Table,便于后续操作)
Table orders=tEnv.from("Orders"); //字段:(a,b,c,rowtime)
//查询表
Table counts=orders
    .groupBy($("a")) //按照a分组
    .select($("a"),$("b").count().as("cnt"));

//将结果Table转为DataSet
DataSet<Row> result=tEnv.toDataSet(counts,Row.class);
result.print();
Scala Table API
import org.apache.flink.api.scala._
import org.apache.flink.table.scala._
import org.apache.flink.table.api.bridge.scala._

//环境配置
val settings=EnvironmentSettings
    .newInstance()
    .inStreamingMode()
    .build();
val tEnv=TableEnvironment.create(settings);

//注册Orders表
//...

//读取已注册的Orders表,返回结果Table(相当于将已经注册的表转为Table,便于后续操作)
val orders=tEnv.from("Orders") //字段:(a,b,c,rowtime)
//查询并打印结果
val result=orders
          .groupBy($"a") //按照a分组
          .select($"a",$"b".count as "cnt")
          .toDataSet[Row] //转为DataSet
          .print()

每小时订单分组求平均值

扫描Orders表,过滤空值,并按照字段a分组,每小时计算一次各组数据中字段b的平均值。

Java Table API
//读取表Orders
Table orders=tEnv.from("Orders"); //字段:(a,b,c,rowtime)
//执行查询
Table result=orders
        //过滤空值
        .filter(
            and(
                $("a").isNotNull(),
                $("b").isNotNull(),
                $("c").isNotNull()
            ))
        //字段a转为小写
        .select($("a").lowerCase().as("a"),$("b"),$("rowtime"))
        //1小时滚动窗口
        .window(Tumble.over(lit(1).hours()).on($("rowtime")).as("hourlyWindow"))
        //按照窗口和字段a分组
        .groupBy($("hourlyWindow"),$("a"))
        //查询字段a,窗口结束时间,字段b平均值
        .select($("a"),$("hourlyWindow").end().as("hour"),$("b").avg().as("avgBillingAmount"));
Scala Table API
//读取Orders表
val orders:Table=tEnv.from("Orders") //字段:(a,b,c,rowtime)
//执行查询
val result:Table=orders
        //过滤空值
        .filter($"a".isNotNull && $"b".isNotNull && $"c".isNotNull)
        //字段a转为小写
        .select($"a".lowerCase() as "a",$"b",$"rowtime")
        //1小时滚动窗口
        .window(Tumble over 1.hour on $"rowtime" as "hourlyWindow")
        //按照窗口,字段a分组
        .groupBy($"hourlyWindow",$"a")
        //查询字段a,窗口结束时间,字段b的平均值
        .select($"a",$"hourlyWindow".end as "hour",$"b".avg as "avgBillingAmount")
            

  • 8
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 很高兴能够回答您的问题,下面是一个简单的 Flink 示例代码:// 创建 Flink 环境 final ExecutionEnvironment env = ExecutionEnvironment.getExecutionEnvironment(); // 从文本文件中读入数据 DataSet<String> text = env.readTextFile("path/to/file.txt"); // 对数据进行转换,以便进行处理 DataSet<Tuple2<String, Integer>> wordCounts = text .flatMap(new LineSplitter()) .groupBy(0) .sum(1); // 将结果输出到控制台 wordCounts.print(); ### 回答2: 以下是一个使用Flink处理流数据的示例代码: ```java import org.apache.flink.api.common.functions.FlatMapFunction; import org.apache.flink.api.java.tuple.Tuple2; import org.apache.flink.streaming.api.datastream.DataStream; import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment; import org.apache.flink.util.Collector; public class FlinkStreamWordCount { public static void main(String[] args) throws Exception { // 创建一个流处理执行环境 final StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment(); // 设置并行度为1,方便观察输出结果 env.setParallelism(1); // 从socket接收数据流 DataStream<String> stream = env.socketTextStream("localhost", 9999); // 计算单词频率 DataStream<Tuple2<String, Integer>> counts = stream.flatMap(new Tokenizer()) .keyBy(0) .sum(1); // 打印结果 counts.print(); // 启动流计算作业 env.execute("Flink Stream WordCount"); } public static final class Tokenizer implements FlatMapFunction<String, Tuple2<String, Integer>> { @Override public void flatMap(String value, Collector<Tuple2<String, Integer>> out) { // 根据空格切分输入文本 String[] words = value.toLowerCase().split("\\s+"); // 遍历所有单词,输出 (单词, 1) 键值对 for (String word : words) { if (word.length() > 0) { out.collect(new Tuple2<>(word, 1)); } } } } } ``` 这个例子中,我们通过Flink从socket接收数据流,并对输入的文本进行单词计数。程序首先创建一个流处理执行环境,然后设置并行度为1,方便观察输出结果。接着,我们使用socketTextStream方法从本地的9999端口接收数据流。 然后,我们实现了一个Tokenizer类,它是一个FlatMapFunction,用于将输入的文本切分成单词,并与值1一起输出。切分过程是将文本转换为小写并根据空格切分。如果单词长度大于0,则将其输出为 (单词, 1) 的键值对。 接下来,我们通过flatMap将切分后的单词流按单词分组,并对每个单词的频率进行累加求和。 最后,我们打印最终的计数结果,并启动流计算作业。 ### 回答3: 下面是一个使用Flink的简单示例代码。这个代码构建了一个简单的数据流处理任务,它读取来自一个socket的输入流数据,对数据进行处理并将结果打印出来。 ```java import org.apache.flink.streaming.api.datastream.DataStream; import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment; import org.apache.flink.streaming.api.functions.source.SocketTextStreamFunction; public class FlinkExample { public static void main(String[] args) throws Exception { // 创建执行环境 StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment(); // 从socket读取数据流 DataStream<String> inputStream = env.addSource(new SocketTextStreamFunction("localhost", 9999, "\n", 3)); // 对数据进行处理 DataStream<String> processedStream = inputStream.map(line -> "Processed: " + line); // 打印处理结果 processedStream.print(); // 启动任务执行 env.execute("Flink Example"); } } ``` 这段代码使用了Flink的`StreamExecutionEnvironment`来创建一个执行环境。通过`addSource`方法从socket读取数据流,并使用`map`函数对数据进行简单处理。最后,我们使用`print`方法将处理结果打印出来。执行环境的`execute`方法会启动任务执行。 要运行这段代码,你需要在本地启动一个socket服务器,并在端口9999上监听。然后运行这个代码,它会从socket服务器读取数据并对其进行处理。处理结果会打印到控制台上。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值