es.upm.fi.dia.oeg.ogsadai.sparql.optimizers.WellDesignedRule3Optimiser.java Source code

Java tutorial

Introduction

Here is the source code for es.upm.fi.dia.oeg.ogsadai.sparql.optimizers.WellDesignedRule3Optimiser.java

Source

// Copyright (c) Copyright (c) The University of Edinburgh, Universidad Politecnica de Madrid, 2009-2012.
//
// LICENCE-START
// Licensed 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.
// LICENCE-END

package es.upm.fi.dia.oeg.ogsadai.sparql.optimizers;

import java.util.ArrayList;
import java.util.List;

import org.apache.log4j.Logger;

import uk.org.ogsadai.dqp.common.CompilerConfiguration;
import uk.org.ogsadai.dqp.common.RequestDetails;
import uk.org.ogsadai.dqp.lqp.Attribute;
import uk.org.ogsadai.dqp.lqp.CommonPredicate;
import uk.org.ogsadai.dqp.lqp.Operator;
import uk.org.ogsadai.dqp.lqp.OperatorID;
import uk.org.ogsadai.dqp.lqp.Predicate;
import uk.org.ogsadai.dqp.lqp.exceptions.LQPException;
import uk.org.ogsadai.dqp.lqp.operators.InnerThetaJoinOperator;
import uk.org.ogsadai.dqp.lqp.operators.LeftOuterJoinOperator;
import uk.org.ogsadai.dqp.lqp.optimiser.Optimiser;
import uk.org.ogsadai.expression.ExpressionFactory;
import uk.org.ogsadai.expression.arithmetic.ExpressionException;
import uk.org.ogsadai.parser.SQLParserException;
import uk.org.ogsadai.parser.sql92query.SQLQueryParser;
import uk.org.ogsadai.resource.dataresource.dqp.RequestDQPFederation;

import org.apache.commons.collections.ListUtils;

import es.upm.fi.dia.oeg.ogsadai.sparql.utils.SparqlDQPUtil;

/**
 * This class detects and applies rule 3 of the well designed patterns described
 * by Jorge Perez, Marcelo Arenas and Claudio Gutierrez. Identifies pattern ((P1
 * OPT P2) AND P3) and transforms it in ((P1 AND P2) OPT P3)
 * 
 * @author Carlos Buil Aranda,Oscar Corcho
 * @email cbuil@fi.upm.es, ocorcho@fi.upm.es
 * @institution Universidad Politecnica de Madrid
 * 
 */
public class WellDesignedRule3Optimiser implements Optimiser {

    /** Copyright notice. */
    private static final String COPYRIGHT_NOTICE = "Copyright (c) Universidad Politecnica de Madrid, 2010";

    /** Logger. */
    private static final Logger LOG = Logger.getLogger(WellDesignedRule3Optimiser.class.getName());

    public void addProperty(String key, String value) {
        // TODO Auto-generated method stub

    }

    public Operator optimise(Operator lqpRoot, RequestDQPFederation requestFederation,
            CompilerConfiguration compilerConfiguration, RequestDetails requestDetails) throws LQPException {
        LOG.info("Into BottomUpLQPWalker...");
        walk(lqpRoot);
        return lqpRoot;
    }

    /**
     * @param lqpRoot
     */
    private void walk(Operator lqpRoot) {
        if (lqpRoot.isBinary()) {
            traverse(lqpRoot.getChild(0));
            traverse(lqpRoot.getChild(1));
        } else {
            traverse(lqpRoot.getChild(0));
        }
    }

    /**
     * @param lqpRoot
     */
    private void traverse(Operator lqpRoot) {
        if (lqpRoot != null) {
            if (lqpRoot.isBinary()) {
                traverse(lqpRoot.getChild(0));
                traverse(lqpRoot.getChild(1));
            } else {
                if (isServiceScan(lqpRoot)) {
                    LOG.info("SERVICE SCAN, attributes: " + lqpRoot.getHeading().getAttributes());
                    if (lqpRoot.getParent().getID() == OperatorID.getInstance("LEFT_OUTER_JOIN")) {
                        if (!lqpRoot.getParent().getChild(0).equals(lqpRoot)) {
                            if (lqpRoot.getParent().getParent().getID() == OperatorID
                                    .getInstance("INNER_THETA_JOIN")) {
                                LOG.debug("Pattern 3 found...");
                                if (checkSafeCondition(lqpRoot.getParent().getParent().getChild(1),
                                        lqpRoot.getParent())) {
                                    LOG.debug("pattern safe: " + lqpRoot.getID());
                                    // pattern ((P1 OPT P2) AND P3) found
                                    // different order than with left child
                                    // (getChild(0))

                                    // careful with the order of the operators
                                    // in this operation, it might be different
                                    // depending on the right/side of the
                                    // pattern found
                                    Operator optimisedOperator = null;
                                    Operator parent = null;
                                    parent = lqpRoot.getParent();
                                    Operator grandPaPaOperator = parent.getParent().getParent();
                                    Operator rightOptOperator = lqpRoot.getParent().getChild(1);
                                    optimisedOperator = reorder(lqpRoot, rightOptOperator);
                                    grandPaPaOperator.disconnect();
                                    try {
                                        // grandPaOperator.disconnect();
                                        grandPaPaOperator.setChild(0, optimisedOperator);
                                        grandPaPaOperator.update();
                                    } catch (LQPException e) {
                                        // TODO Auto-generated catch block
                                        e.printStackTrace();
                                    }
                                } else {
                                    LOG.debug("pattern not safe: " + lqpRoot.getID());
                                }
                            }
                        } else if (!lqpRoot.getParent().getChild(1).equals(lqpRoot)) {
                            if (lqpRoot.getParent().getParent().getID() == OperatorID
                                    .getInstance("INNER_THETA_JOIN")) {
                                LOG.debug("Pattern 3 found...");
                                if (checkSafeCondition(lqpRoot.getParent().getParent().getChild(0),
                                        lqpRoot.getParent())) {
                                    LOG.debug("pattern safe: " + lqpRoot.getID());
                                    // pattern ((P1 OPT P2) AND P3) found
                                    // different order than with left child
                                    // (getChild(0))

                                    // careful with the order of the operators
                                    // in this operation, it might be different
                                    // depending on the right/side of the
                                    // pattern found
                                    Operator optimisedOperator = null;
                                    Operator parent = null;
                                    parent = lqpRoot.getParent();
                                    Operator grandPaPaOperator = parent.getParent().getParent();
                                    Operator rightOptOperator = lqpRoot.getParent().getChild(1);
                                    optimisedOperator = reorder(lqpRoot, rightOptOperator);
                                    grandPaPaOperator.disconnect();
                                    try {
                                        // grandPaOperator.disconnect();
                                        grandPaPaOperator.setChild(0, optimisedOperator);
                                        grandPaPaOperator.update();
                                    } catch (LQPException e) {
                                        // TODO Auto-generated catch block
                                        e.printStackTrace();
                                    }
                                } else {
                                    LOG.debug("pattern NOT safe: " + lqpRoot.getID());
                                }
                            }
                        }

                    }
                } else {
                    traverse(lqpRoot.getChild(0));
                }
            }
        }
        LOG.info("bottom of the LQP");
    }

