Package lupos.engine.operators.index

Source Code of lupos.engine.operators.index.BasicIndexScan$AddConstantBindingIterator

/**
* Copyright (c) 2013, Institute of Information Systems (Sven Groppe and contributors of LUPOSDATE), University of Luebeck
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
* following conditions are met:
*
*   - Redistributions of source code must retain the above copyright notice, this list of conditions and the following
*     disclaimer.
*   - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
*     following disclaimer in the documentation and/or other materials provided with the distribution.
*   - Neither the name of the University of Luebeck nor the names of its contributors may be used to endorse or promote
*     products derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package lupos.engine.operators.index;

import java.io.IOException;
import java.math.BigInteger;
import java.net.URISyntaxException;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import lupos.datastructures.bindings.Bindings;
import lupos.datastructures.bindings.BindingsArrayVarMinMax;
import lupos.datastructures.bindings.BindingsFactory;
import lupos.datastructures.dbmergesortedds.DBMergeSortedBag;
import lupos.datastructures.dbmergesortedds.SortConfiguration;
import lupos.datastructures.items.Item;
import lupos.datastructures.items.Variable;
import lupos.datastructures.items.literal.LanguageTaggedLiteral;
import lupos.datastructures.items.literal.LazyLiteral;
import lupos.datastructures.items.literal.LazyLiteralOriginalContent;
import lupos.datastructures.items.literal.Literal;
import lupos.datastructures.items.literal.LiteralFactory;
import lupos.datastructures.items.literal.TypedLiteral;
import lupos.datastructures.items.literal.URILiteral;
import lupos.datastructures.paged_dbbptree.node.nodedeserializer.StringVarBucketArrayNodeDeSerializer;
import lupos.datastructures.queryresult.IdIteratorQueryResult;
import lupos.datastructures.queryresult.ParallelIterator;
import lupos.datastructures.queryresult.QueryResult;
import lupos.engine.operators.OperatorIDTuple;
import lupos.engine.operators.RootChild;
import lupos.engine.operators.index.adaptedRDF3X.RDF3XIndexScan;
import lupos.engine.operators.index.adaptedRDF3X.RDF3XIndexScan.CollationOrder;
import lupos.engine.operators.index.memoryindex.MemoryIndexScan;
import lupos.engine.operators.messages.BindingsFactoryMessage;
import lupos.engine.operators.messages.BoundVariablesMessage;
import lupos.engine.operators.messages.Message;
import lupos.engine.operators.singleinput.filter.expressionevaluation.Helper;
import lupos.engine.operators.tripleoperator.TriplePattern;
import lupos.engine.operators.tripleoperator.TriplePattern.BooleanAndUnknown;
import lupos.misc.Tuple;
import lupos.optimizations.logical.statistics.Entry;
import lupos.optimizations.logical.statistics.VarBucket;
import lupos.optimizations.physical.joinorder.costbasedoptimizer.operatorgraphgenerator.RDF3XOperatorGraphGenerator;

/**
* Instances of this class are used to process queries by using a special index
* structure for enhancement.<br>
* The index structure has to be initialized previously.
*
*/
public abstract class BasicIndexScan extends RootChild {

  public final static int NONE = 0;
  public final static int MOSTRESTRICTIONS = 1;
  public final static int MOSTRESTRICTIONSLEASTENTRIES = 2;
  public final static int LEASTENTRIES = 3;
  public final static int MERGEJOIN = 4;
  public final static int BINARY = 5;
  public final static int MERGEJOINSORT = 6;
  public final static int NARYMERGEJOIN = 7;
  public final static int BINARYSTATICANALYSIS = 8;

  protected final Root root;

  protected BindingsFactory bindingsFactory;

  // Item is Var or Literal (URILiteral)
  protected Item rdfGraph;

  protected Collection<TriplePattern> triplePatterns;

  public BasicIndexScan(final Root root) {
    super();
    this.root = root;
  }

