package org.streaminer.stream.quantile; import java.io.Serializable; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArrayList; public class SumQuantiles implements IQuantiles<Double>, Serializable { private static final long serialVersionUID = 7331604622548281844L; private int slidingWindowSize = 5000; private int maxBucketCount = 10; private int elementPerBucket = slidingWindowSize / maxBucketCount; private int biggestSeenElement = 0; private Bucket newestBucket = null; private List<Bucket> buckets; public SumQuantiles(int slidingWindowSize, int bucketCount) { this.slidingWindowSize = slidingWindowSize; this.maxBucketCount = bucketCount; elementPerBucket = slidingWindowSize / maxBucketCount; buckets = new CopyOnWriteArrayList<Bucket>(); addNewBucket(); } @Override public void offer(Double value) { biggestSeenElement = Math.max(biggestSeenElement, value.intValue()); newestBucket.learn(value); if (newestBucket.isFull()) { addNewBucket(); } } @Override public Double getQuantile(double q) throws QuantilesException { int overallElementCount = 0; for (Bucket bucket : buckets) { overallElementCount += bucket.getElementCount(); } int wantedRank = (int)((double)overallElementCount * q); int sum = 0; //System.out.println("--------------------------------------" ); //System.out.println("ElementCount " + overallElementCount); //System.out.println("wantedRank " + wantedRank); for (int i = 0; i < biggestSeenElement; i++) { long predict = getAllBucketPrediction(i); sum += predict; // System.out.println(sum); if (sum >= wantedRank) { return (double)i; } } return 0.0; } private void addNewBucket() { Bucket newBucket = new Bucket(); buckets.add(newBucket); newestBucket = newBucket; deleteExcessiveBuckets(); //System.out.println("new"); } /** * delete oldest {@link Bucket} while we have too many of them. */ private void deleteExcessiveBuckets() { while (buckets.size() > maxBucketCount) { buckets.remove(0); } } private int getAllBucketPrediction(int item) { int prediction = 0; for (Bucket bucket : buckets) { prediction += bucket.predict(item); } return prediction; } private class Bucket implements Serializable { private static final long serialVersionUID = -2211156505869843563L; private int elementCount = 0; private Map<String,Integer> counterMap ; public Bucket() { counterMap = new ConcurrentHashMap<String, Integer>(); } public long predict(int item){ String asString = ((Integer)item).toString(); if (counterMap.containsKey(asString)) { return counterMap.get(asString); } return 0; } public void learn(Double item) { int value = item.intValue(); String asString = ((Integer)value).toString(); if (counterMap.containsKey(asString)) { int counter = counterMap.get(asString); counter++; counterMap.put(asString, counter); } else { counterMap.put(asString, 1); } elementCount++; } public int getElementCount() { return elementCount; } public boolean isFull() { return elementCount >= elementPerBucket; } @Override public String toString() { System.out.println("--------------------------------------" ); String out = "Bucket: \n"; for(String key : counterMap.keySet()) { out = out + key + " " +counterMap.get(key) + "\n"; } return out; } } }