接上篇:Flink FileSink 自定义输出路径——BucketingSink

上篇使用BucketingSink 实现了自定义输出路径,现在来看看 StreamingFileSink( 据说是StreamingFileSink 是社区优化后添加的connector,推荐使用)

StreamingFileSink 实现起来会稍微麻烦一点(也是灵活,功能更强大),因为可以自己实现序列化方法(源码里面有实例可以参考-复制)

StreamingFileSink 有两个方法可以输出到文件  forRowFormat 和  forBulkFormat,名字差不多代表的方法的含义:行编码格式和块编码格式

forRowFormat 比较简单,只提供了 SimpleStringEncoder 写文本文件,可以指定编码,如下:

import org.apache.flink.api.common.serialization.SimpleStringEncoder
import org.apache.flink.core.fs.Path
import org.apache.flink.streaming.api.functions.sink.filesystem.StreamingFileSink val input: DataStream[String] = ... val sink: StreamingFileSink[String] = StreamingFileSink
.forRowFormat(new Path(outputPath), new SimpleStringEncoder[String]("UTF-8")) // 所有数据都写到同一个路径
.build() input.addSink(sink)

当然我们的主题还是根据输入数据自定义文件输出路径,就需要重写 DayBucketAssigner,如下:

import java.io.IOException
import java.nio.charset.StandardCharsets
import org.apache.flink.core.io.SimpleVersionedSerializer
import org.apache.flink.shaded.jackson2.com.fasterxml.jackson.databind.node.ObjectNode
import org.apache.flink.streaming.api.functions.sink.filesystem.BucketAssigner class DayBucketAssigner extends BucketAssigner[ObjectNode, String] { /**
* bucketId is the output path
* @param element
* @param context
* @return
*/
override def getBucketId(element: ObjectNode, context: BucketAssigner.Context): String = {
//context.currentProcessingTime()
val day = element.get("date").asText("19790101000000").substring(0, 8)
// wrap can use day + "/" + xxx
day
} override def getSerializer: SimpleVersionedSerializer[String] = { StringSerializer
} /**
* 实现参考 : org.apache.flink.runtime.checkpoint.StringSerializer
*/
object StringSerializer extends SimpleVersionedSerializer[String] {
val VERSION = 77 override def getVersion = 77 @throws[IOException]
override def serialize(checkpointData: String): Array[Byte] = checkpointData.getBytes(StandardCharsets.UTF_8) @throws[IOException]
override def deserialize(version: Int, serialized: Array[Byte]): String = if (version != 77) throw new IOException("version mismatch")
else new String(serialized, StandardCharsets.UTF_8)
}
}

在初始化sink 的时候,指定 BucketAssigner 就可以了

val sinkRow = StreamingFileSink
.forRowFormat(new Path("D:\\idea_out\\rollfilesink"), new SimpleStringEncoder[ObjectNode]("UTF-8"))
.withBucketAssigner(new DayBucketAssigner)
// .withBucketCheckInterval(60 * 60 * 1000l) // 1 hour
.build()

执行结果如下:

2、 forBulkFormat 和forRowFormat 不太一样,需要自己实现 BulkWriterFactory 和  DayBulkWriter,自定义程度高,可以实现自己的  FSDataOutputStream,写出各种格式的文件(forRowFormat 自定义Encoder  也可以,但是如 forBuckFormat 灵活)

// use define BulkWriterFactory and DayBucketAssinger
val sinkBuck = StreamingFileSink
.forBulkFormat(new Path("D:\\idea_out\\rollfilesink"), new DayBulkWriterFactory)
.withBucketAssigner(new DayBucketAssigner())
.build()

实现如下:

