[hibernate-commits] Hibernate SVN: r14300 - in search/trunk/src: java/org/hibernate/search/backend and 4 other directories.

hibernate-commits at lists.jboss.org hibernate-commits at lists.jboss.org
Wed Jan 30 17:47:58 EST 2008


Author: epbernard
Date: 2008-01-30 17:47:58 -0500 (Wed, 30 Jan 2008)
New Revision: 14300

Added:
   search/trunk/src/java/org/hibernate/search/event/FullTextIndexCollectionEventListener.java
   search/trunk/src/java/org/hibernate/search/lucene/
Modified:
   search/trunk/src/java/org/hibernate/search/backend/WorkType.java
   search/trunk/src/java/org/hibernate/search/backend/impl/BatchedQueueingProcessor.java
   search/trunk/src/java/org/hibernate/search/engine/DocumentBuilder.java
   search/trunk/src/java/org/hibernate/search/event/FullTextIndexEventListener.java
   search/trunk/src/test/org/hibernate/search/test/embedded/EmbeddedTest.java
Log:
HSEARCH-56 use Hibernate collection events to index on collection change

Modified: search/trunk/src/java/org/hibernate/search/backend/WorkType.java
===================================================================
--- search/trunk/src/java/org/hibernate/search/backend/WorkType.java	2008-01-30 17:54:10 UTC (rev 14299)
+++ search/trunk/src/java/org/hibernate/search/backend/WorkType.java	2008-01-30 22:47:58 UTC (rev 14300)
@@ -13,6 +13,7 @@
 	ADD,
 	UPDATE,
 	DELETE,
+	COLLECTION,
 	/**
 	 * Used to remove a specific instance
 	 * of a class from an index.

Modified: search/trunk/src/java/org/hibernate/search/backend/impl/BatchedQueueingProcessor.java
===================================================================
--- search/trunk/src/java/org/hibernate/search/backend/impl/BatchedQueueingProcessor.java	2008-01-30 17:54:10 UTC (rev 14299)
+++ search/trunk/src/java/org/hibernate/search/backend/impl/BatchedQueueingProcessor.java	2008-01-30 22:47:58 UTC (rev 14300)
@@ -98,6 +98,7 @@
 
 	public void add(Work work, WorkQueue workQueue) {
 		//don't check for builder it's done in prepareWork
+		//FIXME WorkType.COLLECTION does not play well with batchSize
 		workQueue.add( work );
 		if ( batchSize > 0 && workQueue.size() >= batchSize ) {
 			WorkQueue subQueue = workQueue.splitQueue();
@@ -111,17 +112,33 @@
 		List<Work> queue = workQueue.getQueue();
 		int initialSize = queue.size();
 		List<LuceneWork> luceneQueue = new ArrayList<LuceneWork>( initialSize ); //TODO load factor for containedIn
+		/**
+		 * Collection work type are process second, so if the owner entity has already been processed for whatever reason
+		 * the work will be ignored.
+		 * However if the owner entity has not been processed, an "UPDATE" work is executed
+		 *
+		 * Processing collection works last is mandatory to avoid reindexing a object to be deleted
+		 */
+		processWorkByLayer( queue, initialSize, luceneQueue, Layer.FIRST );
+		processWorkByLayer( queue, initialSize, luceneQueue, Layer.SECOND );
+		workQueue.setSealedQueue( luceneQueue );
+	}
+
+	private void processWorkByLayer(List<Work> queue, int initialSize, List<LuceneWork> luceneQueue, Layer layer) {
 		for ( int i = 0 ; i < initialSize ; i++ ) {
 			Work work = queue.get( i );
-			queue.set( i, null ); // help GC and avoid 2 loaded queues in memory
-			Class entityClass = work.getEntityClass() != null ?
-						work.getEntityClass() :
-						Hibernate.getClass( work.getEntity() );
-			DocumentBuilder<Object> builder = searchFactoryImplementor.getDocumentBuilders().get( entityClass );
-			if ( builder == null ) return; //or exception?
-			builder.addWorkToQueue(entityClass, work.getEntity(), work.getId(), work.getType(), luceneQueue, searchFactoryImplementor );
+			if ( work != null) {
+				if ( layer.isRightLayer( work.getType() ) ) {
+					queue.set( i, null ); // help GC and avoid 2 loaded queues in memory
+					Class entityClass = work.getEntityClass() != null ?
+								work.getEntityClass() :
+								Hibernate.getClass( work.getEntity() );
+					DocumentBuilder<Object> builder = searchFactoryImplementor.getDocumentBuilders().get( entityClass );
+					if ( builder == null ) continue; //or exception?
+					builder.addWorkToQueue(entityClass, work.getEntity(), work.getId(), work.getType(), luceneQueue, searchFactoryImplementor );
+				}
+			}
 		}
-		workQueue.setSealedQueue( luceneQueue );
 	}
 
 	//TODO implements parallel batchWorkers (one per Directory)
