[hibernate-commits] Hibernate SVN: r11531 - in trunk/HibernateExt/search/src: java/org/hibernate/search/engine and 3 other directories.

hibernate-commits at lists.jboss.org hibernate-commits at lists.jboss.org
Wed May 16 18:25:22 EDT 2007


Author: epbernard
Date: 2007-05-16 18:25:22 -0400 (Wed, 16 May 2007)
New Revision: 11531

Added:
   trunk/HibernateExt/search/src/java/org/hibernate/search/FullTextQuery.java
   trunk/HibernateExt/search/src/java/org/hibernate/search/engine/DocumentExtractor.java
   trunk/HibernateExt/search/src/java/org/hibernate/search/engine/EntityInfo.java
   trunk/HibernateExt/search/src/java/org/hibernate/search/engine/Loader.java
   trunk/HibernateExt/search/src/java/org/hibernate/search/engine/ObjectLoader.java
   trunk/HibernateExt/search/src/java/org/hibernate/search/engine/ProjectionLoader.java
   trunk/HibernateExt/search/src/java/org/hibernate/search/engine/QueryLoader.java
Removed:
   trunk/HibernateExt/search/src/java/org/hibernate/search/query/EntityInfo.java
   trunk/HibernateExt/search/src/java/org/hibernate/search/query/FullTextQuery.java
Modified:
   trunk/HibernateExt/search/src/java/org/hibernate/search/FullTextSession.java
   trunk/HibernateExt/search/src/java/org/hibernate/search/engine/DocumentBuilder.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
   trunk/HibernateExt/search/src/java/org/hibernate/search/query/ScrollableResultsImpl.java
   trunk/HibernateExt/search/src/test/org/hibernate/search/test/query/LuceneQuerySortTest.java
   trunk/HibernateExt/search/src/test/org/hibernate/search/test/query/LuceneQueryTest.java
Log:
HSEARCH-51 Use where id in (...) rather than the load() then initialize approach

Copied: trunk/HibernateExt/search/src/java/org/hibernate/search/FullTextQuery.java (from rev 11519, trunk/HibernateExt/search/src/java/org/hibernate/search/query/FullTextQuery.java)
===================================================================
--- trunk/HibernateExt/search/src/java/org/hibernate/search/FullTextQuery.java	                        (rev 0)
+++ trunk/HibernateExt/search/src/java/org/hibernate/search/FullTextQuery.java	2007-05-16 22:25:22 UTC (rev 11531)
@@ -0,0 +1,38 @@
+//$Id: $
+package org.hibernate.search;
+
+import org.apache.lucene.search.Sort;
+import org.hibernate.Query;
+
+/**
+ * The base interface for lucene powered searches.
+ *
+ * @author Hardy Ferentschik
+ */
+//TODO return FullTextQuery rather than Query in useful chain methods
+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.
+	 * @return this for method chaining
+	 */
+	FullTextQuery setSort(Sort sort);
+
+	/**
+	 * Returns the number of hits for this search
+	 *
+	 * Caution:
+	 * The number of results might be slightly different from
+	 * <code>list().size()</code> because list() if the index is
+	 * not in sync with the database at the time of query.
+	 */
+	int resultSize();
+}

Modified: trunk/HibernateExt/search/src/java/org/hibernate/search/FullTextSession.java
===================================================================
--- trunk/HibernateExt/search/src/java/org/hibernate/search/FullTextSession.java	2007-05-16 15:32:33 UTC (rev 11530)
+++ trunk/HibernateExt/search/src/java/org/hibernate/search/FullTextSession.java	2007-05-16 22:25:22 UTC (rev 11531)
@@ -2,8 +2,7 @@
 package org.hibernate.search;
 
 import org.hibernate.classic.Session;