  public BasicIndexScan(final Root root, final Collection<TriplePattern> triplePatterns) {
    this(root);
    this.setTriplePatterns(triplePatterns);
  }

  public BasicIndexScan(final OperatorIDTuple succeedingOperator,
      final Collection<TriplePattern> triplePattern, final Item rdfGraph, final Root root) {
    this.succeedingOperators = new LinkedList<OperatorIDTuple>();
    if (succeedingOperator != null) {
      this.succeedingOperators.add(succeedingOperator);
    }
    this.rdfGraph = rdfGraph;
    this.setTriplePatterns(triplePattern);
    this.root = root;
  }

  public BasicIndexScan(final List<OperatorIDTuple> succeedingOperators,
      final Collection<TriplePattern> triplePattern, final Item rdfGraph, final Root root) {
    this.succeedingOperators = succeedingOperators;
    this.rdfGraph = rdfGraph;
    this.setTriplePatterns(triplePattern);
    this.root=root;
  }

  public Root getRoot(){
    return this.root;
  }

  @Override
  public Message preProcessMessage(final BindingsFactoryMessage msg){
    this.bindingsFactory = msg.getBindingsFactory();
    for(final TriplePattern triplePattern : this.triplePatterns){
      triplePattern.setBindingsFactory(this.bindingsFactory);
    }
    return msg;
  }

  public void setBindingsFactory(final BindingsFactory bindingsFactory){
    this.bindingsFactory= bindingsFactory;
  }

  public BindingsFactory getBindingsFactory(){
    return this.bindingsFactory;
  }

  public void recomputeVariables(){
    this.intersectionVariables = new HashSet<Variable>();
    this.unionVariables = new HashSet<Variable>();
    if (this.triplePatterns != null) {
      for (final TriplePattern tp : this.triplePatterns) {
        tp.recomputeVariables();
        final Collection<Variable> varsOfTP = tp.getUnionVariables();
        this.intersectionVariables.addAll(varsOfTP);
        this.unionVariables.addAll(varsOfTP);
      }
    }
    final Item rdfGraphLocal = this.getGraphConstraint();
    if (rdfGraphLocal != null && rdfGraphLocal.isVariable()) {
      this.intersectionVariables.add((Variable) rdfGraphLocal);
      this.unionVariables.add((Variable) rdfGraphLocal);
    }
  }

  @Override
  public Message preProcessMessage(final BoundVariablesMessage msg) {
    this.recomputeVariables();
    final BoundVariablesMessage result = new BoundVariablesMessage(msg);
    result.getVariables().addAll(this.unionVariables);
    return result;
  }

  /**
   * Joins the triple pattern using the index maps and returns the result.<br>
   * The succeeding operators are passed to the operator pipe to be processed.
   *
   * @param opt
   *            unused parameter
   * @return the result of the performed join
   */
  @Override
  public QueryResult process(final Dataset dataset) {
    final QueryResult queryResult = this.join(dataset);
    if (queryResult == null) {
      return null;
    }
    return queryResult;
  }

