/** Copyright (C) SYSTAP, LLC DBA Blazegraph 2006-2016. All rights reserved. Contact: SYSTAP, LLC DBA Blazegraph 2501 Calvert ST NW #106 Washington, DC 20008 licenses@blazegraph.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package com.bigdata.bop.solutions; import com.bigdata.bop.BOp; import com.bigdata.bop.BOpContext; import com.bigdata.bop.BOpEvaluationContext; import com.bigdata.bop.Bind; import com.bigdata.bop.Constant; import com.bigdata.bop.IBindingSet; import com.bigdata.bop.IConstant; import com.bigdata.bop.IConstraint; import com.bigdata.bop.IValueExpression; import com.bigdata.bop.IVariable; import com.bigdata.bop.IVariableFactory; import com.bigdata.bop.NV; import com.bigdata.bop.PipelineOp; import com.bigdata.bop.TestMockUtility; import com.bigdata.bop.Var; import com.bigdata.bop.bindingSet.ListBindingSet; import com.bigdata.bop.engine.AbstractQueryEngineTestCase; import com.bigdata.bop.engine.BOpStats; import com.bigdata.bop.engine.BlockingBufferWithStats; import com.bigdata.bop.engine.IRunningQuery; import com.bigdata.bop.engine.MockRunningQuery; import com.bigdata.bop.rdf.aggregate.COUNT; import com.bigdata.journal.ITx; import com.bigdata.rdf.internal.IV; import com.bigdata.rdf.internal.impl.literal.XSDIntegerIV; import com.bigdata.rdf.internal.impl.literal.XSDNumericIV; import com.bigdata.rdf.model.BigdataLiteral; import com.bigdata.rdf.sparql.ast.GlobalAnnotations; import com.bigdata.rdf.store.AbstractTripleStore; import com.bigdata.relation.accesspath.IAsynchronousIterator; import com.bigdata.relation.accesspath.IBlockingBuffer; import com.bigdata.relation.accesspath.ThickAsynchronousIterator; import java.math.BigInteger; import java.util.concurrent.FutureTask; import static junit.framework.TestCase.assertEquals; /** * Unit tests for {@link MemoryGroupByOp}. * * @author thompsonbry */ public class TestMemoryGroupByOp extends AbstractAggregationTestCase { public TestMemoryGroupByOp() { } public TestMemoryGroupByOp(String name) { super(name); } @Override protected GroupByOp newFixture(IValueExpression<?>[] select, IValueExpression<?>[] groupBy, IConstraint[] having) { final int groupById = 1; final IVariableFactory variableFactory = new MockVariableFactory(); final IGroupByState groupByState = new GroupByState(// select, groupBy, having); final IGroupByRewriteState groupByRewrite = new GroupByRewriter( groupByState) { private static final long serialVersionUID = 1L; @Override public IVariable<?> var() { return variableFactory.var(); } }; final GroupByOp query = new MemoryGroupByOp(new BOp[] {}, NV.asMap(new NV[] {// new NV(BOp.Annotations.BOP_ID, groupById),// new NV(BOp.Annotations.EVALUATION_CONTEXT, BOpEvaluationContext.CONTROLLER),// new NV(PipelineOp.Annotations.PIPELINED, false),// new NV(PipelineOp.Annotations.MAX_MEMORY, 0),// new NV(GroupByOp.Annotations.GROUP_BY_STATE, groupByState), // new NV(GroupByOp.Annotations.GROUP_BY_REWRITE, groupByRewrite), // })); return query; } @Override protected boolean isPipelinedAggregationOp() { return false; } /** * A variant of * * https://www.w3.org/2009/sparql/docs/tests/data-sparql11/grouping/group03.rq * * with DISTINCT in an aggregate. The test is not intended for * PipelinedAggregationOp because PipelinedAggregationOp does not support * DISTINCT, so it is here rather than in AbstractAggregationTestCase. * * <pre> * @prefix : <http://example/> . * * :s1 :p 1 . * :s1 :q 9 . * :s2 :p 2 . * </pre> * * <pre> * PREFIX : <http://example/> * * SELECT ?w (COUNT(DISTINCT ?v) AS ?S) * { * ?s :p ?v . * OPTIONAL { ?s :q ?w } * } * GROUP BY ?w * </pre> * * The solutions input to the GROUP_BY are: * * <pre> * ?w ?s ?v * 9 s1 1 * s2 2 * </pre> * * The aggregated solutions groups are: * * <pre> * ?w ?S * 9 1 * 1 * </pre> * * @throws ExecutionException * @throws InterruptedException */ public void test_aggregation_groupBy_by_error_values3() { AbstractTripleStore kb = TestMockUtility.mockTripleStore(getName()); try { final String lexiconNamespace = kb.getLexiconRelation().getNamespace(); final GlobalAnnotations globals = new GlobalAnnotations(lexiconNamespace, ITx.READ_COMMITTED); final IVariable<IV> w = Var.var("w"); final IVariable<IV> v = Var.var("v"); final IVariable<IV> S = Var.var("S"); final IVariable<IV> s = Var.var("s"); final IConstant<String> s1 = new Constant<String>("s1"); final IConstant<String> s2 = new Constant<String>("s2"); final IConstant<XSDNumericIV<BigdataLiteral>> num1 = new Constant<XSDNumericIV<BigdataLiteral>>( new XSDNumericIV<BigdataLiteral>(1)); final IConstant<XSDNumericIV<BigdataLiteral>> num2 = new Constant<XSDNumericIV<BigdataLiteral>>( new XSDNumericIV<BigdataLiteral>(2)); final IConstant<XSDNumericIV<BigdataLiteral>> num9 = new Constant<XSDNumericIV<BigdataLiteral>>( new XSDNumericIV<BigdataLiteral>(9)); // COUNT(DISTINCT ?v) AS ?S final IValueExpression<IV> countDistinctVAsS = new Bind(S, new COUNT(true/* distinct */, (IValueExpression<IV>) v)); final GroupByOp query = newFixture(// new IValueExpression[] { w, countDistinctVAsS }, // select new IValueExpression[] { w }, // groupBy null // having ); /** * The test data: * * <pre> * ?w ?s ?v * 9 s1 1 * s2 2 * </pre> */ final IBindingSet data [] = new IBindingSet [] { new ListBindingSet ( new IVariable<?> [] { w, s, v }, new IConstant [] { num9, s1, num1 } ) , new ListBindingSet ( new IVariable<?> [] { s, v }, new IConstant [] { s2, num2 } ) }; /** * The expected solutions: * * <pre> * ?w ?S * 9 1 * 1 * </pre> * * </pre> */ // Note: The aggregates will have gone through type promotion. final IConstant<XSDIntegerIV<BigdataLiteral>> _num1 = new Constant<XSDIntegerIV<BigdataLiteral>>( new XSDIntegerIV<BigdataLiteral>(BigInteger.valueOf(1))); final IBindingSet expected[] = new IBindingSet[] { new ListBindingSet ( new IVariable<?> [] { w, S }, new IConstant [] { num9, _num1 } ), new ListBindingSet ( new IVariable<?> [] { S }, new IConstant [] { _num1 } ) }; final BOpStats stats = query.newStats(); final IAsynchronousIterator<IBindingSet[]> source = new ThickAsynchronousIterator<IBindingSet[]>( new IBindingSet[][] { data }); final IBlockingBuffer<IBindingSet[]> sink = new BlockingBufferWithStats<IBindingSet[]>( query, stats); final IRunningQuery runningQuery = new MockRunningQuery(null/* fed */ , kb.getIndexManager()/* indexManager */ , queryContext ); // Note: [lastInvocation:=true] forces the solutions to be emitted. final BOpContext<IBindingSet> context = new BOpContext<IBindingSet>( runningQuery, -1/* partitionId */ , stats, query/* op */, true/* lastInvocation */, source, sink, null/* sink2 */ ); final FutureTask<Void> ft = query.eval(context); // Run the query. { final Thread t = new Thread() { public void run() { ft.run(); } }; t.setDaemon(true); t.start(); } // Check the solutions. AbstractQueryEngineTestCase.assertSameSolutionsAnyOrder(expected, sink.iterator(), ft); assertEquals(1, stats.chunksIn.get()); assertEquals(2, stats.unitsIn.get()); assertEquals(2, stats.unitsOut.get()); assertEquals(1, stats.chunksOut.get()); } finally { kb.getIndexManager().destroy(); } } // test_aggregation_groupBy_by_error_values3() }