@@ -151,4 +168,15 @@
 		}
 	}
 
+	private static enum Layer {
+	    FIRST,
+		SECOND;
+
+		public boolean isRightLayer(WorkType type) {
+			if (this == FIRST && type != WorkType.COLLECTION) return true;
+			if (this == SECOND && type == WorkType.COLLECTION) return true;
+			return false;
+		}
+	}
+
 }

Modified: search/trunk/src/java/org/hibernate/search/engine/DocumentBuilder.java
===================================================================
--- search/trunk/src/java/org/hibernate/search/engine/DocumentBuilder.java	2008-01-30 17:54:10 UTC (rev 14299)
+++ search/trunk/src/java/org/hibernate/search/engine/DocumentBuilder.java	2008-01-30 22:47:58 UTC (rev 14300)
@@ -392,7 +392,7 @@
 
 	//TODO could we use T instead of EntityClass?
 	public void addWorkToQueue(Class entityClass, T entity, Serializable id, WorkType workType, List<LuceneWork> queue, SearchFactoryImplementor searchFactoryImplementor) {
-		//TODO with the caller loop we are in a n^2: optimize it using a HashMap for work recognition 
+		//TODO with the caller loop we are in a n^2: optimize it using a HashMap for work recognition
 		for (LuceneWork luceneWork : queue) {
 			//any work on the same entity should be ignored
 			if ( luceneWork.getEntityClass() == entityClass
@@ -418,7 +418,7 @@
 		else if ( workType == WorkType.PURGE_ALL ) {
 			queue.add( new PurgeAllLuceneWork( entityClass ) );
 		}
-		else if ( workType == WorkType.UPDATE ) {
+		else if ( workType == WorkType.UPDATE || workType == WorkType.COLLECTION ) {
 			Document doc = getDocument( entity, id );
 			/**
 			 * even with Lucene 2.1, use of indexWriter to update is not an option

Added: search/trunk/src/java/org/hibernate/search/event/FullTextIndexCollectionEventListener.java
===================================================================
--- search/trunk/src/java/org/hibernate/search/event/FullTextIndexCollectionEventListener.java	                        (rev 0)
+++ search/trunk/src/java/org/hibernate/search/event/FullTextIndexCollectionEventListener.java	2008-01-30 22:47:58 UTC (rev 14300)
@@ -0,0 +1,49 @@
+//$
+package org.hibernate.search.event;
+
+import java.io.Serializable;
+
+import org.hibernate.event.PostCollectionRecreateEventListener;
+import org.hibernate.event.PostCollectionRemoveEventListener;
+import org.hibernate.event.PostCollectionUpdateEventListener;
+import org.hibernate.event.PostCollectionRecreateEvent;
+import org.hibernate.event.PostCollectionRemoveEvent;
+import org.hibernate.event.PostCollectionUpdateEvent;
+import org.hibernate.event.AbstractEvent;
+import org.hibernate.search.backend.WorkType;
+
+/**
+ * Support collection event listening (starts from hibernate core 3.2.6)
+ * FIXME deprecate as soon as we target Core 3.3 and merge back into the superclass
+ *
+ * @author Emmanuel Bernard
+ */
+public class FullTextIndexCollectionEventListener extends FullTextIndexEventListener
+		implements PostCollectionRecreateEventListener,
+		PostCollectionRemoveEventListener,
+		PostCollectionUpdateEventListener {
+	public void onPostRecreateCollection(PostCollectionRecreateEvent event) {
+		Object entity = event.getAffectedOwner();
+		if ( used && searchFactoryImplementor.getDocumentBuilders().containsKey( entity.getClass() ) ) {
+			processWork( entity, getId( entity, event ), WorkType.COLLECTION, event );
+		}
+	}
+
+	private Serializable getId(Object entity, AbstractEvent event) {
+		return event.getSession().getPersistenceContext().getEntry( entity ).getId();
+	}
+
+	public void onPostRemoveCollection(PostCollectionRemoveEvent event) {
+		Object entity = event.getAffectedOwner();
+		if ( used && searchFactoryImplementor.getDocumentBuilders().containsKey( entity.getClass() ) ) {
+			processWork( entity, getId( entity, event ), WorkType.COLLECTION, event );
+		}
+	}
+
+	public void onPostUpdateCollection(PostCollectionUpdateEvent event) {
+		Object entity = event.getAffectedOwner();
+		if ( used && searchFactoryImplementor.getDocumentBuilders().containsKey( entity.getClass() ) ) {
+			processWork( entity, getId( entity, event ), WorkType.COLLECTION, event );
+		}
+	}
+}

Modified: search/trunk/src/java/org/hibernate/search/event/FullTextIndexEventListener.java
===================================================================
--- search/trunk/src/java/org/hibernate/search/event/FullTextIndexEventListener.java	2008-01-30 17:54:10 UTC (rev 14299)
+++ search/trunk/src/java/org/hibernate/search/event/FullTextIndexEventListener.java	2008-01-30 22:47:58 UTC (rev 14300)
@@ -35,11 +35,9 @@
 public class FullTextIndexEventListener implements PostDeleteEventListener, PostInsertEventListener,
 		PostUpdateEventListener, Initializable {
 
-	private static final Log log = LogFactory.getLog( FullTextIndexEventListener.class );
-	private boolean used;
+	protected boolean used;
+	protected SearchFactoryImplementor searchFactoryImplementor;
 
-	private SearchFactoryImplementor searchFactoryImplementor;
-
 	public void initialize(Configuration cfg) {
 		searchFactoryImplementor = SearchFactoryImpl.getSearchFactory( cfg );
 		String indexingStrategy = cfg.getProperties().getProperty( Environment.INDEXING_STRATEGY, "event" );
@@ -88,7 +86,7 @@
 		}
 	}
 
-	private void processWork(Object entity, Serializable id, WorkType workType, AbstractEvent event) {
+	protected void processWork(Object entity, Serializable id, WorkType workType, AbstractEvent event) {
 		Work work = new Work(entity, id, workType);
 		searchFactoryImplementor.getWorker().performWork( work, event.getSession() );
 	}

Modified: search/trunk/src/test/org/hibernate/search/test/embedded/EmbeddedTest.java
===================================================================
--- search/trunk/src/test/org/hibernate/search/test/embedded/EmbeddedTest.java	2008-01-30 17:54:10 UTC (rev 14299)
+++ search/trunk/src/test/org/hibernate/search/test/embedded/EmbeddedTest.java	2008-01-30 22:47:58 UTC (rev 14300)
@@ -11,8 +11,14 @@
 import org.apache.lucene.search.TermQuery;
 import org.hibernate.Session;
 import org.hibernate.Transaction;
+import org.hibernate.event.PostCollectionRecreateEventListener;
+import org.hibernate.event.PostInsertEventListener;
+import org.hibernate.event.PostUpdateEventListener;
+import org.hibernate.event.PostCollectionUpdateEventListener;
+import org.hibernate.event.PostCollectionRemoveEventListener;
 import org.hibernate.search.FullTextSession;
 import org.hibernate.search.Search;
+import org.hibernate.search.event.FullTextIndexCollectionEventListener;
 import org.hibernate.search.test.SearchTestCase;
 
 /**
@@ -231,6 +237,14 @@
 
 	}
 
+	protected void configure(org.hibernate.cfg.Configuration cfg) {
+		super.configure( cfg );
+		FullTextIndexCollectionEventListener del = new FullTextIndexCollectionEventListener();
+		cfg.getEventListeners().setPostCollectionRecreateEventListeners( new PostCollectionRecreateEventListener[]{del} );
+		cfg.getEventListeners().setPostCollectionUpdateEventListeners( new PostCollectionUpdateEventListener[]{del} );
+		cfg.getEventListeners().setPostCollectionRemoveEventListeners( new PostCollectionRemoveEventListener[]{del} );
+	}
+
 	protected Class[] getMappings() {
 		return new Class[] {
 				Tower.class,




More information about the hibernate-commits mailing list