  public QueryResult join(final Dataset dataset) {
    try {

      // create a query result object which will gather the results of the
      // inner join
      QueryResult queryResult = null;

      // get the graph constraint from the super class.
      // If it is null, a default graph is used, if not null a named one
      // is used
      final Item graphConstraintItem = this.getGraphConstraint();

      // get a collection of indices using the determined graph constraint
      final Collection<Indices> indicesC = dataset.indexingRDFGraphs(
          graphConstraintItem, false, false, this.root);
      if ((indicesC != null) && !(indicesC.size() == 0)) {

        // if the graph constraint is not null (which means that a named
        // graph is used)
        if (graphConstraintItem != null) {

          if (graphConstraintItem instanceof Variable) {

            final Variable graphConstraint = (Variable) graphConstraintItem;

            // check if named graphs were provided at query time
            if (this.root.namedGraphs != null
                && this.root.namedGraphs.size() > 0) {

              // Convert the named graphs' names into URILiterals
              // to be applicable
              // later on
              for (final String name : this.root.namedGraphs) {

                final Indices indices = dataset.getNamedGraphIndices(LiteralFactory.createURILiteralWithoutLazyLiteral(name));

                final Bindings graphConstraintBindings = this.bindingsFactory.createInstance();
                final URILiteral rdfName = indices.getRdfName();
                graphConstraintBindings.add(graphConstraint, rdfName);
                if (queryResult == null) {
                  queryResult = QueryResult.createInstance(new AddConstantBindingIterator(graphConstraint, rdfName, this.join(indices,
                      graphConstraintBindings).oneTimeIterator()));
                } else {
                  queryResult.addAll(QueryResult.createInstance(new AddConstantBindingIterator(graphConstraint, rdfName, this.join(indices,
                      graphConstraintBindings).oneTimeIterator())));
                }

              }

            }

            // otherwise there might have been named graphs added
            // during the evaluation
            else {

              // get all indices of named graphs and bind them to
              // the graph constraint
              final Collection<Indices> dataSetIndices = dataset.getNamedGraphIndices();
              if (dataSetIndices != null) {

                for (final Indices indices : dataSetIndices) {
                  final Bindings graphConstraintBindings = this.bindingsFactory.createInstance();
                  graphConstraintBindings.add(graphConstraint, indices.getRdfName());
                  if (queryResult == null) {
                    queryResult = QueryResult.createInstance(new AddConstantBindingIterator(graphConstraint, indices.getRdfName(), this.join(indices,
                        graphConstraintBindings).oneTimeIterator()));
                  } else {
                    queryResult.addAll(QueryResult.createInstance(new AddConstantBindingIterator(graphConstraint, indices.getRdfName(), this.join(indices,
                        graphConstraintBindings).oneTimeIterator())));
                  }
                }
              }
            }
          }

          // if the graph constraint is an URILiteral fetch the
          // matching indices object
          // but do not bind anything
          else {
            queryResult = this.join(indicesC);
          }
        }

        // otherwise default graphs are used
        else {
          queryResult = this.join(indicesC);
        }
      }
      return queryResult;
    } catch (final Exception e) {
      System.err.println("Error while joining triple patterns: "+ e);
      e.printStackTrace();
      return null;
    }
  }


  /**
   * Performs a join over a collection of triple patterns
   * @param indicesC all the the index structures which contains the data
   * @return the result of the join
   */
  public QueryResult join(final Collection<Indices> indicesC){
    QueryResult queryResult = null;
    for (final Indices indices : indicesC) {
      if(queryResult == null) {
        queryResult = this.join(indices, this.bindingsFactory.createInstance());
      } else {
        queryResult.addAll(this.join(indices, this.bindingsFactory.createInstance()));
      }
    }
    return queryResult;
  }

  /**
   * Performs a join over a collection of triple patterns and a provided
   * bindings object over data of a certain index structure. The collection of
   * triple patterns is to be retrieved from the super class.
   *
   * @param indices
   *            the index structure which contains the data
   * @param bindings
   *            a bindings resulting from the usage of a named graph
   * @return the result of the join
   */
  public abstract QueryResult join(Indices indices, Bindings bindings);

  public void replace(final Variable var, final Item item) {
    for (final TriplePattern tp : this.triplePatterns){
      tp.replace(var, item);
    }
  }

  public Collection<TriplePattern> getTriplePattern() {
    return this.triplePatterns;
  }

  public void setTriplePatterns(final Collection<TriplePattern> triplePatterns) {
    this.triplePatterns = triplePatterns;
    this.recomputeVariables();
  }

  public Set<Variable> getVarsInTriplePatterns(){
    final HashSet<Variable> vars = new HashSet<Variable>();
    for(final TriplePattern tp: this.getTriplePattern()){
      for(final Item item: tp){
        if(item.isVariable()){
          vars.add((Variable) item);
        }
      }
    }
    return vars;
  }

