package storm.applications.bolt; import java.util.Map; import backtype.storm.tuple.Fields; import backtype.storm.tuple.Tuple; import backtype.storm.tuple.Values; import java.util.HashMap; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import static storm.applications.constants.VoIPSTREAMConstants.*; import storm.applications.model.cdr.CallDetailRecord; import storm.applications.util.bloom.BloomFilter; public class VariationDetectorBolt extends AbstractBolt { private static final Logger LOG = LoggerFactory.getLogger(VariationDetectorBolt.class); private BloomFilter<String> detector; private BloomFilter<String> learner; private int approxInsertSize; private double falsePostiveRate; private double cycleThreshold; @Override public Map<String, Fields> getDefaultStreamFields() { Map<String, Fields> streams = new HashMap<>(); Fields fields = new Fields(Field.CALLING_NUM, Field.CALLED_NUM, Field.ANSWER_TIME, Field.NEW_CALLEE, Field.RECORD); streams.put(Stream.DEFAULT, fields); streams.put(Stream.BACKUP, fields); return streams; } @Override public void initialize() { approxInsertSize = config.getInt(Conf.VAR_DETECT_APROX_SIZE); falsePostiveRate = config.getDouble(Conf.VAR_DETECT_ERROR_RATE); detector = new BloomFilter<>(falsePostiveRate, approxInsertSize); learner = new BloomFilter<>(falsePostiveRate, approxInsertSize); cycleThreshold = detector.size()/Math.sqrt(2); } @Override public void execute(Tuple input) { CallDetailRecord cdr = (CallDetailRecord) input.getValueByField(Field.RECORD); String key = String.format("%s:%s", cdr.getCallingNumber(), cdr.getCalledNumber()); boolean newCallee = false; // add pair to learner learner.add(key); // check if the pair exists // if not, add to the detector if (!detector.membershipTest(key)) { detector.add(key); newCallee = true; } // if number of non-zero bits is above threshold, rotate filters if (detector.getNumNonZero() > cycleThreshold) { rotateFilters(); } Values values = new Values(cdr.getCallingNumber(), cdr.getCalledNumber(), cdr.getAnswerTime(), newCallee, cdr); collector.emit(values); collector.emit(Stream.BACKUP, values); } private void rotateFilters() { BloomFilter<String> tmp = detector; detector = learner; learner = tmp; learner.clear(); } }