View Javadoc

1   package org.appfuse.dao.jpa;
2   
3   import java.util.Collection;
4   import java.util.HashSet;
5   import javax.persistence.EntityManager;
6   import org.apache.commons.logging.Log;
7   import org.apache.commons.logging.LogFactory;
8   import org.apache.lucene.analysis.Analyzer;
9   import org.apache.lucene.index.FieldInfo;
10  import org.apache.lucene.index.IndexReader;
11  import org.apache.lucene.queryParser.MultiFieldQueryParser;
12  import org.apache.lucene.queryParser.ParseException;
13  import org.apache.lucene.search.MatchAllDocsQuery;
14  import org.apache.lucene.search.Query;
15  import org.apache.lucene.util.ReaderUtil;
16  import org.apache.lucene.util.Version;
17  import org.hibernate.search.MassIndexer;
18  import org.hibernate.search.SearchFactory;
19  import org.hibernate.search.indexes.IndexReaderAccessor;
20  import org.hibernate.search.jpa.FullTextEntityManager;
21  import org.hibernate.search.jpa.Search;
22  
23  /**
24   * Utility class to generate lucene queries for hibernate search and perform full reindexing.
25   *
26   * @author jgarcia
27   */
28  public class HibernateSearchJpaTools {
29      protected static final Log log = LogFactory.getLog(HibernateSearchJpaTools.class);
30      /**
31       * Generates a lucene query to search for a given term in all the indexed fields of a class
32       *
33       * @param searchTerm the term to search for
34       * @param searchedEntity the class searched
35       * @param entityManager the entity manager
36       * @param defaultAnalyzer the default analyzer for parsing the search terms
37       * @return
38       * @throws ParseException
39       */
40      public static Query generateQuery(String searchTerm, Class searchedEntity, EntityManager entityManager, Analyzer defaultAnalyzer) throws ParseException {
41          Query qry = null;
42  
43          if (searchTerm.equals("*")) {
44              qry = new MatchAllDocsQuery();
45          } else {
46              // Search in all indexed fields
47  
48              IndexReaderAccessor readerAccessor = null;
49              IndexReader reader = null;
50              try {
51                  FullTextEntityManager fullTextEntityManager = org.hibernate.search.jpa.Search.getFullTextEntityManager(entityManager);
52  
53                  // obtain analyzer to parse the query:
54                  Analyzer analyzer;
55                  if (searchedEntity == null) {
56                      analyzer = defaultAnalyzer;
57                  } else {
58                      analyzer = fullTextEntityManager.getSearchFactory().getAnalyzer(searchedEntity);
59                  }
60  
61                  // search on all indexed fields: generate field list, removing internal hibernate search field name: _hibernate_class
62                  // TODO: possible improvement: cache the fields of each entity
63                  SearchFactory searchFactory = fullTextEntityManager.getSearchFactory();
64                  readerAccessor = searchFactory.getIndexReaderAccessor();
65                  reader = readerAccessor.open(searchedEntity);
66                  Collection<String> fieldNames = new HashSet<>();
67                  for (FieldInfo fieldInfo : ReaderUtil.getMergedFieldInfos(reader)) {
68                      if (fieldInfo.isIndexed) {
69                          fieldNames.add(fieldInfo.name);
70                      }
71                  }
72                  fieldNames.remove("_hibernate_class");
73                  String[] fnames = new String[0];
74                  fnames = fieldNames.toArray(fnames);
75  
76                  // To search on all fields, search the term in all fields
77                  String[] queries = new String[fnames.length];
78                  for (int i = 0; i < queries.length; ++i) {
79                      queries[i] = searchTerm;
80                  }
81  
82                  qry = MultiFieldQueryParser.parse(Version.LUCENE_36, queries, fnames, analyzer);
83              } finally {
84                  if (readerAccessor != null && reader != null) {
85                      readerAccessor.close(reader);
86                  }
87              }
88          }
89          return qry;
90      }
91  
92  
93      /**
94       * Regenerates the index for a given class
95       *
96       * @param clazz the class
97       * @param entityManager the entity manager
98       */
99      public static void reindex(Class clazz, EntityManager entityManager) {
100         FullTextEntityManager txtentityManager = Search.getFullTextEntityManager(entityManager);
101         MassIndexer massIndexer = txtentityManager.createIndexer(clazz);
102         try {
103             massIndexer.startAndWait();
104         } catch (InterruptedException e) {
105             log.error("mass reindexing interrupted: " + e.getMessage());
106         } finally {
107             txtentityManager.flushToIndexes();
108         }
109     }
110 
111     /**
112      * Regenerates all the indexed class indexes
113      *
114      * @param async true if the reindexing will be done as a background thread
115      * @param entityManager the entity manager
116      */
117     public static void reindexAll(boolean async, EntityManager entityManager) {
118         FullTextEntityManager txtentityManager = Search.getFullTextEntityManager(entityManager);
119         MassIndexer massIndexer = txtentityManager.createIndexer();
120         massIndexer.purgeAllOnStart(true);
121         try {
122             if (!async) {
123                 massIndexer.startAndWait();
124             } else {
125                 massIndexer.start();
126             }
127         } catch (InterruptedException e) {
128             log.error("mass reindexing interrupted: " + e.getMessage());
129         } finally {
130             txtentityManager.flushToIndexes();
131         }
132     }
133 }