我正在将数据流导入Flink。对于此数据的每个“实例”,我都有一个时间戳。我可以检测到我要从中获取数据的机器是“正在生产”还是“未正在生产”,这是通过位于其自己的静态类中的自定义平面地图函数完成的。
我想计算机器已经生产/不生产多长时间了。 我当前的方法是在两个简单列表中收集生产和非生产时间戳。对于数据的每个“实例”,我通过从最早的时间戳中减去最新的时间戳来计算当前的生产/非生产持续时间。但是,这给了我错误的结果。当生产状态从生产更改为非生产时,我清除生产的时间戳列表,反之亦然,这样,如果生产再次开始,则持续时间从零开始。
我查看了两个列表,分别收集了它们的时间戳,并且看到了我不了解的内容。我的假设是,只要机器“生产”,生产时间戳列表中的第一个时间戳就保持不变,而每个新数据实例会将新时间戳添加到列表中。 显然,这种假设是错误的,因为我在列表中似乎是随机的时间戳。不过,它们的顺序仍然正确。
这是我的flatmap函数代码:
public static class ImaginePaperDataConverterRich extends RichFlatMapFunction<ImaginePaperData, String> {
private static final long serialVersionUID = 4736981447434827392L;
private transient ValueState<ProductionState> stateOfProduction;
SimpleDateFormat dateFormat = new SimpleDateFormat("dd.MM.yyyy HH:mm:ss.SS");
DateFormat timeDiffFormat = new SimpleDateFormat("dd HH:mm:ss.SS");
String timeDiffString = "00 00:00:00.000";
List<String> productionTimestamps = new ArrayList<>();
List<String> nonProductionTimestamps = new ArrayList<>();
public String calcProductionTime(List<String> timestamps) {
if (!timestamps.isEmpty()) {
try {
Date firstDate = dateFormat.parse(timestamps.get(0));
Date lastDate = dateFormat.parse(timestamps.get(timestamps.size()-1));
long timeDiff = lastDate.getTime() - firstDate.getTime();
if (timeDiff < 0) {
System.out.println("Something weird happened. Maybe EOF.");
return timeDiffString;
}
timeDiffString = String.format("%02d %02d:%02d:%02d.%02d",
TimeUnit.MILLISECONDS.toDays(timeDiff),
TimeUnit.MILLISECONDS.toHours(timeDiff) % TimeUnit.HOURS.toHours(1),
TimeUnit.MILLISECONDS.toMinutes(timeDiff) % TimeUnit.HOURS.toMinutes(1),
TimeUnit.MILLISECONDS.toSeconds(timeDiff) % TimeUnit.MINUTES.toSeconds(1),
TimeUnit.MILLISECONDS.toMillis(timeDiff) % TimeUnit.SECONDS.toMillis(1));
} catch (ParseException e) {
e.printStackTrace();
}
System.out.println("State duration: " + timeDiffString);
}
return timeDiffString;
}
@Override
public void open(Configuration config) {
ValueStateDescriptor<ProductionState> descriptor = new ValueStateDescriptor<>(
"stateOfProduction",
TypeInformation.of(new TypeHint<ProductionState>() {}),
ProductionState.NOT_PRODUCING);
stateOfProduction = getRuntimeContext().getState(descriptor);
}
@Override
public void flatMap(ImaginePaperData ImaginePaperData, Collector<String> output) throws Exception {
List<String> warnings = new ArrayList<>();
JSONObject jObject = new JSONObject();
String productionTime = "0";
String nonProductionTime = "0";
// Data analysis
if (stateOfProduction == null || stateOfProduction.value() == ProductionState.NOT_PRODUCING && ImaginePaperData.actSpeedCl > 60.0) {
stateOfProduction.update(ProductionState.PRODUCING);
} else if (stateOfProduction.value() == ProductionState.PRODUCING && ImaginePaperData.actSpeedCl < 60.0) {
stateOfProduction.update(ProductionState.NOT_PRODUCING);
}
if(stateOfProduction.value() == ProductionState.PRODUCING) {
if (!nonProductionTimestamps.isEmpty()) {
System.out.println("Production has started again, non production timestamps cleared");
nonProductionTimestamps.clear();
}
productionTimestamps.add(ImaginePaperData.timestamp);
System.out.println(productionTimestamps);
productionTime = calcProductionTime(productionTimestamps);
} else {
if(!productionTimestamps.isEmpty()) {
System.out.println("Production has stopped, production timestamps cleared");
productionTimestamps.clear();
}
nonProductionTimestamps.add(ImaginePaperData.timestamp);
warnings.add("Production has stopped.");
System.out.println(nonProductionTimestamps);
//System.out.println("Production stopped");
nonProductionTime = calcProductionTime(nonProductionTimestamps);
}
// The rest is just JSON stuff
我是否必须将这两个时间戳列表保存在ListState中?
编辑:因为另一个用户问,这是我得到的数据。
{'szenario': 'machine01', 'timestamp': '31.10.2018 09:18:39.432069', 'data': {1: 100.0, 2: 100.0, 101: 94.0, 102: 120.0, 103: 65.0}}
我期望的行为是我的flink程序收集了两个列表productionTimestamps和nonProductionTimestamps中的时间戳。然后,我希望我的calcProductionTime方法从第一个时间戳中减去列表中的最后一个时间戳,以获取我第一次检测到该机器在“生产” /“未生产”到停止“生产” /“停止”之间的持续时间。不生产”。
答案 0 :(得分:0)
我发现“看似随机的”时间戳的原因是Apache Flink的并行执行。当并行度设置为> 1时,不再保证事件的顺序。
我的快速解决方案是将程序的并行度设置为1,据我所知,这保证了事件的顺序。