Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/google-chrome/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Scala Spark Streaming-从按键分组的键值对计算统计信息_Scala_Apache Spark_Spark Streaming - Fatal编程技术网

Scala Spark Streaming-从按键分组的键值对计算统计信息

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,

背景: 我正在使用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, Key3=Value11, Key4=Value12,responseTime=100
输出

我想计算不同的度量(平均值、计数等),在给定的批处理间隔内,由流中的不同键分组

  • 键1、键2的平均响应时间(响应时间是每个事件中的一个键)
  • 按键1、键2计数
  • 我迄今为止的努力:

    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(即,需要添加额外的按键分组,而无需太多代码更改)以动态创建元组,并更新正则表达式以覆盖更多情况。我将很快添加我的编辑,以防它对某人有用。