/* * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.addthis.hydra.data.filter.bundle; import java.util.HashMap; import java.util.HashSet; import java.util.TreeMap; import com.addthis.basis.collect.HotMap; import com.addthis.bundle.core.Bundle; import com.addthis.bundle.core.BundleField; import com.addthis.bundle.util.AutoField; import com.addthis.bundle.util.ValueUtil; import com.addthis.bundle.value.ValueLong; import com.addthis.bundle.value.ValueObject; import com.addthis.codec.annotations.FieldConfig; /** * This {@link BundleFilter BundleFilter} <span class="hydra-summary">allows filtering on keys occurring within a time interval a given number of * times</span>. * <p/> * <p>Example:</p> * <pre> * </pre> * * @user-reference */ public final class BundleFilterRecent1 implements BundleFilter { @FieldConfig(codable = true, required = true) private AutoField time; @FieldConfig(codable = true, required = true) private AutoField field; @FieldConfig(codable = true) private int track; // number of unique entries to track @FieldConfig(codable = true) private int sample; // number of data points to sample for each entry @FieldConfig(codable = true) private long minTime; // true under minTime @FieldConfig(codable = true) private long maxTime; // true over maxTime @FieldConfig(codable = true) private long maxCount; // absolute max count for a key @FieldConfig(codable = true) private boolean defaultExit; @FieldConfig(codable = true) private HashSet<String> exclude; @SuppressWarnings("unchecked") private HotMap<String, Mark> cache = new HotMap<>(new HashMap()); @Override public boolean filter(Bundle bundle) { ValueLong timeValue = time.getValue(bundle).asLong(); return timeValue != null ? accept(timeValue.getLong(), field.getValue(bundle)) : false; } /** * @param time time packet received * @param value field value * @return true to process, false to abort */ public synchronized boolean accept(long time, ValueObject value) { if (exclude != null && exclude.contains(value)) { return defaultExit; } String sv = ValueUtil.asNativeString(value); Mark v = cache.get(sv); if (v == null) { v = new Mark(); if (cache.put(sv, v) != null) { System.out.println("ERROR : cache put hit on " + value); } if (cache.size() > track) { cache.removeEldest(); } } long avtime = v.averageTime(time); return avtime == 0 ? defaultExit : (maxCount > 0 && v.count > maxCount) || ((minTime == 0 || avtime < minTime) && (avtime > maxTime)); } /** */ private class Mark { public int count; public long cumTime; public TreeMap<Long, Long> times = new TreeMap<>(); long averageTime(long time) { count++; times.put(time, time); if (times.size() > sample) { times.remove(times.firstKey()); } long delta = times.lastKey() - times.firstKey(); return (count >= sample ? delta / sample : 0); } } }