package storm.applications.bolt; import backtype.storm.topology.OutputFieldsDeclarer; import backtype.storm.tuple.Fields; import backtype.storm.tuple.Tuple; import backtype.storm.tuple.Values; import java.util.HashMap; import java.util.Map; import storm.applications.constants.AdsAnalyticsConstants.Field; import storm.applications.constants.AdsAnalyticsConstants.Stream; import storm.applications.model.ads.AdEvent; /** * * @author Maycon Viana Bordin <mayconbordin@gmail.com> */ public class CtrBolt extends AbstractBolt { private Map<String, Summary> summaries; @Override public Fields getDefaultFields() { return new Fields(Field.QUERY_ID, Field.AD_ID, Field.CTR); } @Override public void initialize() { summaries = new HashMap<>(); } @Override public void execute(Tuple input) { AdEvent event = (AdEvent) input.getValueByField(Field.EVENT); String key = String.format("%d:%d", event.getQueryId(), event.getAdID()); Summary summary = summaries.get(key); // create summary if it don't exists if (summary == null) { summary = new Summary(); summaries.put(key, summary); } // update summary if (input.getSourceStreamId().equals(Stream.CLICKS)) { summary.clicks++; } else { summary.impressions++; } // calculate ctr double ctr = (double)summary.clicks / (double)summary.impressions; collector.emit(input, new Values(event.getQueryId(), event.getAdID(), ctr)); collector.ack(input); } private static class Summary { public long impressions = 0; public long clicks = 0; } }