Spark Structured streaming API支持的输出源有:Console、Memory、File和Foreach。其中Console在前两篇博文中已有详述,而Memory使用非常简单。本文着重介绍File和Foreach两种方式,并介绍如何在源码基本扩展新的输出方式。

1. File

  Structured Streaming支持将数据以File形式保存起来,其中支持的文件格式有四种:json、text、csv和parquet。其使用方式也非常简单只需设置checkpointLocation和path即可。checkpointLocation是检查点保存的路径,而path是真实数据保存的路径。

如下所示的测试例子:

// Create DataFrame representing the stream of input lines from connection to host:port

val lines = spark.readStream

.format("socket")

.option("host", host)

.option("port", port)

.load()

// Split the lines into words

val words = lines.as[String].flatMap(_.split(" "))

// Generate running word count

val wordCounts = words.groupBy("value").count()

// Start running the query that prints the running counts to the console

val query = wordCounts.writeStream

.format("json")

.option("checkpointLocation","root/jar")

.option("path","/root/jar")

.start()

注意:

File形式不能设置"compelete"模型,只能设置"Append"模型。由于Append模型不能有聚合操作,所以将数据保存到外部File时,不能有聚合操作。

2. Foreach

  foreach输出方式只需要实现ForeachWriter抽象类,并实现三个方法,当Structured Streaming接收到数据就会执行其三个方法,如下的测试示例:

/*

* Licensed to the Apache Software Foundation (ASF) under one or more

* contributor license agreements. See the NOTICE file distributed with

* this work for additional information regarding copyright ownership.

* The ASF licenses this file to You under the Apache License, Version 2.0

* (the "License"); you may not use this file except in compliance with

* the License. You may obtain a copy of the License at

*

* http://www.apache.org/licenses/LICENSE-2.0

*

* Unless required by applicable law or agreed to in writing, software

* distributed under the License is distributed on an "AS IS" BASIS,

* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

* See the License for the specific language governing permissions and

* limitations under the License.

*/

// scalastyle:off println

package org.apache.spark.examples.sql.streaming

import org.apache.spark.sql.SparkSession

/**

* Counts words in UTF8 encoded, '\n' delimited text received from the network.

*

* Usage: StructuredNetworkWordCount <hostname> <port>

* <hostname> and <port> describe the TCP server that Structured Streaming

* would connect to receive data.

*

* To run this on your local machine, you need to first run a Netcat server

* `$ nc -lk 9999`

* and then run the example

* `$ bin/run-example sql.streaming.StructuredNetworkWordCount

* localhost 9999`

*/

object StructuredNetworkWordCount {

def main(args: Array[String]) {

if (args.length < 2) {

System.err.println("Usage: StructuredNetworkWordCount <hostname> <port>")

System.exit(1)

}

val host = args(0)

val port = args(1).toInt

val spark = SparkSession

.builder

.appName("StructuredNetworkWordCount")

.getOrCreate()

import spark.implicits._

// Create DataFrame representing the stream of input lines from connection to host:port

val lines = spark.readStream

.format("socket")

.option("host", host)

.option("port", port)

.load()

// Start running the query that prints the running counts to the console

val query = wordCounts.writeStream

.outputMode("append")

.foreach(new ForearchWriter[Row]{

override def open(partitionId:Long,version:Long):Boolean={

println("open")

return true

}

override def process(value:Row):Unit={

val spark = SparkSession.builder.getOrCreate()

val seq = value.mkString.split(" ")

val row = Row.fromSeq(seq)

val rowRDD:RDD[Row] = sparkContext.getOrCreate().parallelize[Row](Seq(row))

val userSchema = new StructType().add("name","String").add("age","String")

val peopleDF = spark.createDataFrame(rowRDD,userSchema)

peopleDF.createOrReplaceTempView(myTable)

spark.sql("select * from myTable").show()

}

override def close(errorOrNull:Throwable):Unit={

println("close")

}

})

.start()

query.awaitTermination()

}

}