import java.io.File
import java.nio.charset.StandardCharsets
import org.apache.flink.api.common.serialization.BulkWriter
import org.apache.flink.core.fs.FSDataOutputStream
import org.apache.flink.shaded.jackson2.com.fasterxml.jackson.databind.node.ObjectNode
import org.apache.flink.util.Preconditions /**
* 实现参考 : org.apache.flink.streaming.api.functions.sink.filesystem.BulkWriterTest
*/
class DayBulkWriter extends BulkWriter[ObjectNode] { val charset = StandardCharsets.UTF_8
var stream: FSDataOutputStream = _ def DayBulkWriter(inputStream: FSDataOutputStream): DayBulkWriter = {
stream = Preconditions.checkNotNull(inputStream);
this
} /**
* write element
*
* @param element
*/
override def addElement(element: ObjectNode): Unit = {
this.stream.write(element.toString.getBytes(charset))
// wrapthis.stream.write('\n')
} override def flush(): Unit = {
this.stream.flush()
} /**
* output stream is input parameter, just flush, close is factory's job
*/
override def finish(): Unit = {
this.flush()
} } /**
* 实现参考 : org.apache.flink.streaming.api.functions.sink.filesystem.BulkWriterTest.TestBulkWriterFactory
*/
class DayBulkWriterFactory extends BulkWriter.Factory[ObjectNode] {
override def create(out: FSDataOutputStream): BulkWriter[ObjectNode] = {
val dayBulkWriter = new DayBulkWriter
dayBulkWriter.DayBulkWriter(out) }
}

执行的结果就不赘述了

又遇到个问题,StreamFileSink 没办法指定输出文件的名字。

BucketingSink 和 StreamingFileSink 的不同

从源码位置来说:

BucketingSink 在 connector 下面,注重输出数据
StreamingFileSink 在api 下面,注重与三方交互

从版本来说:

BucketingSink 比较早就有了
StreamingFileSink 是1.6版本推出的功能(据说是优化后推出的)

从支持的文件系统来说:

BucketingSink     支持Hadoop 文件系统支持的所有文件系统(原文:This connector provides a Sink that writes partitioned files to any filesystem supported by Hadoop FileSystem)
StreamingFileSink 支持Flink FileSystem 抽象文件系统 (原文:This connector provides a Sink that writes partitioned files to filesystems supported by the Flink FileSystem abstraction)

从写数据的方式来说:

BucketingSink     默认的Writer是StringWriter,也提供SequenceFileWriter(字符)
StreamingFileSink 使用 OutputStream + Encoder 对外写数据 (字节)

从文件滚动策略来说:

BucketingSink     提供了时间、条数滚动
StreamingFileSink 默认提供时间(官网有说条数,没看到 This is also configurable but the default policy rolls files based on file size and a timeout,自己实现BulkWriter可以)

从目前(1.7.2)来说,BucketingSink 更开箱即用(功能相对简单),StreamingFileSink更麻烦(更灵活、强大)

只是个初学者,还不太能理解 BucketingSink 和 StreamingFileSink 的差异,等了解之后,再来完善

结论:比较推荐使用StreamingFileSink

理由:功能强大,数据刷新时间更快(没有,BucketingSink默认60S的问题,详情见上篇,最后一段)

