/*
* Licensed to CRATE Technology GmbH ("Crate") under one or more contributor
* license agreements. See the NOTICE file distributed with this work for
* additional information regarding copyright ownership. Crate licenses
* this file to you under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. You may
* obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* However, if you have executed another commercial license agreement
* with Crate these terms will supersede the license and you may use the
* software solely pursuant to the terms of the relevant commercial agreement.
*/
package io.crate.operation.aggregation.impl;
import com.google.common.collect.ImmutableList;
import io.crate.analyze.symbol.Literal;
import io.crate.metadata.FunctionInfo;
import io.crate.operation.aggregation.AggregationTest;
import io.crate.types.ArrayType;
import io.crate.types.DataType;
import io.crate.types.DataTypes;
import org.junit.Test;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.nullValue;
import static org.mockito.Mockito.mock;
public class PercentileAggregationTest extends AggregationTest {
private static final String NAME = "percentile";
private Object[][] executeAggregation(DataType dataType, Object[][] data) throws Exception {
String name = "percentile";
return executeAggregation(name, dataType, data, ImmutableList.of(dataType, DataTypes.DOUBLE));
}
@Test
public void testReturnTypes() throws Exception {
assertEquals(DataTypes.DOUBLE,
functions.getBuiltin(NAME, ImmutableList.of(DataTypes.DOUBLE, DataTypes.DOUBLE)).info().returnType());
assertEquals(new ArrayType(DataTypes.DOUBLE),
functions.getBuiltin(NAME, ImmutableList.of(DataTypes.DOUBLE, new ArrayType(DataTypes.DOUBLE))).info().returnType());
}
@Test
public void testAllTypesReturnSameResult() throws Exception {
for (DataType dataType : DataTypes.NUMERIC_PRIMITIVE_TYPES) {
Double[] fractions = {0.5, 0.8};
Object[][] rows = new Object[10][];
Object[][] rowsArray = new Object[10][];
for (int i = 0; i < rows.length; i++) {
rows[i] = new Object[]{
dataType.value(i), fractions[0]
};
rowsArray[i] = new Object[]{
dataType.value(i), fractions
};
}
Object[][] result = executeAggregation(dataType, rows);
assertEquals(4.5, result[0][0]);
result = executeAggregation(dataType, rowsArray);
assertTrue(result[0][0].getClass().isArray());
assertEquals(2, ((Object[]) result[0][0]).length);
assertEquals(4.5, ((Object[]) result[0][0])[0]);
assertEquals(7.2, ((Object[]) result[0][0])[1]);
}
}
@Test
public void testNullPercentile() throws Exception {
Object[][] result = executeAggregation(DataTypes.INTEGER, new Object[][]{
{1, null},
{10, null}
});
assertTrue(result[0][0] == null);
}
@Test(expected = IllegalArgumentException.class)
public void testEmptyPercentile() throws Exception {
Object[][] result = executeAggregation(DataTypes.INTEGER, new Object[][]{
{1, new Object[]{}},
{10, new Object[]{}}
});
}
@Test(expected = IllegalArgumentException.class)
public void testNullMultiplePercentiles() throws Exception {
Double[] fractions = new Double[]{0.25, null};
Object[][] result = executeAggregation(DataTypes.INTEGER, new Object[][]{
{1, fractions},
{10, fractions}
});
}
@Test(expected = IllegalArgumentException.class)
public void testNegativePercentile() throws Exception {
Object[][] result = executeAggregation(DataTypes.INTEGER, new Object[][]{
{1, -1.2},
{10, -1.2}
});
}
@Test(expected = IllegalArgumentException.class)
public void testTooLargePercentile() throws Exception {
Object[][] result = executeAggregation(DataTypes.INTEGER, new Object[][]{
{1, 1.5},
{10, 1.5}
});
}
@Test(expected = NullPointerException.class)
public void testUnsupportedType() throws Exception {
Object[][] result = executeAggregation(DataTypes.STRING, new Object[][]{
{"Akira", 0.5},
{"Tetsuo", 0.5}
});
}
@Test
public void testNullInputValuesReturnNull() throws Exception {
Object[][] result = executeAggregation(DataTypes.LONG, new Object[][]{
{null, 0.5},
{null, 0.5}
});
assertEquals(result[0][0], null);
}
@Test
public void testEmptyPercentileFuncWithEmptyRows() throws Exception {
Object[][] result = executeAggregation(DataTypes.INTEGER, new Object[][]{});
assertThat(result[0][0], is(nullValue()));
}
public void testIterate() throws Exception {
PercentileAggregation pa = new PercentileAggregation(mock(FunctionInfo.class));
TDigestState state = pa.iterate(null, TDigestState.createEmptyState(), Literal.of(1), Literal.of(0.5));
assertThat(state, is(notNullValue()));
assertThat(state.fractions()[0], is(0.5));
}
@Test
public void testReduceStage() throws Exception {
PercentileAggregation pa = new PercentileAggregation(mock(FunctionInfo.class));
// state 1 -> state 2
TDigestState state1 = TDigestState.createEmptyState();
TDigestState state2 = new TDigestState(100, new double[]{0.5});
state2.add(20.0);
TDigestState reducedState = pa.reduce(null, state1, state2);
assertThat(reducedState.fractions()[0], is(0.5));
assertThat(reducedState.centroidCount(), is(1));
// state 2 -> state 1
state1 = new TDigestState(100, new double[]{0.5});
state1.add(22.0);
state1.add(20.0);
state2 = new TDigestState(100, new double[]{0.5});
state2.add(21.0);
reducedState = pa.reduce(null, state1, state2);
assertThat(reducedState.fractions()[0], is(0.5));
assertThat(reducedState.centroidCount(), is(3));
}
}