flink实时写入hdfs之BucketingSink

flink实时写入hdfs之BucketingSink

    • 背景
    • 依赖
    • 代码
    • 问题:怎么根据数据上的时间来区分写入目录
      • 解决

背景

  • flink写入hdfs有比spark的先天优势,就是自带api(可以配置文件滚动策略的方式,没有小文件的烦恼),而spark自带api有小文件问题,解决小文件问题还得自己用hadoop api去实现(其实也还好,就是不够优雅,实现来说相对也比较麻烦)

依赖

<dependency>
  <groupId>org.apache.flinkgroupId>
  <artifactId>flink-connector-filesystem_2.11artifactId>
  <version>1.9.0version>
dependency>

代码

DataStream<String> input = ...;
BucketingSink<Row> sink = new BucketingSink<>("hdfs://data/test/");
//指定在/data/test/下的路径格式 '/data/test/2020-01-01/00'
sink.setBucketer(new DateTimeBucketer<>("yyyy-MM-dd/HH", ZoneId.of("Asia/Shanghai")));
//设置滚动大小 bytes,默认1024L * 1024L * 384L
sink.setBatchSize(1024L * 1024L * 384L);
//设置滚动间隔 ms, 默认Long.MAX_VALUE
sink.setBatchRolloverInterval(60000);
//还有空闲检测等参数,可以自行配置

input.addSink(hdfsSink)

问题:怎么根据数据上的时间来区分写入目录

上面的代码只是根据写入的时间来区分目录,如何根据数据上的时间来分别写入不同目录?
例如 000, 1577844000000这条数据不一定会写入到哪个目录,但是我想根据1577844000000来写入到相应时间的/data/test/2020-01-01/00下,这样即使数据乱序,也可以分别写入到它对应的时间的目录

解决

  • 我们可以实现自己的Bucketer
public class MyDateTimeBucketer implements Bucketer<Row> {

	//dateTimeFormatter=DateTimeFormatter.ofPattern("yyyy-MM-dd/HH").withZone(zoneId)
	//省略部分代码...

	/**
     * 这个方法用来指定数据写入到哪个目录
     */
	@Override
    public Path getBucketPath(Clock clock, Path basePath, Row element) {
        String fieldTime = element.getField(1).toString();
        if (fieldTime.length() == 10) {
            fieldTime = fieldTime + "000";
        }
        String newDateTimeString = dateTimeFormatter.format(Instant.ofEpochMilli(Long.parseLong(fieldTime)));
        return new Path(basePath + "/" + newDateTimeString);
    }

这样,数据就可以写入到正确的分区,hive也可以建立相应的分区表去读了

有说的不对的地方,或者想交流的 随时砸我

你可能感兴趣的:(flink)