通过使用组合键来刷新数据流键

时间:2018-12-29 07:22:12

标签: scala apache-flink flink-streaming

我的问题与How to support multiple KeyBy in Flink非常相似,只是那个问题是针对Java的,我需要在Scala中给出答案。我在IntelliJ中复制粘贴了提供的解决方案,它自动将复制粘贴的代码片段转换为Scala,然后我对其进行了编辑以适合我的代码。我仍然遇到编译错误(甚至在编译IntelliJ之前就无法检测到代码问题)。基本上,提供给keyBy的参数(keySelector的getKey函数的返回值)与keyBy函数的任何重载版本期望的参数都不匹配。

查找了许多KeySelector的scala代码示例示例,该示例返回了组合键,但未找到任何示例。

import org.apache.flink.api.java.functions.KeySelector
import org.apache.flink.api.java.tuple.Tuple2
import org.myorg.aarna.AAPerMinData
val aa_stats_keyed_stream = aa_stats_stream_w_timestamps.keyBy(new 
    KeySelector[AAPerMinData, Tuple2[String, String]]() {
    @throws[Exception]
    override def getKey(value: AAPerMinData): Tuple2[String, String] = 
    Tuple2.of(value.field1, value.field2)  
})

我在编译代码时遇到以下错误:

Error:(213, 64) overloaded method value keyBy with alternatives:
[K](fun: org.myorg.aarna.AAPerMinData => K)(implicit evidence $2:org.apache.flink.api.common.typeinfo.TypeInformation[K])org.apache.flink.streaming.api.scala.KeyedStream[org.myorg.aarna.AAPerMinData,K] <and>
(firstField: String,otherFields: 
String*)org.apache.flink.streaming.api.scala.KeyedStream[org.myorg.aarna.AAPerMinData,org.apache.flink.api.java.tuple.Tuple] <and>
(fields: Int*)org.apache.flink.streaming.api.scala.KeyedStream[org.myorg.aarna.AAPerMinData,org.apache.flink.api.java.tuple.Tuple]
cannot be applied to (org.apache.flink.api.java.functions.KeySelector[org.myorg.aarna.AAPerMinData,org.apache.flink.api.java.tuple.Tuple2[String,String]])
val aa_stats_keyed_stream = aa_stats_stream_w_timestamps.keyBy(new KeySelector[AAPerMinData, Tuple2[String, String]]() {

我不确定引起此错误的语法中缺少什么。任何帮助是极大的赞赏。一旦解决了此问题,便可以根据组合键进行基于TumblingWindow的摘要。

更新1(2018年12月29日): 更改了代码,以使用KeySelector格式将简单的String类型字段用作键(我知道这可以用更简单的方式完成,我这样做只是为了使基本的KeySelector正常工作)。

  import org.apache.flink.api.java.functions.KeySelector
  import org.myorg.aarna.AAPerMinData
  val aa_stats_keyed_stream = aa_stats_stream_w_timestamps.keyBy(new KeySelector[AAPerMinData, String]() {
    @throws[Exception]
    override def getKey(value: AAPerMinData): String = value.set1.sEntId
  })

这是我收到的错误的屏幕截图(即IntelliJ在鼠标悬停时显示此错误)。 enter image description here

更新2(2018年12月29日)

这有效(对于单键情况)

val aa_stats_keyed_stream = aa_stats_stream_w_timestamps.keyBy[String] 
(_.set1.sEntId)

这不起作用(对于组合键盒)

val aa_stats_keyed_stream = aa_stats_stream_w_timestamps.keyBy([String, String)](_.set1.sEntId, _.set1.field2)

更新3(2018年12月29日) 尝试以下方法,无法使其正常工作。查看错误屏幕截图。

val aa_stats_keyed_stream = aa_stats_stream_w_timestamps.keyBy[(String, String)]((_.set1.sEntId, _.set1.field2))

enter image description here

更新4(2018年12月30日) 现在解决,请参阅接受的答案。对于任何有兴趣的人,这是最终的工作代码,包括使用复合键进行聚合:

// Composite key
val aa_stats_keyed_stream = aa_stats_stream_w_timestamps.keyBy[(String, String)](x => (x.set1.sEntId, x.set1.field2))

// Tumbling window
val aggr_keyed_stream = aa_stats_keyed_stream.window(TumblingEventTimeWindows.of(Time.seconds(60)))

// all set for window based aggregation of a "composite keyed" stream
val aggr_stream = aggr_keyed_stream.apply { (key: (String, String), window: TimeWindow, events: Iterable[AAPerMinData],
                                                 out: Collector[AAPerMinDataAggr]) =>
      out.collect(AAPerMinDataAggrWrapper(key._1 + key._2, // composite
        key._1, key._2, // also needed individual pieces
        window,
        events,
        stream_deferred_live_duration_in_seconds*1000).getAAPerMinDataAggr)}
// print the "mapped" stream for debugging purposes
aggr_stream.print()

1 个答案:

答案 0 :(得分:0)

首先,虽然没有必要,请继续使用Scala元组。除非您出于某种原因必须与Java Tuples进行互操作,否则它将使总体上变得更容易。

然后,不要使用org.apache.flink.api.java.functions.KeySelector。您想通过org.apache.flink.streaming.api.scala.DataStream使用此密钥:

/**
 * Groups the elements of a DataStream by the given K key to
 * be used with grouped operators like grouped reduce or grouped aggregations.
 */
def keyBy[K: TypeInformation](fun: T => K): KeyedStream[T, K] = {

  val cleanFun = clean(fun)
  val keyType: TypeInformation[K] = implicitly[TypeInformation[K]]

  val keyExtractor = new KeySelector[T, K] with ResultTypeQueryable[K] {
    def getKey(in: T) = cleanFun(in)
    override def getProducedType: TypeInformation[K] = keyType
  }
  asScalaStream(new JavaKeyedStream(stream, keyExtractor, keyType))
}

换句话说,只需传递一个将流元素转换为键值的函数(通常,Flink的scala API会尝试惯用)。所以像这样的事情应该做的:

aa_stats_stream_w_timestamps.keyBy[String](value => value.set1.sEntId)

更新:

对于复合钥匙包,请使用

aa_stats_stream_w_timestamps.keyBy[(String, String)](x => (x.set1.sEntId, x.set1.field2))