    /**
     * checks if the current operator's child is a PROJECT + SERVICE_SCAN
     * operator
     * 
     * @param child
     * @return
     */
    private boolean isServiceScan(Operator child) {
        if (child.getChildCount() > 0 & child.getID() == OperatorID.getInstance("PROJECT")) {
            if (child.getChild(0).getID() == OperatorID.getInstance("RDF_SERVICE_SCAN")) {
                return true;
            }
        }
        return false;
    }

    /**
     * checks safe condition (variables in P1 are in P2 and P')
     * 
     * @param ousideOperator
     *            operator P'
     * @param optionalOperator
     *            (P1 OPT P2)
     * 
     * @return true if pattern is safe
     */
    private boolean checkSafeCondition(Operator ousideOperator, Operator optionalOperator) {
        List<String> pPrimeAttrs = new ArrayList<String>();
        // getting variables from left side of AND (parent operator)
        for (Attribute attribute : ousideOperator.getHeading().getAttributes()) {
            pPrimeAttrs.add(attribute.getName());
        }

        // getting variables from P2
        List<String> p2Attrs = new ArrayList<String>();
        for (Attribute attribute : optionalOperator.getChild(1).getHeading().getAttributes()) {
            p2Attrs.add(attribute.getName());
        }
        // p2Attrs.addAll(pPrimeAttrs);

        List<String> intersection = null;
        intersection = new ArrayList<String>();
        intersection = ListUtils.intersection(pPrimeAttrs, p2Attrs);
        // getting variables from P2
        List<String> p1Attrs = new ArrayList<String>();
        for (Attribute attribute : optionalOperator.getChild(0).getHeading().getAttributes()) {
            p1Attrs.add(attribute.getName());
        }

        if (p1Attrs.containsAll(intersection)) {
            return true;
        }
        return false;
    }

    /**
     * This class applies Rule 2 reordering the operators
     * 
     * @param p1Operator
     * @param rightOptOperator
     * @return operator optimised operator
     * 
     */
    private Operator reorder(Operator p1Operator, Operator rightOptOperator) {
        // I get (P1 AND (P2 OPT P3)) p1 is the current operator
        List<String> predicateList = new ArrayList<String>();
        List<Attribute> entry = new ArrayList<Attribute>();
        Operator p2Operator = null;
        p2Operator = rightOptOperator;
        Operator p3Operator = null;
        if (!rightOptOperator.getParent().getParent().getChild(0).equals(rightOptOperator.getParent())) {
            p3Operator = rightOptOperator.getParent().getParent().getChild(0);
        } else {
            p3Operator = rightOptOperator.getParent().getParent().getChild(1);
        }

        // add all attributes to the AND operator
        entry.addAll(p1Operator.getHeading().getAttributes());
        entry.addAll(p3Operator.getHeading().getAttributes());

        predicateList = SparqlDQPUtil.getPredicate(entry);
        Operator newOptional = null;

        // I just use the first predicate
        Predicate p = null;
        Operator newInnerJoin = null;
        try {
            p = new CommonPredicate(ExpressionFactory.buildExpression(
                    SQLQueryParser.getInstance().parseSQLForCondition(predicateList.get(0)), null));
            newInnerJoin = new InnerThetaJoinOperator(p);
            SparqlDQPUtil.connectBinary(newInnerJoin, p1Operator, p3Operator);
            newInnerJoin.update();

            // I create now the OPTIONAL part which will be connected to the
            // previous AND

            entry = new ArrayList<Attribute>();
            entry.addAll(newInnerJoin.getHeading().getAttributes());
            entry.addAll(p2Operator.getHeading().getAttributes());
            // I create new join condition using new AND operator attributes
            // and left child attributes from OPT
            predicateList = SparqlDQPUtil.getPredicate(entry);

            p = new CommonPredicate(ExpressionFactory.buildExpression(
                    SQLQueryParser.getInstance().parseSQLForCondition(predicateList.get(0)), null));
            newOptional = new LeftOuterJoinOperator(p);
            SparqlDQPUtil.connectBinary(newOptional, newInnerJoin, p2Operator);
            newOptional.update();

        } catch (ExpressionException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (SQLParserException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (LQPException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        return newOptional;
    }
}