Package org.openrdf.query.algebra.evaluation.cursors

Source Code of org.openrdf.query.algebra.evaluation.cursors.GroupCursor$Entry

/*
* Copyright Aduna (http://www.aduna-software.com/) (c) 1997-2007.
*
* Licensed under the Aduna BSD-style license.
*/
package org.openrdf.query.algebra.evaluation.cursors;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import info.aduna.lang.ObjectUtil;

import org.openrdf.cursor.CollectionCursor;
import org.openrdf.cursor.Cursor;
import org.openrdf.model.Literal;
import org.openrdf.model.Value;
import org.openrdf.model.impl.LiteralImpl;
import org.openrdf.model.vocabulary.XMLSchema;
import org.openrdf.query.BindingSet;
import org.openrdf.query.algebra.AggregateOperator;
import org.openrdf.query.algebra.Count;
import org.openrdf.query.algebra.Group;
import org.openrdf.query.algebra.GroupElem;
import org.openrdf.query.algebra.Max;
import org.openrdf.query.algebra.Min;
import org.openrdf.query.algebra.ValueExpr;
import org.openrdf.query.algebra.evaluation.EvaluationStrategy;
import org.openrdf.query.algebra.evaluation.QueryBindingSet;
import org.openrdf.store.StoreException;

/**
* @author David Huynh
* @author Arjohn Kampman
*/
public class GroupCursor extends CollectionCursor<BindingSet> {

  /*--------------*
   * Constructors *
   *--------------*/

  public GroupCursor(EvaluationStrategy strategy, Group group, BindingSet parentBindings)
    throws StoreException
  {
    super(createIterator(strategy, group, parentBindings));

  }

  /*---------*
   * Methods *
   *---------*/

  private static Iterator<BindingSet> createIterator(EvaluationStrategy strategy, Group group,
      BindingSet parentBindings)
    throws StoreException
  {
    Collection<BindingSet> bindingSets;
    Collection<Entry> entries;
    boolean ordered = false;

    if (ordered) {
      bindingSets = new ArrayList<BindingSet>();
      entries = buildOrderedEntries(strategy, group, parentBindings);
    }
    else {
      bindingSets = new HashSet<BindingSet>();
      entries = buildUnorderedEntries(strategy, group, parentBindings);
    }

    for (Entry entry : entries) {
      QueryBindingSet sol = new QueryBindingSet(parentBindings);

      for (String name : group.getGroupBindingNames()) {
        Value value = entry.getPrototype().getValue(name);
        if (value != null) {
          // Potentially overwrites bindings from super
          sol.setBinding(name, value);
        }
      }

      for (GroupElem ge : group.getGroupElements()) {
        Value value = processAggregate(strategy, entry.getSolutions(), ge.getOperator());
        if (value != null) {
          // Potentially overwrites bindings from super
          sol.setBinding(ge.getName(), value);
        }
      }

      bindingSets.add(sol);
    }

    return bindingSets.iterator();
  }

  private static Collection<Entry> buildOrderedEntries(EvaluationStrategy strategy, Group group,
      BindingSet parentBindings)
    throws StoreException
  {
    Cursor<BindingSet> iter = strategy.evaluate(group.getArg(), parentBindings);

    try {
      List<Entry> orderedEntries = new ArrayList<Entry>();
      Map<Key, Entry> entries = new HashMap<Key, Entry>();

      BindingSet bindingSet;
      while ((bindingSet = iter.next()) != null) {
        Key key = new Key(group, bindingSet);
        Entry entry = entries.get(key);

        if (entry == null) {
          entry = new Entry(bindingSet);
          entries.put(key, entry);
          orderedEntries.add(entry);
        }

        entry.addSolution(bindingSet);
      }

      return orderedEntries;
    }
    finally {
      iter.close();
    }
  }

  private static Collection<Entry> buildUnorderedEntries(EvaluationStrategy strategy, Group group,
      BindingSet parentBindings)
    throws StoreException
  {
    Cursor<BindingSet> iter = strategy.evaluate(group.getArg(), parentBindings);

    try {
      Map<Key, Entry> entries = new HashMap<Key, Entry>();

      BindingSet sol;
      while ((sol = iter.next()) != null) {
        Key key = new Key(group, sol);
        Entry entry = entries.get(key);

        if (entry == null) {
          entry = new Entry(sol);
          entries.put(key, entry);
        }

        entry.addSolution(sol);
      }

      return entries.values();
    }
    finally {
      iter.close();
    }

  }

