[Mulgara-svn] r1511 - trunk/src/jar/resolver-lucene/java/org/mulgara/resolver/lucene

ronald at mulgara.org ronald at mulgara.org
Tue Feb 17 12:36:20 UTC 2009


Author: ronald
Date: 2009-02-17 04:36:16 -0800 (Tue, 17 Feb 2009)
New Revision: 1511

Modified:
   trunk/src/jar/resolver-lucene/java/org/mulgara/resolver/lucene/FullTextStringIndex.java
   trunk/src/jar/resolver-lucene/java/org/mulgara/resolver/lucene/FullTextStringIndexTuples.java
   trunk/src/jar/resolver-lucene/java/org/mulgara/resolver/lucene/LuceneResolver.java
Log:
Second attempt at allowing lucene-resolver results to be lazy. Split the
FullTextStringIndexTuples into two, and materialize it for all queries
except fully unconstrained $s $p $o queries (so that things like export
can stream the result out). Support for definable-prefixes is now back in,
albeit in a limited fashion (HybridTuples does not support it, hence it's
only supported in the non-materialized scenario).

Also added some optimizations like sorting the hits by document-id order
for faster doc retrieval.

Modified: trunk/src/jar/resolver-lucene/java/org/mulgara/resolver/lucene/FullTextStringIndex.java
===================================================================
--- trunk/src/jar/resolver-lucene/java/org/mulgara/resolver/lucene/FullTextStringIndex.java	2009-02-17 11:45:47 UTC (rev 1510)
+++ trunk/src/jar/resolver-lucene/java/org/mulgara/resolver/lucene/FullTextStringIndex.java	2009-02-17 12:36:16 UTC (rev 1511)
@@ -31,6 +31,8 @@
 import java.io.IOException;
 import java.io.Reader;
 import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
 import java.util.List;
 
 // Log4J
@@ -818,6 +820,14 @@
       return hits.get(n).score;
     }
 
