Apache Flink:使用事件时间从多个输入文件中对数据集进行排序和创建DataStream

时间:2017-05-24 19:18:38

标签: apache-flink flink-streaming

目前,我正在开发一个项目,其中我有一个CSV文件需要预处理才能进行流处理"。因此,我需要执行批处理和流处理。具体来说,我的data.csv文件需要在特定字段上进行预处理和排序,该字段将作为流处理的EventTime时间戳。下面的批处理脚本生成预处理的输出:

final ExecutionEnvironment env = ExecutionEnvironment.getExecutionEnvironment();
DataSet<Tuple3<Long, String, String>> compactData = env
    .readTextFile("data.csv")
    .flatMap(new RichFlatMapFunction<String, Tuple3<Long, String, String>>() {
      private CustomDelegate delegate;
      @Override
      public void open(Configuration parameters) throws Exception {
        delegate = new CustomDelegate();
      }
      @Override
      public void flatMap(String s, Collector<Tuple3<Long, String, String>> out)
          throws Exception {
        Tuple3<Long, String, String> datum = delegate.deserializeRide(s);
        if (datum != null)
          out.collect(datum);
      }
    });
compactData.partitionByRange(0)
    .sortPartition(0, Order.ASCENDING)
    .writeAsCsv("output_dir", "\n", ",");
env.execute();

我的默认并行度是32,当批处理脚本(上面)结束执行时,output_dir目录被创建,它包含32个文件。

问题1:我的问题是这些文件是否是基于全局订单生成的。实质上,与文件2中的记录相比,文件1中的记录是否具有较小的值(依此类推。)?如果不是,我怎样才能保证以前或同等的东西?

正如我上面提到的,我使用output_dir中的文件作为我的流处理作业的输入,该作业由前一个字段(即EventTime)加时间戳。流作业的代码如下:

StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
env.setStreamTimeCharacteristic(TimeCharacteristic.EventTime);
// Phase 0: Collect input and create timestamps
DataStream<Tuple3<Long, String, Integer>> dataStream = env
    .readTextFile("output_dir")
    .map(new MapFunction<String, Tuple3<Long, String, Integer>>() {
      @Override
      public Tuple3<Long, String, Integer> map(String s) throws Exception {
        String[] tokens = s.split(",");
        return new Tuple3<Long, String, Integer>(Long.parseLong(tokens[0]),
            tokens[1] + "-" + tokens[2], 1);
      }
    })
    .assignTimestampsAndWatermarks(
        new AscendingTimestampExtractor<Tuple3<Long, String, Integer>>() {
          @Override
          public long extractAscendingTimestamp(Tuple3<Long, String, Integer> t) {
            return t.f0;
          }
        });
env.execute();

问题2:我将目录output_dir定义为输入,其中包含按字段0排序的文件。是否会根据排序对数据流进行解析并放置在数据流中我想要(即,在他们的领域0)。如果不是,我相信我会在分配时间戳方面遇到问题(对吗?)?我是否可以从多个文件中读取DataStream(就像我现在一样),或者我是否必须将所有文件合并为一个文件,并通过从单个文件中串行读取所有记录来创建DataStream?

1 个答案:

答案 0 :(得分:2)

  

问题1 :我的问题是这些文件是否是基于全球订单生成的。实质上,与文件2中的记录相比,文件1中的记录是否具有较小的值(依此类推。)?如果不是,我怎样才能保证以前或同等的东西?

没有。由于有32个分区,因此每个分区中的数据都是有序的。但不保证不同输出文件之间的数据顺序。您可以手动将sortPartition运算符的并行性设置为1,或者实现自己的分区程序而不是散列分区程序。

  

问题2 :我将目录output_dir定义为输入,其中包含在字段0上排序的文件。记录是否会根据我想要的顺序进行解析并放置在数据流上(即,在他们的领域0)。如果不是,我相信我会在分配时间戳方面遇到问题(对吗?)?我可以从多个文件中读取DataStream(就像我现在一样),或者我是否必须将所有文件合并为一个,并通过从单个文件中串行读取所有记录来创建DataStream?

假设有32个输出文件,如果你的流媒体作业的并行性也是32,那么每个文件将被一个并行性消耗,来自这个输入文件的所有数据将根据出现的数据顺序进行处理。当前并行性的文件。但是,一旦您尝试从32个并行性聚合数据或尝试对数据进行混洗,数据的顺序就不再排序了。如果您希望接收器全局排序数据,您可能必须将所有数据放在一个文件中,并使用具有一个并行性的流式作业处理它们。

相关问题