  private static Value processAggregate(EvaluationStrategy strategy, Set<BindingSet> bindingSets,
      AggregateOperator operator)
    throws StoreException
  {
    if (operator instanceof Count) {
      Count countOp = (Count)operator;

      ValueExpr arg = countOp.getArg();

      if (arg != null) {
        Set<Value> values = makeValueSet(strategy, arg, bindingSets);
        return new LiteralImpl(Integer.toString(values.size()), XMLSchema.INTEGER);
      }
      else {
        return new LiteralImpl(Integer.toString(bindingSets.size()), XMLSchema.INTEGER);
      }
    }
    else if (operator instanceof Min) {
      Min minOp = (Min)operator;

      Set<Value> values = makeValueSet(strategy, minOp.getArg(), bindingSets);

      // FIXME: handle case where 'values' is empty
      double min = Double.POSITIVE_INFINITY;
      for (Value v : values) {
        if (v instanceof Literal) {
          Literal l = (Literal)v;
          try {
            min = Math.min(min, Double.parseDouble(l.getLabel()));
          }
          catch (NumberFormatException e) {
            // ignore
          }
        }
      }

      return new LiteralImpl(Double.toString(min), XMLSchema.DOUBLE);
    }
    else if (operator instanceof Max) {
      Max maxOp = (Max)operator;

      Set<Value> values = makeValueSet(strategy, maxOp.getArg(), bindingSets);

      // FIXME: handle case where 'values' is empty
      double max = Double.NEGATIVE_INFINITY;
      for (Value v : values) {
        if (v instanceof Literal) {
          Literal l = (Literal)v;
          try {
            max = Math.max(max, Double.parseDouble(l.getLabel()));
          }
          catch (NumberFormatException e) {
            // ignore
          }
        }
      }

      return new LiteralImpl(Double.toString(max), XMLSchema.DOUBLE);
    }

    return null;
  }

  private static Set<Value> makeValueSet(EvaluationStrategy strategy, ValueExpr arg,
      Set<BindingSet> bindingSets)
    throws StoreException
  {
    Set<Value> valueSet = new HashSet<Value>();

    for (BindingSet s : bindingSets) {
      Value value = strategy.evaluate(arg, s);
      if (value != null) {
        valueSet.add(value);
      }
    }

    return valueSet;
  }

  /**
   * A unique key for a set of existing bindings.
   *
   * @author David Huynh
   */
  protected static class Key {

    private Group group;

    private BindingSet bindingSet;

    private int hash;

    public Key(Group group, BindingSet bindingSet) {
      this.group = group;
      this.bindingSet = bindingSet;

      for (String name : group.getGroupBindingNames()) {
        Value value = bindingSet.getValue(name);
        if (value != null) {
          this.hash ^= value.hashCode();
        }
      }
    }

    @Override
    public int hashCode() {
      return hash;
    }

    @Override
    public boolean equals(Object other) {
      if (other instanceof Key && other.hashCode() == hash) {
        BindingSet otherSolution = ((Key)other).bindingSet;

        for (String name : group.getGroupBindingNames()) {
          Value v1 = bindingSet.getValue(name);
          Value v2 = otherSolution.getValue(name);

          if (!ObjectUtil.nullEquals(v1, v2)) {
            return false;
          }
        }

        return true;
      }

      return false;
    }
  }

  protected static class Entry {

    private BindingSet prototype;

    private Set<BindingSet> bindingSets;

    public Entry(BindingSet prototype) {
      this.prototype = prototype;
      this.bindingSets = new HashSet<BindingSet>();
    }

    public BindingSet getPrototype() {
      return prototype;
    }

    public void addSolution(BindingSet bindingSet) {
      bindingSets.add(bindingSet);
    }

    public Set<BindingSet> getSolutions() {
      return bindingSets;
    }
  }
}
TOP

Related Classes of org.openrdf.query.algebra.evaluation.cursors.GroupCursor$Entry

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.