package resa.evaluation.topology.vld;
import backtype.storm.generated.GlobalStreamId;
import backtype.storm.task.OutputCollector;
import backtype.storm.task.TopologyContext;
import backtype.storm.topology.OutputFieldsDeclarer;
import backtype.storm.topology.base.BaseRichBolt;
import backtype.storm.tuple.Fields;
import backtype.storm.tuple.Tuple;
import backtype.storm.tuple.Values;
import resa.util.ConfigUtil;
import resa.util.Counter;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;
/**
* Created by ding on 14-7-3.
*/
public class Aggregater extends BaseRichBolt implements Constant {
private class FrameContext {
String frameId;
int featDescCount = 0;
int curr = 0;
Map<Integer, Counter> imageCounter = new HashMap<>();
FrameContext(String frameId) {
this.frameId = frameId;
}
void update(int[] matchedImages) {
curr++;
for (int i = 0; i < matchedImages.length; i += 2) {
imageCounter.computeIfAbsent(matchedImages[i], (k) -> new Counter()).incAndGet(matchedImages[i + 1]);
}
}
boolean isFinish() {
return indexPieces == curr && featDescCount != 0;
}
}
private Map<String, FrameContext> pendingFrames;
private OutputCollector collector;
private double minPercentage;
private int indexPieces;
@Override
public void prepare(Map stormConf, TopologyContext context, OutputCollector collector) {
pendingFrames = new HashMap<>();
this.collector = collector;
minPercentage = ConfigUtil.getDouble(stormConf, CONF_MATCH_RATIO, 0.5);
String srcComp = context.getThisSources().keySet().stream()
.filter(stream -> stream.get_streamId().equals(STREAM_MATCH_IMAGES))
.map(GlobalStreamId::get_componentId)
.findFirst().orElseThrow(() -> new RuntimeException("Can not find source comp"));
indexPieces = context.getComponentTasks(srcComp).size();
}
@Override
public void execute(Tuple input) {
FrameContext fCtx = pendingFrames.computeIfAbsent(input.getStringByField(FIELD_FRAME_ID),
(k) -> new FrameContext(k));
switch (input.getSourceStreamId()) {
case STREAM_FEATURE_COUNT:
fCtx.featDescCount = input.getIntegerByField(FIELD_FEATURE_CNT);
break;
case STREAM_MATCH_IMAGES:
fCtx.update((int[]) input.getValueByField(FIELD_MATCH_IMAGES));
break;
default:
throw new IllegalStateException("Bad stream");
}
if (fCtx.isFinish()) {
String out = fCtx.frameId + ":" + fCtx.imageCounter.entrySet().stream()
.filter(e -> (double) e.getValue().get() / fCtx.featDescCount > minPercentage)
.map(e -> e.getKey().toString()).collect(Collectors.joining(","));
System.out.println(out);
// just for metrics output
collector.emit(new Values(out));
pendingFrames.remove(fCtx.frameId);
}
collector.ack(input);
}
@Override
public void declareOutputFields(OutputFieldsDeclarer declarer) {
declarer.declare(new Fields("out"));
}
}