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

hibernate-commits at lists.jboss.org hibernate-commits at lists.jboss.org
Tue Jun 5 16:58:24 EDT 2007


Author: epbernard
Date: 2007-06-05 16:58:24 -0400 (Tue, 05 Jun 2007)
New Revision: 11633

Added:
   trunk/HibernateExt/search/src/java/org/hibernate/search/backend/OptimizeLuceneWork.java
   trunk/HibernateExt/search/src/test/org/hibernate/search/test/session/OptimizeTest.java
Modified:
   trunk/HibernateExt/search/src/java/org/hibernate/search/SearchFactory.java
   trunk/HibernateExt/search/src/java/org/hibernate/search/backend/impl/jms/JMSBackendQueueProcessor.java
   trunk/HibernateExt/search/src/java/org/hibernate/search/backend/impl/lucene/LuceneBackendQueueProcessor.java
   trunk/HibernateExt/search/src/java/org/hibernate/search/backend/impl/lucene/LuceneWorker.java
   trunk/HibernateExt/search/src/java/org/hibernate/search/impl/SearchFactoryImpl.java
Log:
HSEARCH-72 optimize inspired by Andrew Hahn's patch

Modified: trunk/HibernateExt/search/src/java/org/hibernate/search/SearchFactory.java
===================================================================
--- trunk/HibernateExt/search/src/java/org/hibernate/search/SearchFactory.java	2007-06-05 18:35:57 UTC (rev 11632)
+++ trunk/HibernateExt/search/src/java/org/hibernate/search/SearchFactory.java	2007-06-05 20:58:24 UTC (rev 11633)
@@ -20,4 +20,14 @@
 	 * for a given entity
 	 */
 	DirectoryProvider getDirectoryProvider(Class entity);
+
+	/**
+	 * Optimize all indexes
+	 */
+	void optimize();
+
+	/**
+	 * Optimize the index holding <code>entityType</code>
+	 */
+	void optimize(Class entityType);
 }

Added: trunk/HibernateExt/search/src/java/org/hibernate/search/backend/OptimizeLuceneWork.java
===================================================================
--- trunk/HibernateExt/search/src/java/org/hibernate/search/backend/OptimizeLuceneWork.java	                        (rev 0)
+++ trunk/HibernateExt/search/src/java/org/hibernate/search/backend/OptimizeLuceneWork.java	2007-06-05 20:58:24 UTC (rev 11633)
@@ -0,0 +1,14 @@
+//$Id$
+package org.hibernate.search.backend;
+
+import java.io.Serializable;
+
+/**
+ * @author Andrew Hahn
+ * @author Emmanuel Bernard
+ */
+public class OptimizeLuceneWork extends LuceneWork {
+	public OptimizeLuceneWork(Class entity) {
+		super( null, entity );
+	}
+}

Modified: trunk/HibernateExt/search/src/java/org/hibernate/search/backend/impl/jms/JMSBackendQueueProcessor.java
===================================================================
--- trunk/HibernateExt/search/src/java/org/hibernate/search/backend/impl/jms/JMSBackendQueueProcessor.java	2007-06-05 18:35:57 UTC (rev 11632)
+++ trunk/HibernateExt/search/src/java/org/hibernate/search/backend/impl/jms/JMSBackendQueueProcessor.java	2007-06-05 20:58:24 UTC (rev 11633)
@@ -3,6 +3,7 @@
 
 import java.io.Serializable;
 import java.util.List;
+import java.util.ArrayList;
 import javax.jms.JMSException;
 import javax.jms.ObjectMessage;
 import javax.jms.QueueConnection;
@@ -11,6 +12,7 @@
 
 import org.hibernate.HibernateException;
 import org.hibernate.search.backend.LuceneWork;
