package edu.washington.escience.myria.operator.apply; import static org.junit.Assert.assertEquals; import org.junit.Test; import com.google.common.collect.ImmutableList; import edu.washington.escience.myria.DbException; import edu.washington.escience.myria.Schema; import edu.washington.escience.myria.Type; import edu.washington.escience.myria.expression.ConstantExpression; import edu.washington.escience.myria.expression.Expression; import edu.washington.escience.myria.expression.IntDivideExpression; import edu.washington.escience.myria.expression.PlusExpression; import edu.washington.escience.myria.expression.StateExpression; import edu.washington.escience.myria.expression.VariableExpression; import edu.washington.escience.myria.operator.SingletonRelation; import edu.washington.escience.myria.operator.StatefulApply; import edu.washington.escience.myria.operator.BatchTupleSource; import edu.washington.escience.myria.storage.TupleBatch; import edu.washington.escience.myria.storage.TupleBatchBuffer; import edu.washington.escience.myria.storage.TupleUtils; import edu.washington.escience.myria.util.TestEnvVars; public class StatefulApplyTest { private final int NUM_TUPLES = 2 * TupleUtils.getBatchSize(Type.LONG_TYPE); private final int SMALL_NUM_TUPLES = 10; @Test public void testStatefulApplyRange() throws DbException { final Schema schema = new Schema(ImmutableList.of(Type.STRING_TYPE), ImmutableList.of("name")); final TupleBatchBuffer tbb = new TupleBatchBuffer(schema); for (long i = 0; i < NUM_TUPLES; i++) { tbb.putString(0, "Foo" + i); } Expression initializer = new Expression("counter", new ConstantExpression(Type.LONG_TYPE, "-1")); Expression expression = new Expression("index", new StateExpression(0)); Expression increment = new Expression( new PlusExpression( new StateExpression(0), new ConstantExpression(Type.LONG_TYPE, "1"))); ImmutableList.Builder<Expression> Initializers = ImmutableList.builder(); Initializers.add(initializer); ImmutableList.Builder<Expression> Expressions = ImmutableList.builder(); Expressions.add(expression); ImmutableList.Builder<Expression> Updaters = ImmutableList.builder(); Updaters.add(increment); StatefulApply apply = new StatefulApply( new BatchTupleSource(tbb), Expressions.build(), Initializers.build(), Updaters.build()); apply.open(TestEnvVars.get()); TupleBatch result; int resultSize = 0; while (!apply.eos()) { result = apply.nextReady(); if (result != null) { assertEquals(1, result.getSchema().numColumns()); assertEquals(Type.LONG_TYPE, result.getSchema().getColumnType(0)); for (int curI = 0; curI < result.numTuples(); curI++) { long i = curI + resultSize; assertEquals(i, result.getLong(0, curI)); } resultSize += result.numTuples(); } } assertEquals(NUM_TUPLES, resultSize); apply.close(); } @Test public void testStatefulApplyRunningMean() throws DbException { final Schema schema = new Schema(ImmutableList.of(Type.LONG_TYPE), ImmutableList.of("salary")); final TupleBatchBuffer tbb = new TupleBatchBuffer(schema); for (long i = 0; i < SMALL_NUM_TUPLES; i++) { tbb.putLong(0, i + 1); } Expression initializeCounter = new Expression("counter", new ConstantExpression(Type.LONG_TYPE, "0")); Expression initializeSum = new Expression("sum", new ConstantExpression(Type.LONG_TYPE, "0")); Expression updateCounter = new Expression( new PlusExpression( new StateExpression(0), new ConstantExpression(Type.LONG_TYPE, "1"))); Expression updateSum = new Expression(new PlusExpression(new StateExpression(1), new VariableExpression(0))); Expression avg = new Expression( "average", new IntDivideExpression(new StateExpression(1), new StateExpression(0))); ImmutableList.Builder<Expression> Initializers = ImmutableList.builder(); Initializers.add(initializeCounter); Initializers.add(initializeSum); ImmutableList.Builder<Expression> Updaters = ImmutableList.builder(); Updaters.add(updateCounter); Updaters.add(updateSum); ImmutableList.Builder<Expression> Expressions = ImmutableList.builder(); Expressions.add(avg); Expressions.add(new Expression("number", new VariableExpression(0))); StatefulApply apply = new StatefulApply( new BatchTupleSource(tbb), Expressions.build(), Initializers.build(), Updaters.build()); apply.open(TestEnvVars.get()); TupleBatch result; int resultSize = 0; while (!apply.eos()) { result = apply.nextReady(); if (result != null) { assertEquals(2, result.getSchema().numColumns()); assertEquals(Type.LONG_TYPE, result.getSchema().getColumnType(0)); assertEquals(Type.LONG_TYPE, result.getSchema().getColumnType(1)); for (int curI = 0; curI < result.numTuples(); curI++) { long i = curI + resultSize + 1; long sum = i * (i + 1) / 2; long runningAverage = sum / i; assertEquals(runningAverage, result.getLong(0, curI)); } resultSize += result.numTuples(); } } assertEquals(SMALL_NUM_TUPLES, resultSize); apply.close(); } @Test public void testCounterOnSingleton() throws DbException { SingletonRelation singleton = new SingletonRelation(); Expression emitExpression = new Expression("x", new StateExpression(0)); Expression initExpression = new Expression("cntr", new ConstantExpression(0)); Expression updateExpression = new Expression( "cntr", new PlusExpression(new StateExpression(0), new ConstantExpression(1))); StatefulApply apply = new StatefulApply( singleton, ImmutableList.of(emitExpression), ImmutableList.of(initExpression), ImmutableList.of(updateExpression)); apply.open(TestEnvVars.get()); assertEquals("x", apply.getSchema().getColumnName(0)); int count = 0; while (!apply.eos()) { TupleBatch tb = apply.nextReady(); if (tb == null) { continue; } for (int i = 0; i < tb.numTuples(); ++i) { assertEquals(count + 1, tb.getInt(0, i)); count++; } } apply.close(); assertEquals(1, count); } @Test public void testBug547UpdateNotNeedsCompile() throws DbException { final Schema schema = Schema.ofFields(Type.INT_TYPE); final TupleBatchBuffer tbb = new TupleBatchBuffer(schema); for (int i = 0; i < 3; ++i) { tbb.putInt(0, i); } Expression emitExpression = new Expression("x", new StateExpression(0)); Expression initExpression = new Expression("old", new ConstantExpression(-1)); Expression updateExpression = new Expression("old", new VariableExpression(0)); StatefulApply apply = new StatefulApply( new BatchTupleSource(tbb), ImmutableList.of(emitExpression), ImmutableList.of(initExpression), ImmutableList.of(updateExpression)); apply.open(TestEnvVars.get()); assertEquals("x", apply.getSchema().getColumnName(0)); int old = -1; while (!apply.eos()) { TupleBatch tb = apply.nextReady(); if (tb == null) { continue; } for (int i = 0; i < tb.numTuples(); ++i) { old++; assertEquals(old, tb.getInt(0, i)); } } apply.close(); assertEquals(2, old); } }