  public void setGraphConstraint(final Item graph) {
    this.rdfGraph = graph;
  }

  public Item getGraphConstraint() {
    return this.rdfGraph;
  }

  @Override
  public String toString() {
    String s = "Index Scan on";

    if (this.triplePatterns != null && this.triplePatterns.size()>0) {
      for (final TriplePattern tp : this.triplePatterns) {
        s += "\n" + tp.toString();
      }
    } else {
      s += " no triple pattern";
    }

    if (this.rdfGraph != null) {
      s += "\nGraph" + this.rdfGraph;
    }

    return s;
  }

  @Override
  public String toString(final lupos.rdf.Prefix prefixInstance) {
    final StringBuffer s = new StringBuffer("Index Scan on");

    if (this.triplePatterns != null && this.triplePatterns.size()>0) {
      for (final TriplePattern tp : this.triplePatterns) {
        s.append("\n" + tp.toString(prefixInstance));
      }
    } else {
      s.append(" no triple pattern");
    }

    if (this.rdfGraph != null) {
      s.append("\nGraph" + this.rdfGraph.toString());
    }

    return s.toString();
  }

  public boolean occurInSubjectOrPredicateOrObjectOriginalStringDoesNotDiffer(
      final Variable var) {
    for (final TriplePattern tp : this.triplePatterns) {
      if (tp.getPos(0).equals(var) || tp.getPos(1).equals(var)) {
        return true;
      }
      if (tp.getPos(2).equals(var)) {
        final BooleanAndUnknown bau = tp.getObjectOriginalStringMayDiffer();
        if (bau == BooleanAndUnknown.UNKNOWN) {
          final Collection<TriplePattern> ztp = this.getTriplePattern();
          final Collection<TriplePattern> ctp = new LinkedList<TriplePattern>();
          try {
            ctp.add(tp);
            this.setTriplePatterns(ctp);
            if (this instanceof RDF3XIndexScan) {
              ((RDF3XIndexScan) this)
              .setCollationOrder(RDF3XOperatorGraphGenerator.getCollationOrder(tp, new LinkedList<Variable>()));

            }
            final QueryResult qr = this.join(this.root.dataset);
            if (qr == null) {
              this.setTriplePatterns(ztp);
              return true;
            }
            final Iterator<Bindings> itb = qr.oneTimeIterator();
            try {
              while (itb.hasNext()) {
                final Bindings b = itb.next();
                Literal literal = b.get(var);
                if (literal.originalStringDiffers()){
                  return false;
                } else if(!LiteralFactory.semanticInterpretationOfLiterals){
                  if(literal instanceof LazyLiteral){
                    literal = ((LazyLiteral) literal).getLiteral();
                  }
                  if(literal instanceof LanguageTaggedLiteral){
                    final String language = ((LanguageTaggedLiteral)literal).getLanguage();
                    if(language.compareTo(language.toUpperCase())!=0){
                      return false;
                    }
                  } else if(literal instanceof TypedLiteral){
                    if(Helper.isNumeric(literal)){
                      final String content = Helper.unquote(((TypedLiteral) literal).getContent());
                      if(content.startsWith("+")){
                        return false;
                      }
                      try{
                        final Object type = Helper.getType(literal);
                        String content2;
                        if(type instanceof BigInteger){
                          content2 = Helper.getInteger(literal).toString();
                        } else if(type instanceof Double){
                          content2 = Helper.getDouble(literal).toString();
                        } else if(type instanceof Float){
                          content2 = Helper.getFloat(literal).toString();
                        } else {
                          content2 = Helper.getBigDecimal(literal).toString();
                        }
                        if(content2.compareTo(content)!=0){
                          return false;
                        }
                      } catch(final Exception e) {
                        return false;
                      }
                    }
                  }
                }
              }
            } finally {
              if (itb instanceof ParallelIterator) {
                ((ParallelIterator<Bindings>) itb).close();
              }
            }
          } finally {
            this.setTriplePatterns(ztp);
          }
        }
        if (bau == BooleanAndUnknown.TRUE) {
          return false;
        } else {
          return true;
        }
      }
    }
    return true;
  }