// scalastyle:on println

  上述程序是直接继承ForeachWriter类的接口,并实现了open()、process()、close()三个方法。若采用显示定义一个类来实现,需要注意Scala的泛型设计,如下所示:

class myForeachWriter[T<:Row](stream:CatalogTable) extends ForearchWriter[T]{

override def open(partionId:Long,version:Long):Boolean={

println("open")

true

}

override def process(value:T):Unit={

println(value)

}

override def close(errorOrNull:Throwable):Unit={

println("close")

}

}

3. 自定义

  若上述Spark Structured Streaming API提供的数据输出源仍不能满足要求,那么还有一种方法可以使用:修改源码。

如下通过实现一种自定义的Console来介绍这种使用方式:

3.1 ConsoleSink

  Spark有一个Sink接口,用户可以实现该接口的addBatch方法,其中的data参数是接收的数据,如下所示直接将其输出到控制台:

class ConsoleSink(streamName:String) extends Sink{

override def addBatch(batchId:Long, data;DataFrame):Unit = {

data.show()

}

}

3.2 DataStreamWriter

  在用户自定义的输出形式时,并调用start()方法后,Spark框架会去调用DataStreamWriter类的start()方法。所以用户可以直接在该方法中添加自定义的输出方式,如我们向其传递上述创建的ConsoleSink类示例,如下所示:

def start():StreamingQuery={

if(source == "memory"){

...

}else if(source=="foreach"){

...

}else if(source=="consoleSink"){

val streamName:String = extraOption.get("streamName") mathc{

case Some(str):str

case None=>throw new AnalysisException("streamName option must be specified for Sink")

}

val sink = new consoleSink(streamName)

df.sparkSession.sessionState.streamingQueryManager.startQuery(

extraOption.get("queryName"),

extraOption.get("checkpointLocation"),

df,

sink,

outputMode,

useTempCheckpointLocaltion = true,

recoverFromCheckpointLocation = false,

trigger = trigger

)

}else{

...

}

}

3.3 Structured Streaming

  在前两部修改和实现完成后,用户就可以按正常的Structured Streaming API方式使用了,唯一不同的是在输出形式传递的参数是"consoleSink"字符串,如下所示:

def execute(stream:CatalogTable):Unit={

val spark = SparkSession

.builder

.appName("StructuredNetworkWordCount")

.getOrCreate()

/**1. 获取数据对象DataFrame*/

val lines = spark.readStream

.format("socket")

.option("host", "localhost")

.option("port", 9999)

.load()

/**2. 启动Streaming开始接受数据源的信息*/

val query:StreamingQuery = lines.writeStream

.outputMode("append")

.format("consoleSink")

.option("streamName","myStream")

.start()

query.awaitTermination()

}

4. 参考文献

[1]. Structured Streaming Programming Guide.

