Package lupos.optimizations.physical.joinorder.costbasedoptimizer.splitheuristic

Source Code of lupos.optimizations.physical.joinorder.costbasedoptimizer.splitheuristic.SplitStarShapedJoinOrPath

/**
* 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.optimizations.physical.joinorder.costbasedoptimizer.splitheuristic;

import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import lupos.datastructures.items.Item;
import lupos.datastructures.items.Variable;
import lupos.engine.operators.tripleoperator.TriplePattern;
import lupos.optimizations.logical.statistics.Statistics;
import lupos.optimizations.logical.statistics.VarBucket;
import lupos.optimizations.physical.joinorder.costbasedoptimizer.plan.LeafNodePlan;

/**
* This class splits a huge star-shaped join or a path
*/
public class SplitStarShapedJoinOrPath implements SplitHeuristic {

  @Override
  public List<List<LeafNodePlan>> split(List<LeafNodePlan> initialPlans) {
    // We split the plan at star-shaped joins!
    final HashMap<Item, LinkedList<LeafNodePlan>> starJoins = new HashMap<Item, LinkedList<LeafNodePlan>>();
    final HashMap<Item, LinkedList<LeafNodePlan>> helperStarJoins = new HashMap<Item, LinkedList<LeafNodePlan>>();
    for (final LeafNodePlan lnp : initialPlans) {
      TriplePattern tp = lnp.getTriplePatterns().iterator().next();
      final Item subject = tp.getPos(0);
      LinkedList<LeafNodePlan> list = starJoins.get(subject);
      if (list == null){
        list = new LinkedList<LeafNodePlan>();
     
      list.add(lnp);
      starJoins.put(subject, list);
      final Item predicate = tp.getPos(1);
      if (predicate instanceof Variable) {
        list = helperStarJoins.get(predicate);
        if (list == null)
          list = new LinkedList<LeafNodePlan>();
        list.add(lnp);
        helperStarJoins.put(predicate, list);
      }
      final Item object = tp.getPos(2);
      if (object instanceof Variable) {
        list = helperStarJoins.get(object);
        if (list == null)
          list = new LinkedList<LeafNodePlan>();
        list.add(lnp);
        helperStarJoins.put(object, list);
      }
    }
    final Collection<LinkedList<LeafNodePlan>> lltp = new LinkedList<LinkedList<LeafNodePlan>>();
    lltp.addAll(starJoins.values());
    for (final LinkedList<LeafNodePlan> ltp : lltp) {
      if (ltp.size() == 1) {
        // look if the object or predicate can be joined with other
        // triple patterns!
        final LeafNodePlan lnp = ltp.get(0);
        final TriplePattern tp = lnp.getTriplePatterns().iterator().next();
        if (tp.getPos(2) instanceof Variable) {
          if (starJoins.get(tp.getPos(2)) != null) {
            if (!tp.getPos(2).equals(tp.getPos(0))) {
              starJoins.get(tp.getPos(2)).add(lnp);
              starJoins.remove(tp.getPos(0));
              continue;
            }
          }
          if (helperStarJoins.get(tp.getPos(0)) != null) {
            boolean flagCont = false;
            for (final LeafNodePlan lnp2 : helperStarJoins.get(tp.getPos(0))) {
              final TriplePattern tp2 = lnp2.getTriplePatterns().iterator().next();
              if (!tp2.equals(tp)) {
                starJoins.get(tp2.getPos(0)).add(lnp);
                starJoins.remove(tp.getPos(0));
                flagCont = true;
                break;
              }
            }
            if (flagCont)
              continue;
          }
          if (helperStarJoins.get(tp.getPos(2)) != null) {
            boolean flagCont = false;
            for (final LeafNodePlan lnp2 : helperStarJoins.get(tp.getPos(2))) {
              final TriplePattern tp2 = lnp2.getTriplePatterns().iterator().next();
              if (!tp2.equals(tp)) {
                starJoins.get(tp2.getPos(0)).add(lnp);
                starJoins.remove(tp.getPos(0));
                flagCont = true;
                break;
              }
            }
            if (flagCont)
              continue;
          }
        }
        if (tp.getPos(1) instanceof Variable) {
          if (starJoins.get(tp.getPos(1)) != null) {
            if (!tp.getPos(1).equals(tp.getPos(0))) {
              starJoins.get(tp.getPos(1)).add(lnp);
              starJoins.remove(tp.getPos(0));
              continue;
            }
          }
          if (helperStarJoins.get(tp.getPos(0)) != null) {
            boolean flagCont = false;
            for (final LeafNodePlan lnp2 : helperStarJoins.get(tp.getPos(0))) {
              final TriplePattern tp2 = lnp2.getTriplePatterns().iterator().next();
              if (!tp2.equals(tp)) {
                starJoins.get(tp2.getPos(0)).add(lnp);
                starJoins.remove(tp.getPos(0));
                flagCont = true;
                break;
              }
            }
            if (flagCont)
              continue;
          }
          if (helperStarJoins.get(tp.getPos(1)) != null) {
            boolean flagCont = false;
            for (final LeafNodePlan lnp2 : helperStarJoins.get(tp.getPos(1))) {
              final TriplePattern tp2 = lnp2.getTriplePatterns().iterator().next();
              if (!tp2.equals(tp)) {
                starJoins.get(tp2.getPos(0)).add(lnp);
                starJoins.remove(tp.getPos(0));
                flagCont = true;
                break;
              }
            }
            if (flagCont)
              continue;
          }
        }
      }
    }
    @SuppressWarnings("unchecked")
    final LinkedList<LeafNodePlan>[] solution = new LinkedList[starJoins.size()];
    final Iterator<LinkedList<LeafNodePlan>> starJoinsIterator = starJoins
        .values().iterator();
    for (int i = 0; i < starJoins.size(); i++){
      solution[i] = starJoinsIterator.next();
    }

    if (solution.length == 1) {
      // We have to split one huge star-shaped join!

      // find out the two triple patterns with the smallest
      // cardinalities to split the join!
      final LeafNodePlan[] initialPlansArray = initialPlans.toArray(new LeafNodePlan[0]);
      int max0;
      int max1;
      if (initialPlansArray[0].getCardinality() <= initialPlansArray[1].getCardinality()) {
        max0 = 0;
        max1 = 1;
      } else {
        max0 = 1;
        max1 = 0;
      }
      for (int i = 2; i < initialPlansArray.length; i++) {
        if (initialPlansArray[i].getCardinality() < initialPlansArray[max1].getCardinality()) {
          if (initialPlansArray[i].getCardinality() < initialPlansArray[max0].getCardinality()) {
            max1 = max0;
            max0 = i;
          } else
            max1 = i;
        }
      }
      final LinkedList<LeafNodePlan> left = new LinkedList<LeafNodePlan>();
      left.add(initialPlansArray[max0]);
      final LinkedList<LeafNodePlan> right = new LinkedList<LeafNodePlan>();
      right.add(initialPlansArray[max1]);
      // now split the join by putting the current triple pattern to
      // the one, which will have the smallest
      // cardinality when joined with max0 or with max1!
      for (int i = 0; i < initialPlansArray.length; i++) {
        if (i == max0 || i == max1){
          continue;
        }
       
        Map<Variable, VarBucket> selectivityMax0 = Statistics.estimateJoinSelectivity(initialPlansArray[max0].getSelectivity(), initialPlansArray[i].getSelectivity());
        // compute the cardinality of the join result as well as its cost
        double cardMax0 = 0.0;
        if (selectivityMax0 != null) {
          if (selectivityMax0.size() > 0) {
            cardMax0 = selectivityMax0.values().iterator().next().getSum();
          }
        }       
       
        Map<Variable, VarBucket> selectivityMax1 = Statistics.estimateJoinSelectivity(initialPlansArray[max1].getSelectivity(), initialPlansArray[i].getSelectivity());
        // compute the cardinality of the join result as well as its cost
        double cardMax1 = 0.0;
        if (selectivityMax1 != null) {
          if (selectivityMax1.size() > 0) {
            cardMax1 = selectivityMax1.values().iterator().next().getSum();
          }
        }       
       
        if(cardMax0 < cardMax1){
          left.add(initialPlansArray[i]);
        } else {
          right.add(initialPlansArray[i]);
        }       
      }
      if (left.size() == 1 || right.size() == 1) {
        // greedy: just have two similar big subgraphs! Just distribute the leaf nodes with small sizes in the two subgraphs!
        Collections.sort(initialPlans,
            new Comparator<LeafNodePlan>() {
              @Override
              public int compare(final LeafNodePlan o1, final LeafNodePlan o2) {
                if (o1.getCardinality() == o2.getCardinality()){
                  return 0;
                } else if (o1.getCardinality() < o2.getCardinality()){
                  return -1;
                } else {
                  return 1;
                }
              }
            });
        left.clear();
        right.clear();
        boolean leftIsNext = true;
        for(LeafNodePlan lnp: initialPlans){
          if(leftIsNext){
            left.add(lnp);
          } else {
            right.add(lnp);
          }
          leftIsNext = !leftIsNext;
        }
        return this.generateResult(left, right);       
      } else {
        return this.generateResult(left, right);
      }
    } else {

      int max = 0;

      for (int i = 1; i < solution.length; i++) {
        if (solution[i].size() > solution[max].size())
          max = i;
      }
      if (solution[max].size() == 1) {
        // join is a path join

        // generate plans for paths by dividing the path in the middle:
        HashMap<Item, LeafNodePlan> subjects = new HashMap<Item, LeafNodePlan>();
        for(final LeafNodePlan lnp: initialPlans){
          TriplePattern tp=lnp.getTriplePatterns().iterator().next();
          subjects.put(tp.getPos(0), lnp);
        }
        LeafNodePlan startingLeafNode = null;
        // find the starting triple pattern of the path:
        for(final LeafNodePlan lnp: initialPlans){
          TriplePattern tp=lnp.getTriplePatterns().iterator().next();
          if(!subjects.containsKey(tp.getPos(2))){
            // found starting triple pattern of the path!
            startingLeafNode = lnp;
            break;
          }
        }
        // join path is a ring?! => just take one of the leaf nodes as starting point!
        if(startingLeafNode==null){
          startingLeafNode = initialPlans.get(0);
        }
        LinkedList<LeafNodePlan> splittedPart = new LinkedList<LeafNodePlan>();
        splittedPart.add(startingLeafNode);
        LeafNodePlan current = startingLeafNode;
        // now follow the path
        for(int i=1; i<initialPlans.size()/2; i++){
          TriplePattern tp = current.getTriplePatterns().iterator().next();
          LeafNodePlan lnp = subjects.get(tp.getPos(2));
          if(lnp!=null){
            splittedPart.add(lnp);
            current = lnp;
          } else {
            throw new RuntimeException("Expected that the join is a path join, but obviously it is not!");
          }
        }
       
        return generateResultByDividing(initialPlans, splittedPart);

      }

      // join has at least one star-shaped join:
      // split the huge join by separating a huge
      // star-shaped join from the rest!
      return generateResultByDividing(initialPlans, solution[max]);     
    }
  }

  /**
   * This method generates the result by adding the parameters left and right to a list
   * @param left one part of the leaf node plans to join
   * @param right the other part of the leaf node plans to join
   * @return a list containing left and right
   */
  private LinkedList<List<LeafNodePlan>> generateResult(List<LeafNodePlan> left, List<LeafNodePlan> right){
    LinkedList<List<LeafNodePlan>> result = new LinkedList<List<LeafNodePlan>>();
    result.add(left);
    result.add(right);
    return result;
  }
 
  /**
   * This method generates the result by adding the parameter splittedPart and other leaf node plans from initialPlans to a list
   * @param initialPlans all leaf node plans
   * @param splittedPart the part of initialPlans to split
   * @return a list containing splittedPart  and (initialPlans - splittedPart) as elements
   */
  private LinkedList<List<LeafNodePlan>> generateResultByDividing(List<LeafNodePlan> initialPlans, List<LeafNodePlan> splittedPart){
    LinkedList<List<LeafNodePlan>> result = new LinkedList<List<LeafNodePlan>>();
    result.add(splittedPart);
   
    LinkedList<LeafNodePlan> otherPart = new LinkedList<LeafNodePlan>(initialPlans);
    otherPart.removeAll(splittedPart);
    result.add(otherPart);
   
    return result;
  }
}
TOP

Related Classes of lupos.optimizations.physical.joinorder.costbasedoptimizer.splitheuristic.SplitStarShapedJoinOrPath

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.