-import org.hibernate.Query;
-import org.hibernate.search.query.FullTextQuery;
+import org.hibernate.search.FullTextQuery;
 
 /**
  * Extends the Hibernate {@link Session} with Full text search and indexing capabilities

Modified: trunk/HibernateExt/search/src/java/org/hibernate/search/engine/DocumentBuilder.java
===================================================================
--- trunk/HibernateExt/search/src/java/org/hibernate/search/engine/DocumentBuilder.java	2007-05-16 15:32:33 UTC (rev 11530)
+++ trunk/HibernateExt/search/src/java/org/hibernate/search/engine/DocumentBuilder.java	2007-05-16 22:25:22 UTC (rev 11531)
@@ -19,12 +19,12 @@
 import org.apache.lucene.index.Term;
 import org.hibernate.Hibernate;
 import org.hibernate.annotations.common.AssertionFailure;
-import org.hibernate.annotations.common.util.ReflectHelper;
 import org.hibernate.annotations.common.reflection.ReflectionManager;
 import org.hibernate.annotations.common.reflection.XAnnotatedElement;
 import org.hibernate.annotations.common.reflection.XClass;
 import org.hibernate.annotations.common.reflection.XMember;
 import org.hibernate.annotations.common.reflection.XProperty;
+import org.hibernate.annotations.common.util.ReflectHelper;
 import org.hibernate.search.SearchException;
 import org.hibernate.search.SearchFactory;
 import org.hibernate.search.annotations.Boost;
@@ -109,6 +109,10 @@
 		}
 	}
 
+	public String getIdentifierName() {
+		return idGetter.getName();
+	}
+
 	private void initializeMember(XProperty member, PropertiesMetadata propertiesMetadata, boolean isRoot,
 								  String prefix, Set<XClass> processedClasses) {
 		Keyword keywordAnn = member.getAnnotation( Keyword.class );

Added: trunk/HibernateExt/search/src/java/org/hibernate/search/engine/DocumentExtractor.java
===================================================================
--- trunk/HibernateExt/search/src/java/org/hibernate/search/engine/DocumentExtractor.java	                        (rev 0)
+++ trunk/HibernateExt/search/src/java/org/hibernate/search/engine/DocumentExtractor.java	2007-05-16 22:25:22 UTC (rev 11531)
@@ -0,0 +1,24 @@
+//$Id: $
+package org.hibernate.search.engine;
+
+import org.apache.lucene.document.Document;
+import org.hibernate.search.SearchFactory;
+import org.hibernate.search.engine.EntityInfo;
+
+/**
+ * @author Emmanuel Bernard
+ */
+public class DocumentExtractor {
+	private SearchFactory searchFactory;
+	public DocumentExtractor(SearchFactory searchFactory) {
+		this.searchFactory = searchFactory;
+	}
+
+	public EntityInfo extract(Document document, String... fields) {
+		EntityInfo entityInfo = new EntityInfo();
+		entityInfo.clazz = DocumentBuilder.getDocumentClass( document );
+		entityInfo.id = DocumentBuilder.getDocumentId( searchFactory, entityInfo.clazz, document );
+		//TODO read fields
+		return entityInfo;
+	}
+}

Copied: trunk/HibernateExt/search/src/java/org/hibernate/search/engine/EntityInfo.java (from rev 11296, trunk/HibernateExt/search/src/java/org/hibernate/search/query/EntityInfo.java)
===================================================================
--- trunk/HibernateExt/search/src/java/org/hibernate/search/engine/EntityInfo.java	                        (rev 0)
+++ trunk/HibernateExt/search/src/java/org/hibernate/search/engine/EntityInfo.java	2007-05-16 22:25:22 UTC (rev 11531)
@@ -0,0 +1,15 @@
+//$Id: $
+package org.hibernate.search.engine;
+
+import java.io.Serializable;
+
+/**
+ *
+ * @author Emmanuel Bernard
+ */
+//Move to egine?
+public class EntityInfo {
+	public Class clazz;
+	public Serializable id;
+	public Object[] projection;
+}

Added: trunk/HibernateExt/search/src/java/org/hibernate/search/engine/Loader.java
===================================================================
--- trunk/HibernateExt/search/src/java/org/hibernate/search/engine/Loader.java	                        (rev 0)
+++ trunk/HibernateExt/search/src/java/org/hibernate/search/engine/Loader.java	2007-05-16 22:25:22 UTC (rev 11531)
@@ -0,0 +1,17 @@
+//$Id: $
+package org.hibernate.search.engine;
+
+import java.util.List;
+
+import org.hibernate.Session;
+import org.hibernate.search.SearchFactory;
+import org.hibernate.search.engine.EntityInfo;
+
+/**
+ * @author Emmanuel Bernard
+ */
+public interface Loader {
+	void init(Session session, SearchFactory searchFactory);
+	Object load(EntityInfo entityInfo);
+	List load(EntityInfo... entityInfos);
+}

