[Mulgara-svn] r1736 - trunk/src/jar/krule/java/org/mulgara/krule

alexhall at mulgara.org alexhall at mulgara.org
Fri Jun 12 00:35:29 UTC 2009


Author: alexhall
Date: 2009-06-11 17:35:28 -0700 (Thu, 11 Jun 2009)
New Revision: 1736

Modified:
   trunk/src/jar/krule/java/org/mulgara/krule/Rule.java
Log:
Modify the rule engine to support any multiple of 3 columns in the selection variables of a rule's query.  This allows rules to have multiple atoms in their heads, and is a more efficient implementation than splitting such rules into multiple rules with the same body and one head atom each.

Modified: trunk/src/jar/krule/java/org/mulgara/krule/Rule.java
===================================================================
--- trunk/src/jar/krule/java/org/mulgara/krule/Rule.java	2009-06-11 02:02:17 UTC (rev 1735)
+++ trunk/src/jar/krule/java/org/mulgara/krule/Rule.java	2009-06-12 00:35:28 UTC (rev 1736)
@@ -17,21 +17,32 @@
 package org.mulgara.krule;
 
 // Java 2 standard packages
+import static org.mulgara.krule.RuleStructure.UNINITIALIZED;
+
 import java.io.Serializable;
-import java.util.*;
+import java.math.BigInteger;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
 
-// Third party packages
 import org.apache.log4j.Logger;
-
-// Locally written packages
-import org.mulgara.query.*;
+import org.mulgara.query.Answer;
+import org.mulgara.query.AnswerImpl;
+import org.mulgara.query.Cursor;
+import org.mulgara.query.Query;
+import org.mulgara.query.QueryException;
+import org.mulgara.query.TuplesException;
+import org.mulgara.query.Variable;
 import org.mulgara.resolver.OperationContext;
 import org.mulgara.resolver.spi.LocalizedTuples;
 import org.mulgara.resolver.spi.Resolver;
 import org.mulgara.resolver.spi.ResolverException;
+import org.mulgara.resolver.spi.Statements;
 import org.mulgara.resolver.spi.SystemResolver;
