一、DataSet API
1.1、DataSet API 之 DataSource
- 基于集合 fromCollection(Collection)
- 基于文件 readTextFile(Path)
1.2、DataSet API 之 Transformation
| 算子 | 解释 |
|---|---|
| map | 输入一个元素进行处理,返回一个元素 |
| mapPartition | 类似map,一次处理一个分区的数据 |
| flatMap | 输入一个元素进行处理,可以返回多个元素 |
| filter | 对数据进行过滤,符合条件的数据会被留下 |
| reduce | 对当前元素和上一次的结果进行聚合操作 |
| aggregate | sum(),min(),max()等 |
package com.strivelearn.flink.dataset;
import java.util.Arrays;
import java.util.Iterator;
import org.apache.flink.api.common.functions.MapPartitionFunction;
import org.apache.flink.api.java.ExecutionEnvironment;
import org.apache.flink.api.java.operators.DataSource;
import org.apache.flink.api.java.operators.MapPartitionOperator;
import org.apache.flink.util.Collector;
/**
* @author strivelearn
* @version BatchMapPartitionJava.java, 2023年01月15日
*/
public class BatchMapPartitionJava {
public static void main(String[] args) throws Exception {
// 获取执行环境
ExecutionEnvironment env = ExecutionEnvironment.getExecutionEnvironment();
// 生成数据源
DataSource<String> stringDataSource = env.fromCollection(Arrays.asList("hello you", "hello me"));
// 每次处理一个分区的数据
MapPartitionOperator<String, String> stringStringMapPartitionOperator = stringDataSource.mapPartition(new MapPartitionFunction<String, String>() {
@Override
public void mapPartition(Iterable<String> iterable, Collector<String> collector) throws Exception {
Iterator<String> iterator = iterable.iterator();
while (iterator.hasNext()) {
String line = iterator.next();
String[] words = line.split(" ");
for (String word : words) {
collector.collect(word);
}
}
}
});
stringStringMapPartitionOperator.print();
}
}
| 算子 | 解释 |
|---|---|
| distinct | 返回数据集中去重之后的元素 |
| join | 内连接 |
| outerJoin | 外连接 |
| cross | 获取两个数据集的笛卡尔积 |
| union | 返回多个数据集的总和,数据类型需要一致 |
| first-n | 获取集合中的前N个元素 |
内连接代码示范
package com.strivelearn.flink.dataset;
import java.util.ArrayList;
import java.util.Arrays;
import org.apache.flink.api.common.functions.JoinFunction;
import org.apache.flink.api.java.ExecutionEnvironment;
import org.apache.flink.api.java.operators.DataSource;
import org.apache.flink.api.java.tuple.Tuple2;
import org.apache.flink.api.java.tuple.Tuple3;
/**
* @author strivelearn
* @version BatchJoinJava.java, 2023年01月15日
*/
public class BatchJoinJava {
public static void main(String[] args) throws Exception {
// 获取执行环境
ExecutionEnvironment env = ExecutionEnvironment.getExecutionEnvironment();
// 初始化第一份数据 Tuple2<用户id,用户姓名>
ArrayList<Tuple2<Integer, String>> data1 = new ArrayList<>();
data1.add(new Tuple2<>(1, "lily"));
data1.add(new Tuple2<>(2, "tom"));
data1.add(new Tuple2<>(3, "lucy"));
DataSource<Tuple2<Integer, String>> datasource1 = env.fromCollection(data1);
// 初始化第二份数据 Tuple2<用户id,所在城市>
ArrayList<Tuple2<Integer, String>> data2 = new ArrayList<>();
data2.add(new Tuple2<>(1, "suzhou"));
data2.add(new Tuple2<>(2, "hangzhou"));
data2.add(new Tuple2<>(4, "shanghai"));
DataSource<Tuple2<Integer, String>> datasource2 = env.fromCollection(data2);
datasource1.join(datasource2).where(0).equalTo(0).with(new JoinFunction<Tuple2<Integer, String>, Tuple2<Integer, String>, Tuple3<Integer, String, String>>() {
@Override
public Tuple3<Integer, String, String> join(Tuple2<Integer, String> first, Tuple2<Integer, String> second) throws Exception {
return new Tuple3<>(first.f0, first.f1, second.f1);
}
}).print();
}
}
输出结果 (1,lily,suzhou) (2,tom,hangzhou)
外连接代码演示
package com.strivelearn.flink.dataset;
import org.apache.flink.api.common.functions.JoinFunction;
import org.apache.flink.api.java.ExecutionEnvironment;
import org.apache.flink.api.java.operators.DataSource;
import org.apache.flink.api.java.tuple.Tuple2;
import org.apache.flink.api.java.tuple.Tuple3;
import java.util.ArrayList;
/**
* 外连接
* @author strivelearn
* @version BatchOuterJoinJava.java, 2023年01月15日
*/
public class BatchOuterJoinJava {
public static void main(String[] args) throws Exception {
// 获取执行环境
ExecutionEnvironment env = ExecutionEnvironment.getExecutionEnvironment();
// 初始化第一份数据 Tuple2<用户id,用户姓名>
ArrayList<Tuple2<Integer, String>> data1 = new ArrayList<>();
data1.add(new Tuple2<>(1, "lily"));
data1.add(new Tuple2<>(2, "tom"));
data1.add(new Tuple2<>(3, "lucy"));
DataSource<Tuple2<Integer, String>> datasource1 = env.fromCollection(data1);
// 初始化第二份数据 Tuple2<用户id,所在城市>
ArrayList<Tuple2<Integer, String>> data2 = new ArrayList<>();
data2.add(new Tuple2<>(1, "suzhou"));
data2.add(new Tuple2<>(2, "hangzhou"));
data2.add(new Tuple2<>(3, "shanghai"));
DataSource<Tuple2<Integer, String>> datasource2 = env.fromCollection(data2);
datasource1.join(datasource2).where(0).equalTo(0).with(new JoinFunction<Tuple2<Integer, String>, Tuple2<Integer, String>, Tuple3<Integer, String, String>>() {
@Override
public Tuple3<Integer, String, String> join(Tuple2<Integer, String> first, Tuple2<Integer, String> second) throws Exception {
return new Tuple3<>(first.f0, first.f1, second.f1);
}
}).print();
}
}
输出:
(3,lucy,null) (1,lily,suzhou) (2,tom,hangzhou)
笛卡尔积 cross
package com.strivelearn.flink.dataset;
import org.apache.flink.api.java.ExecutionEnvironment;
import org.apache.flink.api.java.operators.DataSource;
import java.util.Arrays;
/**
* cross 获取两个数据集的笛卡尔积
* @author strivelearn
* @version BatchCrossJava.java, 2023年01月15日
*/
public class BatchCrossJava {
public static void main(String[] args) throws Exception {
// 获取执行环境
ExecutionEnvironment env = ExecutionEnvironment.getExecutionEnvironment();
// 初始化第一份数据
DataSource<Integer> dataSource1 = env.fromCollection(Arrays.asList(1, 2));
// 初始化第二份数据
DataSource<String> dataSource2 = env.fromCollection(Arrays.asList("a", "b"));
dataSource1.cross(dataSource2).print();
}
}
输出
(1,a) (1,b) (2,a) (2,b)
获取集合中的前N个元素
package com.strivelearn.flink.dataset;
import org.apache.flink.api.common.operators.Order;
import org.apache.flink.api.java.ExecutionEnvironment;
import org.apache.flink.api.java.operators.DataSource;
import org.apache.flink.api.java.tuple.Tuple2;
import java.util.ArrayList;
import java.util.Arrays;
/**
* first-n 获取集合的前N个元素
* @author xys
* @version BatchFirstNJava.java, 2023年01月15日
*/
public class BatchFirstNJava {
public static void main(String[] args) throws Exception {
// 获取执行环境
ExecutionEnvironment env = ExecutionEnvironment.getExecutionEnvironment();
ArrayList<Tuple2<Integer, String>> dataSource = new ArrayList<>();
dataSource.add(new Tuple2<>(1, "lily"));
dataSource.add(new Tuple2<>(2, "tom"));
dataSource.add(new Tuple2<>(3, "lucy"));
dataSource.add(new Tuple2<>(4, "zhangsan"));
dataSource.add(new Tuple2<>(5, "ali"));
dataSource.add(new Tuple2<>(6, "hero"));
DataSource<Tuple2<Integer, String>> tuple2DataSource = env.fromCollection(dataSource);
// 获取前3条数据,按照数据插入的顺序
tuple2DataSource.first(3).print();
System.out.println("======分割线======");
// 根据数据中的第一列进行分组,获取每组的前2个元素
tuple2DataSource.groupBy(0).first(2).print();
System.out.println("======分割线======");
// 根据数据中的第一列分组,再根据第二列进行组内排序【倒序】,获取每组的前2个元素
// 分组排序取TopN
tuple2DataSource.groupBy(0).sortGroup(1, Order.DESCENDING).first(2).print();
}
}
输出
(1,lily) (2,tom) (3,lucy) ======分割线====== (3,lucy) (1,lily) (5,ali) (6,hero) (4,zhangsan) (2,tom) ======分割线====== (3,lucy) (1,lily) (5,ali) (6,hero) (4,zhangsan) (2,tom)
1.3、DataSet API 之 DataSink
- writeAsText() 将元素以字符串形式逐行写入,这些字符串通过调用每个元素的toString()方法来获取
- writeAsCsv() 将元祖以逗号分隔写入文件中,行和字段之间的分隔符是可配置的,每个字段的值来自对象的toString方法
- print() 打印每个元素的toString()方法的值到标准输出
二、Flink Table API 和SQL
是一种关系型的API,用户可以像操作MySQL数据库表一样操作数据,而不需要写代码。更不需要手工对代码进行调优
实现流批统一的 Blink planner 中由于没有了 DataSet 的概念,已经不再使用 BatchTableEnvironment
<!--想要在本地ide运行添加此依赖-->
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-table-planner_2.12</artifactId>
<version>1.16.0</version>
<scope>test</scope>
</dependency>
<!--使用table api 和sql添加此依赖-->
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-table-api-java-bridge</artifactId>
<version>1.16.0</version>
<scope>provided</scope>
</dependency>
package com.strivelearn.flink.tableapi;
import org.apache.flink.table.api.EnvironmentSettings;
import org.apache.flink.table.api.Table;
import org.apache.flink.table.api.TableEnvironment;
import static org.apache.flink.table.api.Expressions.$;
/**
* @author strivelearn
* @version TableApiAndSqlOpJava.java, 2023年01月15日
*/
public class TableApiAndSqlOpJava {
public static void main(String[] args) {
EnvironmentSettings streamMode = EnvironmentSettings.newInstance().useBlinkPlanner().inStreamingMode().build();
TableEnvironment sTableEnv = TableEnvironment.create(streamMode);
sTableEnv.executeSql("create table myTable" + "(id int,name String)" + "with('connector.type'='filesystem'," + "'connector.path'='/Users/strivelearn/Desktop',"
+ "'format.type'='csv')");
// 使用table api 进行查询
Table result = sTableEnv.from("myTable").select($("id"), $("name")).filter($("id").isGreater(1));
result.execute().print();
// 使用SQL实现数据查询和过滤操作
Table table = sTableEnv.sqlQuery("select id,name from myTable where id>1");
table.execute().print();
}
}
2.1、DataStream、DataSet和Table之间的互相转换
-
使用DataStream创建表,主要包含下面两种情况:
- 使用DataStream创建view视图
- 使用DataStream创建Table对象
-
使用DataSet创建表
注意:此时只能使用旧的执行引擎,新的blink执行引擎不支持和DataSet转换
-
将表转换为DataSteam
流式查询的结果Table会被动态的更新,即每个新的记录到达输入流时结果就会发生变化,因此,转换此动态查询的DataStream需要对表的更新进行编码。
Append Mode:这个模式只适用于当动态表仅由insert操作进行修改时,之前添加的数据不会被更新
Retract Mode:可以使用此模型,它使用一个Boolean标识来编码insert和delete操作
-
将表转换为DataSet