Package de.fuberlin.wiwiss.d2rq.engine

Source Code of de.fuberlin.wiwiss.d2rq.engine.TripleRelationJoiner$AttributeSet

package de.fuberlin.wiwiss.d2rq.engine;

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

import com.hp.hpl.jena.graph.Triple;
import com.hp.hpl.jena.sparql.core.Var;

import de.fuberlin.wiwiss.d2rq.algebra.AliasMap;
import de.fuberlin.wiwiss.d2rq.algebra.AliasMap.Alias;
import de.fuberlin.wiwiss.d2rq.algebra.Attribute;
import de.fuberlin.wiwiss.d2rq.algebra.Join;
import de.fuberlin.wiwiss.d2rq.algebra.VariableConstraints;
import de.fuberlin.wiwiss.d2rq.algebra.NodeRelation;
import de.fuberlin.wiwiss.d2rq.algebra.OrderSpec;
import de.fuberlin.wiwiss.d2rq.algebra.ProjectionSpec;
import de.fuberlin.wiwiss.d2rq.algebra.Relation;
import de.fuberlin.wiwiss.d2rq.algebra.RelationImpl;
import de.fuberlin.wiwiss.d2rq.algebra.RelationName;
import de.fuberlin.wiwiss.d2rq.algebra.TripleRelation;
import de.fuberlin.wiwiss.d2rq.expr.Conjunction;
import de.fuberlin.wiwiss.d2rq.expr.Expression;
import de.fuberlin.wiwiss.d2rq.nodes.NodeMaker;
import de.fuberlin.wiwiss.d2rq.sql.ConnectedDB;

class TripleRelationJoiner {
 
  public static TripleRelationJoiner create(boolean allOptimizations) {
    return new TripleRelationJoiner(new VariableConstraints(),
        Collections.<Triple>emptyList(), Collections.<NodeRelation>emptyList(),
        allOptimizations);
  }

  private final VariableConstraints nodeSets;
  private final List<Triple> joinedTriplePatterns;
  private final List<NodeRelation> joinedTripleRelations;
  private final boolean useAllOptimizations;
 
  private TripleRelationJoiner(VariableConstraints nodeSets,
      List<Triple> patterns, List<NodeRelation> relations, boolean useAllOptimizations) {
    this.nodeSets = nodeSets;
    this.joinedTriplePatterns = patterns;
    this.joinedTripleRelations = relations;
    this.useAllOptimizations = useAllOptimizations;
  }
 
  public List<TripleRelationJoiner> joinAll(Triple pattern,
      List<NodeRelation> candidates) {
    List<TripleRelationJoiner> results = new ArrayList<TripleRelationJoiner>();
    for (NodeRelation tripleRelation: candidates) {
      TripleRelationJoiner nextJoiner = join(pattern, tripleRelation);
      if (nextJoiner != null) {
        results.add(nextJoiner);
      }
    }
    return results;
  }
 
  private static boolean isUnique(ConnectedDB database, RelationName originalName,
      Set<String> attributeNames)
  {
    Map<String,List<String>> uniqueKeys = database.getUniqueKeyColumns(originalName);
    if (uniqueKeys != null) {
    for (List<String> indexColumns: uniqueKeys.values()) {
        if (attributeNames.containsAll(indexColumns)) {
          return true;
        }
      }
    }
    List<Attribute> primaryKeys = database.schemaInspector().primaryKeyColumns(originalName);
    if (primaryKeys != null) {
      for (Attribute attr: primaryKeys) {
        if (!attributeNames.contains(attr.attributeName()))
          return false;
      }
      return true;
    }
    return false;
  }
 
  private static class AttributeSet {
    RelationName relationName = null;
    Set<String> attributeNames = new TreeSet<String>();
   
    /*
     * Determine the attributes that make up a nodemakers projection spec
     * all must stem from the same table
     */
    static AttributeSet createFrom(NodeMaker nodeMaker)
    {
      AttributeSet attributes = new AttributeSet();
      Set<ProjectionSpec> projectionSpecs = nodeMaker.projectionSpecs();
      boolean err = projectionSpecs.isEmpty();
     
      Iterator<ProjectionSpec> projectionIterator = projectionSpecs.iterator();
      while (projectionIterator.hasNext() && !err) {
        ProjectionSpec projection = (ProjectionSpec) projectionIterator.next();
       
        Set<Attribute> reqAttr = projection.requiredAttributes();
        Iterator<Attribute> j = reqAttr.iterator();
        while (j.hasNext() && !err) {
          Attribute a = (Attribute) j.next();
          if (attributes.relationName == null)
            attributes.relationName = a.relationName();
          else if (!attributes.relationName.equals(a.relationName()))
            err = true;
         
          attributes.attributeNames.add(a.attributeName());
        }
       
//        if (projection instanceof Attribute) {
//          Attribute a = (Attribute) projection;
//          if (attributes.relationName == null)
//            attributes.relationName = a.relationName();
//          else if (!attributes.relationName.equals(a.relationName()))
//            err = true;
//         
//          attributes.attributeNames.add(a.attributeName());
//        } else {
//          err = true;
//        }
      }
     
      if (!err)
        return attributes;
     
      return null;
    }
  }
 