+    public void sort() {
+      Collections.sort(hits, new Comparator<ScoreDoc>() {
+        public int compare(ScoreDoc sd1, ScoreDoc sd2) {
+          return (sd1.doc < sd2.doc) ? -1 : (sd1.doc == sd2.doc) ? 0 : +1;
+        }
+      });
+    }
+
     public void close() throws IOException {
       if (closed) return;
 

Modified: trunk/src/jar/resolver-lucene/java/org/mulgara/resolver/lucene/FullTextStringIndexTuples.java
===================================================================
--- trunk/src/jar/resolver-lucene/java/org/mulgara/resolver/lucene/FullTextStringIndexTuples.java	2009-02-17 11:45:47 UTC (rev 1510)
+++ trunk/src/jar/resolver-lucene/java/org/mulgara/resolver/lucene/FullTextStringIndexTuples.java	2009-02-17 12:36:16 UTC (rev 1511)
@@ -40,7 +40,7 @@
 import org.apache.log4j.Logger;
 import org.apache.lucene.document.Document;
 import org.apache.lucene.document.FieldSelector;
-import org.apache.lucene.document.FieldSelectorResult;
+import org.apache.lucene.document.MapFieldSelector;
 
 // JRDf
 import org.jrdf.graph.BlankNode;
@@ -51,7 +51,6 @@
 import org.mulgara.query.Constraint;
 import org.mulgara.query.ConstraintElement;
 import org.mulgara.query.LocalNode;
-import org.mulgara.query.QueryException;
 import org.mulgara.query.TuplesException;
 import org.mulgara.query.Variable;
 import org.mulgara.query.rdf.LiteralImpl;
@@ -64,65 +63,50 @@
 import org.mulgara.store.tuples.Annotation;
 import org.mulgara.store.tuples.DefinablePrefixAnnotation;
 import org.mulgara.store.tuples.MandatoryBindingAnnotation;
+import org.mulgara.store.tuples.RowComparator;
 import org.mulgara.store.tuples.Tuples;
+import org.mulgara.store.tuples.TuplesOperations;
 
 /**
- * A {@link Tuples} backed by a {@link FullTextStringIndex}.
+ * A {@link Tuples} backed by a {@link FullTextStringIndex}. This is split into two parts, an
+ * upper layer which mostly delegates all methods to another tuples, and a lower layer which is
+ * a direct tuples around the lucene search hits. This allows us to conditionally materialize
+ * the results by materializing the lower-layer tuples.
  *
+ * <p>The observed performance of lucene is such that running one larger query is faster than
+ * running, say, 100 smaller queries; at the same time, however, retrieving all the documents
+ * for the results usually takes several times longer than the actual query took. We therefore
+ * run a single query for the given constraint (rather than, say, running a query on each
+ * <code>beforeFirst</code> with the currently bound values) which gathers the document id's
+ * and scores. The documents are then retrieved on-demand by the lower-layer tuples; for most
+ * queries we then just materialize that tuples rather than creating our own document-cache
+ * (lucene does not explicitly cache documents) so repeated iterations over the results are
+ * fast.
+ *
  * @created 2002-03-27
- *
  * @author <a href="http://staff.pisoftware.com/raboczi">Simon Raboczi</a>
- *
- * @version $Revision: 1.10 $
- *
- * @modified $Date: 2005/05/02 20:07:57 $
- *
- * @maintenanceAuthor $Author: raboczi $
- *
  * @company <A href="mailto:info at PIsoftware.com">Plugged In Software</A>
- *
  * @copyright &copy; 2002-2004 <A href="http://www.PIsoftware.com/">Plugged In
  *      Software Pty Ltd</A>
- *
  * @licence <a href="{@docRoot}/../../LICENCE">Mozilla Public License v1.1</a>
  */
 class FullTextStringIndexTuples extends AbstractTuples implements Resolution, Cloneable {
   /** Logger.  */
   private final static Logger logger = Logger.getLogger(FullTextStringIndexTuples.class);
 
-  /** The native Lucene query result to represent as a {@link Tuples}. */
-  private FullTextStringIndex.Hits hits;
-
-  /** Which fields to load from the documents. */
-  private FieldSelector fieldSelector;
-
-  /**
-   * The current document within the {@link #hits}.
-   *
-   * A Lucene document hit corresponds to a {@link Tuples} row.
-   */
-  private Document document;
-
-  /** The index of the next {@link #document} within the {@link #hits}. */
-  private int nextDocumentIndex = 0;
-
   /** Session used to localize Lucene text into string pool nodes. */
   private final ResolverSession session;
 
-  /** The number of items in tuples */
-  private long rowCount = -1;
-
   /** The upper bound on the number of items in tuples */
   private long rowUpperBound = -1;
 
+  /** The real results. */
+  private Tuples results = null;
+
   /** The list of variables as found in the constraint */
   private final List<Variable> constrVariableList = new ArrayList<Variable>(4);
   /** The list of lucene keys corresponding to the variables found in the constraint */
   private final List<String> constrLuceneKeyList = new ArrayList<String>(3);
-  /** The current list of variables (possibly re-ordered from definePrefix()) */
-  private final List<Variable> variableList = new ArrayList<Variable>(4);
-  /** The list of lucene keys corresponding to the (re-ordered) variable-list */
-  private final List<String> luceneKeyList = new ArrayList<String>(3);
 
   private final FullTextStringIndex fullTextStringIndex;
   private final LuceneConstraint constraint;
@@ -146,10 +130,10 @@
    * @param fullTextStringIndex PARAMETER TO DO
    * @param constraint the single constraint
    * @param session a session context for globalization, etc
-   * @throws QueryException if the set of triples couldn't be determined
+   * @throws TuplesException if the set of triples couldn't be determined
    */
   FullTextStringIndexTuples(FullTextStringIndex fullTextStringIndex,
-      LuceneConstraint constraint, ResolverSession session) throws QueryException {
+      LuceneConstraint constraint, ResolverSession session) throws TuplesException {
     this.fullTextStringIndex = fullTextStringIndex;
     this.session = session;
     this.constraint = constraint;
@@ -186,8 +170,25 @@
 
     setVariables(constrVariableList);
 
-    variableList.addAll(constrVariableList);
-    luceneKeyList.addAll(constrLuceneKeyList);
+    /* run the query now and materialize the result; it is often much faster to run a large query
+     * and grab all resulting lucene documents than it is to run many smaller queries. Ideally we
+     * would try and figure out which approach is better on a query-by-query basis.
+     *
+     * One special case is the all-variable query, which retrieves the whole db - this one is not
+     * materialized because it's usually only used by export().
+     */
+    String subject = getString(subjectElement);
+    String predicate = getString(predicateElement);
+    String object = getString(objectElement);
+
+    results = new SearchHitsTuples(subject, predicate, object);
+    if (subject != null || predicate != null || object != null) {
+      Tuples old = results;
+      long t0 = System.currentTimeMillis();
+      results = TuplesOperations.materialize(results);
+      logger.debug("materialized " + results.getRowCount() + " lucene results() in " + (System.currentTimeMillis() - t0));
+      old.close();
+    }
   }
 
   //
@@ -195,55 +196,31 @@
   //
 
   public void beforeFirst(long[] prefix, int suffixTruncation) throws TuplesException {
-    final String subject = getString(subjectElement, prefix);
-    final String predicate = getString(predicateElement, prefix);
-    final String object = getString(objectElement, prefix);
-    assert (constraint.getScoreVar() == null || object != null) :
+    assert (constraint.getScoreVar() == null ||
+            getString(objectElement, prefix, constrVariableList) != null) :
            "Internal error: lucene-query string not bound even though a score is requested";
 
-    if (logger.isDebugEnabled()) {
-      logger.debug("Searching for " + subject + " : " + predicate + " : " + object);
-    }
+    results.beforeFirst(prefix, suffixTruncation);
+  }
 
-    try {
-      hits = fullTextStringIndex.find(subject, predicate, object);
-    } catch (FullTextStringIndexException e) {
-      throw new TuplesException("Couldn't generate answer from text index: subject='" + subject +
-                                "', predicate='" + predicate + "', object='" + object + "'", e);
-    }
-
-    fieldSelector = new FieldSelector() {
-      public FieldSelectorResult accept(String fieldName) {
-        if (fieldName.equals(FullTextStringIndex.SUBJECT_KEY) && subject == null ||
-            fieldName.equals(FullTextStringIndex.PREDICATE_KEY) && predicate == null ||
-            (fieldName.equals(FullTextStringIndex.LITERAL_KEY) ||
-             fieldName.equals(FullTextStringIndex.REVERSE_LITERAL_KEY)) && object == null) {
-          return FieldSelectorResult.LOAD;
-        } else {
-          return FieldSelectorResult.NO_LOAD;
-        }
-      }
-    };
-
-    document = null;
-    nextDocumentIndex = 0;
-    rowCount = -1;
-    rowUpperBound = -1;
+  private String getString(ConstraintElement ce) throws TuplesException {
+    return getString(ce, NO_PREFIX, constrVariableList);
   }
 
-  private String getString(ConstraintElement ce, long[] prefix) throws TuplesException {
+  private String getString(ConstraintElement ce, long[] prefix, List<Variable> vars) throws TuplesException {
     long boundVal = 0;
+
     if (ce instanceof LocalNode) {
       boundVal = ((LocalNode)ce).getValue();
     } else if (ce instanceof Variable) {
-      int idx = variableList.indexOf(ce);
+      int idx = vars.indexOf(ce);
       boundVal = (idx < prefix.length) ? prefix[idx] : 0;
     }
 
     if (boundVal == 0) return null;
 
     try {
-      Object val =  session.globalize(boundVal);
+      Object val = session.globalize(boundVal);
       if (val instanceof URIReference) return ((URIReference)val).getURI().toString();
       if (val instanceof Literal) return ((Literal)val).getLexicalForm();
       if (val instanceof BlankNode) return "";
@@ -255,62 +232,43 @@
   }
 
   public void close() throws TuplesException {
-    try {
-      if (hits != null) hits.close();
-    } catch (IOException ioe) {
-      throw new TuplesException("Error closing fulltext index hits", ioe);
-    }
+    if (results != null)
+      results.close();
   }
 
   public FullTextStringIndexTuples clone() {
-    FullTextStringIndexTuples clone = (FullTextStringIndexTuples) super.clone();
-    if (hits != null) clone.hits = hits.clone();
+    FullTextStringIndexTuples clone = (FullTextStringIndexTuples)super.clone();
+    if (results != null) clone.results = (Tuples)results.clone();
     return clone;
   }
 
   public long getColumnValue(int column) throws TuplesException {
-    try {
-      if (column >= 0 && column < luceneKeyList.size()) {
-        String luceneKey = luceneKeyList.get(column);
-        if (luceneKey == FullTextStringIndex.LITERAL_KEY)
-          return session.localize(new LiteralImpl(document.get(luceneKey)));
-        else
-          return session.localize(new URIReferenceImpl(new URI(document.get(luceneKey))));
-      } else if (column == luceneKeyList.size()) {
-        // Generate the score column
-        return session.localize(new LiteralImpl(hits.score(nextDocumentIndex - 1)));
-      } else {
-        throw new TuplesException("Column " + column + " does not exist");
-      }
-    } catch (IOException e) {
-      throw new TuplesException("Couldn't get column " + column + " value", e);
-    } catch (LocalizeException e) {
-      throw new TuplesException("Couldn't localize column " + column + " value", e);
-    } catch (URISyntaxException e) {
-      throw new TuplesException("Couldn't get column " + column + " value", e);
-    }
+    return results.getColumnValue(column);
   }
 
   public long getRowCount() throws TuplesException {
-    if ((rowCount == -1) && (hits != null)) {
-      rowCount = hits.length();
-    }
+    if (results == null)
+      beforeFirst();
 
-    return rowCount;
+    return results.getRowCount();
   }
 
   public long getRowUpperBound() throws TuplesException {
+    return (results != null) ? results.getRowUpperBound() : getRowUpperBoundEstimate();
+  }
+
+  private long getRowUpperBoundEstimate() throws TuplesException {
     if (rowUpperBound == -1) {
       try {
-        rowUpperBound = (hits != null) ? getRowCount() :
-            fullTextStringIndex.getMaxDocs(getString(subjectElement, Tuples.NO_PREFIX),
-                                           getString(predicateElement, Tuples.NO_PREFIX),
-                                           getString(objectElement, Tuples.NO_PREFIX));
+        rowUpperBound = (results != null) ? results.getRowCount() :
+            fullTextStringIndex.getMaxDocs(getString(subjectElement),
+                                           getString(predicateElement),
+                                           getString(objectElement));
       } catch (FullTextStringIndexException e) {
         throw new TuplesException("Couldn't row upper-bound from text index: subject='" +
-                                  getString(subjectElement, Tuples.NO_PREFIX) + "', predicate='" +
-                                  getString(predicateElement, Tuples.NO_PREFIX) + "', object='" +
-                                  getString(objectElement, Tuples.NO_PREFIX) + "'", e);
+                                  getString(subjectElement) + "', predicate='" +
+                                  getString(predicateElement) + "', object='" +
+                                  getString(objectElement) + "'", e);
       }
     }
 
@@ -323,17 +281,6 @@
     if (bound == 0) return Tuples.ZERO;
     if (bound == 1) return Tuples.ONE;
     return Tuples.MANY;
-
-    /* Exact, but slower
-    if (getRowUpperBound() == 0) return Tuples.ZERO;
-
-    if (hits == null) beforeFirst();
-
-    long count = getRowCount();
-    if (count == 0) return Tuples.ZERO;
-    if (count == 1) return Tuples.ONE;
-    return Tuples.MANY;
-    */
   }
 
   /**
@@ -346,29 +293,28 @@
   }
 
   public boolean hasNoDuplicates() throws TuplesException {
-    return false;
+    if (results == null)
+      beforeFirst();
+    return results.hasNoDuplicates();
   }
 
-  public List<Tuples> getOperands() {
-    return Collections.<Tuples>emptyList();
+  public boolean isMaterialized() {
+    return (results != null) && results.isMaterialized();
   }
 
-  public boolean next() throws TuplesException {
-    assert hits != null : "next() called without beforeFirst()";
-
-    try {
-      if (nextDocumentIndex < getRowCount()) {
-        document = hits.doc(nextDocumentIndex++, fieldSelector);
-        return true;
-      } else {
-        document = null;
-        return false;
-      }
-    } catch (IOException e) {
-      throw new TuplesException("Couldn't obtain next Lucene hit", e);
+  public RowComparator getComparator() {
+    if (results != null) {
+      return results.getComparator();
+    } else {
+      return null;
     }
   }
 
+  public boolean next() throws TuplesException {
+    assert results != null : "next() called without beforeFirst()";
+    return results.next();
+  }
+
   public Constraint getConstraint() {
     return constraint;
   }
@@ -378,6 +324,10 @@
     return false;
   }
 
+  public List<Tuples> getOperands() {
+    return Collections.singletonList(results);
+  }
+
   public Annotation getAnnotation(Class<? extends Annotation> annotationClass) throws TuplesException {
     // the object (lucene query string) is required when a score is requested
     if (annotationClass == MandatoryBindingAnnotation.class &&
@@ -385,33 +335,196 @@
       return new MandatoryBindingAnnotation(new Variable[] { (Variable)objectElement });
     }
 
-    // support re-ordering the variables so any variables can be bound in the prefix
-    if (annotationClass == DefinablePrefixAnnotation.class) {
-      return new DefinablePrefixAnnotation() {
-        public void definePrefix(Set boundVars) throws TuplesException {
-          if (boundVars.contains(constraint.getScoreVar()))
-            throw new TuplesException("Score variable may not be bound");
+    return (results != null) ? results.getAnnotation(annotationClass) : null;
+  }
 
-          variableList.clear();
-          luceneKeyList.clear();
+  private class SearchHitsTuples extends AbstractTuples {
+    /** The current list of variables (possibly re-ordered from definePrefix()) */
+    private final List<Variable> variableList = new ArrayList<Variable>(4);
+    /** The list of lucene keys corresponding to the (re-ordered) variable-list */
+    private final List<String> luceneKeyList = new ArrayList<String>(3);
 
-          for (boolean useBound : new boolean[] { true, false }) {
-            for (int idx = 0; idx < constrLuceneKeyList.size(); idx++) {
-              Variable var = constrVariableList.get(idx);
+    /** The native Lucene query result to represent as a {@link Tuples}. */
+    private FullTextStringIndex.Hits hits;
 
-              if (boundVars.contains(var) == useBound) {
-                variableList.add(var);
-                luceneKeyList.add(constrLuceneKeyList.get(idx));
+    /** Which fields to load from the documents. */
+    private final FieldSelector fieldSelector;
+
+    /**
+     * The current document within the {@link #hits}.
+     *
+     * A Lucene document hit corresponds to a {@link Tuples} row.
+     */
+    private Document document;
+
+    /** The index of the next {@link #document} within the {@link #hits}. */
+    private int nextDocumentIndex = 0;
+
+    /** the currently bound value for the subject, or null if not bound */
+    private String subject;
+    /** the currently bound value for the predicate, or null if not bound */
+    private String predicate;
+    /** the currently bound value for the object, or null if not bound */
+    private String object;
+
+    public SearchHitsTuples(final String subject, final String predicate, final String object) throws TuplesException {
+      if (logger.isDebugEnabled()) {
+        logger.debug("Searching for " + subject + " : " + predicate + " : " + object);
+      }
+
+      // run the query
+      try {
+        hits = fullTextStringIndex.find(subject, predicate, object);
+      } catch (FullTextStringIndexException e) {
+        throw new TuplesException("Couldn't generate answer from text index: subject='" + subject +
+                                  "', predicate='" + predicate + "', object='" + object + "'", e);
+      }
+
+      // sort the result in doc-id order for faster document retrieval
+      hits.sort();
+
+      // make sure we only load those fields we need (=> faster document retrieval)
+      List<String> load = new ArrayList<String>(3);
+      if (subject == null) load.add(FullTextStringIndex.SUBJECT_KEY);
+      if (predicate == null) load.add(FullTextStringIndex.PREDICATE_KEY);
+      if (object == null) load.add(FullTextStringIndex.LITERAL_KEY);
+      fieldSelector = new MapFieldSelector(load);
+
+      // prepare for iterating
+      document = null;
+      nextDocumentIndex = 0;
+
+      variableList.addAll(constrVariableList);
+      luceneKeyList.addAll(constrLuceneKeyList);
+
+      setVariables(variableList);
+    }
+
+    public void beforeFirst(long[] prefix, int suffixTruncation) throws TuplesException {
+      subject = getString(subjectElement, prefix, variableList);
+      predicate = getString(predicateElement, prefix, variableList);
+      object = getString(objectElement, prefix, variableList);
+
+      document = null;
+      nextDocumentIndex = 0;
+    }
+
+    public boolean next() throws TuplesException {
+      try {
+        while (nextDocumentIndex < hits.length()) {
+          document = hits.doc(nextDocumentIndex++, fieldSelector);
+          if (matches(subject, document.get(FullTextStringIndex.SUBJECT_KEY)) &&
+              matches(predicate, document.get(FullTextStringIndex.PREDICATE_KEY)) &&
+              matches(object, document.get(FullTextStringIndex.LITERAL_KEY))) {
+            return true;
+          }
+        }
+
+        document = null;
+        return false;
+      } catch (IOException e) {
+        throw new TuplesException("Couldn't obtain next Lucene hit", e);
+      }
+    }
+
+    private boolean matches(String bound, String found) {
+      return bound == null || found == null || bound.equals(found);
+    }
+
+    public long getRowCount() throws TuplesException {
+      return hits.length();
+    }
+
+    public long getRowUpperBound() throws TuplesException {
+      return hits.length();
+    }
+
+    public int getRowCardinality() throws TuplesException {
+      switch (hits.length()) {
+        case 0: return Tuples.ZERO;
+        case 1: return Tuples.ONE;
+        default: return Tuples.MANY;
+      }
+    }
+
+    public List<Tuples> getOperands() {
+      return Collections.<Tuples>emptyList();
+    }
+
+    public long getColumnValue(int column) throws TuplesException {
+      try {
+        if (column >= 0 && column < luceneKeyList.size()) {
+          String luceneKey = luceneKeyList.get(column);
+          if (luceneKey == FullTextStringIndex.LITERAL_KEY)
+            return session.localize(new LiteralImpl(document.get(luceneKey)));
+          else
+            return session.localize(new URIReferenceImpl(new URI(document.get(luceneKey))));
+        } else if (column == luceneKeyList.size()) {
+          // Generate the score column
+          return session.localize(new LiteralImpl(hits.score(nextDocumentIndex - 1)));
+        } else {
+          throw new TuplesException("Column " + column + " does not exist");
+        }
+      } catch (IOException e) {
+        throw new TuplesException("Couldn't get column " + column + " value", e);
+      } catch (LocalizeException e) {
+        throw new TuplesException("Couldn't localize column " + column + " value", e);
+      } catch (URISyntaxException e) {
+        throw new TuplesException("Couldn't get column " + column + " value", e);
+      }
+    }
+
+    public boolean isColumnEverUnbound(int column) throws TuplesException {
+      return false;
+    }
+
+    public boolean hasNoDuplicates() throws TuplesException {
+      return false;
+    }
+
+    public void close() throws TuplesException {
+      try {
+        if (hits != null) hits.close();
+      } catch (IOException ioe) {
+        throw new TuplesException("Error closing fulltext index hits", ioe);
+      }
+    }
+
+    public SearchHitsTuples clone() {
+      SearchHitsTuples clone = (SearchHitsTuples)super.clone();
+      if (hits != null) clone.hits = hits.clone();
+      return clone;
+    }
+
+    public Annotation getAnnotation(Class<? extends Annotation> annotationClass) throws TuplesException {
+      // support re-ordering the variables so any variables can be bound in the prefix
+      if (annotationClass == DefinablePrefixAnnotation.class) {
+        return new DefinablePrefixAnnotation() {
+          public void definePrefix(Set boundVars) throws TuplesException {
+            if (boundVars.contains(constraint.getScoreVar()))
+              throw new TuplesException("Score variable may not be bound");
+
+            variableList.clear();
+            luceneKeyList.clear();
+
+            for (boolean useBound : new boolean[] { true, false }) {
+              for (int idx = 0; idx < constrLuceneKeyList.size(); idx++) {
+                Variable var = constrVariableList.get(idx);
+
+                if (boundVars.contains(var) == useBound) {
+                  variableList.add(var);
+                  luceneKeyList.add(constrLuceneKeyList.get(idx));
+                }
               }
             }
+
+            if (constraint.getScoreVar() != null) variableList.add(constraint.getScoreVar());
+            setVariables(variableList);
           }
+        };
+      }
 
-          if (constraint.getScoreVar() != null) variableList.add(constraint.getScoreVar());
-          setVariables(variableList);
-        }
-      };
+      return null;
     }
-
-    return null;
   }
 }

Modified: trunk/src/jar/resolver-lucene/java/org/mulgara/resolver/lucene/LuceneResolver.java
===================================================================
--- trunk/src/jar/resolver-lucene/java/org/mulgara/resolver/lucene/LuceneResolver.java	2009-02-17 11:45:47 UTC (rev 1510)
+++ trunk/src/jar/resolver-lucene/java/org/mulgara/resolver/lucene/LuceneResolver.java	2009-02-17 12:36:16 UTC (rev 1511)
@@ -71,9 +71,6 @@
 import org.mulgara.resolver.spi.ResolverException;
 import org.mulgara.resolver.spi.ResolverSession;
 import org.mulgara.resolver.spi.Statements;
-import org.mulgara.resolver.spi.TuplesWrapperResolution;
-import org.mulgara.store.tuples.Tuples;
-import org.mulgara.store.tuples.TuplesOperations;
 import org.mulgara.util.conversion.html.HtmlToTextConverter;
 
 /**
@@ -372,23 +369,13 @@
     // generate the tuples
     try {
       FullTextStringIndex stringIndex = getFullTextStringIndex(((LocalNode)modelElement).getValue());
-
-      /* run the query now and materialize the result; it is often much faster to run a large query
-       * and grab all resulting lucene documents than it is to run many smaller queries. Ideally we
-       * would try and figure out which approach is better on a query-by-query basis.
-       */
-      Tuples tmpTuples = new FullTextStringIndexTuples(stringIndex, (LuceneConstraint)constraint, resolverSession);
-      Tuples tuples = TuplesOperations.sort(tmpTuples);
-      tmpTuples.close();
-
-      return new TuplesWrapperResolution(tuples, constraint);
-    } catch (TuplesException te) {
-      throw new QueryException("Failed to sort tuples and close", te);
-
+      return new FullTextStringIndexTuples(stringIndex, (LuceneConstraint)constraint, resolverSession);
     } catch (IOException ioe) {
       throw new QueryException("Failed to open string index", ioe);
     } catch (FullTextStringIndexException ef) {
       throw new QueryException("Query failed against string index", ef);
+    } catch (TuplesException te) {
+      throw new QueryException("Failed to query string index", te);
     }
   }
 




More information about the Mulgara-svn mailing list