Apache flink ApacheFlink-使用数据流中的值动态创建流数据源
我正在尝试使用Apache Flink构建一个示例应用程序,该应用程序执行以下操作:Apache flink ApacheFlink-使用数据流中的值动态创建流数据源,apache-flink,Apache Flink,我正在尝试使用Apache Flink构建一个示例应用程序,该应用程序执行以下操作: 从卡夫卡队列中读取股票符号流(例如“CSCO”、“FB”) 对于每个符号,执行当前价格的实时查找,并将值流化以供下游处理 *更新到原始帖子* 我将map函数移动到一个单独的类中,并且没有得到运行时错误消息“MapFunction的实现不再是可序列化的。对象可能包含或引用不可序列化的字段” 我现在面临的问题是,卡夫卡主题“股票价格”,我试图写的价格,是没有收到他们。我正在尝试排除故障,并将发布任何更新 publi
public class RetrieveStockPrices {
@SuppressWarnings("serial")
public static void main(String[] args) throws Exception {
final StreamExecutionEnvironment streamExecEnv = StreamExecutionEnvironment.getExecutionEnvironment();
streamExecEnv.setStreamTimeCharacteristic(TimeCharacteristic.IngestionTime);
Properties properties = new Properties();
properties.setProperty("bootstrap.servers", "localhost:9092");
properties.setProperty("zookeeper.connect", "localhost:2181");
properties.setProperty("group.id", "stocks");
DataStream<String> streamOfStockSymbols = streamExecEnv.addSource(new FlinkKafkaConsumer08<String>("stocksymbol", new SimpleStringSchema(), properties));
DataStream<String> stockPrice =
streamOfStockSymbols
//get unique keys
.keyBy(new KeySelector<String, String>() {
@Override
public String getKey(String trend) throws Exception {
return trend;
}
})
//collect events over a window
.window(TumblingEventTimeWindows.of(Time.seconds(60)))
//return the last event from the window...all elements are the same "Symbol"
.apply(new WindowFunction<String, String, String, TimeWindow>() {
@Override
public void apply(String key, TimeWindow window, Iterable<String> input, Collector<String> out) throws Exception {
out.collect(input.iterator().next().toString());
}
})
.map(new StockSymbolToPriceMapFunction());
streamExecEnv.execute("Retrieve Stock Prices");
}
}
public class StockSymbolToPriceMapFunction extends RichMapFunction<String, String> {
@Override
public String map(String stockSymbol) throws Exception {
final StreamExecutionEnvironment streamExecEnv = StreamExecutionEnvironment.getExecutionEnvironment();
streamExecEnv.setStreamTimeCharacteristic(TimeCharacteristic.IngestionTime);
System.out.println("StockSymbolToPriceMapFunction: stockSymbol: " + stockSymbol);
DataStream<String> stockPrices = streamExecEnv.addSource(new LookupStockPrice(stockSymbol));
stockPrices.keyBy(new CustomKeySelector()).addSink(new FlinkKafkaProducer08<String>("localhost:9092", "stockprices", new SimpleStringSchema()));
return "100000";
}
private static class CustomKeySelector implements KeySelector<String, String> {
@Override
public String getKey(String arg0) throws Exception {
return arg0.trim();
}
}
}
public class LookupStockPrice extends RichSourceFunction<String> {
public String stockSymbol = null;
public boolean isRunning = true;
public LookupStockPrice(String inSymbol) {
stockSymbol = inSymbol;
}
@Override
public void open(Configuration parameters) throws Exception {
isRunning = true;
}
@Override
public void cancel() {
isRunning = false;
}
@Override
public void run(SourceFunction.SourceContext<String> ctx)
throws Exception {
String stockPrice = "0";
while (isRunning) {
//TODO: query Google Finance API
stockPrice = Integer.toString((new Random()).nextInt(100)+1);
ctx.collect(stockPrice);
Thread.sleep(10000);
}
}
}
公共类RetrieveStockPrices{
@抑制警告(“串行”)
公共静态void main(字符串[]args)引发异常{
最终StreamExecutionEnvironment streamExecEnv=StreamExecutionEnvironment.getExecutionEnvironment();
StreamXecenv.setStreamTimeCharacteristic(时间特征.摄取时间);
属性=新属性();
setProperty(“bootstrap.servers”,“localhost:9092”);
setProperty(“zookeeper.connect”,“localhost:2181”);
属性。setProperty(“group.id”、“股票”);
DataStream streamOfStockSymbols=streamXecenv.addSource(新的FlinkKafkaConsumer08(“stocksymbol”,新的SimpleStringSchema(),属性));
数据流股价=
股票符号流
//获取唯一密钥
.keyBy(新的KeySelector(){
@凌驾
公共字符串getKey(字符串趋势)引发异常{
回归趋势;
}
})
//通过窗口收集事件
.window(TumblingEventTimeWindows.of(时间秒(60)))
//从窗口返回最后一个事件…所有元素都是相同的“符号”
.apply(新的WindowFunction(){
@凌驾
public void apply(字符串键、时间窗口、Iterable输入、收集器输出)引发异常{
out.collect(input.iterator().next().toString());
}
})
.map(新的StockSymbolToPriceMapFunction());
执行(“检索股票价格”);
}
}
公共类StockSymbolToPriceMapFunction扩展了RichMapFunction{
@凌驾
公共字符串映射(字符串stockSymbol)引发异常{
最终StreamExecutionEnvironment streamExecEnv=StreamExecutionEnvironment.getExecutionEnvironment();
StreamXecenv.setStreamTimeCharacteristic(时间特征.摄取时间);
System.out.println(“StockSymbolOpriceMapfunction:stockSymbol:”+stockSymbol);
DataStream stockPrices=streamExecEnv.addSource(新lookupstockprices(stockSymbol));
stockPrices.keyBy(新的CustomKeySelector()).addSink(新的flinkkapkaproducer08(“localhost:9092”,“stockPrices”,新的SimpleStringSchema());
返回“100000”;
}
私有静态类CustomKeySelector实现KeySelector{
@凌驾
公共字符串getKey(字符串arg0)引发异常{
返回arg0.trim();
}
}
}
公共类LookupStockPrice扩展了RichSourceFunction{
公共字符串stockSymbol=null;
公共布尔值isRunning=true;
公共LookupStockPrice(字符串inSymbol){
stockSymbol=inSymbol;
}
@凌驾
public void open(配置参数)引发异常{
isRunning=true;
}
@凌驾
public void cancel(){
isRunning=false;
}
@凌驾
公共无效运行(SourceFunction.SourceContext ctx)
抛出异常{
字符串stockPrice=“0”;
当(正在运行时){
//TODO:查询谷歌金融API
股票价格=整数.toString((new Random()).nextInt(100)+1);
ctx.托收(股票价格);
睡眠(10000);
}
}
}
StreamExecutionEnvironment
不缩进以在流媒体应用程序的操作员内部使用。非预期意味着,这不受测试和鼓励。它可能会工作并做一些事情,但很可能表现不好,可能会杀死您的应用程序
程序中的stocksymboltopricemap函数
为每个传入记录指定一个全新的独立流媒体应用程序。但是,由于不调用streamxecenv.execute()
程序不会启动,map
方法将返回,而不执行任何操作
如果调用
streamExecEnv.execute()
,该函数将在workers JVM中启动一个新的本地Flink群集,并在此本地Flink群集上启动应用程序。本地Flink实例将占用大量堆空间,在启动几个集群之后,工人可能会因为OutOfMemoryError
而死亡,这不是您希望发生的。是否可以动态创建流以响应传入数据?您可以实现一个FlatMapFunction
,该函数根据到达的记录动态读取和发送数据。例如,如果您有一个具有文件名的流,则可以使用FlatMapFunction
打开这些文件并发出它们的数据。但是,所有记录的输出类型必须相同。另外,正确处理事件时间语义可能是一个挑战,但这更像是动态添加源的一般问题。@FabianHueske我正在解决一个类似的用例。因此,如果我必须使用FlatMapFunction,那么我们必须使用scala/Java中的普通文件API读取文件,而不是使用Flink的readTextFile。原因是我们不能使用S