Flink Keyed State实践:实现蒙特卡洛模拟求Pi

flink中的状态分为两类:Keyed StateOperator State;Keyed State是只能定义在KeyedStream的状态, 每一类状态都有 Managed StateRaw 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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值