Flink FileSink 自定义输出路径——StreamingFileSink、BucketingSink 和 StreamingFileSink简单比较的更多相关文章

  1. Flink FileSink 自定义输出路径——BucketingSink

    今天看到有小伙伴在问,就想着自己实现一下. 问题: Flink FileSink根据输入数据指定输出位置,比如讲对应日期的数据输出到对应目录 输入数据: 20190716 输出到路径 20190716 ...

  2. Hadoop案例(五)过滤日志及自定义日志输出路径(自定义OutputFormat)

    过滤日志及自定义日志输出路径(自定义OutputFormat) 1.需求分析 过滤输入的log日志中是否包含xyg (1)包含xyg的网站输出到e:/xyg.log (2)不包含xyg的网站输出到e: ...

  3. Lrc2srt精灵,增加自定义输出编码

    2015.4.8 对中文支持有点问题,修改了一下,支持自定义输出编码! 修改了建议行末偏移,通常100到200最好了,人的反应时间! http://files.cnblogs.com/files/ro ...

  4. VS 工程的 输出路径和工作路径的区别

    输出路径,是vs编译项目生成可执行文件的路径:工作路径是环境变量,比如我们在程序中写相对路径,就是以这个路径为基础的.在默认情况下,输出路径和工作路径都不写的话,默认是程序的bin下面的debug或者 ...

  5. HD1385Minimum Transport Cost(Floyd + 输出路径)

    Minimum Transport Cost Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/O ...

  6. EDIUS设置自定义输出的方法

    在做后期视频剪辑时,往往根据需求,需要输出不同分辨率格式的视频文件,那在EDIUS中,如何自定义输出设置,使之符合自己的需要呢?下面小编就来详细讲讲EDIUS自定义输出的一二事吧. 当剪辑完影片,设置 ...

  7. C++builder XE 安装控件 及输出路径

    C++builder XE 安装控件 与cb6不一样了,和delphi可以共用一个包. 启动RAD Studio.打开包文件. Project>Options>Delphi Compile ...

  8. HDU 1385 Minimum Transport Cost (最短路,并输出路径)

    题意:给你n个城市,一些城市之间会有一些道路,有边权.并且每个城市都会有一些费用. 然后你一些起点和终点,问你从起点到终点最少需要多少路途. 除了起点和终点,最短路的图中的每个城市的费用都要加上. 思 ...

  9. web项目Log4j日志输出路径配置问题

    问题描述:一个web项目想在一个tomcat下运行多个实例(通过修改war包名称的实现),然后每个实例都将日志输出到tomcat的logs目录下实例名命名的文件夹下进行区分查看每个实例日志,要求通过尽 ...

随机推荐

  1. 题解 UVa10892

    题目大意 多组数据,每组数据给定一个整数 \(n\),求满足 \(LCM(x,y)=n\) 的不同无序整数对 \((x,y)\) 的数目. 分析 若有 \(LCM(x,y)=n\),则有 \(GCD( ...

  2. Java获取视频的大小、时长

    前端上传视频之后,根据上传的视频文件获取视频的大小和时长 1.获取视频时长 private String ReadVideoTime(File source) { Encoder encoder = ...

  3. RabbitMQ 关键词

    RabbitMQ是流行的开源消息队列系统,用erlang语言开发.RabbitMQ是AMQP(高级消息队列协议)的标准实现. RabbitMQ中间件分为服务端(RabbitMQ Server)和客户端 ...

  4. npm 删除指定的某个包以及再次安装

    npm uninstall xxxx --save-dev //删除包及删除配置项 npm install xxx@version //安装指定版本 npm install //覆盖

  5. Django+element ui前后端不分离的博客程序

    最近把去年写的一个烂尾博客(使用了django1.11和element ui)又重新完善了一下,修改了样式和增加了新功能 github链接:https://github.com/ngauerh/Nag ...

  6. leetcode解题报告(28):Remove Linked List Elements

    描述 Remove all elements from a linked list of integers that have value val. Example Given: 1 --> 2 ...

  7. Codevs 2185【模板】最长公共上升子序列

    题目描述 Description 熊大妈的奶牛在小沐沐的熏陶下开始研究信息题目.小沐沐先让奶牛研究了最长上升子序列,再让他们研究了最长公共子序列,现在又让他们要研究最长公共上升子序列了.小沐沐说,对于 ...

  8. Linux运维:安装CentOS7图解

    Ago linux运维群: 93324526 笔者QQ:578843228 此篇博文针对最小化安装,和只有图解.有不懂地方,欢迎加群询问. 此篇以CentOS7.2为例

  9. Kafka 深入核心参数配置

    Kafka 真是一个异常稳定的组件,服务器上我们部署了 kafka_2.11-1.0.1 版本的 kafka 除了几次计算时间太长触发了 rebalance 以外,基本没有处理过什么奇怪的问题. 但是 ...

  10. 模板 - 数学 - 数论 - Min_25筛

    终于知道发明者的正确的名字了,是Min_25,这个筛法速度为亚线性的\(O(\frac{n^{\frac{3}{4}}}{\log x})\),用于求解具有下面性质的积性函数的前缀和: 在 \(p\) ...