算子
MapPartition
此算子在一个来自上游的并行分区里处理数据。它以一个迭代器来引入上游分区的数据,并且支持任意数量的结果输出。每个输入分区的数据数量取决于并行度和上游算子。
data.mapPartition(new MapPartitionFunction<String, Long>() {public void mapPartition(Iterable<String> values, Collector<Long> out) {long c = 0;for (String s : values) {c++;}out.collect(c);}});
ReduceGroup
合并组里的一堆数据。此算子可以应用于全量数据或者一个分组后的数据集。
data.reduceGroup(new GroupReduceFunction<Integer, Integer> {public void reduce(Iterable<Integer> values, Collector<Integer> out) {int prefixSum = 0;for (Integer i : values) {prefixSum += i;out.collect(prefixSum);}}});
Distinct
Join
此算子为内连接,即某方存在另一方不存在的key,舍弃该key对应数据。
Cross
此算子对两个数据流的数据类型不做一致性的要求,所有数据会两两结合,生成新的字符串。与Join不同,Join需要双方按照约定的键进行等值连接,Cross任意两两都可组合。
Hash-Partition
此算子对数据中指定的某个字段做hash,hash结果相同的落到同一分区。
Range-Partition
此算子先抽样确定key的上下限,然后根据分区数划分各个分区的上下限,然后后续的key根据大小归入对应的分区。
Sort Partition
First-n
用来输出每个分区中前n个数据,这个是分组后的每组内前n个。“前n个”可以是按照数据读取的前后顺序,也可以是按照某个字段排序后的顺序。
Sum,Min,Max
一般接在groupBy后面。在分组后的组内进行求和,求最小值和最大值。一般用在tuple数据结构上,最后的结果除了被用来分组的和计算的字段,其他字段取组内最后一个数据的字段值。
andSum,andMin,andMax
一般接在sum、min和max后面,继续在组里对其他字段进行类似操作,这样的话,被计算的字段的值就不是默认的组内最后一个数据的该字段值,而是此次计算后的sum或者min或者max。与.aggregate(MIN, 2)不同,后者是在上次计算的基础上对所有结果再次做聚合,前后两次没有联系。
Source
readFileOfPrimitives(path, delimiter, Class)
从文件读取,直接读成最后的数据结构。按照约定的分割方式来分割文件中的数据,要么是按行分割,要么是按指定的分隔符号。
Example
ExecutionEnvironment env = ExecutionEnvironment.getExecutionEnvironment();// read text file from local files systemDataSet<String> localLines = env.readTextFile("file:///path/to/my/textfile");// read text file from an HDFS running at nnHost:nnPortDataSet<String> hdfsLines = env.readTextFile("hdfs://nnHost:nnPort/path/to/my/textfile");// read a CSV file with three fieldsDataSet<Tuple3<Integer, String, Double>> csvInput = env.readCsvFile("hdfs:///the/CSV/file").types(Integer.class, String.class, Double.class);// read a CSV file with five fields, taking only two of themDataSet<Tuple2<String, Double>> csvInput = env.readCsvFile("hdfs:///the/CSV/file").includeFields("10010") // take the first and the fourth field.types(String.class, Double.class);// read a CSV file with three fields into a POJO (Person.class) with corresponding fieldsDataSet<Person>> csvInput = env.readCsvFile("hdfs:///the/CSV/file").pojoType(Person.class, "name", "age", "zipcode");// read a file from the specified path of type SequenceFileInputFormatDataSet<Tuple2<IntWritable, Text>> tuples =env.createInput(HadoopInputs.readSequenceFile(IntWritable.class, Text.class, "hdfs://nnHost:nnPort/path/to/file"));// creates a set from some given elementsDataSet<String> value = env.fromElements("Foo", "bar", "foobar", "fubar");// generate a number sequenceDataSet<Long> numbers = env.generateSequence(1, 10000000);// Read data from a relational database using the JDBC input formatDataSet<Tuple2<String, Integer> dbData =env.createInput(JdbcInputFormat.buildJdbcInputFormat().setDrivername("org.apache.derby.jdbc.EmbeddedDriver").setDBUrl("jdbc:derby:memory:persons").setQuery("select name, age from persons").setRowTypeInfo(new RowTypeInfo(BasicTypeInfo.STRING_TYPE_INFO, BasicTypeInfo.INT_TYPE_INFO)).finish());// Note: Flink's program compiler needs to infer the data types of the data items which are returned// by an InputFormat. If this information cannot be automatically inferred, it is necessary to// manually provide the type information as shown in the examples above.
csv解析
parseQuotedStrings(char quoteChar),此函数用来使用指定字符来使解析器忽略解析该字符包裹起来的整个字符串,一般常见的有双引号。比如”a, b”,c,d最后会被解析成三段,分别是(a, b)、(c)、(d)。
迭代计算
类似于DataSteam中的迭代,DataSet中一个很重要的功能就是数据集迭代计算,对应到各种机器学习的算法,迭代是很常见的一个计算模式。Flink DataSet支持两种类型的迭代。
Bulk Iterations
最典型的代码骨架就是先用iterate(int)来将一个普通DataSet转化为IterativeDataSet,然后在IterativeDataSet上进行单次迭代所需的计算,定义完单次迭代的计算流程后,在初始IterativeDataSet上使用closeWith(DataSet)来指定添加一系列单次迭代计算算子的DataSet来做数据回流。
Delta Iterations
这种迭代利用了一种算法特性,某些算法的结果总有一部分并不是在每次迭代中都会改变的。所以Delta Iterations会在每次迭代中将一部分数据回流(wordset),而另一个部分则保持作为状态,并在每次迭代中更新(solution set)。
在函数中操作数据
禁用数据重用(默认)
- 从集合中collect数据是安全的。但是当读取数据的函数结束后,该数据可能会改变,所以在对该数据的读取操作后保存数据可能不安全(后续被篡改)。
- 你可以在函数中emit数据,但是当emit后再读数据不安全,因为emit后可能会被修改。
语义注解
Flink允许用户添加字段转发注解或者函数来使得Flink可以推断如何在多个算子之间重用排序和分区,使用语义注解可以显著较少不必要的网络shuffle和不必要的排序,来加速程序的执行,提高性能。Forwarded Fields Annotation
@ForwardedFields("f0->f2")public class MyMap implementsMapFunction<Tuple2<Integer, Integer>, Tuple3<String, Integer, Integer>> {@Overridepublic Tuple3<String, Integer, Integer> map(Tuple2<Integer, Integer> val) {return new Tuple3<String, Integer, Integer>("foo", val.f1 / 2, val.f0);}}
Non-Forwarded Fields
@NonForwardedFields("f1") // second field is not forwardedpublic class MyMap implementsMapFunction<Tuple2<Integer, Integer>, Tuple2<Integer, Integer>> {@Overridepublic Tuple2<Integer, Integer> map(Tuple2<Integer, Integer> val) {return new Tuple2<Integer, Integer>(val.f0, val.f1 / 2);}}
Read Fields
@ReadFields("f0; f3") // f0 and f3 are read and evaluated by the function.public class MyMap implementsMapFunction<Tuple4<Integer, Integer, Integer, Integer>,Tuple2<Integer, Integer>> {@Overridepublic Tuple2<Integer, Integer> map(Tuple4<Integer, Integer, Integer, Integer> val) {if(val.f0 == 42) {return new Tuple2<Integer, Integer>(val.f0, val.f1);} else {return new Tuple2<Integer, Integer>(val.f3+10, val.f1);}}}
