在Apache Derby中创建用户定义的聚合函数

时间:2014-06-24 20:38:40

标签: java derby

我需要在Derby中创建一个用户自定义聚合(UDA)函数(具体来说,是一个Variance函数),但我仍然坚持使用正确的编写方法。

到目前为止,我有UDA的“模板”:

public class Variance<V extends Comparable<V>> implements Aggregator<V,V,Variance<V>> {
    private ArrayList<V> _values;
    public Variance() {/*Empty constructor*/}
    public void init() {_values = new ArrayList<V>(); }
    public void accumulate(V v) { _values.add(v); }
    public void merge(Variance<V> o) { _values.addAll(o._values); }
    public V terminate() {
        // Here is my issue!!!
    }
}

我面临的问题是:要计算方差,我需要计算这样的事情:

V sum, sumSq;
int n = _values.size();
if(n <= 0)
    return null;
// Initialize sum and sumSq to "zero"
for(V v : _values) {
    sum += v; // Or somehow add v to sum
    sumSq += Math.pow(v, 2); // Or somehow add (v^2) to sumSq
}
return (sumSq - n * Math.pow(sum / n, 2)) / n;

...但我不知道如何判断这只对数字类型(整数,十进制或浮点值)有效。

我想我的代码中遗漏了一些内容,但我不知道是否有办法告诉该程序V是数字的,因此,我可以对类型{的值使用算术运算{1}}。

所以,具体问题是:

  • 有没有办法对值执行此操作(加法,减法,产品,功率)?
  • 我是否应该更改V的定义(稍微扩展一个“数字”类,如V)?

2 个答案:

答案 0 :(得分:1)

查看Derby的数据类型:

DECIMAL = java.math.BigDecimal
INTEGER = java.lang.Integer
FLOAT = java.lang.Float or java.lang.Double 

FLOAT将根据您在创建时指定的精度转换为不同的Java对象,默认为java.lang.Double

添加数字

你遇到的第一个问题就是简单地将值相加(很多二元运算符的错误操作数类型&#39; +&#39; 错误)。即使你可以使用Integer,Float和Double工作,你会发现因为BigDecimal没有直接映射到Java原语,所以它不能与标准的原始算术运算符一起使用,因此它具有自己的add方法在对象上。

引用,Mark Peters answer to a similar issue;

  

有些方法你可以一起破解这个,但老实说,   仿制药根本就不是去这里的方法。为每个人构建一个方法   具体的原始包装类型并分别实现它们。它&#39; 11   让它变得通用是太令人头疼的事了;算术   操作不可能一般发生。

平方值

您遇到的第二个问题是您正在使用电源方法。

Math.pow()使用双参数 - 因此Integer或Double计算应该没问题。 Float可能会显示意外的结果,因为将float转换为double会导致转换后的值出现奇怪的额外数字。

Math.pow的结果类型是Double,您可以通过定义聚合器来解决这个问题,以便终止方法结果类型始终为Double,例如:

public class Variance<V extends Number & Comparable<V>> 
    implements Aggregator<V, Double, Variance<V>> {

正如我们之前看到的,BigDecimal与其他人有点不同,并且有自己的pow()方法,其结果类型是BigDecimal值。

<强>结论

鉴于上述情况,我建议不要尝试通用解决方案,而是为要支持的每个类类型实现多个方差聚合器。例如你可以实现类似的东西:

Aggregator<Integer, Double, Variance<Integer>>
Aggregator<Double, Double, Variance<Double>>
Aggregator<Float, Double, Variance<Float>>
Aggregator<BigDecimal, BigDecimal, Variance<BigDecimal>>  

答案 1 :(得分:0)

//that is not the best answer, but works 
            import org.apache.derby.agg.Aggregator; 
            import java.util.ArrayList;

            public class Variance<V extends Double> implements Aggregator<V,V,Variance<V>> {
              private ArrayList<V> list =null; 

               public Variance() {}

               public void init() {
                 list= new ArrayList<>(); 
               }

               public void accumulate(V value) {
                 list.add(value); 
               }

               public void merge(Variance<V> another) {
                 list.addAll(another.list); 
               }

               public V terminate() {
                 double sum=0, sumSq=0;
            int n = list.size();
            if(n <= 0)
                return null;
            // Initialize sum and sumSq to "zero"
            for(Double v : list) {
                sum += v; // Or somehow add v to sum
                sumSq += Math.pow(v, 2); // Or somehow add (v^2) to sumSq
            }
            return (V)(new Double((sumSq - n * Math.pow(sum / n, 2)) / n) ) ;
               }



                public static void main(String [] args) {
                  Variance<Double> v= new Variance<>(); 
                    v.init(); 
                    v.accumulate(new Double(8.0)); 
                     v.accumulate(new Double(6.0)); 
                     v.accumulate(new Double(10.0)); 

                     System.out.println(v.terminate()); 
                }
            }