[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