Added: trunk/HibernateExt/search/src/java/org/hibernate/search/engine/ObjectLoader.java
===================================================================
--- trunk/HibernateExt/search/src/java/org/hibernate/search/engine/ObjectLoader.java	                        (rev 0)
+++ trunk/HibernateExt/search/src/java/org/hibernate/search/engine/ObjectLoader.java	2007-05-16 22:25:22 UTC (rev 11531)
@@ -0,0 +1,50 @@
+//$Id: $
+package org.hibernate.search.engine;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hibernate.Hibernate;
+import org.hibernate.ObjectNotFoundException;
+import org.hibernate.Session;
+import org.hibernate.search.SearchFactory;
+import org.hibernate.search.engine.EntityInfo;
+
+/**
+ * @author Emmanuel Bernard
+ */
+public class ObjectLoader implements Loader {
+	private static final Log log = LogFactory.getLog( ObjectLoader.class );
+	private Session session;
+
+	public void init(Session session, SearchFactory searchFactory) {
+		this.session = session;
+	}
+
+	public Object load(EntityInfo entityInfo) {
+		return session.get( entityInfo.clazz, entityInfo.id );
+	}
+
+	public List load(EntityInfo... entityInfos) {
+		//use load to benefit from the batch-size
+		//we don't face proxy casting issues since the exact class is extracted from the index
+		for (EntityInfo entityInfo : entityInfos) {
+			session.load( entityInfo.clazz, entityInfo.id );
+		}
+		List result = new ArrayList(entityInfos.length);
+		for (EntityInfo entityInfo : entityInfos) {
+			try {
+				Object entity = session.load( entityInfo.clazz, entityInfo.id );
+				Hibernate.initialize( entity );
+				result.add( entity );
+			}
+			catch (ObjectNotFoundException e) {
+				log.debug( "Object found in Search index but not in database: "
+						+ e.getEntityName() + " wih id " + e.getIdentifier() );
+			}
+		}
+		return result;
+	}
+}

Added: trunk/HibernateExt/search/src/java/org/hibernate/search/engine/ProjectionLoader.java
===================================================================
--- trunk/HibernateExt/search/src/java/org/hibernate/search/engine/ProjectionLoader.java	                        (rev 0)
+++ trunk/HibernateExt/search/src/java/org/hibernate/search/engine/ProjectionLoader.java	2007-05-16 22:25:22 UTC (rev 11531)
@@ -0,0 +1,29 @@
+//$Id: $
+package org.hibernate.search.engine;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.hibernate.Session;
+import org.hibernate.search.SearchFactory;
+import org.hibernate.search.engine.EntityInfo;
+
+/**
+ * @author Emmanuel Bernard
+ */
+public class ProjectionLoader implements Loader {
+	public void init(Session session, SearchFactory searchFactory) {
+	}
+
+	public Object load(EntityInfo entityInfo) {
+		return entityInfo.projection;
+	}
+
+	public List load(EntityInfo... entityInfos) {
+		List results = new ArrayList(entityInfos.length);
+		for (EntityInfo entityInfo : entityInfos) {
+			results.add( entityInfo.projection );
+		}
+		return results;
+	}
+}

