Package com.hp.hpl.jena.sparql.engine.iterator

Source Code of com.hp.hpl.jena.sparql.engine.iterator.QueryIterGroup

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF 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.
*/

package com.hp.hpl.jena.sparql.engine.iterator;

import java.util.ArrayList ;
import java.util.Collection ;
import java.util.Iterator ;
import java.util.List ;

import org.apache.jena.atlas.iterator.Iter ;
import org.apache.jena.atlas.iterator.IteratorDelayedInitialization ;
import org.apache.jena.atlas.lib.MultiMap ;
import org.apache.jena.atlas.lib.Pair ;

import com.hp.hpl.jena.graph.Node ;
import com.hp.hpl.jena.sparql.core.Var ;
import com.hp.hpl.jena.sparql.core.VarExprList ;
import com.hp.hpl.jena.sparql.engine.ExecutionContext ;
import com.hp.hpl.jena.sparql.engine.QueryIterator ;
import com.hp.hpl.jena.sparql.engine.binding.Binding ;
import com.hp.hpl.jena.sparql.engine.binding.BindingFactory ;
import com.hp.hpl.jena.sparql.engine.binding.BindingMap ;
import com.hp.hpl.jena.sparql.expr.ExprAggregator ;
import com.hp.hpl.jena.sparql.expr.NodeValue ;
import com.hp.hpl.jena.sparql.expr.aggregate.Accumulator ;

public class QueryIterGroup extends QueryIterPlainWrapper
{
  private final QueryIterator embeddedIterator;

  public QueryIterGroup(QueryIterator qIter,
                          VarExprList groupVars,
                          List<ExprAggregator> aggregators,
                          ExecutionContext execCxt)
    {
        super(null, execCxt) ;
        this.embeddedIterator = qIter;
        Iterator<Binding> iter = calc(qIter, groupVars, aggregators, execCxt) ;
        setIterator(iter) ;
    }

  @Override
  public void requestCancel()
  {
      this.embeddedIterator.cancel();
      super.requestCancel() ;
  }
 
    // Phase 1 : Consume the input iterator, assigning groups (keys)
    //           and push rows through the aggregator function.
   
    // Phase 2 : Go over the group bindings and assign the value of each aggregation.
 
  private static Pair<Var, Accumulator> placeholder = Pair.create((Var)null, (Accumulator)null) ;
 
   
    private static Iterator<Binding> calc(final QueryIterator iter,
                                          final VarExprList groupVarExpr, final List<ExprAggregator> aggregators,
                                          final ExecutionContext execCxt)
    {
        return new IteratorDelayedInitialization<Binding>() {
            @Override
            protected Iterator<Binding> initializeIterator() {

                boolean noAggregators =  ( aggregators == null || aggregators.size() == 0 ) ;
               
                // Phase 1 : assign bindings to buckets by key and pump through the aggregrators.
                MultiMap<Binding, Pair<Var, Accumulator>> accumulators = MultiMap.createMapList() ;

                for ( ; iter.hasNext() ; )
                {
                    Binding b = iter.nextBinding() ;
                    Binding key = genKey(groupVarExpr, b, execCxt) ;

                    if ( noAggregators )
                    {
                        // Put in a dummy to remember the input.
                        accumulators.put(key, placeholder ) ;
                        continue ;
                    }

                    Collection<Pair<Var, Accumulator>> accs = accumulators.get(key) ;
                    // Create if does not exist.
                    if ( accs == null )
                    {
                        for ( ExprAggregator agg : aggregators )
                        {
                            Accumulator x = agg.getAggregator().createAccumulator() ;
                            Var v = agg.getVar() ;
                            accumulators.put(key, Pair.create(v, x)) ;
                        }
                        accs = accumulators.get(key) ;
                    }

                    // Do the per-accumulator calculation.
                    for ( Pair<Var, Accumulator> pair : accs )
                        pair.getRight().accumulate(b, execCxt) ;
                }

                // Phase 2 : Empty input
                // has as iter.hasNext false at start.

                // If there are no binding from the input stage, two things can happen.
                //   If there are no aggregators, there are no groups.
                //   If there are aggregators, then they may have a default value.

                if ( accumulators.isEmpty() )
                {
                    if ( noAggregators )
                    {
                        // No rows to group, no aggregators.
                        // ==> No result rows.
                        return Iter.nullIterator() ;
                    }
                   
                    BindingMap binding = BindingFactory.create() ;

                    for ( Iterator<ExprAggregator> aggIter = aggregators.iterator() ; aggIter.hasNext() ; )
                    {
                        ExprAggregator agg = aggIter.next();
                        Var v = agg.getVar() ;
                        Node value = agg.getAggregator().getValueEmpty() ;
                        if ( value != null )
                            binding.add(v, value) ;
                    }
                       
                    if ( binding == null )
                        // This does not happen if there are any aggregators.
                        return Iter.nullIterator() ;
                    // cast to get the static type inference to work.
                    return Iter.singletonIter((Binding)binding) ;
                }

                // Phase 2 : There was input and so there are some groups.
                // For each bucket, get binding, add aggregator values to the binding.
                // We used AccNull so there are always accumulators.
               
                if ( noAggregators )
                    // We used placeholder so there are always the key.
                    return accumulators.keys().iterator() ;
               
                List<Binding> results = new ArrayList<Binding>() ;

                for ( Binding k : accumulators.keys() )
                {
                    Collection<Pair<Var, Accumulator>> accs = accumulators.get(k) ;
                    BindingMap b = BindingFactory.create(k) ;
                   
                    for ( Pair<Var, Accumulator> pair : accs )
                    {
                        Var v = pair.getLeft() ;
                        NodeValue value = pair.getRight().getValue() ;
                        Node n = (value==null) ? null : value.asNode() ;
                        if ( v == null || n == null )
                        {}
                        else
                            b.add(v, n) ;
                    }
                    results.add(b) ;
                }
                return results.iterator() ;
            }
        };
    }
   
    static private Binding genKey(VarExprList vars, Binding binding, ExecutionContext execCxt)
    {
        return copyProject(vars, binding, execCxt) ;
    }
   
    static private Binding copyProject(VarExprList vars, Binding binding, ExecutionContext execCxt)
    {
        // No group vars (implicit or explicit) => working on whole result set.
        // Still need a BindingMap to assign to later.
        BindingMap x = BindingFactory.create() ;
        for ( Iterator<Var> iter = vars.getVars().iterator() ; iter.hasNext() ; )
        {
            Var var = iter.next() ;
            Node node = vars.get(var, binding, execCxt) ;
            // Null returned for unbound and error.
            if ( node != null )
                x.add(var, node) ;
        }
        return x ;
    }
}
TOP

Related Classes of com.hp.hpl.jena.sparql.engine.iterator.QueryIterGroup

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.