  private List<RelationName> getRelationNames(NodeMaker nodeMaker)
  {
    List<RelationName> result = new ArrayList<RelationName>();
    Set<ProjectionSpec> projectionSpecs = nodeMaker.projectionSpecs();
    for (ProjectionSpec spec: projectionSpecs) {
      for (Attribute a: spec.requiredAttributes()) {
        result.add(a.relationName());
      }
    }
    return result;
  }
 
  public TripleRelationJoiner join(Triple pattern, NodeRelation relation) {
    List<Triple> newPatterns = new ArrayList<Triple>(joinedTriplePatterns);
    newPatterns.add(pattern);
    List<NodeRelation> newRelations = new ArrayList<NodeRelation>(joinedTripleRelations);
    newRelations.add(relation);

    VariableConstraints nodeSets = new VariableConstraints();
    for (int i = 0; i < newPatterns.size(); i++) {
      Triple t = (Triple) newPatterns.get(i);
      NodeRelation r = newRelations.get(i);

      if (useAllOptimizations) {
        /*
         * Before adding a NodeMaker, try to adopt aliases from existing NodeMakers
         * in order to prevent unnecessary self-joins (#2798308)
         */
        // This failed when originalName had more than 1 alias r.baseRelation (fixed, GM)
        List<String> names = new ArrayList<String>();
 
        if (t.getSubject().isVariable())
          names.add(t.getSubject().getName());
        if (t.getPredicate().isVariable())
          names.add(t.getPredicate().getName());
        if (t.getObject().isVariable())
          names.add(t.getObject().getName());
 
        for (String name: names) {
          Var nameVar = Var.alloc(name);
          NodeMaker n = (NodeMaker) nodeSets.toMap().get(nameVar);
          if (n != null/* && n instanceof TypedNodeMaker*/) {

            AttributeSet attributes = AttributeSet.createFrom(n);
            /*
             * If we would set an alias to this table...
             */
            if (attributes != null) {
              AliasMap amap = (AliasMap)(nodeSets.relationAliases().get(nameVar));
              RelationName originalName = amap.originalOf(attributes.relationName);
              if (r.baseRelation().aliases().hasAlias(originalName)) {

                /*
                 * ... and indexes are in place to guarantee uniqueness of the attribute combination...
                 */
                if (isUnique(r.baseRelation().database(), originalName, attributes.attributeNames)) {
                 
                  if (t.getSubject().isVariable() && t.getSubject().getName().equals(name)) {
                    // ... then first find the right relation name...
                    AttributeSet existing = AttributeSet.createFrom(r.nodeMaker(TripleRelation.SUBJECT));
                    if (existing != null && existing.attributeNames.equals(attributes.attributeNames)) {
                      // ... then apply it
                      r = r.renameSingleRelation(existing.relationName, attributes.relationName);
                      newRelations.set(i, r);
                    }
                  }
                 
                  if (t.getPredicate().isVariable() && t.getPredicate().getName().equals(name)) {
                    // ... then first find the right relation name...
                    AttributeSet existing = AttributeSet.createFrom(r.nodeMaker(TripleRelation.PREDICATE));
                    if (existing != null && existing.attributeNames.equals(attributes.attributeNames)) {
                      // ... then apply it
                      r = r.renameSingleRelation(existing.relationName, attributes.relationName);
                      newRelations.set(i, r);
                    }
                  }
                 
                  if (t.getObject().isVariable() && t.getObject().getName().equals(name)) {
                    // ... then first find the right relation name...
                    AttributeSet existing = AttributeSet.createFrom(r.nodeMaker(TripleRelation.OBJECT));
                    if (existing != null && existing.attributeNames.equals(attributes.attributeNames)) {
                      // ... then apply it
                      r = r.renameSingleRelation(existing.relationName, attributes.relationName);
                      newRelations.set(i, r);
                    }
                  }
                }             
              }
            }
          }
        }
      }
     
      if (t.getObject().isVariable()) {
        List<RelationName> relationNames = getRelationNames(
            r.nodeMaker(TripleRelation.OBJECT));
        Set<Alias> aliases = new HashSet<Alias>();
               
        for (RelationName rname: relationNames) {
          if (r.baseRelation().aliases().isAlias(rname))
            aliases.add(new AliasMap.Alias(r.baseRelation().aliases().originalOf(rname), rname));
        }
        nodeSets.add(Var.alloc(t.getObject()), r.nodeMaker(TripleRelation.OBJECT), new AliasMap(aliases));
      }
     
      if (t.getPredicate().isVariable()) {
        List<RelationName> relationNames = getRelationNames(
            r.nodeMaker(TripleRelation.PREDICATE));
        Set<Alias> aliases = new HashSet<Alias>();
               
        for (RelationName rname: relationNames) {
          if (r.baseRelation().aliases().isAlias(rname))
            aliases.add(new AliasMap.Alias(r.baseRelation().aliases().originalOf(rname), rname));
        }
        nodeSets.add(Var.alloc(t.getPredicate()), r.nodeMaker(TripleRelation.PREDICATE), new AliasMap(aliases));
      }
     
      if (t.getSubject().isVariable()) {
        List<RelationName> relationNames = getRelationNames(
            r.nodeMaker(TripleRelation.SUBJECT));
        Set<Alias> aliases = new HashSet<Alias>();
               
        for (RelationName rname: relationNames) {
          if (r.baseRelation().aliases().isAlias(rname))
            aliases.add(new AliasMap.Alias(r.baseRelation().aliases().originalOf(rname), rname));
        }
        nodeSets.add(Var.alloc(t.getSubject()), r.nodeMaker(TripleRelation.SUBJECT), new AliasMap(aliases));
      }

    }
    if (!nodeSets.satisfiable()) {
      return null;
    }
    return new TripleRelationJoiner(nodeSets, newPatterns, newRelations, useAllOptimizations);
  }
 
