![](/img/trans.png)
[英]Flink Table API not able to convert DataSet to DataStream
[英]Flink - Convert Avro datastream to table
我在 Kafka 中有 Avro 格式的消息。 這些必須轉換為表格並使用SQL進行選擇,然后轉換為stream,最后下沉。 有多個具有不同 Avro 模式的 Kafka 主題,因此需要動態表。
這是我正在使用的代碼
StreamExecutionEnvironment env = ...;
StreamTableEnvironment tableEnv = StreamTableEnvironment.create(env);
FlinkKafkaConsumer<MyAvroClass> kafkaConsumer = ...;
var kafkaInputStream = env.addSource(kafkaConsumer, "kafkaInput");
Table table = tableEnv.fromDataStream(kafkaInputStream);
tableEnv.executeSql("DESCRIBE " + table).print();
...
MyAvroClass
是 Avro class,它擴展了SpecificRecordBase
並包含一個數組。
此 class 的代碼。
public class MyAvroClass extends SpecificRecordBase implements SpecificRecord {
// avro fields
private String event_id;
private User user;
private List<Item> items;
// getter, setters, constructors, builders, ...
}
我無法訪問items
字段的元素。 當我打印表描述時,我看到項目是 ANY 類型
+------------+-------------------------------------------------------------+------+-----+--------+-----------+
| name | type | null | key | extras | watermark |
+------------+-------------------------------------------------------------+------+-----+--------+-----------+
| event_id | STRING | true | | | |
| items | LEGACY('RAW', 'ANY<java.util.List>') | true | | | |
| user | LEGACY('STRUCTURED_TYPE', 'POJO<com.company.events.User>') | true | | | |
+------------+-------------------------------------------------------------+------+-----+--------+-----------+
如何將其轉換為可用於查詢 from 項目的類型? 提前致謝
我目前正在為此目的使用這種方法。
public static <T extends SpecificRecord> Table toTable(StreamTableEnvironment tEnv,
DataStream<T> dataStream,
Class<T> cls) {
RichMapFunction<T, Row> avroSpecific2RowConverter = new RichMapFunction<>() {
private transient AvroSerializationSchema<T> avro2bin = null;
private transient AvroRowDeserializationSchema bin2row = null;
@Override
public void open(Configuration parameters) throws Exception {
avro2bin = AvroSerializationSchema.forSpecific(cls);
bin2row = new AvroRowDeserializationSchema(cls);
}
@Override
public Row map(T value) throws Exception {
byte[] bytes = avro2bin.serialize(value);
Row row = bin2row.deserialize(bytes);
return row;
}
};
SingleOutputStreamOperator<Row> rows = dataStream.map(avroSpecific2RowConverter)
// https://issues.apache.org/jira/browse/FLINK-23885
.returns(AvroSchemaConverter.convertToTypeInfo(cls));
return tEnv.fromDataStream(rows);
}
我遇到了類似的問題,盡管官方支持 Flink Table 的類型插值無法獲取 java.util.List 或 java.util.Map。 我找到了一個解決方法(閱讀:HACK)我想分享。
第 1 步:將數據映射到 POJO 時,堅持使用您知道會正確插值的字段。 在我的例子中,我有 Map<String, String> 插值失敗LEGACY('RAW', ANY<java.util.Map>)
。 我將它連接成一個字符串(例如,逗號分隔的條目,其中每個條目都是“key:value”。它們連接成一個字符串)。
第 2 步:對於您的輸入數據 stream,確保將其轉換為 DataStream[MY_POJO_TYPE]。
第 3 步:Go 提前執行Table table = tableEnv.fromDataStream(kafkaInputStream);
照常。
第 4 步:使用ScalarFunction對表執行另一個轉換。 在我的例子中,我編寫了一個用戶定義的標量 function 和 output Map<String, String>。 奇怪的是,當在表抽象中插入 Map 數據時,Flink 能夠將類型正確地插入到 Flink MAP 類型中。
這是用戶定義的標量 function 的粗略示例(在 Java 中):
import java.util.Arrays;
import java.util.Map;
import java.util.stream.Collectors;
import org.apache.flink.table.functions.ScalarFunction;
public class TagsMapTypeScalarFunction extends ScalarFunction {
// See
// https://nightlies.apache.org/flink/flink-docs-master/docs/dev/table/functions/udfs/#scalar-functions for reference implementation and how interfacing with ScalarFunction works.
public Map<String, String> eval(String s) {
// input is comma delimited key:value pairs.
return Arrays.stream(s.split(","))
.filter(kv -> kv != "")
.map(kv -> kv.split(":"))
.filter(pair -> pair.length == 2)
.filter(pair -> Arrays.stream(pair).allMatch(token -> token != ""))
.collect(Collectors.toMap(pair -> pair[0].trim(), pair -> pair[1].trim()));
}
}
這是調用的大致樣子(在 Scala 中):
//This table has a field "tags" which is the comma-delimited, key:value squished string.
val transformedTable = tableEnv.fromDataStream(kafkaInputStream: DataStream[POJO])
tableEnv.createTemporaryFunction(
"TagsMapTypeScalarFunction",
classOf[TagsMapTypeScalarFunction]
);
val anotherTransform =
transformedTable
.select($"*", call("TagsMapTypeScalarFunction", $"tags").as("replace_tags"))
.dropColumns($"tags")
.renameColumns($"replace_tags".as("tags"))
anotherTransform
從 map 轉換為字符串,然后返回為 map 確實是一項“繁忙”的工作。但總比被卡住好。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.