  /**
   * This method is overridden by subclasses, e.g. RDF3XIndexScan
   * @param triplePattern the triple pattern to be considered
   * @param variables the variables the minimum and maximum value of which is determined
   * @return the minimum and maximum values of the given variables, null if determining the minimum and maximum is not supported
   */
  public Map<Variable, Tuple<Literal, Literal>> getMinMax(final TriplePattern triplePattern, final Collection<Variable> variables) {
    return null;
  }

  protected static final int MaxNumberBuckets = 500;

  protected final static Map<String, VarBucket[]> histograms = createHistogramMap();

  protected static Map<String, VarBucket[]> createHistogramMap() {
    try {
      return (Indices.usedDatastructure != Indices.DATA_STRUCT.DBBPTREE) ? null
          : Collections
              .synchronizedMap(new lupos.datastructures.paged_dbbptree.DBBPTree<String, VarBucket[]>(
                  1000,
                  1000,
                  new StringVarBucketArrayNodeDeSerializer()));
    } catch (final IOException e) {
      System.err.println(e);
      e.printStackTrace();
    }
    return null;
  }

  public static int getMaxNumberBuckets() {
    return MaxNumberBuckets;
  }

  protected static String getKey(final TriplePattern tp) {
    final HashMap<Variable, Variable> alreadyUsedVariables = new HashMap<Variable, Variable>();
    String key = "";
    for (int i = 0; i < 3; i++) {
      if (tp.getPos(i).isVariable()) {
        Variable v = alreadyUsedVariables.get(tp.getPos(i));
        if (v == null) {
          v = new Variable("" + alreadyUsedVariables.size());
          alreadyUsedVariables.put((Variable) tp.getPos(i), v);
        }
        key += v.toString();
      } else {
        if (tp.getPos(i) instanceof LazyLiteralOriginalContent) {
          key += "\""
              + ((LazyLiteralOriginalContent) tp.getPos(i))
                  .getCodeOriginalContent() + "\"";
        } else if (tp.getPos(i) instanceof LazyLiteral) {
          key += "\"" + ((LazyLiteral) tp.getPos(i)).getCode() + "\"";
        } else {
          key += tp.getPos(i).toString();
        }
      }
    }
    return key;
  }

  protected static Map<Variable, VarBucket> getVarBuckets(
      final TriplePattern tp, final VarBucket[] vba) {
    final Map<Variable, VarBucket> map = new HashMap<Variable, VarBucket>();
    final HashSet<Variable> alreadyUsedVariables = new HashSet<Variable>();
    int index = 0;
    for (int i = 0; i < 3; i++) {
      if (tp.getPos(i).isVariable()) {
        if (!alreadyUsedVariables.contains(tp.getPos(i))) {
          alreadyUsedVariables.add((Variable) tp.getPos(i));
          if (vba[index] != null) {
            map.put((Variable) tp.getPos(i), vba[index]);
          }
          index++;
        }
      }
    }
    return map;
  }

  protected void storeVarBuckets(final TriplePattern tp,
      final Map<Variable, VarBucket> map, final String key) {
    final HashSet<Variable> alreadyUsedVariables = new HashSet<Variable>();
    final VarBucket[] vba = new VarBucket[tp.getVariables().size()];
    int index = 0;
    for (int i = 0; i < 3; i++) {
      if (tp.getPos(i).isVariable()) {
        if (!alreadyUsedVariables.contains(tp.getPos(i))) {
          alreadyUsedVariables.add((Variable) tp.getPos(i));
          vba[index] = map.get(tp.getPos(i));
          index++;
        }
      }
    }
    // System.out.println("No hit for " + tp + " with key " + key);
    histograms.put(key, vba);
  }

