package org.araqne.logdb.query.aggregator;
import java.util.Arrays;
import java.util.List;
import org.araqne.logdb.Row;
import org.araqne.logdb.query.aggregator.Covariance.CovarianceMapper;
import org.araqne.logdb.query.aggregator.Covariance.CovarianceReducer;
import org.araqne.logdb.query.aggregator.Variance.VarianceMapper;
import org.araqne.logdb.query.aggregator.Variance.VarianceReducer;
import org.araqne.logdb.query.command.NumberUtil;
import org.araqne.logdb.query.expr.Expression;
public class CorrelationCoefficient extends AbstractAggregationFunction {
Covariance covar;
StdDev stddev1;
StdDev stddev2;
public CorrelationCoefficient(List<Expression> exprs) {
super(exprs);
covar = new Covariance(exprs);
stddev1 = new StdDev(Arrays.asList(exprs.get(0)));
stddev2 = new StdDev(Arrays.asList(exprs.get(1)));
}
@Override
public String getName() {
return "correl";
}
@Override
public void apply(Row map) {
covar.apply(map);
stddev1.apply(map);
stddev2.apply(map);
}
@Override
public Object eval() {
Number covarValue = (Number) covar.eval();
Number stddevValue1 = (Number) stddev1.eval();
Number stddevValue2 = (Number) stddev2.eval();
if (covarValue == null || stddevValue1 == null || stddevValue2 == null)
return null;
else
return NumberUtil.div(covarValue, NumberUtil.mul(stddevValue1, stddevValue2));
}
@Override
public void merge(AggregationFunction func) {
CorrelationCoefficient other = (CorrelationCoefficient) func;
this.covar.merge(other.covar);
this.stddev1.merge(other.stddev1);
this.stddev2.merge(other.stddev2);
}
@Override
public Object[] serialize() {
Object[] result1 = this.covar.serialize();
Object[] result2 = this.stddev1.serialize();
Object[] result3 = this.stddev2.serialize();
int resultLength = result1.length + result2.length + result3.length;
Object[] result = new Object[resultLength];
for (int i = 0; i < resultLength; i++) {
if (i < result1.length)
result[i] = result1[i];
else if (i < result1.length + result2.length)
result[i] = result2[i - result1.length];
else if (i < result1.length + result2.length + result3.length)
result[i] = result3[i - result1.length - result2.length];
}
return result;
}
@Override
public void deserialize(Object[] values) {
Object[] values1 = covar.serialize();
Object[] values2 = stddev1.serialize();
Object[] values3 = stddev2.serialize();
for (int i = 0; i < values.length; i++) {
if (i < values1.length)
values1[i] = values[i];
else if (i < values1.length + values2.length)
values2[i - values1.length] = values[i];
else if (i < values1.length + values2.length + values3.length)
values3[i - values1.length - values2.length] = values[i];
}
covar.deserialize(values1);
stddev1.deserialize(values2);
stddev2.deserialize(values3);
}
@Override
public void clean() {
covar.clean();
stddev1.clean();
stddev2.clean();
}
@Override
public AggregationFunction clone() {
CorrelationCoefficient correl = new CorrelationCoefficient(exprs);
correl.covar = (Covariance) this.covar.clone();
correl.stddev1 = (StdDev) this.stddev1.clone();
correl.stddev2 = (StdDev) this.stddev2.clone();
return correl;
}
@Override
public boolean canBeDistributed() {
return true;
}
@Override
public AggregationFunction mapper(List<Expression> exprs) {
return new CorrelationCoefficientMapper(exprs);
}
@Override
public AggregationFunction reducer(List<Expression> exprs) {
return new CorrelationCoefficientReducer(exprs);
}
@Override
public String toString() {
return "correl(" + exprs.get(0) + ", " + exprs.get(1) + ")";
}
public static class CorrelationCoefficientMapper extends AbstractAggregationFunction {
CovarianceMapper covarMapper;
VarianceMapper varMapper1;
VarianceMapper varMapper2;
public CorrelationCoefficientMapper(List<Expression> exprs) {
super(exprs);
covarMapper = new CovarianceMapper(exprs);
varMapper1 = new VarianceMapper(Arrays.asList(exprs.get(0)));
varMapper2 = new VarianceMapper(Arrays.asList(exprs.get(1)));
}
@Override
public String getName() {
return "correlMapper";
}
@Override
public void apply(Row map) {
covarMapper.apply(map);
varMapper1.apply(map);
varMapper2.apply(map);
}
@Override
public Object eval() {
return this.serialize();
}
@Override
public void merge(AggregationFunction func) {
CorrelationCoefficientMapper other = (CorrelationCoefficientMapper) func;
this.covarMapper.merge(other.covarMapper);
this.varMapper1.merge(other.varMapper1);
this.varMapper2.merge(other.varMapper2);
}
@Override
public Object[] serialize() {
Object[] result1 = this.covarMapper.serialize();
Object[] result2 = this.varMapper1.serialize();
Object[] result3 = this.varMapper2.serialize();
Object[] result = new Object[3];
result[0] = result1;
result[1] = result2;
result[2] = result3;
return result;
}
@Override
public void deserialize(Object[] values) {
covarMapper.deserialize((Object[]) values[0]);
varMapper1.deserialize((Object[]) values[1]);
varMapper2.deserialize((Object[]) values[2]);
}
@Override
public void clean() {
covarMapper.clean();
varMapper1.clean();
varMapper2.clean();
}
@Override
public AggregationFunction clone() {
CorrelationCoefficientMapper correlMapper = new CorrelationCoefficientMapper(this.exprs);
correlMapper.covarMapper = (CovarianceMapper) this.covarMapper.clone();
correlMapper.varMapper1 = (VarianceMapper) this.varMapper1.clone();
correlMapper.varMapper2 = (VarianceMapper) this.varMapper2.clone();
return correlMapper;
}
@Override
public String toString() {
return "correlMapper(" + exprs.get(0) + ", " + exprs.get(1) + ")";
}
}
public static class CorrelationCoefficientReducer extends AbstractAggregationFunction {
CovarianceReducer covarReducer;
VarianceReducer varReducer1;
VarianceReducer varReducer2;
public CorrelationCoefficientReducer(List<Expression> exprs) {
super(exprs);
covarReducer = new CovarianceReducer(exprs);
varReducer1 = new VarianceReducer(exprs);
varReducer2 = new VarianceReducer(exprs);
}
@Override
public String getName() {
return "correlReducer";
}
@Override
public void apply(Row map) {
Expression expr = exprs.get(0);
Object obj = expr.eval(map);
if (obj == null || !(obj instanceof Object[]))
return;
Object[] values = (Object[]) obj;
Object[] values1 = (Object[]) values[0];
Object[] values2 = (Object[]) values[1];
Object[] values3 = (Object[]) values[2];
AggregationFunction covarReducer = new CovarianceReducer(exprs);
AggregationFunction varReducer1 = new VarianceReducer(exprs);
AggregationFunction varReducer2 = new VarianceReducer(exprs);
covarReducer.deserialize(values1);
varReducer1.deserialize(values2);
varReducer2.deserialize(values3);
this.covarReducer.merge(covarReducer);
this.varReducer1.merge(varReducer1);
this.varReducer2.merge(varReducer2);
}
@Override
public Object eval() {
Number covarValue = (Number) covarReducer.eval();
Number varReducerValue1 = (Number) varReducer1.eval();
Number varReducerValue2 = (Number) varReducer2.eval();
if (covarValue == null || varReducerValue1 == null || varReducerValue2 == null)
return null;
else {
double stddevValue1 = Math.sqrt(varReducerValue1.doubleValue());
double stddevValue2 = Math.sqrt(varReducerValue2.doubleValue());
return NumberUtil.div(covarValue, stddevValue1 * stddevValue2);
}
}
@Override
public void merge(AggregationFunction func) {
CorrelationCoefficientReducer other = (CorrelationCoefficientReducer) func;
this.covarReducer.merge(other.covarReducer);
this.varReducer1.merge(other.varReducer1);
this.varReducer2.merge(other.varReducer2);
}
@Override
public Object[] serialize() {
Object[] result1 = this.covarReducer.serialize();
Object[] result2 = this.varReducer1.serialize();
Object[] result3 = this.varReducer2.serialize();
Object[] result = new Object[3];
result[0] = result1;
result[1] = result2;
result[2] = result3;
return result;
}
@Override
public void deserialize(Object[] values) {
covarReducer.deserialize((Object[]) values[0]);
varReducer1.deserialize((Object[]) values[1]);
varReducer2.deserialize((Object[]) values[2]);
}
@Override
public void clean() {
covarReducer.clean();
varReducer1.clean();
varReducer2.clean();
}
@Override
public AggregationFunction clone() {
CorrelationCoefficientReducer correlReducer = new CorrelationCoefficientReducer(exprs);
correlReducer.covarReducer = (CovarianceReducer) this.covarReducer.clone();
correlReducer.varReducer1 = (VarianceReducer) this.varReducer1.clone();
correlReducer.varReducer2 = (VarianceReducer) this.varReducer2.clone();
return correlReducer;
}
@Override
public String toString() {
return "correlReducer(" + exprs.get(0) + ")";
}
}
}