私は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
}
}
基本的に、エスパーはここでは関係のないロジックに基づいて、必要なときにいつでも enter(value) と leave(value) を呼び出します。そして、 getValue() を呼び出して結果を計算します。
パーセンタイルを計算したいので、これを処理するために利用可能なすべての数値が必要です。これを行うには、これを numbers というグローバル リストに格納し、getValue() ですべての数値をDescriptiveStatisticsインスタンスに入れ、必要な統計を処理します。
私の推測では、リストを新しい DescriptiveStatistics オブジェクトとして配置するたびに、並べ替えを行う必要があります。DescriptiveStatistics のようなオブジェクトをグローバル オブジェクトとして維持する方法はありますか?
グローバル オブジェクトとして ArrayList と DescriptiveStatistics を使用する唯一の理由は、DescriptiveStatistics に remove メソッドがないことです。つまり、オブジェクトを値で削除することはできません。
実際には、このクラスには常に何百ものインスタンスが実行されており、それぞれに対して getValue() が 1 ~ 10 秒ごとに呼び出されます。現時点ではパフォーマンスの問題はありませんが、将来の問題を回避するために最適化のヘルプを探しています。
別の説明:-
私がここでやっていることは、数字のリストを維持することです。Esper は enter() メソッドと leave() メソッドを何度も呼び出して、リストに残すべき数字を教えてくれます。私の場合、これは時間ベースの集計です。過去 1 分間の数値に基づいて計算したいと esper に伝えました。
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() がありますが、それは私がやりたいことではありません。