flink中的状态分为两类:Keyed State、Operator State;Keyed State是只能定义在KeyedStream的状态, 每一类状态都有 Managed State和Raw state两种托管方式;flink中内置了以下几种托管的状态:
- ValueState<T>:单值状态
- ListState<T>:多值状态
- ReducingState<T>:Reduce函数的状态
- AggregatingState<T>:聚合函数的状态
- MapState<T>:Map函数的状态
更多息请参照flink官网,本文会讲一下flink中Keyed State的的使用方式,并结合Flink中的状态实现蒙特卡洛方法模拟求圆周率Pi
蒙特卡洛
蒙特卡罗方法是一种模拟计算方法。原理是通过大量随机样本,去了解一个系统,进而近似得到所要计算的值,蒙特卡洛方法在金融学,经济学,计算物理学等领域应用非常广泛。
利用蒙特卡洛求圆周率的原理:
正方形内部有一个相切的圆,它们的面积之比是π/4。
现在,在这个正方形内部,随机产生n个点(即n个坐标对 (x, y)),计算它们与中心点的距离,从而判断是否落在圆的内部。
如果这些点均匀分布,那么圆内的点应该占到所有点的 π/4,因此将这个比值乘以4,就是π的值
flink 代码实现
// 定义一个MonteCarlo类
case class MonteCarloPoint(x: Double, y: Double) {
def pi = if (x * x + y * y <= 1) 1 else 0
}
object MonteCarko extends App {
// 自定义一个Source,实现随机坐标点的生成
class MonteCarloSource extends RichSourceFunction[MonteCarloPoint] {
val env = StreamExecutionEnvironment.getExecutionEnvironment
// state 需要在RichFunction中实现
val myMapFun = new RichMapFunction[(Long, MonteCarloPoint), (Long, Double)] {
// 定义原始状态
var countAndPi: ValueState[(Long, Long)] = _
override def map(value: (Long, MonteCarloPoint)): (Long, Double) = {
// 通过 ValueState.value获取状态值
val tmpCurrentSum = countAndPi.value
val currentSum = if (tmpCurrentSum != null) {
tmpCurrentSum
} else {
(0L, 0L)
}
val allcount = currentSum._1 + 1
val picount = currentSum._2 + value._2.pi
// 计算新的状态值
val newState: (Long, Long) = (allcount, picount)
// 更新状态值
countAndPi.update(newState)
//输出总样本量和模拟极速那的Pi值
(allcount, 4.0 * picount / allcount)
}
override def open(parameters: Configuration): Unit = {
countAndPi = getRuntimeContext.getState(
new ValueStateDescriptor[(Long, Long)]("MonteCarloPi", createTypeInformation[(Long, Long)])
)
}
}
// 添加数据源
val dataStream: DataStream[MonteCarloPoint] = env.addSource(new MonteCarloSource)
// 转换成KeyedStream
val keyedStream= dataStream.map((1L, _)).keyBy(0)
// 调用定义好的RichFunction并打印结果
keyedStream.map(myMapFun).print()
env.execute("Monte Carko Test")
}
结果查看
(21,3.238095238095238)
(22,3.272727272727273)
(23,3.3043478260869565)
...
(971,3.073120494335736)
(972,3.074074074074074)
(973,3.07502569373073)
...
(6143713,3.1411675643051686)
(6143714,3.1411677040956008)
(6143715,3.1411671928141196)
(6143716,3.1411666815328054)
从结果看到,随着样本的增加,计算的值越来越接近Pi的真实值
参考资料
https://ci.apache.org/projects/flink/flink-docs-release-1.8/dev/stream/state/state.html
http://ruanyifeng.com/blog/2015/07/monte-carlo-method.html