Package org.jboss.seam.wiki.core.search

Source Code of org.jboss.seam.wiki.core.search.IndexManager

package org.jboss.seam.wiki.core.search;

import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.Term;
import org.hibernate.ScrollableResults;
import org.hibernate.search.FullTextSession;
import org.hibernate.search.store.DirectoryProvider;
import org.jboss.seam.Component;
import org.jboss.seam.annotations.Logger;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.async.Asynchronous;
import org.jboss.seam.log.Log;
import org.jboss.seam.wiki.util.Progress;
import org.jboss.seam.wiki.core.model.WikiNode;

import javax.persistence.EntityManager;
import javax.transaction.UserTransaction;
import java.math.BigDecimal;

/**
* Management the Lucene index.
*
* @author Christian Bauer
*/
@Name("indexManager")
public class IndexManager {

    @Logger
    static Log log;

    // TODO: Read the Hibernate Seach configuration option instead, when it becomes available as an API
    public int batchSize = 500;

    /**
     * Runs asynchronously and re-indexes the given entity class after purging the index.
     *
     * @param entityClass the class to purge and re-index
     * @param progress a value holder that is continously updated while the asynchronous procedure runs
     */
    @Asynchronous
    public void rebuildIndex(Class entityClass, Progress progress) {

        log.info("asynchronously rebuilding Lucene index for entity: " + entityClass);

        UserTransaction userTx = null;

        try {
            progress.setStatus("Purging index");
            log.debug("deleting indexed documents of entity: " + entityClass.getName());
            userTx = (UserTransaction)org.jboss.seam.Component.getInstance("org.jboss.seam.transaction.transaction");
            userTx.begin();

            EntityManager em = (EntityManager) Component.getInstance("entityManager");
            FullTextSession ftSession = (FullTextSession)em.getDelegate();

            // Delete all documents with "_hibernate_class" term of the selected entity
            DirectoryProvider dirProvider = ftSession.getSearchFactory().getDirectoryProviders(entityClass)[0];
            IndexReader reader = IndexReader.open(dirProvider.getDirectory());

            // TODO: This is using an internal term of HSearch
            reader.deleteDocuments(new Term("_hibernate_class", entityClass.getName()));
            reader.close();

            // Optimize index
            progress.setStatus("Optimizing index");
            log.debug("optimizing index (merging segments)");
            ftSession.getSearchFactory().optimize(entityClass);

            userTx.commit();

            progress.setStatus("Building index");
            log.debug("indexing documents in batches of: " + batchSize);

            // Now re-index with HSearch
            em = (EntityManager) Component.getInstance("entityManager");
            ftSession = (FullTextSession)em.getDelegate();

            // TODO: Let's run this in auto-commit mode, assuming we have READ COMMITTED isolation anyway and non-repeatable reads
            //userTx.setTransactionTimeout(3600);
            //userTx.begin();

            // Use HQL instead of Criteria to eager fetch lazy properties
            String query = "select o from " + entityClass.getName() + " o fetch all properties";
            if (WikiNode.class.isAssignableFrom(entityClass)) {
                // If it's a WikiNode, fetch the associated User instances, avoiding N+1 selects
                query = "select o from " + entityClass.getName() + " o inner join fetch o.createdBy left join fetch o.lastModifiedBy fetch all properties";
            }
            ScrollableResults cursor = ftSession.createQuery(query).scroll();

            cursor.last();
            int count = cursor.getRowNumber() + 1;
            log.debug("total documents in database: " + count);

            if (count > 0) {
                cursor.first(); // Reset to first result row
                int i = 0;
                while (true) {
                    i++;
                    Object o = cursor.get(0);
                    log.debug("indexing instance " + i + ": " + o);
                    ftSession.index(o);
                    if (i % batchSize == 0) {
                        log.debug("ending batch, beginning new batch");
                        ftSession.clear(); // Clear persistence context for each batch
                    }
                    progress.setPercentComplete( new Double(100d/count*i).intValue() );
                    log.debug(progress);

                    if (cursor.isLast())
                        break;
                    else
                        cursor.next();
                }
            }
            cursor.close();
            //userTx.commit();

            progress.setStatus(Progress.COMPLETE);
            log.debug("indexing complete of entity class: " + entityClass);

        } catch (Exception ex) {
            /*
            try {
                if (userTx != null) userTx.rollback();
            } catch (Exception rbEx) {
                rbEx.printStackTrace();
            }
            */
            throw new RuntimeException(ex);
        }

    }


}
TOP

Related Classes of org.jboss.seam.wiki.core.search.IndexManager

TOP
Copyright © 2015 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.