-import org.mulgara.resolver.spi.TuplesWrapperStatements;
-import static org.mulgara.krule.RuleStructure.UNINITIALIZED;
+import org.mulgara.store.tuples.Tuples;
 
 /**
  * Represents a single executable rule.
@@ -225,7 +236,7 @@
    * @throws ResolverException There was an error inserting the data.
    */
   private void insertData(Answer answer, Resolver resolver, SystemResolver sysResolver) throws TuplesException, ResolverException {
-    TuplesWrapperStatements statements = convertToStatements(answer, sysResolver);
+    Statements statements = convertToStatements(answer, sysResolver);
     try {
       resolver.modifyModel(targetGraph, statements, true);
     } finally {
@@ -235,16 +246,131 @@
 
 
   /**
-   * Converts an Answer with 3 selection values to a set of statements for insertion.
+   * Converts an Answer with a multiple of 3 selection values to a set of statements for insertion.
    * @param answer The answer to convert.
    * @param resolver The resolver used for localizing the results, since Answers are globalized.
    *        TODO: remove this round trip of local->global->local.
    * @return A set of Statements.
    * @throws TuplesException The statements could not be instantiated.
    */
-  private TuplesWrapperStatements convertToStatements(Answer answer, SystemResolver resolver) throws TuplesException {
-    Variable[] vars = answer.getVariables();
-    assert vars.length == 3;
-    return new TuplesWrapperStatements(new LocalizedTuples(resolver, answer, true), vars[0], vars[1], vars[2]);
+  private Statements convertToStatements(Answer answer, SystemResolver resolver) throws TuplesException {
+    assert answer.getVariables().length % 3 == 0;
+    return new TuplesStatements(new LocalizedTuples(resolver, answer, true));
   }
+  
+  /**
+   * Wrapper for converting a Tuples to a Statements object.  Unlike the
+   * TuplesWrapperStatements class, this class handles Tuples whose row length is
+   * an arbitrary multiple of 3.  Subject, predicate, and object are determined
+   * by column index in the Tuples, not by a variable mapping as is the case
+   * in TuplesWrapperStatements.
+   */
+  protected static class TuplesStatements implements Statements {
+    
+    private static List<Variable> variables = 
+      Arrays.asList(Statements.SUBJECT, Statements.PREDICATE, Statements.OBJECT);
+    
+    private static int statementSize = variables.size();
+    
+    private int wrappedRowLength;
+    private int statementsPerRow;
+    private int offsetInRow = 0;
+    private Tuples tuples;
+    
+    /**
+     * Construct a wrapper around the tuples.
+     * @param tuples The Tuples to convert to statements; the number of columns
+     * must be a multiple of three.
+     */
+    public TuplesStatements(Tuples tuples) {
+      this.tuples = tuples;
+      if (tuples.getNumberOfVariables() % 3 != 0) throw new IllegalArgumentException("Number of variables must be a multiple of 3");
+      this.wrappedRowLength = tuples.getNumberOfVariables();
+      this.statementsPerRow = wrappedRowLength / statementSize;
+    }
+
+    public long getObject() throws TuplesException {
+      return tuples.getColumnValue(offsetInRow + 2);
+    }
+
+    public long getPredicate() throws TuplesException {
+      return tuples.getColumnValue(offsetInRow + 1);
+    }
+
+    public long getSubject() throws TuplesException {
+      return tuples.getColumnValue(offsetInRow);
+    }
+
+    public void beforeFirst() throws TuplesException {
+      // Setting the offset past the end of the row forces a call to tuples.next()
+      offsetInRow = wrappedRowLength;
+      tuples.beforeFirst();
+    }
+
+    public Object clone() {
+      try {
+        TuplesStatements cloned = (TuplesStatements)super.clone();
+        cloned.tuples = (Tuples)tuples.clone();
+        return cloned;
+      } catch (CloneNotSupportedException e) {
+        throw new Error("Clone ought to be supported.");
+      }
+    }
+
+    public void close() throws TuplesException {
+      tuples.close();
+    }
+
+    public int getColumnIndex(Variable column) throws TuplesException {
+      return variables.indexOf(column);
+    }
+
+    public int getNumberOfVariables() {
+      return variables.size();
+    }
+
+    public int getRowCardinality() throws TuplesException {
+      int cardinality = tuples.getRowCardinality();
+      if (cardinality == Cursor.ONE && statementsPerRow > 1) {
+        cardinality = Cursor.MANY;
+      }
+      return cardinality;
+    }
+
+    public long getRowCount() throws TuplesException {
+      if (statementsPerRow > 1) {
+        BigInteger rowCount = BigInteger.valueOf(tuples.getRowCount());
+        rowCount = rowCount.multiply(BigInteger.valueOf(statementsPerRow));
+        return rowCount.bitLength() > 63 ? Long.MAX_VALUE : rowCount.longValue();
+      }
+      return tuples.getRowCount();
+    }
+
+    public long getRowUpperBound() throws TuplesException {
+      if (statementsPerRow > 1) {
+        BigInteger rowBound = BigInteger.valueOf(tuples.getRowUpperBound());
+        rowBound = rowBound.multiply(BigInteger.valueOf(statementsPerRow));
+        return rowBound.bitLength() > 63 ? Long.MAX_VALUE : rowBound.longValue();
+      }
+      return tuples.getRowUpperBound();
+    }
+
+    public Variable[] getVariables() {
+      return variables.toArray(new Variable[statementSize]);
+    }
+
+    public boolean isUnconstrained() throws TuplesException {
+      return tuples.isUnconstrained();
+    }
+
+    public boolean next() throws TuplesException {
+      offsetInRow += statementSize;
+      if (offsetInRow >= wrappedRowLength) {
+        offsetInRow = 0;
+        return tuples.next();
+      }
+      return true;
+    }
+    
+  }
 }




More information about the Mulgara-svn mailing list