  public final Map<Variable, VarBucket> getVarBucketsOriginal(
      final TriplePattern tp,
      final Class<? extends Bindings> classBindings,
      final Collection<Variable> joinPartners,
      final Map<Variable, Literal> minima,
      final Map<Variable, Literal> maxima) {
    final HashSet<Variable> joinPartnersTP = new HashSet<Variable>();
    joinPartnersTP.addAll(joinPartners);
    joinPartnersTP.retainAll(tp.getVariables());
    Map<Variable, VarBucket> intermediate = null;
    String key = null;
    if (Indices.usedDatastructure == Indices.DATA_STRUCT.DBBPTREE) {
      key = getKey(tp);
      // System.out.println(key);
      final VarBucket[] vba = histograms.get(key);
      if (vba != null) {
        intermediate = getVarBuckets(tp, vba);
        if (intermediate.keySet().containsAll(joinPartnersTP)) {
          boolean flag = true;
          for (final Variable v : joinPartners) {
            final Literal min = minima.get(v);
            if (intermediate.get(v) == null
                || min != null
                && (intermediate.get(v).minimum == null || !min
                    .equals(intermediate.get(v).minimum))) {
              flag = false;
              break;
            }
            final Literal max = maxima.get(v);
            if (max != null
                && (intermediate.get(v).maximum == null || !max
                    .equals(intermediate.get(v).maximum))) {
              flag = false;
              break;
            }
          }
          if (flag) {
            intermediate.keySet().retainAll(joinPartnersTP);
            if (classBindings == BindingsArrayVarMinMax.class) {
              for (final Variable v : intermediate.keySet()) {
                final VarBucket vb = intermediate.get(v);
                final Literal l[] = new Literal[vb.selectivityOfInterval
                    .size()];
                int indexLiteral = 0;
                for (final Entry entry : vb.selectivityOfInterval) {
                  l[indexLiteral] = entry.literal;
                  indexLiteral++;
                }
                tp.addHistogram(v, l, vb.getSum());
              }
            }
            return intermediate;
          }
        }
      }
    }
    // first determine the result size of the triple pattern!
    final Map<Variable, VarBucket> result = new HashMap<Variable, VarBucket>();
    final Collection<TriplePattern> ztp = this.getTriplePattern();
    final Collection<TriplePattern> ctp = new LinkedList<TriplePattern>();
    ctp.add(tp);
    this.setTriplePatterns(ctp);
    if (this instanceof RDF3XIndexScan) {
      ((RDF3XIndexScan) this).setCollationOrder(RDF3XOperatorGraphGenerator.getCollationOrder(tp, joinPartners));
      ((RDF3XIndexScan) this).setMinimaMaxima(minima, maxima);

    }
    final QueryResult qrSize = this.join(this.root.dataset);
    if (qrSize == null) {
      // System.out.println("No result for " + tp);
      return null;
    }

    int size = 0;

    if (classBindings == BindingsArrayVarMinMax.class) {
      final Map<Variable, Integer> hmvi = this.bindingsFactory.getPosVariables();
      final Integer[] minArray = new Integer[hmvi.size()];
      final Integer[] maxArray = new Integer[hmvi.size()];

      final Iterator<Bindings> itbSize = qrSize.oneTimeIterator();
      while (itbSize.hasNext()) {
        final Bindings b = itbSize.next();
        for (final Variable v : b.getVariableSet()) {
          final LazyLiteral ll = (LazyLiteral) b.get(v);
          final int pos = hmvi.get(v);
          if (minArray[pos] == null || minArray[pos] > ll.getCode()) {
            minArray[pos] = ll.getCode();
          }
          if (maxArray[pos] == null || maxArray[pos] < ll.getCode()) {
            maxArray[pos] = ll.getCode();
          }
        }
        size++;

        for (int i = 0; i < minArray.length; i++) {
          if (minArray[i] != null) {
            tp.addMinMaxLazyLiteral(i, minArray[i], maxArray[i]);
          }
        }
      }
    } else {
      int maxId = 1;
      if (qrSize instanceof IdIteratorQueryResult) {
        maxId = ((IdIteratorQueryResult) qrSize).getMaxId();
      }

      final int[][] min = new int[maxId][];
      final int[][] max = new int[maxId][];

      size = qrSize.oneTimeSize();

      for (int id = 0; id < maxId; id++) {
        if (min[id] != null) {
          for (int i = 0; i < min[id].length; i++) {
            tp.addMinMaxPresortingNumbers(i, min[id].length,
                id, min[id][i], max[id][i]);
          }
        }
      }
    }

    qrSize.release();

    if (size == 0) {
      System.out.println("No result for " + tp);
      return null;
    }

    // System.out.println("(Statistics) " + tp + ", " + size
    // + " triples retrieved");
    tp.setCardinality(size);

    for (final Variable v : joinPartnersTP) {
      if (intermediate != null && intermediate.containsKey(v)) {
        boolean flag = true;
        final Literal min = minima.get(v);
        if (intermediate.get(v) == null
            || min != null
            && (intermediate.get(v).minimum == null || !min
                .equals(intermediate.get(v).minimum))) {
          flag = false;
        }
        final Literal max = maxima.get(v);
        if (max != null
            && (intermediate.get(v).maximum == null || !max
                .equals(intermediate.get(v).maximum))) {
          flag = false;
        }
        if (flag) {
          result.put(v, intermediate.get(v));
          continue;
        }
      }
      // get result of triple pattern in the correct sorted way!
      final Collection<Variable> cv = new LinkedList<Variable>();
      cv.add(v);
      if (this instanceof RDF3XIndexScan) {
        ((RDF3XIndexScan) this).setCollationOrder(CollationOrder.getCollationOrder(tp, cv));
      }

      QueryResult qr = this.join(this.root.dataset);

      if (this instanceof MemoryIndexScan) {
        // additional sorting phase according to variable v needed
        // for memory index approach!
        final DBMergeSortedBag<Bindings> sort = new DBMergeSortedBag<Bindings>(
            new SortConfiguration(), new Comparator<Bindings>() {
              @Override
              public int compare(final Bindings arg0, final Bindings arg1) {
                return arg0.get(v).compareToNotNecessarilySPARQLSpecificationConform(arg1.get(v));
              }
            }, Bindings.class);
        final Iterator<Bindings> itb = qr.oneTimeIterator();
        while (itb.hasNext()) {
          sort.add(itb.next());
        }
        qr = QueryResult.createInstance(sort.iterator());
      }
      if (qr == null) {
        return result;
      }

      if (size == 0) {
        qr.release();
        return result;
      }
      final double bucketSize = (double) size / MaxNumberBuckets;
      final Iterator<Bindings> ib = qr.oneTimeIterator();
      final VarBucket vb = new VarBucket();
      vb.minimum = minima.get(v);
      vb.maximum = maxima.get(v);
      Entry currentEntry = new Entry();
      Literal lastLiteral = null;
      while (ib.hasNext()) {
        final Bindings b = ib.next();
        final Literal next = b.get(v);
        if (lastLiteral == null
            || lastLiteral
                .compareToNotNecessarilySPARQLSpecificationConform(next) != 0) {
          currentEntry.distinctLiterals += 1.0;
          lastLiteral = next;
        }
        currentEntry.selectivity += 1.0;
        if (currentEntry.selectivity >= bucketSize) {
          currentEntry.literal = b.get(v);
          if (ib.hasNext()) {
            Bindings b2 = ib.next();
            while (ib.hasNext()
                && b2
                    .get(v)
                    .compareToNotNecessarilySPARQLSpecificationConform(
                        currentEntry.literal) == 0) {
              currentEntry.selectivity += 1.0;
              b2 = ib.next();
            }
            vb.selectivityOfInterval.add(currentEntry);
            currentEntry = new Entry();
            currentEntry.distinctLiterals = 1.0;
            currentEntry.selectivity = 1.0;
            if (!ib.hasNext()
                && b2
                    .get(v)
                    .compareToNotNecessarilySPARQLSpecificationConform(
                        next) != 0) {
              currentEntry.literal = b2.get(v);
              vb.selectivityOfInterval.add(currentEntry);
            }
          } else {
            vb.selectivityOfInterval.add(currentEntry);
          }
        }
      }
      qr.release();
      result.put(v, vb);
      if (intermediate != null) {
        intermediate.put(v, vb);
      }
    }
    this.setTriplePatterns(ztp);

    if (classBindings == BindingsArrayVarMinMax.class) {
      for (final Variable v : result.keySet()) {
        final VarBucket vb = result.get(v);
        final Literal l[] = new Literal[vb.selectivityOfInterval.size()];
        int indexLiteral = 0;
        for (final Entry entry : vb.selectivityOfInterval) {
          l[indexLiteral] = entry.literal;
          indexLiteral++;
        }
        tp.addHistogram(v, l, vb.getSum());
      }
    }
    if (Indices.usedDatastructure == Indices.DATA_STRUCT.DBBPTREE) {
      if (intermediate != null) {
        this.storeVarBuckets(tp, intermediate, key);
      } else {
        this.storeVarBuckets(tp, result, key);
      }
    }
    return result;
  }