Added: trunk/HibernateExt/search/src/java/org/hibernate/search/engine/QueryLoader.java
===================================================================
--- trunk/HibernateExt/search/src/java/org/hibernate/search/engine/QueryLoader.java	                        (rev 0)
+++ trunk/HibernateExt/search/src/java/org/hibernate/search/engine/QueryLoader.java	2007-05-16 22:25:22 UTC (rev 11531)
@@ -0,0 +1,83 @@
+//$Id: $
+package org.hibernate.search.engine;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hibernate.Criteria;
+import org.hibernate.Session;
+import org.hibernate.Hibernate;
+import org.hibernate.annotations.common.AssertionFailure;
+import org.hibernate.criterion.Disjunction;
+import org.hibernate.criterion.Restrictions;
+import org.hibernate.search.SearchFactory;
+import org.hibernate.search.engine.EntityInfo;
+
+/**
+ * @author Emmanuel Bernard
+ */
+public class QueryLoader implements Loader {
+	private static final Log log = LogFactory.getLog( QueryLoader.class );
+	private static final int MAX_IN_CLAUSE = 500;
+	private static final List EMPTY_LIST = new ArrayList(0);
+
+	private Session session;
+	private Class entityType;
+	private SearchFactory searchFactory;
+
+	public void init(Session session, SearchFactory searchFactory) {
+		this.session = session;
+		this.searchFactory = searchFactory;
+	}
+
+	public void setEntityType(Class entityType) {
+		this.entityType = entityType;
+	}
+
+
+
+	public Object load(EntityInfo entityInfo) {
+		return session.get( entityInfo.clazz, entityInfo.id );
+	}
+
+	public List load(EntityInfo... entityInfos) {
+		final int maxResults = entityInfos.length;
+		if ( maxResults == 0) return EMPTY_LIST;
+		if (entityType == null) throw new AssertionFailure("EntityType not defined");
+		Criteria criteria = session.createCriteria( entityType );
+
+		DocumentBuilder builder = searchFactory.getDocumentBuilders().get( entityType );
+		String idName = builder.getIdentifierName();
+		int loop = maxResults / MAX_IN_CLAUSE;
+		boolean exact = maxResults % MAX_IN_CLAUSE == 0;
+		if (!exact) loop++;
+		Disjunction disjunction = Restrictions.disjunction();
+		for (int index = 0 ; index < loop ; index++) {
+			int max = index*MAX_IN_CLAUSE + MAX_IN_CLAUSE <= maxResults ?
+					index*MAX_IN_CLAUSE + MAX_IN_CLAUSE :
+					maxResults;
+			List ids = new ArrayList(max - index*MAX_IN_CLAUSE);
+			for (int entityInfoIndex = index * MAX_IN_CLAUSE ; entityInfoIndex < max ; entityInfoIndex++) {
+				ids.add(entityInfos[entityInfoIndex].id);
+			}
+			disjunction.add( Restrictions.in( idName, ids ) );
+		}
+		criteria.add( disjunction );
+		criteria.setMaxResults( maxResults ); //is it faster
+		criteria.list(); //load all objects
+
+		//mandatory to keep the same ordering
+		List result = new ArrayList(entityInfos.length);
+		for (EntityInfo entityInfo : entityInfos) {
+			Object element = session.load( entityInfo.clazz, entityInfo.id );
+			if ( Hibernate.isInitialized( element ) ) {
+				//all existing elements should have been loaded by the query,
+				//the other ones are missing ones
+				result.add( element );
+			}
+		}
+		return result;
+	}
+}

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-16 15:32:33 UTC (rev 11530)
+++ trunk/HibernateExt/search/src/java/org/hibernate/search/impl/FullTextSessionImpl.java	2007-05-16 22:25:22 UTC (rev 11531)
@@ -42,10 +42,10 @@
 import org.hibernate.persister.entity.EntityPersister;
 import org.hibernate.search.FullTextSession;
 import org.hibernate.search.SearchFactory;
+import org.hibernate.search.FullTextQuery;
 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;

Deleted: trunk/HibernateExt/search/src/java/org/hibernate/search/query/EntityInfo.java
===================================================================
--- trunk/HibernateExt/search/src/java/org/hibernate/search/query/EntityInfo.java	2007-05-16 15:32:33 UTC (rev 11530)
+++ trunk/HibernateExt/search/src/java/org/hibernate/search/query/EntityInfo.java	2007-05-16 22:25:22 UTC (rev 11531)
@@ -1,12 +0,0 @@
-//$Id: $
-package org.hibernate.search.query;
-
-import java.io.Serializable;
-
-/**
- * @author Emmanuel Bernard
- */
-class EntityInfo {
-	public Class clazz;
-	public Serializable id;
-}

