使用mapWithState Spark Streaming过滤部分重复项

时间:2018-05-02 15:23:55

标签: scala apache-spark streaming bigdata spark-streaming

我们有一个DStream,例如

val ssc = new StreamingContext(sc, Seconds(1))

val kS = KafkaUtils.createDirectStream[String, TMapRecord](
  ssc,
  PreferConsistent,
  Subscribe[String, TMapRecord](topicsSetT, kafkaParamsInT)).
  mapPartitions(part => {
    part.map(_.value())
  }).
  mapPartitions(part1 => {
    part1.map(c => {
      TMsg(1,
        c.field1,
        c.field2, //And others
        c.startTimeSeconds
      )
    })
  })

因此每个RDD都有一堆TMsg个对象,其中包含一些(技术)关键字段,可用于解除DStream的重新分配。基本上,如果我们有两个TMsg对象在一个或两个DISCRETIZED RDD field1field2相同,并且它们相差不到1秒(我们看{{1} }},它' 重复

我查看了mapWithState。 是的我可以创建K - > V DStream喜欢

startTimeSeconds

所以我可以使用该功能,但不了解如何使用它来过滤重复项。

窗口函数无法提供帮助,因为解决方案是用DStream编写的,所以我无法使用(结构化流).deduplicate函数。

任何解决方案?感谢

P.S。 Spark版本是2.2

1 个答案:

答案 0 :(得分:1)

您可以使用mapWithState。有一个很好的manual how to use Stateful Streaming。 在你的情况下,你可以:

1.设置checkpoin:

val ssc = new StreamingContext(sc, Seconds(1))
ssc.checkpoint("path/to/persistent/storage")

2.定义更新功能:

def update(key: (String, String),
           value: Option[Int],
           state: State[Int]): Option[((String, String), Int)] = {
  (value, state.getOption()) match {
    case (Some(_), Some(_)) => None
    case (Some(v), _) =>
      # you can update your state in any value you want
      # it is just a marker that value not new
      state.update(value.get)
      Option((key, v))
    case (_, _) if state.isTimingOut() => None
  }
}

3.制定州规格:

val stateSpec =
  StateSpec
    .function(update _)
    # it is important to define how long 
    # you want to check duplication
    # in this example check interval is 1 second.
    .timeout(Seconds(1))

4.使用方式:

ks
  # make key->value pairs
  .map(m => (m.field1, m.field2) -> m.startTimeSeconds)
  .mapWithState(stateSpec)

如果你想取最后一个值,更新功能可能是:

  def update(key: (String, String),
                       value: Option[Int],
                       state: State[Int]): Option[((String, String), Int)] = {
    (value, state.getOption()) match {
      case (Some(_), Some(_)) => None
      case (Some(v), _) =>
        state.update(value.get)
        None
      case (_, _) if state.isTimingOut() => Option((key, value.get))
    }
  }