  public Map<Variable, VarBucket> getVarBuckets(final TriplePattern tp,
      final Class<? extends Bindings> classBindings,
      final Collection<Variable> joinPartners,
      final Map<Variable, Literal> minima,
      final Map<Variable, Literal> maxima) {
    return this.getVarBucketsOriginal(tp, classBindings, joinPartners, minima, maxima);
  }

  /**
   * Returns whether or not the join order of the triple patterns inside this index scan operator should be optimized.
   * This is for almost all index scan operator types true (but not for PredicateIndexScan)
   * @return whether or not the join order of the triple patterns inside this index scan operator should be optimized
   */
  public boolean joinOrderToBeOptimized(){
    return true;
  }

  public static class AddConstantBindingIterator implements Iterator<Bindings>{

    protected final Variable var;
    protected final Literal literal;
    protected final Iterator<Bindings> originalIterator;
    protected Bindings next = null;
    protected static Literal emptyURI;

    {
      try {
        emptyURI = LiteralFactory.createURILiteral("<>");
      } catch (final URISyntaxException e) {
        System.err.println(e);
        e.printStackTrace();
      }
    }

    public AddConstantBindingIterator(final Variable var, final Literal literal, final Iterator<Bindings> originalIterator){
      this.var = var;
      this.literal = literal;
      this.originalIterator = originalIterator;
    }