Deleted: trunk/HibernateExt/search/src/java/org/hibernate/search/query/FullTextQuery.java
===================================================================
--- trunk/HibernateExt/search/src/java/org/hibernate/search/query/FullTextQuery.java	2007-05-16 15:32:33 UTC (rev 11530)
+++ trunk/HibernateExt/search/src/java/org/hibernate/search/query/FullTextQuery.java	2007-05-16 22:25:22 UTC (rev 11531)
@@ -1,36 +0,0 @@
-//$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
-	 *
-	 * Caution:
-	 * The number of results might be slightly different from
-	 * <code>list().size()</code> because list() if the index is
-	 * not in sync with the database at the time of query.
-	 */
-	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-16 15:32:33 UTC (rev 11530)
+++ trunk/HibernateExt/search/src/java/org/hibernate/search/query/FullTextQueryImpl.java	2007-05-16 22:25:22 UTC (rev 11531)
@@ -2,7 +2,6 @@
 package org.hibernate.search.query;
 
 import java.io.IOException;
-import java.io.Serializable;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashSet;
@@ -21,26 +20,30 @@
 import org.apache.lucene.search.IndexSearcher;
 import org.apache.lucene.search.MultiSearcher;
 import org.apache.lucene.search.Searcher;
+import org.apache.lucene.search.Sort;
 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;
 import org.hibernate.LockMode;
 import org.hibernate.Query;
 import org.hibernate.ScrollMode;
 import org.hibernate.ScrollableResults;
 import org.hibernate.Session;
-import org.hibernate.ObjectNotFoundException;
 import org.hibernate.engine.SessionImplementor;
 import org.hibernate.engine.query.ParameterMetadata;
 import org.hibernate.impl.AbstractQueryImpl;
+import org.hibernate.search.SearchFactory;
+import org.hibernate.search.FullTextQuery;
 import org.hibernate.search.engine.DocumentBuilder;
-import org.hibernate.search.SearchFactory;
+import org.hibernate.search.engine.DocumentExtractor;
+import org.hibernate.search.engine.Loader;
+import org.hibernate.search.engine.ObjectLoader;
+import org.hibernate.search.engine.QueryLoader;
+import org.hibernate.search.engine.EntityInfo;
 import org.hibernate.search.util.ContextHelper;
 
 /**
- * Implementation of {@link org.hibernate.search.query.FullTextQuery}
+ * Implementation of {@link org.hibernate.search.FullTextQuery}
  *
  * @author Emmanuel Bernard
  * @author Hardy Ferentschik
@@ -55,7 +58,19 @@
 	private Integer maxResults;
 	private Integer resultSize;
 	private Sort sort;
+	private static Loader noLoader = new Loader() {
+		public void init(Session session, SearchFactory searchFactory) {
+		}
 
+		public Object load(EntityInfo entityInfo) {
+			throw new UnsupportedOperationException( "noLoader should not be used" );
+		}
+
+		public List load(EntityInfo... entityInfos) {
+			throw new UnsupportedOperationException( "noLoader should not be used" );
+		}
+	};
+
 	/**
 	 * classes must be immutable
 	 */
@@ -68,8 +83,9 @@
 	}
 
 
