apache beam入門之輸入輸出SDK調用(批處理)

目錄: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>即可

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章