目录:apache beam 个人使用经验总结目录和入门指导(Java)
众所周知数据处理分批处理和流处理,beam是基于底层计算引擎并支持2者的。 这一章先只介绍批处理的几种数据输入方式,即一次性全部输入全部数据的方式。
内存输入数据
内存输入方式之前介绍过了,可以通过组装Create类进行内存输入
PCollection<String> pcStart = pipeline.apply(
Create.of(
"HELLO!",
"THIS IS BEAM DEMO!",
"HAPPY STUDY!"));
也可也输入其他数据类型
PCollection<Integer> pcStartInt = pipeline.apply(Create.of(1,2,3,4));
Create.of里的内容可以是T… , 或者是Iterable<T>
本地文本
输入
PCollection<String> pText =
pipeline.apply(TextIO.read().from("beam.txt"));
from里是文本文件的路径
读入后,会自动根据换行符进行分割,分割成1个个String类型的数据集元素。
当我读入如下beam.txt文本,并用PrintStrFn进行输出时的情况:
可以看到确实是根据换行符进行了分割
输出
输出的sdk使用方式如下:
pText.apply(TextIO.write().to("/tmp/beamtest").withSuffix(".txt").withoutSharding());
注意事项:如果是基于分布式计算引擎,使用TextIo读取和输出本地文件很可能会失败,除非文件路径在每一个executor节点都存在。
hdfs文本输入
上面提到如果是在分布式计算引擎上计算,读取本地文件可能会失败,因此分布式读取文本都是基于hdfs文件进行操作的。
hdfs输入方式步骤如下:
1.pom文件增加hdfs依赖包
<dependency>
<groupId>org.apache.beam</groupId>
<artifactId>beam-sdks-java-io-hadoop-file-system</artifactId>
<version>{beam.version}</version>
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-hdfs</artifactId>
<version>{hadoop.version}</version>
</dependency>
2.使用的PipelineOption至少要继承自HadoopFileSystemOptions
public interface MyTestOption extends HadoopFileSystemOptions {...
3.创建的option要设置hdfs配置
MyTestOption option = PipelineOptionsFactory.fromArgs(args).withoutStrictParsing().as(MyTestOption.class);
Configuration conf = new Configuration();
// 输入fs.defaultFS(可参考集群的core-site.xml)
conf.set("fs.defaultFS", "hdfs://hacluster");
// 输入文件系统执行引擎
conf.set("fs.hdfs.impl", "org.apache.hadoop.hdfs.DistributedFileSystem");
List<Configuration> list = new ArrayList<Configuration>();
list.add(conf);
option.setHdfsConfiguration(list);
4.调用TextIo
PCollection<String> pText =
pipeline.apply(TextIO.read().from("hdfs://hacluster/user/beam.txt"));
hdfs文本输出sdk使用方式同本地文本输出。
jdbc输入
输入
简单的jdbc输入可使用JdbcIO这个sdk, 首先得引入org.apache.beam的beam-sdks-java-io-jdbc这个包。
然后输入如下代码:
PCollection<String> pReadColumnFirst = pipeline.apply(
JdbcIO.<String>read()
// 组装数据连接信息
.withDataSourceConfiguration(configuration)
// 组装查询语句
.withQuery("select name from worker")
// 如何把resultSet转成需要的数据集元素
.withRowMapper(new JdbcRowMapper())
// 元素需要设定正确编码,否则可能无法识别。
.withCoder(StringUtf8Coder.of())
);
configuration的生成方式如下:
JdbcIO.DataSourceConfiguration configuration
= JdbcIO.DataSourceConfiguration
.create(dbDriver, url)
.withUsername(userName)
.withPassword(password);
JdbcRowMapper的定义如下,需要实现JdbcIo.RowMapper接口:
static class JdbcRowMapper implements JdbcIO.RowMapper<String> {
// 如何将Jdbc的ResultSet转成需要的元素
@Override
public String mapRow(ResultSet resultSet) throws Exception {
return resultSet.getString(1);
}
}
对于编码的选取,可以见apache beam入门之编码Coder相关
***注意事项: 该jdbcIO仅支持读少量数据,如果要读入超过jvm限制的数据,则会出现omm报错
输出
输出要用preStatement的方式做插入或更新操作
pReadColumnFirst.apply(
JdbcIO.<String>write()
.withDataSourceConfiguration(configuration)
.withStatement("update worker set level = 10 where name = ?")
.withPreparedStatementSetter(new JdbcPreStatementSetter()));
JdbcPreStatementSetter的实现如下,就是定义了如何把数据集中的元素set到Statement中
static class JdbcPreStatementSetter implements JdbcIO.PreparedStatementSetter<String> {
@Override
public void setParameters(String element, PreparedStatement preparedStatement) throws Exception {
preparedStatement.setObject(1, element);
}
}
自定义输入方式
如果beam自带的sdk无法满足需求(例如希望加入一些安全认证或者异常操作等),则可以用自定义的输入方式。
自定义输入需要先定义一个新的DoFn类,输入类型定义为Void,如下所示:
static class SafeReadFn extends DoFn<Void, String> {
@ProcessElement
public void processElement(ProcessContext context) {
// 可运行业务需要所的安全认证
safeLogin();
// 用自己定义的方式读取数据
String readElement = readData(context);
// 输出数据
context.output(readElement);
}
}
注意这个执行类中,不需要取输入元素,因为输入元素Void一般都是null,不需要取。
然后先通过Create.of()建立1个空的Void元素,然后在处理这个元素时, 进行自定义输入即可。
PCollection<String> pReadData
= pipeline.apply(Create.<Void>of(null))
.apply(ParDo.of(new SafeReadFn()));
输出同理,如果是自定义输出(即后面不再有计算操作), 定义1个DoFn<类型, Void>即可