-	public void setSort(Sort sort) {
+	public FullTextQuery setSort(Sort sort) {
 		this.sort = sort;
+		return this;
 	}
 
 	/**
@@ -86,51 +102,68 @@
 		//find the directories
 		Searcher searcher = buildSearcher( searchFactory );
 		if ( searcher == null ) {
-		   	return new IteratorImpl( new ArrayList<EntityInfo>(0), (Session) this.session);
+		   	return new IteratorImpl( new ArrayList<EntityInfo>(0), noLoader );
 		}
 		try {
 			Hits hits = getHits( searcher );
-			setResultSize( hits );
 			int first = first();
 			int max = max( first, hits );
+			Session sess = (Session) this.session;
+
 			List<EntityInfo> entityInfos = new ArrayList<EntityInfo>( max - first + 1 );
+			DocumentExtractor extractor = new DocumentExtractor( searchFactory );
 			for ( int index = first; index <= max; index++ ) {
 				Document document = hits.doc( index );
-				EntityInfo entityInfo = new EntityInfo();
-				entityInfo.clazz = DocumentBuilder.getDocumentClass( document );
-				entityInfo.id = DocumentBuilder.getDocumentId( searchFactory, entityInfo.clazz, document );
-				entityInfos.add( entityInfo );
+				entityInfos.add( extractor.extract( document ) );
 			}
-			return new IteratorImpl( entityInfos, (Session) this.session );
+			Loader loader = getLoader(sess, searchFactory);
+			return new IteratorImpl( entityInfos, loader );
 		}
 		catch (IOException e) {
 			throw new HibernateException( "Unable to query Lucene index", e );
 		}
 		finally {
-         try {
-            searcher.close();
-         } catch (IOException e) {
-            log.warn("Unable to properly close searcher during lucene query: " + getQueryString(), e);
-         }
-      }
+			try {
+				searcher.close();
+			}
+			catch (IOException e) {
+				log.warn( "Unable to properly close searcher during lucene query: " + getQueryString(), e );
+			}
+		}
 	}
 
+	private Loader getLoader(Session session, SearchFactory searchFactory) {
+		if (classes.length == 1) {
+			QueryLoader loader = new QueryLoader();
+			loader.init( session, searchFactory );
+			loader.setEntityType( classes[0] );
+			return loader;
+		}
+		else {
+			final ObjectLoader objectLoader = new ObjectLoader();
+			objectLoader.init( session, searchFactory );
+			return objectLoader;
+		}
+	}
+
 	public ScrollableResults scroll() throws HibernateException {
 		//keep the searcher open until the resultset is closed
 		SearchFactory searchFactory = ContextHelper.getSearchFactoryBySFI( session );
-		
+
 		//find the directories
 		Searcher searcher = buildSearcher( searchFactory );
 		//FIXME: handle null searcher
 		Hits hits;
 		try {
 			hits = getHits( searcher );
-			setResultSize( hits );
 			int first = first();
 			int max = max( first, hits );
-			return new ScrollableResultsImpl( searcher, hits, first, max, (Session) this.session, searchFactory );
+			DocumentExtractor extractor = new DocumentExtractor( searchFactory );
+			Loader loader = getLoader( (Session) this.session, searchFactory );
+			return new ScrollableResultsImpl( searcher, hits, first, max, extractor, loader);
 		}
 		catch (IOException e) {
+			//close only in case of exception
 			try {
 				if ( searcher != null ) searcher.close();
 			}
@@ -154,41 +187,23 @@
 		Hits hits;
 		try {
 			hits = getHits( searcher );
-			setResultSize( hits );
 			int first = first();
 			int max = max( first, hits );
-			List result = new ArrayList( max - first + 1 );
 			Session sess = (Session) this.session;
+			List<EntityInfo> infos = new ArrayList<EntityInfo>( max - first + 1 );
+			DocumentExtractor extractor = new DocumentExtractor( searchFactory );
 			for ( int index = first; index <= max; index++ ) {
 				Document document = hits.doc( index );
-				Class clazz = DocumentBuilder.getDocumentClass( document );
-				Serializable id = DocumentBuilder.getDocumentId( searchFactory, clazz, document );
-				result.add( sess.load( clazz, id ) );
-				//use load to benefit from the batch-size
-				//we don't face proxy casting issues since the exact class is extracted from the index
+				infos.add( extractor.extract( document ) );
 			}
-			//then initialize the objects
-			List excludedObects = new ArrayList();
-			for ( Object element : result ) {
-				try {
-					Hibernate.initialize( element );
-				}
-				catch (ObjectNotFoundException e) {
-					log.debug( "Object found in Search index but not in database: "
-							+ e.getEntityName() + " wih id " + e.getIdentifier() );
-					excludedObects.add( element );
-				}
-			}
-			if ( excludedObects.size() > 0 ) {
-				result.removeAll( excludedObects );
-			}
-			return result;
+			Loader loader = getLoader( sess, searchFactory );
+			return loader.load( infos.toArray( new EntityInfo[infos.size()]) );
 		}
 		catch (IOException e) {
 			throw new HibernateException( "Unable to query Lucene index", e );
 		}
 		finally {
-			if ( searcher != null ) try {
+			try {
 				searcher.close();
 			}
 			catch (IOException e) {
@@ -213,6 +228,7 @@
 		else {
 			hits = searcher.search( query, sort );
 		}
+		setResultSize( hits );
 		return hits;
 	}
 
@@ -327,7 +343,6 @@
 				Hits hits;
 				try {
 					hits = getHits( searcher );
-					setResultSize( hits );
 				}
 				catch (IOException e) {
 					throw new HibernateException( "Unable to query Lucene index", e );
@@ -346,12 +361,12 @@
 		return this.resultSize;
 	}
 
-	public Query setFirstResult(int firstResult) {
+	public FullTextQuery setFirstResult(int firstResult) {
 		this.firstResult = firstResult;
 		return this;
 	}
 
-	public Query setMaxResults(int maxResults) {
+	public FullTextQuery setMaxResults(int maxResults) {
 		this.maxResults = maxResults;
 		return this;
 	}

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-16 15:32:33 UTC (rev 11530)
+++ trunk/HibernateExt/search/src/java/org/hibernate/search/query/IteratorImpl.java	2007-05-16 22:25:22 UTC (rev 11531)
@@ -5,7 +5,8 @@
 import java.util.List;
 import java.util.NoSuchElementException;
 
-import org.hibernate.Session;
+import org.hibernate.search.engine.Loader;
+import org.hibernate.search.engine.EntityInfo;
 
 /**
  * @author Emmanuel Bernard
@@ -14,16 +15,16 @@
 public class IteratorImpl implements Iterator {
 
 	private final List<EntityInfo> entityInfos;
-	private final Session session;
 	private int index = 0;
 	private final int size;
 	private Object next;
 	private int nextObjectIndex = -1;
+	private Loader loader;
 
-	public IteratorImpl(List<EntityInfo> entityInfos, Session session) {
+	public IteratorImpl(List<EntityInfo> entityInfos, Loader loader) {
 		this.entityInfos = entityInfos;
-		this.session = session;
 		this.size = entityInfos.size();
+		this.loader = loader;
 	}
 
 	//side effect is to set up next
@@ -37,7 +38,7 @@
 				next = null;
 				return false;
 			}
-			next = session.get( entityInfos.get( index ).clazz, entityInfos.get( index ).id );
+			next = loader.load( entityInfos.get( index ) );
 			if ( next == null ) {
 				index++;
 			}

Modified: trunk/HibernateExt/search/src/java/org/hibernate/search/query/ScrollableResultsImpl.java
===================================================================
--- trunk/HibernateExt/search/src/java/org/hibernate/search/query/ScrollableResultsImpl.java	2007-05-16 15:32:33 UTC (rev 11530)
+++ trunk/HibernateExt/search/src/java/org/hibernate/search/query/ScrollableResultsImpl.java	2007-05-16 22:25:22 UTC (rev 11531)
@@ -9,16 +9,18 @@
 import java.util.Calendar;
 import java.util.Date;
 import java.util.Locale;
+import java.util.Map;
 import java.util.TimeZone;
+import java.util.HashMap;
 
 import org.apache.lucene.document.Document;
 import org.apache.lucene.search.Hits;
 import org.apache.lucene.search.Searcher;
 import org.hibernate.HibernateException;
 import org.hibernate.ScrollableResults;
-import org.hibernate.Session;
-import org.hibernate.search.engine.DocumentBuilder;
-import org.hibernate.search.SearchFactory;
+import org.hibernate.search.engine.DocumentExtractor;
+import org.hibernate.search.engine.Loader;
+import org.hibernate.search.engine.EntityInfo;
 import org.hibernate.type.Type;
 
 /**
@@ -34,21 +36,23 @@
 	private final int first;
 	private final int max;
 	private int current;
-	private final Session session;
 	private EntityInfo[] entityInfos;
-	private final SearchFactory searchFactory;
+	private Loader loader;
+	private DocumentExtractor documentExtractor;
+	private Map<EntityInfo, Object[]> resultContext;
 
 	public ScrollableResultsImpl(
-			Searcher searcher, Hits hits, int first, int max, Session session, SearchFactory searchFactory
+			Searcher searcher, Hits hits, int first, int max, DocumentExtractor extractor, Loader loader
 	) {
 		this.searcher = searcher;
 		this.hits = hits;
 		this.first = first;
 		this.max = max;
 		this.current = first;
-		this.session = session;
-		this.searchFactory = searchFactory;
-		entityInfos = new EntityInfo[max - first + 1];
+		this.loader = loader;
+		this.documentExtractor = extractor;
+		this.entityInfos = new EntityInfo[max - first + 1];
+		this.resultContext = new HashMap<EntityInfo, Object[]>(max - first + 1);
 	}
 
 	public boolean next() throws HibernateException {
@@ -103,7 +107,6 @@
 		if ( current < first || current > max ) return null; //or exception?
 		EntityInfo info = entityInfos[current - first];
 		if ( info == null ) {
-			info = new EntityInfo();
 			Document document = null;
 			try {
 				document = hits.doc( current );
@@ -111,14 +114,16 @@
 			catch (IOException e) {
 				throw new HibernateException( "Unable to read Lucene hits[" + current + "]", e );
 			}
-			info.clazz = DocumentBuilder.getDocumentClass( document );
 			//FIXME should check that clazz match classes but this complexify a lot the firstResult/maxResult
-			info.id = DocumentBuilder.getDocumentId( searchFactory, info.clazz, document );
+			info = documentExtractor.extract( document );
 			entityInfos[current - first] = info;
 		}
-		return new Object[]{
-				session.get( info.clazz, info.id )
-		};
+		if ( !resultContext.containsKey( info ) ) {
+			Object loaded = loader.load( info );
+			if ( !loaded.getClass().isArray() ) loaded = new Object[] { loaded };
+			resultContext.put( info, (Object[]) loaded );
+		}
+		return resultContext.get( info );
 	}
 
 	public Object get(int i) throws HibernateException {

Modified: trunk/HibernateExt/search/src/test/org/hibernate/search/test/query/LuceneQuerySortTest.java
===================================================================
--- trunk/HibernateExt/search/src/test/org/hibernate/search/test/query/LuceneQuerySortTest.java	2007-05-16 15:32:33 UTC (rev 11530)
+++ trunk/HibernateExt/search/src/test/org/hibernate/search/test/query/LuceneQuerySortTest.java	2007-05-16 22:25:22 UTC (rev 11531)
@@ -14,7 +14,7 @@
 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.FullTextQuery;
 import org.hibernate.search.test.SearchTestCase;
 
 

Modified: trunk/HibernateExt/search/src/test/org/hibernate/search/test/query/LuceneQueryTest.java
===================================================================
--- trunk/HibernateExt/search/src/test/org/hibernate/search/test/query/LuceneQueryTest.java	2007-05-16 15:32:33 UTC (rev 11530)
+++ trunk/HibernateExt/search/src/test/org/hibernate/search/test/query/LuceneQueryTest.java	2007-05-16 22:25:22 UTC (rev 11531)
@@ -7,7 +7,7 @@
 import org.hibernate.search.test.SearchTestCase;
 import org.hibernate.search.FullTextSession;
 import org.hibernate.search.Search;
-import org.hibernate.search.query.FullTextQuery;
+import org.hibernate.search.FullTextQuery;
 import org.hibernate.Transaction;
 import org.hibernate.Hibernate;
 import org.hibernate.ScrollableResults;
@@ -51,6 +51,12 @@
 		assertEquals( "Query with explicit class filter", 2, result.size() );
 
 		query = parser.parse( "summary:Festina Or brand:Seiko" );
+		hibQuery = s.createFullTextQuery( query, Clock.class );
+		result = hibQuery.list();
+		assertNotNull( result );
+		assertEquals( "Query with one class filter", 1, result.size() );
+
+		query = parser.parse( "summary:Festina Or brand:Seiko" );
 		hibQuery = s.createFullTextQuery( query );
 		result = hibQuery.list();
 		assertNotNull( result );




More information about the hibernate-commits mailing list