0

私は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() がありますが、それは私がやりたいことではありません。

4

1 に答える 1

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
    }

}
于 2012-08-29T15:49:57.320 に答える