Scala Spark Streaming-从按键分组的键值对计算统计信息
背景: 我正在使用Spark Streaming来流式处理来自Kafka的事件,这些事件以逗号分隔的键值对的形式出现 下面是一个如何将事件流式传输到spark应用程序的示例Scala Spark Streaming-从按键分组的键值对计算统计信息,scala,apache-spark,spark-streaming,Scala,Apache Spark,Spark Streaming,背景: 我正在使用Spark Streaming来流式处理来自Kafka的事件,这些事件以逗号分隔的键值对的形式出现 下面是一个如何将事件流式传输到spark应用程序的示例 Key1=Value1, Key2=Value2, Key3=Value3, Key4=Value4,responseTime=200 Key1=Value5, Key2=Value6, Key3=Value7, Key4=Value8,responseTime=150 Key1=Value9, Key2=Value10,
Key1=Value1, Key2=Value2, Key3=Value3, Key4=Value4,responseTime=200
Key1=Value5, Key2=Value6, Key3=Value7, Key4=Value8,responseTime=150
Key1=Value9, Key2=Value10, Key3=Value11, Key4=Value12,responseTime=100
输出:
我想计算不同的度量(平均值、计数等),在给定的批处理间隔内,由流中的不同键分组
val stream = KafkaUtils
.createDirectStream[String, String, StringDecoder, StringDecoder](
ssc, kafkaParams, topicsSet)
val pStream = stream.persist()
val events: DStream[String] = pStream.flatMap(_._2.split(","))
val pairs= events.map(data => data.split("=")).map(array => (array(0), array(1)))
// pairs results in tuples of (Key1, Value1), (Key2, Value2) and so on.
更新-03/04
密钥Key1、Key2…可能在传入流中无序到达
感谢您的输入/提示。一种可能的解决方案如下:
- 创建一个表示每条记录的case类,这样我们就不用处理元组了:
case class Record( key1: String, key2: String, key3: String, key4: String, rt: Double)
- 使用regexp解析记录并删除格式错误的条目:
import scala.util.matching.Regex val recordPattern = new Regex( "^Key1=(.*?), ?Key2=(.*?), ?Key3=(.*?), ?Key4=(.*?), ?" ++ "responseTime=(0-9+)$" ) val records = pStream.map { case recordPattern(key1, key2, key3, key4, rt) => Some(Record(key1, key2, key3, key4, rt.toDouble)) case _ => None }.flatMap(x => x) // Drop malformed
- 将数据重塑为键值对:
val pairs = records.map(r => ((r.key1, r.key2), r.rt))
- 创建一个分区器并使用
聚合统计信息:StatCounter
import org.apache.spark.util.StatCounter import org.apache.spark.HashPartitioner val paritioner: HashPartitioner = ??? pairs.combineByKey[StatCounter]( StatCounter(_), _ merge _, _ merge _, paritioner )
- 提取感兴趣的字段:
stats.mapValues(s => (s.count, s.mean))
val kvPattern = "(\\w+)=(\\w+)".r
val pairs = pStream.map(line => {
val kvs = kvPattern.findAllMatchIn(line)
.map(m => (m.group(1), m.group(2))).toMap
// This will discard any malformed lines
// (lack of key1, key2, lack or invalid format of responseTime)
Try((
(kvs("Key1"), kvs("Key2")),
kvs("responseTime").toDouble
))
}).flatMap(_.toOption)
然后像以前一样继续。您能提供预期的输出类型和到目前为止的尝试吗?这并不是你真正想要的。@zero323-好的,我用预期的输出类型和我到目前为止的尝试更新了我的问题。如果我能通过,我会把答案贴出来。谢谢。我格式化了一点。你在更新上打败了我:)。发帖后我意识到我错过了格式。谢谢当然:)是否要计算每个窗口的统计信息?如果是这样的话,您是否考虑过使用
数据帧
?谢谢。这可能有用。唯一需要注意的是,我可能忘了在我的问题中提到的是key1,key2不一定每次都在相同的序列中,所以正则表达式不匹配。我在考虑应用更通用的解决方案,因此按键值元组进行查找,从而按配置查找key1、key2。想法?这也是使用StatCounter的一个很好的技巧。然后你必须用另一种方式解析它。将键值对提取到Map
中应该很好。这里确实没有快速修复方法。你可以尝试一些类似于编辑的东西,但这在很大程度上取决于上下文和要求。你为我节省了不少时间。你是火花大师!!希望我能给你买一杯咖啡/啤酒:)编辑中的方法确实有效,但必须进行修改以满足我的要求#2(即,需要添加额外的按键分组,而无需太多代码更改)以动态创建元组,并更新正则表达式以覆盖更多情况。我将很快添加我的编辑,以防它对某人有用。