+import org.hibernate.search.backend.OptimizeLuceneWork;
 
 /**
  * @author Emmanuel Bernard
@@ -26,6 +28,14 @@
 	}
 
 	public void run() {
+		List<LuceneWork> filteredQueue = new ArrayList<LuceneWork>(queue);
+		for (LuceneWork work : queue) {
+			if ( work instanceof OptimizeLuceneWork ) {
+				//we don't want optimization to be propagated
+				filteredQueue.remove( work );
+			}
+		}
+		if ( filteredQueue.size() == 0) return;
 		factory.prepareJMSTools();
 		QueueConnection cnn;
 		QueueSender sender;
@@ -36,7 +46,7 @@
 			session = cnn.createQueueSession( false, QueueSession.AUTO_ACKNOWLEDGE );
 
 			ObjectMessage message = session.createObjectMessage();
-			message.setObject( (Serializable) this.queue );
+			message.setObject( (Serializable) filteredQueue );
 
 			sender = session.createSender( factory.getJmsQueue() );
 			sender.send( message );

Modified: trunk/HibernateExt/search/src/java/org/hibernate/search/backend/impl/lucene/LuceneBackendQueueProcessor.java
===================================================================
--- trunk/HibernateExt/search/src/java/org/hibernate/search/backend/impl/lucene/LuceneBackendQueueProcessor.java	2007-06-05 18:35:57 UTC (rev 11632)
+++ trunk/HibernateExt/search/src/java/org/hibernate/search/backend/impl/lucene/LuceneBackendQueueProcessor.java	2007-06-05 20:58:24 UTC (rev 11633)
@@ -8,6 +8,7 @@
 import org.hibernate.search.backend.AddLuceneWork;
 import org.hibernate.search.backend.LuceneWork;
 import org.hibernate.search.backend.Workspace;
+import org.hibernate.search.backend.OptimizeLuceneWork;
 import org.hibernate.search.engine.SearchFactoryImplementor;
 
 /**
@@ -64,6 +65,7 @@
 	private long getWorkHashCode(LuceneWork luceneWork, Workspace workspace) {
 		long h = workspace.getDocumentBuilder( luceneWork.getEntityClass() ).hashCode() * 2;
 		if ( luceneWork instanceof AddLuceneWork ) h+=1; //addwork after deleteWork
+		if ( luceneWork instanceof OptimizeLuceneWork ) h+=2; //optimize after everything
 		return h;
 	}
 }

Modified: trunk/HibernateExt/search/src/java/org/hibernate/search/backend/impl/lucene/LuceneWorker.java
===================================================================
--- trunk/HibernateExt/search/src/java/org/hibernate/search/backend/impl/lucene/LuceneWorker.java	2007-06-05 18:35:57 UTC (rev 11632)
+++ trunk/HibernateExt/search/src/java/org/hibernate/search/backend/impl/lucene/LuceneWorker.java	2007-06-05 20:58:24 UTC (rev 11633)
@@ -17,6 +17,7 @@
 import org.hibernate.search.backend.DeleteLuceneWork;
 import org.hibernate.search.backend.LuceneWork;
 import org.hibernate.search.backend.Workspace;
+import org.hibernate.search.backend.OptimizeLuceneWork;
 import org.hibernate.search.engine.DocumentBuilder;
 
 /**
@@ -39,6 +40,9 @@
 		else if ( DeleteLuceneWork.class.isAssignableFrom( luceneWork.getClass() ) ) {
 			performWork( (DeleteLuceneWork) luceneWork );
 		}
+		else if ( OptimizeLuceneWork.class.isAssignableFrom( luceneWork.getClass() ) ) {
+			performWork( (OptimizeLuceneWork) luceneWork );
+		}
 		else {
 			throw new AssertionFailure( "Unknown work type: " + luceneWork.getClass() );
 		}
@@ -106,4 +110,19 @@
 			}
 		}
 	}
+
+	public void performWork(OptimizeLuceneWork work) {
+		Class entity = work.getEntityClass();
+		if ( log.isTraceEnabled() )
+			log.trace( "optimize Lucene index: " + entity );
+		//TODO get a batchIndexWriter of some kind that deals with different merge factors and all
+		//TODO this one should not compete with a regular IndexWriter (ie exception from the workspace)
+		IndexWriter writer = workspace.getIndexWriter( entity );
+		try {
+			writer.optimize();
+		}
+		catch (IOException e) {
+			throw new SearchException( "Unable to optimize Lucene index: " + entity, e );
+		}
+	}
 }

Modified: trunk/HibernateExt/search/src/java/org/hibernate/search/impl/SearchFactoryImpl.java
===================================================================
--- trunk/HibernateExt/search/src/java/org/hibernate/search/impl/SearchFactoryImpl.java	2007-06-05 18:35:57 UTC (rev 11632)
+++ trunk/HibernateExt/search/src/java/org/hibernate/search/impl/SearchFactoryImpl.java	2007-06-05 20:58:24 UTC (rev 11633)
@@ -6,6 +6,8 @@
 import java.util.Map;
 import java.util.Set;
 import java.util.WeakHashMap;
+import java.util.List;
+import java.util.ArrayList;
 import java.util.concurrent.locks.ReentrantLock;
 
 import org.apache.lucene.analysis.Analyzer;
@@ -15,20 +17,21 @@
 import org.hibernate.annotations.common.reflection.java.JavaReflectionManager;
 import org.hibernate.cfg.Configuration;
 import org.hibernate.mapping.PersistentClass;
+import org.hibernate.search.Environment;
+import org.hibernate.search.SearchException;
+import org.hibernate.search.Version;
 import org.hibernate.search.annotations.Indexed;
 import org.hibernate.search.backend.BackendQueueProcessorFactory;
 import org.hibernate.search.backend.Worker;
 import org.hibernate.search.backend.WorkerFactory;
+import org.hibernate.search.backend.LuceneWork;
+import org.hibernate.search.backend.OptimizeLuceneWork;
 import org.hibernate.search.engine.DocumentBuilder;
 import org.hibernate.search.engine.SearchFactoryImplementor;
 import org.hibernate.search.reader.ReaderProvider;
 import org.hibernate.search.reader.ReaderProviderFactory;
 import org.hibernate.search.store.DirectoryProvider;
 import org.hibernate.search.store.DirectoryProviderFactory;
-import org.hibernate.search.SearchFactory;
-import org.hibernate.search.Version;
-import org.hibernate.search.Environment;
-import org.hibernate.search.SearchException;
 import org.hibernate.util.ReflectHelper;
 
 /**
@@ -37,9 +40,11 @@
 public class SearchFactoryImpl implements SearchFactoryImplementor {
 	private static ThreadLocal<WeakHashMap<Configuration, SearchFactoryImpl>> contexts =
 			new ThreadLocal<WeakHashMap<Configuration, SearchFactoryImpl>>();
+
 	static {
 		Version.touch();
 	}
+
 	private Map<Class, DocumentBuilder<Object>> documentBuilders = new HashMap<Class, DocumentBuilder<Object>>();
 	//keep track of the index modifiers per DirectoryProvider since multiple entity can use the same directory provider
 	private Map<DirectoryProvider, ReentrantLock> lockableDirectoryProviders =
@@ -111,11 +116,11 @@
 			}
 		}
 		Set<Class> indexedClasses = documentBuilders.keySet();
-		for ( DocumentBuilder builder : documentBuilders.values() ) {
+		for (DocumentBuilder builder : documentBuilders.values()) {
 			builder.postInitialize( indexedClasses );
 		}
-		worker = WorkerFactory.createWorker(cfg, this);
-		readerProvider = ReaderProviderFactory.createReaderProvider(cfg, this);
+		worker = WorkerFactory.createWorker( cfg, this );
+		readerProvider = ReaderProviderFactory.createReaderProvider( cfg, this );
 	}
 
 	//code doesn't have to be multithreaded because SF creation is not.
@@ -123,13 +128,13 @@
 	//FIXME this is ugly, impl.staticmethod, fix that
 	public static SearchFactoryImpl getSearchFactory(Configuration cfg) {
 		WeakHashMap<Configuration, SearchFactoryImpl> contextMap = contexts.get();
-		if (contextMap == null) {
+		if ( contextMap == null ) {
 			contextMap = new WeakHashMap<Configuration, SearchFactoryImpl>( 2 );
 			contexts.set( contextMap );
 		}
 		SearchFactoryImpl searchFactory = contextMap.get( cfg );
-		if ( searchFactory == null) {
-			searchFactory = new SearchFactoryImpl(cfg);
+		if ( searchFactory == null ) {
+			searchFactory = new SearchFactoryImpl( cfg );
 
 			contextMap.put( cfg, searchFactory );
 		}
@@ -174,4 +179,20 @@
 		DocumentBuilder<Object> documentBuilder = getDocumentBuilders().get( entity );
 		return documentBuilder == null ? null : documentBuilder.getDirectoryProvider();
 	}
+
+	public void optimize() {
+		Set<Class> clazzs = getDocumentBuilders().keySet();
+		for (Class clazz : clazzs) {
+			optimize( clazz );
+		}
+	}
+
+	public void optimize(Class entityType) {
+		if ( ! getDocumentBuilders().containsKey( entityType ) ) {
+			throw new SearchException("Entity not indexed: " + entityType);
+		}
+		List<LuceneWork> queue = new ArrayList<LuceneWork>(1);
+		queue.add( new OptimizeLuceneWork( entityType ) );
+		getBackendQueueProcessorFactory().getProcessor( queue ).run();
+	}
 }

Added: trunk/HibernateExt/search/src/test/org/hibernate/search/test/session/OptimizeTest.java
===================================================================
--- trunk/HibernateExt/search/src/test/org/hibernate/search/test/session/OptimizeTest.java	                        (rev 0)
+++ trunk/HibernateExt/search/src/test/org/hibernate/search/test/session/OptimizeTest.java	2007-06-05 20:58:24 UTC (rev 11633)
@@ -0,0 +1,105 @@
+//$Id$
+package org.hibernate.search.test.session;
+
+import java.io.File;
+
+import org.apache.lucene.analysis.StopAnalyzer;
+import org.apache.lucene.queryParser.QueryParser;
+import org.hibernate.Transaction;
+import org.hibernate.event.PostDeleteEventListener;
+import org.hibernate.event.PostInsertEventListener;
+import org.hibernate.event.PostUpdateEventListener;
+import org.hibernate.search.Environment;
+import org.hibernate.search.FullTextSession;
+import org.hibernate.search.Search;
+import org.hibernate.search.event.FullTextIndexEventListener;
+import org.hibernate.search.impl.FullTextSessionImpl;
+import org.hibernate.search.store.FSDirectoryProvider;
+import org.hibernate.search.test.SearchTestCase;
+
+/**
+ * @author Emmanuel Bernard
+ */
+public class OptimizeTest extends SearchTestCase {
+
+	public void testOptimize() throws Exception {
+		FullTextSession s = Search.createFullTextSession( openSession() );
+		Transaction tx = s.beginTransaction();
+		int loop = 2000;
+		for (int i = 0; i < loop; i++) {
+			Email email = new Email();
+			email.setId( (long) i + 1 );
+			email.setTitle( "JBoss World Berlin" );
+			email.setBody( "Meet the guys who wrote the software" );
+			s.persist( email );
+		}
+		tx.commit();
+		s.close();
+
+		s = Search.createFullTextSession( openSession() );
+		tx = s.beginTransaction();
+		s.getSearchFactory().optimize( Email.class );
+		tx.commit();
+		s.close();
+
+		//check non indexed object get indexed by s.index
+		s = new FullTextSessionImpl( openSession() );
+		tx = s.beginTransaction();
+		QueryParser parser = new QueryParser( "id", new StopAnalyzer() );
+		int result = s.createFullTextQuery( parser.parse( "body:wrote" ) ).getResultSize();
+		assertEquals( 2000, result );
+		s.createQuery( "delete " + Email.class.getName() ).executeUpdate();
+		tx.commit();
+		s.close();
+	}
+
+	protected void configure(org.hibernate.cfg.Configuration cfg) {
+		File sub = getBaseIndexDir();
+		cfg.setProperty( "hibernate.search.default.indexBase", sub.getAbsolutePath() );
+		cfg.setProperty( "hibernate.search.default.directory_provider", FSDirectoryProvider.class.getName() );
+		cfg.setProperty( Environment.ANALYZER_CLASS, StopAnalyzer.class.getName() );
+	}
+
+	protected void setUp() throws Exception {
+		File sub = getBaseIndexDir();
+		sub.mkdir();
+		File[] files = sub.listFiles();
+		for (File file : files) {
+			if ( file.isDirectory() ) {
+				delete( file );
+			}
+		}
+		//super.setUp(); //we need a fresh session factory each time for index set up
+		buildSessionFactory( getMappings(), getAnnotatedPackages(), getXmlFiles() );
+	}
+
+	private File getBaseIndexDir() {
+		File current = new File( "." );
+		File sub = new File( current, "indextemp" );
+		return sub;
+	}
+
+	protected void tearDown() throws Exception {
+		super.tearDown();
+		File sub = getBaseIndexDir();
+		delete( sub );
+	}
+
+	private void delete(File sub) {
+		if ( sub.isDirectory() ) {
+			for (File file : sub.listFiles()) {
+				delete( file );
+			}
+			sub.delete();
+		}
+		else {
+			sub.delete();
+		}
+	}
+
+	protected Class[] getMappings() {
+		return new Class[] {
+				Email.class
+		};
+	}
+}




More information about the hibernate-commits mailing list