  public NodeRelation toNodeRelation() {
    return new NodeRelation(
        joinedBaseRelation().select(
            nodeSets.constraint()).project(nodeSets.allProjections()),
        nodeSets.toMap());
  }
 
  private Relation joinedBaseRelation() {
    List<Relation> relations = new ArrayList<Relation>();
    for (NodeRelation tripleRelation: joinedTripleRelations) {
      relations.add(tripleRelation.baseRelation());
    }
    return joinRelations(relations, Expression.TRUE);
  }
 
  /**
   * Static convenience function that joins several {@link Relation}s into one. Exposed here
   * because it can be used in the old FastPath engine.
   *
   * @param relations A set of {@link Relation}s
   * @param additionalCondition An additional expression, e.g. join condition
   * @return A relation that is the join of the inputs
   */
  private Relation joinRelations(Collection<Relation> relations, Expression additionalCondition) {
    if (relations.isEmpty()) {
      return Relation.TRUE;
    }
    ConnectedDB connectedDB = ((Relation) relations.iterator().next()).database();
    AliasMap joinedAliases = AliasMap.NO_ALIASES;
    Collection<Expression> expressions = new HashSet<Expression>();
    expressions.add(additionalCondition);
    Collection<Expression> softConditions = new HashSet<Expression>();
    Set<Join> joins = new HashSet<Join>();
    Set<ProjectionSpec> projections = new HashSet<ProjectionSpec>();
    int limit = Relation.NO_LIMIT;
    int limitInverse = Relation.NO_LIMIT;
    List<OrderSpec> orderSpecs = null;
   
    for (Relation relation: relations) {
      joinedAliases = joinedAliases.applyTo(relation.aliases());
      expressions.add(relation.condition());
      softConditions.add(relation.softCondition());
      joins.addAll(relation.joinConditions());
      projections.addAll(relation.projections());
      orderSpecs = orderSpecs == null ? relation.orderSpecs() : orderSpecs;
      limit = Relation.combineLimits(limit, relation.limit());
      limitInverse = Relation.combineLimits(limitInverse, relation.limitInverse());
    }
    // TODO: Determine correct uniqueness instead of just false.
    // The new relation is unique if it is joined only on unique node sets.
    // A node set is unique if it is constrained by only unique node makers.
   
    // In the meantime, copy the uniqueness from the relation if there's just one
    boolean isUnique = relations.size() == 1 && (relations.iterator().next()).isUnique();
    return new RelationImpl(connectedDB, joinedAliases, Conjunction.create(expressions),
        Conjunction.create(softConditions),
        joins, projections, isUnique, orderSpecs, limit, limitInverse);
  }
}
TOP

Related Classes of de.fuberlin.wiwiss.d2rq.engine.TripleRelationJoiner$AttributeSet

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.