[hibernate-commits] Hibernate SVN: r11518 - in trunk/HibernateExt/search/src: java/org/hibernate/search/impl and 2 other directories.

hibernate-commits at lists.jboss.org hibernate-commits at lists.jboss.org
Sun May 13 18:05:25 EDT 2007


Author: epbernard
Date: 2007-05-13 18:05:24 -0400 (Sun, 13 May 2007)
New Revision: 11518

Added:
   trunk/HibernateExt/search/src/java/org/hibernate/search/query/FullTextQuery.java
   trunk/HibernateExt/search/src/test/org/hibernate/search/test/query/LuceneQuerySortTest.java
Modified:
   trunk/HibernateExt/search/src/java/org/hibernate/search/FullTextSession.java
   trunk/HibernateExt/search/src/java/org/hibernate/search/impl/FullTextSessionImpl.java
   trunk/HibernateExt/search/src/java/org/hibernate/search/query/FullTextQueryImpl.java
   trunk/HibernateExt/search/src/java/org/hibernate/search/query/IteratorImpl.java
Log:
HSEARCH-4 Support for Lucene sort (Hardy Ferentschik)

Modified: trunk/HibernateExt/search/src/java/org/hibernate/search/FullTextSession.java
===================================================================
--- trunk/HibernateExt/search/src/java/org/hibernate/search/FullTextSession.java	2007-05-13 21:21:11 UTC (rev 11517)
+++ trunk/HibernateExt/search/src/java/org/hibernate/search/FullTextSession.java	2007-05-13 22:05:24 UTC (rev 11518)
@@ -3,6 +3,7 @@
 
 import org.hibernate.classic.Session;
 import org.hibernate.Query;
+import org.hibernate.search.query.FullTextQuery;
 
 /**
  * Extends the Hibernate {@link Session} with Full text search and indexing capabilities
@@ -15,7 +16,7 @@
 	 * of type <code>entities</code> and their respective subclasses.
 	 * If no entity is provided, no type filtering is done.
 	 */
-	Query createFullTextQuery(org.apache.lucene.search.Query luceneQuery, Class... entities);
+	FullTextQuery createFullTextQuery(org.apache.lucene.search.Query luceneQuery, Class... entities);
 
 	/**
 	 * Force the (re)indexing of a given <b>managed</b> object.

Modified: trunk/HibernateExt/search/src/java/org/hibernate/search/impl/FullTextSessionImpl.java
===================================================================
--- trunk/HibernateExt/search/src/java/org/hibernate/search/impl/FullTextSessionImpl.java	2007-05-13 21:21:11 UTC (rev 11517)
+++ trunk/HibernateExt/search/src/java/org/hibernate/search/impl/FullTextSessionImpl.java	2007-05-13 22:05:24 UTC (rev 11518)
@@ -45,6 +45,7 @@
 import org.hibernate.search.backend.WorkType;
 import org.hibernate.search.engine.DocumentBuilder;
 import org.hibernate.search.query.FullTextQueryImpl;
+import org.hibernate.search.query.FullTextQuery;
 import org.hibernate.search.util.ContextHelper;
 import org.hibernate.stat.SessionStatistics;
 import org.hibernate.type.Type;
@@ -71,7 +72,7 @@
      * 
 	 * @param entities must be immutable for the lifetime of the query object
 	 */