Spark Structured Streaming框架(3)之数据输出源详解的更多相关文章

  1. Spark Structured Streaming框架(2)之数据输入源详解

    Spark Structured Streaming目前的2.1.0版本只支持输入源:File.kafka和socket. 1. Socket Socket方式是最简单的数据输入源,如Quick ex ...

  2. Spark Structured Streaming框架(2)之数据输入源详解

    Spark Structured Streaming目前的2.1.0版本只支持输入源:File.kafka和socket. 1. Socket Socket方式是最简单的数据输入源,如Quick ex ...

  3. Spark Structured streaming框架(1)之基本使用

     Spark Struntured Streaming是Spark 2.1.0版本后新增加的流计算引擎,本博将通过几篇博文详细介绍这个框架.这篇是介绍Spark Structured Streamin ...

  4. Spark Structured Streaming框架(1)之基本用法

     Spark Struntured Streaming是Spark 2.1.0版本后新增加的流计算引擎,本博将通过几篇博文详细介绍这个框架.这篇是介绍Spark Structured Streamin ...

  5. Spark Structured Streaming框架(4)之窗口管理详解

    1. 结构 1.1 概述 Structured Streaming组件滑动窗口功能由三个参数决定其功能:窗口时间.滑动步长和触发时间. 窗口时间:是指确定数据操作的长度: 滑动步长:是指窗口每次向前移 ...

  6. Spark Structured Streaming框架(5)之进程管理

    Structured Streaming提供一些API来管理Streaming对象.用户可以通过这些API来手动管理已经启动的Streaming,保证在系统中的Streaming有序执行. 1. St ...

  7. Kafka:ZK+Kafka+Spark Streaming集群环境搭建(二十九):推送avro格式数据到topic,并使用spark structured streaming接收topic解析avro数据

    推送avro格式数据到topic 源代码:https://github.com/Neuw84/structured-streaming-avro-demo/blob/master/src/main/j ...

  8. Kafka:ZK+Kafka+Spark Streaming集群环境搭建(十一)定制一个arvo格式文件发送到kafka的topic,通过Structured Streaming读取kafka的数据

    将arvo格式数据发送到kafka的topic 第一步:定制avro schema: { "type": "record", "name": ...

  9. DataFlow编程模型与Spark Structured streaming

    流式(streaming)和批量( batch):流式数据,实际上更准确的说法应该是unbounded data(processing),也就是无边界的连续的数据的处理:对应的批量计算,更准确的说法是 ...

随机推荐

  1. asp.net core mvc视频A:笔记2-1.控制器定义

    方式一:以Controller结尾 方式二:不以Controller结尾 思考 默认路由规则为 运行示例(这里不需要写testcontroller,只写test就可以了) 同理测试test类中的控制器 ...

  2. 在Java中怎样高效的推断数组中是否包括某个元素

    来自 http://www.hollischuang.com/archives/1269? 怎样检查一个数组(无序)是否包括一个特定的值?这是一个在Java中经经常使用到的并且非常实用的操作.同一时候 ...

  3. call_user_func — 把第一个参数作为回调函数调用

    call_user_func — 把第一个参数作为回调函数调用 说明 mixed call_user_func ( callable $callback [, mixed $parameter [, ...

  4. IntelliJ IDEA(2017)下载并破解

    idea激活,JetBrain旗下软件激活 我在修改这个博主的文章再添加了code码 http://blog.csdn.net/qq_24504453/article/details/77407329 ...

  5. Sql效能优化总结(续)- sql语句优化篇

    今晚继续进行Sql效能问题的分享,今天主要是一些具体的sql优化方法和思路分享,若看过后你也有其他想法,欢迎一起探讨,好了,进入今天的主题. 针对性地对一些耗资源严重的具体应用进行优化 出现效能问题时 ...

  6. Android Camera子系统之源码View

    本文基于Android 4.2.2+Linux3.6.9+SAMA5D3 SoC从源码的角度审视Android Camera子系统. 应用层 Androd原生Camera应用 /system/app/ ...

  7. 机器学习12—FP-growth学习笔记

    test12.py #-*- coding:utf-8 import sys sys.path.append("fpGrowth.py") import fpGrowth from ...

  8. nginx做反向代理proxy_pass,proxy_redirect的使用

     大 | 中 | 小  今天用nginx作为trac的反代,发现一个问题,就是登入登出跳转的时候是白页,看了下网页相应内容,发现相应的location是空的.查了一下发现是只单纯用了proxy_pas ...

  9. 深入了解Erlang 垃圾回收机制以及其重要性(转)

    声明:本片文章是由Hackernews上的[Erlang Garbage Collection Details and Why ItMatters][1]编译而来,本着学习和研究的态度,进行的编译,转 ...

  10. shell脚本57问

    [1]交互方式.非交互方式.Shell脚本是什么? 经常与linux打交道,肯定对shell这个词不陌生.不明白shell意思的,可以自行翻译:外壳.去壳. 这个翻译结果怎么可以与计算机系统联系起来呢 ...