    @Override
    public boolean hasNext() {
      if(this.next!=null) {
        return true;
      }
      this.next = this.computeNext();
      return (this.next!=null);
    }

    @Override
    public Bindings next() {
      if(this.next!=null){
        final Bindings znext = this.next;
        this.next = null;
        return znext;
      } else {
        return this.computeNext();
      }
    }

    public Bindings computeNext(){
      Bindings inter;
      do {
        inter = this.originalIterator.next();
        if(inter==null) {
          return null;
        }
      } while(inter.get(this.var)!= null && inter.get(this.var).compareToNotNecessarilySPARQLSpecificationConform(this.literal)!=0 && inter.get(this.var).compareToNotNecessarilySPARQLSpecificationConform(emptyURI)!=0);
      // comparison with emptyURI for running W3C testcases successfully (import of relative URI was meant to be the URI of the named graph!)
      inter.add(this.var, this.literal);
      return inter;
    }

    @Override
    public void remove() {
      this.originalIterator.remove();
    }
  }

  @Override
  public BasicIndexScan clone() {
    final BasicIndexScan bis = (BasicIndexScan) super.clone();
    bis.bindingsFactory = this.bindingsFactory;
    return bis;
  }

}
TOP

Related Classes of lupos.engine.operators.index.BasicIndexScan$AddConstantBindingIterator

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.