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. 微软认知服务:QnA Maker使用示例

    简介 QnA Maker 从用户提供的内容(包括 FAQ URL.文档和编辑内容)中提取所有可能存在的问答对:利用易于使用的界面编辑.删除和添加问答对,然后将知识库作为 API 终结点进行发布:QnA ...

  2. PHP使用微软认知服务Face API

    下面主要介绍基于PHP语言,基于guzzle类库,调用微软最新推出的认知服务:人脸识别. 实验环境: IDE:Eclipse for PHP Developers Version: Neon.1 Re ...

  3. TCP是如何保证包的顺序传输

    转自:http://blog.csdn.net/ggxxkkll/article/details/7894112 大家都知道,TCP提供了最可靠的数据传输,它给发送的每个数据包做顺序化(这看起来非常烦 ...

  4. junit测试时报No runnable methods错误的解决方法

    1.因为你@Test时import的是@org.testng.annotations.Test所以会报错 解决方法:改为import org.junit.Test;就可以了

  5. vi 详解

    1.vi的基本概念 基本上vi可以分为三种状态,分别是命令模式(command mode).插入模式(Insert mode)和底行模式(last line mode),各模式的功能区分如下: ...

  6. php 在linux 用fopen() 函数打开,file_get_contents(),fread()函数 读取 另外一台服务器映射过来的文件 总是返回false,null的情况。

    php 在linux 用fopen() 函数打开,fread()函数 读取  另外一台服务器映射过来的文件 总是返回false,null的情况. #获取平台类型   $type='android';  ...

  7. 从零开始学android -- dialog

    先看个效果图 activity_main.xml <?xml version="1.0" encoding="utf-8"?> <Linear ...

  8. 如何使用eclipse创建Maven工程及其子模块

    http://blog.csdn.net/jasonchris/article/details/8838802 http://www.tuicool.com/articles/RzyuAj 1,首先创 ...

  9. PHP-Manual的学习----【序言】

    2017年6月27日16:57:32 学习资料:2015-PHP-Manual 打好坚实的基础是做任何事的前提 序言: 笔记: 1.PHP,即"PHP: Hypertext Preproce ...

  10. AngularJS form $addControl 注冊控件control

    需求背景: 在form中使用编写的某component directive时.想通过form's name来对form中控件进行操作, 如使用$invalid等来ng-disabled btn. 解决 ...