文章目錄
在flink中,StreamingFileSink是一個很重要的把流式數據寫入文件系統的sink,可以支持寫入行格式(json,csv等)的數據,以及列格式(orc、parquet)的數據。
hive作爲一個廣泛的數據存儲,而ORC作爲hive經過特殊優化的列式存儲格式,在hive的存儲格式中佔有很重要的地位。今天我們主要講一下使用StreamingFileSink將流式數據以ORC的格式寫入文件系統,這個功能是flink 1.11版本開始支持的。
StreamingFileSink簡介
StreamingFileSink提供了兩個靜態方法來構造相應的sink,forRowFormat用來構造寫入行格式數據的sink,forBulkFormat方法用來構造寫入列格式數據的sink,
我們看一下方法forBulkFormat。
public static <IN> StreamingFileSink.DefaultBulkFormatBuilder<IN> forBulkFormat(
final Path basePath, final BulkWriter.Factory<IN> writerFactory) {
return new StreamingFileSink.DefaultBulkFormatBuilder<>(basePath, writerFactory, new DateTimeBucketAssigner<>());
}
這裏需要兩個參數,第一個是一個寫入的路徑,第二個是一個用於創建writer的實現BulkWriter.Factory接口的工廠類。
寫入orc工廠類
首先我們要引入相應的pom
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-orc_2.11</artifactId>
<version>1.11.0</version>
</dependency>
flink爲我們提供了寫入orc格式的工廠類OrcBulkWriterFactory,我們簡單看下這個工廠類的一些變量。
@PublicEvolving
public class OrcBulkWriterFactory<T> implements BulkWriter.Factory<T> {
private static final Path FIXED_PATH = new Path(".");
private final Vectorizer<T> vectorizer;
private final Properties writerProperties;
private final Map<String, String> confMap;
private OrcFile.WriterOptions writerOptions;
public OrcBulkWriterFactory(Vectorizer<T> vectorizer) {
this(vectorizer, new Configuration());
}
public OrcBulkWriterFactory(Vectorizer<T> vectorizer, Configuration configuration) {
this(vectorizer, null, configuration);
}
public OrcBulkWriterFactory(Vectorizer<T> vectorizer, Properties writerProperties, Configuration configuration) {
...................
}
.............
}
向量化操作
flink使用了hive的VectorizedRowBatch來寫入ORC格式的數據,所以需要把輸入數據組織成VectorizedRowBatch對象,而這個轉換的功能就是由OrcBulkWriterFactory中的變量—也就是抽象類Vectorizer類完成的,主要實現的方法就是org.apache.flink.orc.vector.Vectorizer#vectorize方法。
- 在flink中,提供了一個支持RowData輸入格式的RowDataVectorizer,在方法vectorize中,根據不同的類型,將輸入的RowData格式的數據轉成VectorizedRowBatch類型。
@Override
public void vectorize(RowData row, VectorizedRowBatch batch) {
int rowId = batch.size++;
for (int i = 0; i < row.getArity(); ++i) {
setColumn(rowId, batch.cols[i], fieldTypes[i], row, i);
}
}
-
如果用戶想將自己的輸入格式以orc格式寫入,那麼需要繼承抽象類Vectorizer,並且實現自己的轉換方法vectorize。
-
如果用戶在寫入orc文件之後,想添加一些自己的元數據信息,可以覆蓋org.apache.flink.orc.vector.Vectorizer#addUserMetadata方法來添加相應的信息。
構造OrcBulkWriterFactory
工廠類一共提供了三個構造方法,我們看到最全的一個構造方法一共接受三個參數,第一個就是我們上面講到的Vectorizer對象,第二個是一個寫入orc格式的配置屬性,第三個是hadoop的配置文件.
寫入的配置來自https://orc.apache.org/docs/hive-config.html,具體可以是以下的值.
key | 缺省值 | 註釋 |
---|---|---|
orc.compress | ZLIB | high level compression = {NONE, ZLIB, SNAPPY} |
orc.compress.size | 262,144 | compression chunk size |
orc.stripe.size | 67,108,864 | memory buffer in bytes for writing |
orc.row.index.stride | 10,000 | number of rows between index entries |
orc.create.index | true | create indexes? |
orc.bloom.filter.columns | ”” | comma separated list of column names |
orc.bloom.filter.fpp | 0.05 | bloom filter false positive rate |
實例講解
最後,我們通過一個簡單的實例來講解一下具體的使用。
構造source
首先我們自定義一個source,模擬生成RowData數據,我們這個也比較簡單,主要是生成了一個int和double類型的隨機數.
public static class MySource implements SourceFunction<RowData>{
@Override
public void run(SourceContext<RowData> sourceContext) throws Exception{
while (true){
GenericRowData rowData = new GenericRowData(2);
rowData.setField(0, (int) (Math.random() * 100));
rowData.setField(1, Math.random() * 100);
sourceContext.collect(rowData);
Thread.sleep(10);
}
}
@Override
public void cancel(){
}
}
構造OrcBulkWriterFactory
接下來定義構造OrcBulkWriterFactory需要的參數。
//寫入orc格式的屬性
final Properties writerProps = new Properties();
writerProps.setProperty("orc.compress", "LZ4");
//定義類型和字段名
LogicalType[] orcTypes = new LogicalType[]{new IntType(), new DoubleType()};
String[] fields = new String[]{"a1", "b2"};
TypeDescription typeDescription = OrcSplitReaderUtil.logicalTypeToOrcType(RowType.of(
orcTypes,
fields));
//構造工廠類OrcBulkWriterFactory
final OrcBulkWriterFactory<RowData> factory = new OrcBulkWriterFactory<>(
new RowDataVectorizer(typeDescription.toString(), orcTypes),
writerProps,
new Configuration());
構造StreamingFileSink
StreamingFileSink orcSink = StreamingFileSink
.forBulkFormat(new Path("file:///tmp/aaaa"), factory)
.build();
完整的代碼請參考:
https://github.com/zhangjun0x01/bigdata-examples/blob/master/flink/src/main/java/connectors/filesystem/StreamingWriteFileOrc.java
更多精彩內容,歡迎關注公衆號:【大數據技術與應用實戰】