我是Java的新手,并且一直在使用Esper CEP引擎。然而,这个问题与Esper无关,它更像是一个Java问题。
首先,我的班级: -
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.math3.stat.descriptive.DescriptiveStatistics;
import com.espertech.esper.epl.agg.AggregationSupport;
import com.espertech.esper.epl.agg.AggregationValidationContext;
public class CustomPercentiles extends AggregationSupport {
private List<Double> numbers = new ArrayList<Double>();
public CustomPercentiles(){
super();
}
public void clear() {
numbers.clear();
}
public void enter(Object arg0) {
Double value = (Double) (double) (Integer) arg0;
if (value > 0){
//Not interested in < 1
numbers.add(value);
}
}
public void leave(Object arg0) {
Double value = (Double) (double) (Integer) arg0;
if (value > 0){
//Not interested in < 1
numbers.remove(value);
}
}
public Object getValue() {
DescriptiveStatistics stats = new DescriptiveStatistics();
Map<String, Integer> result = new HashMap<String, Integer>();
for (Double number:numbers.subList(0, numbers.size())){
stats.addValue(number);
}
result.put("median", (int) stats.getPercentile(50));
result.put("pct90", (int) stats.getPercentile(90));
result.put("pct10", (int) stats.getPercentile(10));
result.put("mean", (int) stats.getMean());
result.put("std", (int) stats.getStandardDeviation());
return result ;
}
public Class getValueType() {
return Object.class;
}
@Override
public void validate(AggregationValidationContext arg0) {
// TODO Auto-generated method stub
}
}
基本上,Esper会根据逻辑不相关的方式调用enter(value)并保留(value)。它调用getValue()来获得计算结果。
由于我想计算百分位数,我需要所有可用的数字来处理它。为此,我将其存储在名为numbers的全局列表中,并在getValue()中将所有数字放入DescriptiveStatistics实例中,然后处理我需要的统计信息。
我的假设是,每次将列表作为新的DescriptiveStatistics对象时,都需要进行排序。有什么方法可以将类似DescriptiveStatistics的对象维护为我的全局对象吗?
我使用ArrayList和DescriptiveStatistics作为我的全局对象的唯一原因是DescriptiveStatistics没有remove方法。即我无法按值删除对象。
实际上,在任何给定时间都有数百个此类的实例运行,并且每1至10秒调用每个实例的getValue()。我目前没有任何性能问题,但我正在寻找一些优化帮助以避免将来出现问题。
替代解释: -
我在这里做的是保留一个数字列表。 Esper会多次调用enter()和leave()方法来告诉我列表中应该保留哪些数字。在我的情况下,这是基于时间的聚合。我告诉esper我想根据最近1分钟的数字进行计算。
So on 00:00:00 esper calls enter(10)
my numbers becomes [10]
So on 00:00:05 esper calls enter(15)
my numbers becomes [10, 15]
So on 00:00:55 esper calls enter(10)
my numbers becomes [10, 15, 10]
So on 00:01:00 esper calls leave(10)
my numbers becomes [15, 10]
So on 00:01:05 esper calls leave(15)
my numbers becomes [15]
现在,在这段时间内,getValue()可能已被多次调用。每次调用时,都应根据当前数字内容返回计算。
getValue()计算第10,第50和第90百分位数。为了计算百分位数,DescriptiveStatistics需要对数字进行排序。 (100个数字的第10个百分位将是排序后的第10个数字。)。
所以我正在寻找一种能够从DescriptiveStatistics实例中取出任何仲裁号的方法。或者要求推荐其他一些可以给我中位数和百分位数的图书馆,同时能够在知道价值的同时从列表中取出一个数字。
DescriptiveStatistics有一个removeMostRecentValue(),但这不是我想要做的。
答案 0 :(得分:0)
据我了解,您要求使用DescriptiveStatistics - 类作为列表,而不是“数字”。这意味着,您希望动态添加和删除DescriptiveStatistics变量中的数字。
据我所知,没有比你现在所做的更好的方法。
在再次计算百分位数之前,您确定需要使用该功能从列表中删除特定号码吗?这不一定是新的数字吗?
听起来有点像你想学习更多Java的基础知识。
无论如何,由于我无法真正为您提供问题的合格答案,我认为我至少会帮助您纠正一些代码,以遵循更好的做法:
public class CustomPercentiles extends AggregationSupport {
private List<Double> numbers = new ArrayList<Double>();
//Methods that are inherited from super-classes and interfaces
//should have the "@Override" annotation,
//both for the compiler to check if it really is inherited,
//but also to make it more clear which methods are new in this class.
@Override
public void clear() {
numbers.clear();
}
@Override
public void enter(Object value) {
double v = (double) value;
if (v > 0){
numbers.add(v);
}
}
@Override
public void leave(Object value) {
double v = (double) value;
if (v > 0){
numbers.remove(v);
}
}
@Override
public Object getValues() {
DescriptiveStatistics stats = new DescriptiveStatistics();
Map<String, Integer> result = new HashMap<String, Integer>();
//It is unnecessary to call number.subList(0, numbers.size())
//since it will just return the entire list.
for (Double number : numbers){
stats.addValue(number);
}
result.put("median", (int) stats.getPercentile(50));
result.put("pct90", (int) stats.getPercentile(90));
result.put("pct10", (int) stats.getPercentile(10));
result.put("mean", (int) stats.getMean());
result.put("std", (int) stats.getStandardDeviation());
return result ;
}
//Judgning from the API of AggregationSupport,
//I would say this method should return Double.class
//(it basically seems like a bad way of implementing generics).
//Are you sure it should return Object.class?
public Class getValueType() {
return Object.class;
}
@Override
public void validate(AggregationValidationContext arg0) {
// TODO Auto-generated method stub
}
}