-	public Query createFullTextQuery(org.apache.lucene.search.Query luceneQuery, Class... entities) {
+	public FullTextQuery createFullTextQuery(org.apache.lucene.search.Query luceneQuery, Class... entities) {
 		return new FullTextQueryImpl( luceneQuery, entities, sessionImplementor, new ParameterMetadata(null, null) );
 	}
 

Added: trunk/HibernateExt/search/src/java/org/hibernate/search/query/FullTextQuery.java
===================================================================
--- trunk/HibernateExt/search/src/java/org/hibernate/search/query/FullTextQuery.java	                        (rev 0)
+++ trunk/HibernateExt/search/src/java/org/hibernate/search/query/FullTextQuery.java	2007-05-13 22:05:24 UTC (rev 11518)
@@ -0,0 +1,33 @@
+//$Id: $
+package org.hibernate.search.query;
+
+import org.apache.lucene.search.Sort;
+import org.hibernate.Query;
+
+/**
+ * The base interface for lucene powered searches.
+ *
+ * @author Hardy Ferentschik
+ */
+public interface FullTextQuery extends Query {
+	//todo Determine what other lucene specific features to expose via this
+	// interface. Maybe we should give access to the underlying lucene hit
+	// objects?
+
+	/**
+	 * Allows to let lucene sort the results. This is useful when you have
+	 * additional sort requirements on top of the default lucene ranking.
+	 * Without lucene sorting you would have to retrieve the full result set and
+	 * order the hibernate objects.
+	 *
+	 * @param sort The lucene sort object.
+	 */
+	void setSort(Sort sort);
+
+	/**
+	 * Returns the number of hits for this search
+	 *
+	 * @return The number of hits for this search
+	 */
+	int resultSize();
+}

Modified: trunk/HibernateExt/search/src/java/org/hibernate/search/query/FullTextQueryImpl.java
===================================================================
--- trunk/HibernateExt/search/src/java/org/hibernate/search/query/FullTextQueryImpl.java	2007-05-13 21:21:11 UTC (rev 11517)
+++ trunk/HibernateExt/search/src/java/org/hibernate/search/query/FullTextQueryImpl.java	2007-05-13 22:05:24 UTC (rev 11518)
@@ -22,6 +22,7 @@
 import org.apache.lucene.search.MultiSearcher;
 import org.apache.lucene.search.Searcher;
 import org.apache.lucene.search.TermQuery;
+import org.apache.lucene.search.Sort;
 import org.apache.lucene.store.Directory;
 import org.hibernate.Hibernate;
 import org.hibernate.HibernateException;
@@ -39,10 +40,13 @@
 import org.hibernate.search.util.ContextHelper;
 
 /**
+ * Implementation of {@link org.hibernate.search.query.FullTextQuery}
+ *
  * @author Emmanuel Bernard
+ * @author Hardy Ferentschik
  */
 //TODO implements setParameter()
-public class FullTextQueryImpl extends AbstractQueryImpl {
+public class FullTextQueryImpl extends AbstractQueryImpl implements FullTextQuery {
 	private static final Log log = LogFactory.getLog( FullTextQueryImpl.class );
 	private org.apache.lucene.search.Query luceneQuery;
 	private Class[] classes;
@@ -50,6 +54,7 @@
 	private Integer firstResult;
 	private Integer maxResults;
 	private int resultSize;
+	private Sort sort;
 
 	/**
 	 * classes must be immutable
@@ -62,6 +67,11 @@
 		this.classes = classes;
 	}
 
+
+	public void setSort(Sort sort) {
+		this.sort = sort;
+	}
+
 	/**
 	 * Return an interator on the results.
 	 * Retrieve the object one by one (initialize it during the next() operation)
@@ -79,8 +89,7 @@
 		   	return new IteratorImpl( new ArrayList<EntityInfo>(0), (Session) this.session);
 		}
 		try {
-			org.apache.lucene.search.Query query = filterQueryByClasses( luceneQuery );
-			Hits hits = searcher.search( query );
+			Hits hits = getHits( searcher );
 			setResultSize( hits );
 			int first = first();
 			int max = max( first, hits );
@@ -118,8 +127,7 @@
 		//FIXME: handle null searcher
 		Hits hits;
 		try {
-			org.apache.lucene.search.Query query = filterQueryByClasses( luceneQuery );
-			hits = searcher.search( query );
+			hits = getHits( searcher );
 			setResultSize( hits );
 			int first = first();
 			int max = max( first, hits );
@@ -148,8 +156,7 @@
 		if (searcher == null) return new ArrayList(0);
 		Hits hits;
 		try {
-			org.apache.lucene.search.Query query = filterQueryByClasses( luceneQuery );
-			hits = searcher.search( query );
+			hits = getHits( searcher );;
 			setResultSize( hits );
 			int first = first();
 			int max = max( first, hits );
@@ -193,6 +200,25 @@
 		}
 	}
 
+	/**
+	 * Execute the lucene search and return the machting hits.
+	 *
+	 * @param searcher The index searcher.
+	 * @return The lucene hits.
+	 * @throws IOException in case there is an error executing the lucene search.
+	 */
+	private Hits getHits(Searcher searcher) throws IOException {
+		Hits hits;
+		org.apache.lucene.search.Query query = filterQueryByClasses( luceneQuery );
+		if(sort == null){
+			hits = searcher.search( query );
+		}
+		else {
+			hits = searcher.search( query, sort );
+		}
+		return hits;
+	}
+
 	private org.apache.lucene.search.Query filterQueryByClasses(org.apache.lucene.search.Query luceneQuery) {
 		//A query filter is more practical than a manual class filtering post query (esp on scrollable resultsets)
 		//it also probably minimise the memory footprint

Modified: trunk/HibernateExt/search/src/java/org/hibernate/search/query/IteratorImpl.java
===================================================================
--- trunk/HibernateExt/search/src/java/org/hibernate/search/query/IteratorImpl.java	2007-05-13 21:21:11 UTC (rev 11517)
+++ trunk/HibernateExt/search/src/java/org/hibernate/search/query/IteratorImpl.java	2007-05-13 22:05:24 UTC (rev 11518)
@@ -17,43 +17,43 @@
 	private final Session session;
 	private int index = 0;
 	private final int size;
-   private Object next;
-   private int nextObjectIndex = -1;
+	private Object next;
+	private int nextObjectIndex = -1;
 
-   public IteratorImpl(List<EntityInfo> entityInfos, Session session) {
+	public IteratorImpl(List<EntityInfo> entityInfos, Session session) {
 		this.entityInfos = entityInfos;
 		this.session = session;
 		this.size = entityInfos.size();
 	}
 
-   //side effect is to set up next
-   public boolean hasNext() {
-      if (nextObjectIndex == index) return next != null;
-      next = null;
-      nextObjectIndex = -1;
-      do {
-         if ( index >= size ) {
-            nextObjectIndex = index;
-            next = null;
-            return false;
-         }
-         next = session.get( entityInfos.get( index ).clazz, entityInfos.get( index ).id );
-         if (next == null) {
-            index++;
-         }
-         else {
-            nextObjectIndex = index;
-         }
-      }
-      while( next == null );
-      return true;
-   }
+	//side effect is to set up next
+	public boolean hasNext() {
+		if ( nextObjectIndex == index ) return next != null;
+		next = null;
+		nextObjectIndex = -1;
+		do {
+			if ( index >= size ) {
+				nextObjectIndex = index;
+				next = null;
+				return false;
+			}
+			next = session.get( entityInfos.get( index ).clazz, entityInfos.get( index ).id );
+			if ( next == null ) {
+				index++;
+			}
+			else {
+				nextObjectIndex = index;
+			}
+		}
+		while ( next == null );
+		return true;
+	}
 
 	public Object next() {
-      //hasNext() has side effect
-      if ( ! hasNext() ) throw new NoSuchElementException("Out of boundaries");
-      index++;
-      return next;
+		//hasNext() has side effect
+		if ( !hasNext() ) throw new NoSuchElementException( "Out of boundaries" );
+		index++;
+		return next;
 	}
 
 	public void remove() {

Added: trunk/HibernateExt/search/src/test/org/hibernate/search/test/query/LuceneQuerySortTest.java
===================================================================
--- trunk/HibernateExt/search/src/test/org/hibernate/search/test/query/LuceneQuerySortTest.java	                        (rev 0)
+++ trunk/HibernateExt/search/src/test/org/hibernate/search/test/query/LuceneQuerySortTest.java	2007-05-13 22:05:24 UTC (rev 11518)
@@ -0,0 +1,100 @@
+//$Id: $
+package org.hibernate.search.test.query;
+
+import java.util.List;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.lucene.analysis.StopAnalyzer;
+import org.apache.lucene.queryParser.QueryParser;
+import org.apache.lucene.search.Query;
+import org.apache.lucene.search.Sort;
+import org.apache.lucene.search.SortField;
+import org.hibernate.Transaction;
+import org.hibernate.search.FullTextSession;
+import org.hibernate.search.Search;
+import org.hibernate.search.Version;
+import org.hibernate.search.query.FullTextQuery;
+import org.hibernate.search.test.SearchTestCase;
+
+
+/**
+ * @author Hardy Ferentschik
+ */
+public class LuceneQuerySortTest extends SearchTestCase {
+
+	/**
+	 * Class logger.
+	 */
+	private static Log log = LogFactory.getLog( Version.class );
+
+	/**
+	 * Test that we can change the default sort order of the lucene search result.
+	 *
+	 * @throws Exception in case the test fails.
+	 */
+	public void testList() throws Exception {
+		FullTextSession s = Search.createFullTextSession( openSession() );
+		createTestBooks(s);
+		Transaction tx = s.beginTransaction();
+		QueryParser parser = new QueryParser("title", new StopAnalyzer() );
+
+		Query query = parser.parse( "summary:lucene" );
+		FullTextQuery hibQuery = s.createFullTextQuery( query, Book.class );
+		List<Book> result = hibQuery.list();
+		assertNotNull( result );
+		assertEquals( "Wrong number of test results.", 3, result.size() );
+		// make sure that the order is according to in which order the books got inserted
+		// into the index.
+		int id = 1;
+		for(Book b : result) {
+			assertEquals("Expected another id", new Integer(id), b.getId());
+			id++;
+		}
+
+		// now the same query, but with a lucene sort specified.
+		query = parser.parse( "summary:lucene" );
+		hibQuery = s.createFullTextQuery( query, Book.class );
+		Sort sort = new Sort(new SortField("id", true));
+		hibQuery.setSort(sort);
+		result = hibQuery.list();
+		assertNotNull( result );
+		assertEquals( "Wrong number of test results.", 3, result.size() );
+		id = 3;
+		for(Book b : result) {
+			assertEquals("Expected another id", new Integer(id), b.getId());
+			id--;
+		}
+
+
+		tx.commit();
+		s.close();
+	}
+
+	/**
+	 * Helper method creating three books with the same title and summary.
+	 * When searching for these books the results should be returned in the order
+	 * they got added to the index.
+	 *
+	 * @param s The full text session used to index the test data.
+	 */
+	private void createTestBooks(FullTextSession s) {
+		Transaction tx = s.beginTransaction();
+		Book book = new Book(1, "Hibernate & Lucene", "This is a test book.");
+		s.save(book);
+		book = new Book(2, "Hibernate & Lucene", "This is a test book.");
+		s.save(book);
+		book = new Book(3, "Hibernate & Lucene", "This is a test book.");
+		s.save(book);
+		tx.commit();
+		s.clear();
+	}
+
+	protected Class[] getMappings() {
+		return new Class[] {
+				Book.class,
+				AlternateBook.class,
+				Clock.class
+		};
+	}
+}




More information about the hibernate-commits mailing list