有这样需求,消息发来是站点名stationName,但与需要和mysql中维度表join站点名的三字码stationCode(唯一标识符)。
flink版本1.6.3,maven配置如下:
com.google.guava
guava
25.1-jre
mysql
mysql-connector-java
5.1.6
com.alibaba
druid
1.1.16
com.alibaba
fastjson
1.2.47
读取kafka消息
final StreamExecutionEnvironment env = StreamExecutionEnvironment.createLocalEnvironment();
//链接kafka消息
String kafkaBrokers=KafkaConfig.KAFKA_BROKER_LIST;
String topicName="topic-test";
Properties propsConsumer = new Properties();
propsConsumer.setProperty("bootstrap.servers",kafkaBrokers) ;
propsConsumer.setProperty("group.id", "trafficwisdom-streaming");
propsConsumer.put("enable.auto.commit", false);
propsConsumer.put("max.poll.records", 1000);
FlinkKafkaConsumer011 consumer = new FlinkKafkaConsumer011(topicName, new SimpleStringSchema(), propsConsumer);
consumer.setStartFromLatest();
DataStream stream = env.addSource(consumer);
DataStream, String>> filterStream = stream.map(new MapFunction, String>>() {
@Override
public Tuple2, String> map(String value) throws Exception {
//格式转换忽略
JSONObject jsonObject = JSON.parseObject(value);
String fromPlace = jsonObject.getString("FromPlace");
String toPlace = jsonObject.getString("ToPlace");
String searchData = jsonObject.getString("SelectDate");
String response = jsonObject.getString("Response");
return Tuple2.of(Tuple3.of(fromPlace, toPlace, searchData), response);
}
});
filterStream.print();
新建异步链接mysql的类AsyncStationCodeMultiRequest
public class AsyncStationCodeMultiRequest extends RichAsyncFunction, String>, Tuple2, String>> {
private transient DruidDataSource dataSource;
private transient ListeningExecutorService executorService;
private transient volatile Cache stationNameCache;
@Override
public void open(Configuration parameters) throws Exception {
//初始化多线程
executorService = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(10));
//缓存设置
stationNameCache = CacheBuilder., String>newBuilder().maximumSize(2000).expireAfterWrite(1, TimeUnit.DAYS) .build();
//建立druid线程池
dataSource = new DruidDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUsername("root"); dataSource.setPassword("1111");
dataSource.setUrl("jdbc:mysql://xxxxx:3306/wisdom");
dataSource.setInitialSize(5);
dataSource.setMinIdle(10);
dataSource.setMaxActive(20);
}
@Override
public void asyncInvoke(Tuple2, String> input, ResultFuture, String>> resultFuture) throws Exception {
//异步多线程处理
executorService.submit(() -> {
try {
//逻辑处理,省略
.......
if(trainTicketNoBOList.size()>0) {
trainTicketBO.setData(trainTicketNoBOList);
String parseResult = JSON.toJSONString(trainTicketBO);
resultFuture.complete(Collections.singleton(Tuple2.of(Tuple3.of(fromStationCode, toStationCode, searchDate), parseResult)));
}
} catch (Exception e) {
logger.error(e.getMessage());
resultFuture.complete(Collections.singleton(Tuple2.of(Tuple3.of(null, null, null), null)));
}
});
}
private List ticketLogChange(String response) throws SQLException {
TrainInfoList trainInfoList = JSON.parseObject(response, TrainInfoList.class);
//省略处理逻辑
.....
里面调用getStationName(stationName)方法
......
return trainTicketNoBOList;
}
//先从guava缓存取得站名与之匹配的stationCode,如果没有,从mysql查
private String getStationName(String stationName) throws SQLException {
return stationNameCache.getIfPresent(stationName) != null ? stationNameCache.getIfPresent(stationName) : getStationCodeFromSql(stationName);
}
//从mysql中查到stationCode,且存入guava缓存
private String getStationCodeFromSql(String stationName) throws SQLException {
String sql = "select station_code,station_name from wisdom.station_train_base where station_name='" + stationName + "' limit 1";
PreparedStatement pstmt;
String stationCode = null;
Connection connection = null;
try {
connection=dataSource.getConnection();
pstmt = (PreparedStatement) connection.prepareStatement(sql);
ResultSet rs = pstmt.executeQuery();
while (rs.next()) {
stationCode = rs.getString("station_code");
}
} finally {
if(connection!=null) {
connection.close();
}
}
if (stationCode != null) {
stationNameCache.put(stationName, stationCode);
}
return stationCode;
}
@Override
public void close() throws Exception {
dataSource.close();
ExecutorUtils.gracefulShutdown(2, TimeUnit.MINUTES, executorService);
}
}
主流程
DataStream, String>> dimTable = AsyncDataStream.unorderedWait(filterStream, new AsyncStationCodeMultiRequest(), 2, TimeUnit.SECONDS, 100)
.filter(s -> s.f0.f0 != null && s.f0.f1 != null);
dimTable.print();
dimTable就是打宽表后的数据结果。