Flink流计算编程--如何实现基于KEY/VALUE的List State
来源:互联网 发布:软件板块拓尔思 编辑:程序博客网 时间:2024/04/29 19:44
1、ListState简介
Flink提供了3种基于KEY/VALUE的state的实现方式,分别是:
ValueState<T>ListState<T>ReducingState<T>
官方文档中关于state的使用可以参考这里:Working with State
之前文章中,有一个使用ValueState的例子:ValueState,而ValueState适用于拿到上一条记录,或者上一个窗口中的记录,即ValueState存放的数据仅仅是一条记录,这在很多情况下都很有用。例如上一个窗口中的某些值要传递到下一个窗口,或者上一条记录中的某个值要传递到下一个记录等等。
而ListState则是将需要某些值存到一个List中(Iterable),即缓存的数据不仅仅是1个值,而是多个值。这在很多情况下也很有用,例如计算的数值要包含全天的每一个记录,那么此时只有将每一个记录的值存成一个列表,才可以计算。
2、ListState例子
如何获取ListState?
先定义ListState,并override RichFunction的open方法:
var state : ListState[TransactionListState] = null
override def open(config : Configuration) : Unit = {state = getRuntimeContext.getListState[TransactionListState](new ListStateDescriptor[TransactionListState]("VWAP List State",classOf[TransactionListState]))}
其中,ListStateDescriptor类提供了几种不同的定义方式:
这里我选择了第一种,2个参数分别是ListStateDescriptor的名字以及typeClass。
查询列表与添加数据到列表:
state.add(。。。)listState = state.get()
完整的代码如下:
package toptrade.ComputeClassimport org.apache.flink.api.common.functions.RichFlatMapFunctionimport org.apache.flink.api.common.state.{ListState, ListStateDescriptor}import org.apache.flink.configuration.Configurationimport org.apache.flink.util.Collector/** * 计算VWAP标准差 * 利用Flink提供的基于key/vale的ListState来完成 * 将每一分钟的分钟VOLUME以及分钟VWAP放入一个列表,每分钟的计算都是基于此 * 在每天盘前,都要清空ListState列表,并且盘前的VWAP是0(没有比较) */object TransactionListStateFunction { var state : ListState[TransactionListState] = null var volume = BigDecimal.valueOf(0.0) var VWAP = BigDecimal.valueOf(0.0) var listState : java.lang.Iterable[TransactionListState] = null class TransactionListStateFunction extends RichFlatMapFunction[(String,Int,String,String,BigDecimal,BigDecimal,BigDecimal,BigDecimal,BigDecimal,BigDecimal,BigDecimal,BigDecimal,BigDecimal,BigDecimal,BigDecimal,BigDecimal,BigDecimal,BigDecimal,BigDecimal,BigDecimal,BigDecimal), (String, Int, String, String, BigDecimal, BigDecimal, BigDecimal, BigDecimal, BigDecimal, BigDecimal, BigDecimal, BigDecimal, BigDecimal, BigDecimal, BigDecimal, BigDecimal, BigDecimal, BigDecimal, BigDecimal, BigDecimal, BigDecimal)]{ override def open(config : Configuration) : Unit = { state = getRuntimeContext.getListState[TransactionListState](new ListStateDescriptor[TransactionListState]("VWAP List State",classOf[TransactionListState])) } override def flatMap(in: (String, Int, String, String, BigDecimal, BigDecimal, BigDecimal, BigDecimal, BigDecimal, BigDecimal, BigDecimal, BigDecimal, BigDecimal, BigDecimal, BigDecimal, BigDecimal, BigDecimal, BigDecimal, BigDecimal, BigDecimal, BigDecimal), out: Collector[(String, Int, String, String, BigDecimal, BigDecimal, BigDecimal, BigDecimal, BigDecimal, BigDecimal, BigDecimal, BigDecimal, BigDecimal, BigDecimal, BigDecimal, BigDecimal, BigDecimal, BigDecimal, BigDecimal, BigDecimal, BigDecimal)]): Unit = { /** * init */ if(state.get() == null){ volume = BigDecimal.valueOf(0.0) VWAP = BigDecimal.valueOf(0.0) state.add(TransactionListState(volume,VWAP)) }else{ //get Iterable listState = state.get() } var VWAP_SD : BigDecimal = BigDecimal.valueOf(0.0) /** * 盘前,需要将state清空 */ if(in._3 < "0930"){ state.clear() state.add(TransactionListState(in._5,in._7)) listState = state.get() VWAP_SD = BigDecimal.valueOf(0.0) }else{ val volume = in._5 val VWAP = in._7 val vwap_accum = in._14 /** * 每次先添加当前分钟的VOLUME与VWAP到列表中 */ state.add(TransactionListState(volume,VWAP)) listState = state.get() import scala.collection.JavaConverters._ val scalaState = listState.asScala.toList //计算累计VOLUME var sum_volume = BigDecimal.valueOf(0.0) for(elem <- scalaState){ sum_volume = sum_volume.+(elem.volume) } //开始计算 var SD = BigDecimal.valueOf(0.0) for(elem <- scalaState){ val first = elem.volume./(sum_volume) val second = BigDecimal.valueOf(Math.pow(elem.VWAP.-(vwap_accum).toDouble,2)) SD = SD.+(first.*(second)) } VWAP_SD = BigDecimal.valueOf(Math.sqrt(SD.toDouble)).setScale(4,BigDecimal.RoundingMode.HALF_UP) } out.collect(in._1,in._2,in._3,in._4,in._5,in._6,in._7,in._8,in._9,in._10,in._11,in._12,in._13,in._14,VWAP_SD,in._16,in._17,in._18,in._19,in._20,in._21) } } case class TransactionListState(volume : BigDecimal, VWAP : BigDecimal)}
3、总结
Flink提供了基于key/value的3种State接口,其中ListState接口适用于缓存多个值用于之后的计算。在具体实现时,由于state必须基于key,且必须获取getRuntimeContext,因此,使用state必须同时满足2个条件:
1、直接基于keyedStream或者由keyedStream转换的windowedStream2、必须继承RichFunction
在实际的实现时,由于windowedStream在scala中不能实现RichWindowFunction,因此我在main中使用Flatmap间接实现了windowFunction中的功能:
val fromTransactionDataStream = watermarkTransaction .keyBy(_.code) .window(TumblingEventTimeWindows.of(Time.seconds(60)))
val onlyTransaction = fromTransactionDataStream .apply(new StockTransactionApply) .keyBy(_._3) .flatMap(new TransactionStateFlatMapFunction)
引用
https://ci.apache.org/projects/flink/flink-docs-master/apis/streaming/state.html
http://mail-archives.apache.org/mod_mbox/flink-user/201606.mbox/%3CCAGco–Y-UxKWoJwKDJQ5GQt_Mjr_V8VqOEeGdusc97PWmE0qyg@mail.gmail.com%3E
- Flink流计算编程--如何实现基于KEY/VALUE的List State
- Flink源码解析之State的实现
- Flink流计算编程--Flink扩容、程序升级前后的思考
- Flink流计算编程--流处理引擎的选型
- Flink流计算编程--Kafka+Flink整合demo
- Flink流计算编程--Flink sink to Oracle
- Flink流计算编程--状态与检查点
- Flink流计算编程--Session Window实战
- 【Flink】流计算框架Flink与Storm的性能对比
- 简单的key-value实现
- 【云星数据---Apache Flink实战系列(精品版)】:Flink流处理API详解与编程实战001-Flink基于流的wordcount示例001
- 云星数据---Apache Flink实战系列(精品版)】:Flink流处理API详解与编程实战002-Flink基于流的wordcount示例002
- 云星数据---Apache Flink实战系列(精品版)】:Flink流处理API详解与编程实战003-Flink基于流的window操作001
- 云星数据---Apache Flink实战系列(精品版)】:Flink流处理API详解与编程实战004-Flink基于流的window操作002
- 云星数据---Apache Flink实战系列(精品版)】:Flink流处理API详解与编程实战005-Flink基于流的window操作003
- Flink流计算编程:双流中实现Inner Join、Left Join与Right Join
- 基于共享内存的key-value存储
- 基于共享内存的key-value存储
- JavaScript编写异或函数
- Android官方的sdk,ndk,build-tools,android-x, tools,adt...下载地址
- 传值传参和引用传参
- PHP常量PHP_SAPI与函数php_sapi_name()简介,PHP运行环境检测
- 蚂蚁碰撞概率计算
- Flink流计算编程--如何实现基于KEY/VALUE的List State
- MySql 数据文件默认位置&导入数据文件
- 自然语言处理
- SQL常用命令查询地址
- Fragment:关于Avoid non-default constructors in fragments的错误
- HDU1106-排序
- storm学习(2) 进阶word_count 程序
- mysql、sqlserver、db2、oracle、hsql数据库获取数据库连接方法及分页函数
- 1, libyuv 编译 for android