title: Can Hibernate Search index build performance be improved using projection?
body: <p>I have an entity containing around 40 columns and 7 collections. The collections are not lazy loaded. Indexing 500 000 entities using Hibernate Search MassIndexer takes around 2-3 hours. I use the code below:</p>
  
  <pre><code>fullTextSession.createIndexer()
          .batchSizeToLoadObjects(1000)
          .threadsToLoadObjects(8).start();
  </code></pre>
  
  <p>I even tried using lazy loading to see what the difference would be, and then it takes around 1 hour, which is not as fast as I would hope for.</p>
  
  <p>To try out what the performance would be like if having an entity containing only the columns that I want to index, 3 columns including the ID column, I created an entity containing only those three columns. Indexing was now very rapid, it only took 3 minutes.</p>
  
  <p>The approach to use a different entity is not what I want since it would require a manual update of the index every time the original entity is updated (as far as I understand how it works). I then thought of using the flushToIndexes() approach and projection, instead of MassIndexer.</p>
  
  <p>I wrote up the code below based on <a href="https://docs.jboss.org/hibernate/search/4.4/reference/en-US/html_single/#search-batchindex-flushtoindexes" rel="nofollow">https://docs.jboss.org/hibernate/search/4.4/reference/en-US/html_single/#search-batchindex-flushtoindexes</a> and added the projection part.</p>
  
  <pre><code>Session session = sessionFactory.openSession();
  try {
      int batchSize = 1000;
      FullTextSession fullTextSession = Search.getFullTextSession(session);
      fullTextSession.setFlushMode(FlushMode.MANUAL);
      fullTextSession.setCacheMode(CacheMode.IGNORE);
      Transaction transaction = fullTextSession.beginTransaction();
      //Scrollable results will avoid loading too many objects in memory
      ScrollableResults results = fullTextSession.createCriteria( Report.class )
          .setProjection(Projections.projectionList()
                  .add(Projections.property("reportId"), "reportId")
                  .add(Projections.property("header"), "header")
                  .add(Projections.property("description"), "description")
                  )
          .setResultTransformer(Transformers.aliasToBean(Report.class))
          .setFetchSize(batchSize)
          .scroll( ScrollMode.FORWARD_ONLY );
      int index = 0;
      while( results.next() ) {
          index++;
          fullTextSession.index( results.get(0) ); //index each element
          if (index % batchSize == 0) {
              fullTextSession.flushToIndexes(); //apply changes to indexes
              fullTextSession.clear(); //free memory since the queue is processed
          }
      }
      transaction.commit();
  } catch (Exception e) {
      log.error(e);
  } finally {
      session.close();
  }
  </code></pre>
  
  <p>When running the code I get an exception in the code (at <code>fullTextSession.index(results.get(0));</code>) when it tries to index the first element:</p>
  
  <blockquote>
    <p>org.hibernate.TransientObjectException: The instance was not associated with this session</p>
  </blockquote>
  
  <p>I don't understand why I get this exception. I have read that it can occur if using different Hibernate sessions, but in this case I am doing all work within one Hibernate session.</p>
  
  <p>Have anyone else tried to use projection together with Hibernate Search indexing? Should it be possible to use? Any information on the subject is appreciated.</p>
  
  <p>Some version information: I'm using Hibernate 4.2.17.Final and Hibernate Search 4.4.6.Final. I can't use the latest version because of dependencies.</p>