Hibernate Search(基于version3.4)--第六章Manual index changes

当Hibernate core应用实体类的改变到数据库,Hibernate Search也会自动地探测这些改变并更新index(除非禁用事件监听器)。有时候并不是通过Hibernate来修改数据库的数据,像当还原数据库的备份或数据是不同的方式生成的。对于这样的用例,Hibernate Search暴露了Manual Index API来明确地更新,删除index中的单一实体,或重建整个数据库的index,或删除某个指定类型的所有引用。

 

所有的这些方法只影响 Lucene Index,并不会修改数据库。

 

6.1. Adding instances to the index

使用FullTextSession.index(T entity),你可以直接地添加或更新一个具体的对象实例到index。如果该实例已经存在index中,那么就会更新index。index的改变只能在transaction commit时应用。

 

Example 6.1. Indexing an entity via FullTextSession.index(T entity)

 

Java代码 复制代码 收藏代码
  1. FullTextSession fullTextSession = Search.getFullTextSession(session);
  2. Transaction tx = fullTextSession.beginTransaction();
  3. Object customer = fullTextSession.load( Customer.class, 8 );
  4. fullTextSession.index(customer);
  5. tx.commit(); //index only updated at commit time
FullTextSession fullTextSession = Search.getFullTextSession(session);
Transaction tx = fullTextSession.beginTransaction();
Object customer = fullTextSession.load( Customer.class, 8 );
fullTextSession.index(customer);
tx.commit(); //index only updated at commit time

6.2. Deleting instances from the index

也可以不删除数据库数据的情况下,删除指定类的Lucene index。这个操作称为purging,也是通过FullTextSession来完成的。

 

Example 6.2. Purging a specific instance of an entity from the index

 

Java代码 复制代码 收藏代码
  1. FullTextSession fullTextSession = Search.getFullTextSession(session);
  2. Transaction tx = fullTextSession.beginTransaction();
  3. for (Customer customer : customers) {
  4. fullTextSession.purge( Customer.class, customer.getId() );
  5. }
  6. tx.commit(); //index is updated at commit time
FullTextSession fullTextSession = Search.getFullTextSession(session);
Transaction tx = fullTextSession.beginTransaction();
for (Customer customer : customers) {
    fullTextSession.purge( Customer.class, customer.getId() );
}
tx.commit(); //index is updated at commit time

 

 

purging只会移除index中指定id的实体,对数据库不产生影响。

 

如果你需要移除某个类的所有index,你可以使用purgeAll方法。这个操作也会移除类的子类。

Example 6.3. Purging all instances of an entity from the index

 

Java代码 复制代码 收藏代码
  1. FullTextSession fullTextSession = Search.getFullTextSession(session);
  2. Transaction tx = fullTextSession.beginTransaction();
  3. fullTextSession.purgeAll( Customer.class );
  4. //optionally optimize the index
  5. //fullTextSession.getSearchFactory().optimize( Customer.class );
  6. tx.commit(); //index changes are applied at commit time
FullTextSession fullTextSession = Search.getFullTextSession(session);
Transaction tx = fullTextSession.beginTransaction();
fullTextSession.purgeAll( Customer.class );
//optionally optimize the index
//fullTextSession.getSearchFactory().optimize( Customer.class );
tx.commit(); //index changes are applied at commit time 

 

 

推荐在purging操作之后optimize the index。

 

Note:方法index,purge,purgeAll同样适用FullTextEntityManager。

 

Note:所有manual indexing methods (index, purge and purgeAll)只会影响index,不会影响数据库,然而它们必须是事务的,在事务提交之前或使用flushToIndexes方法之前,它们是不会被应用的

 

 

6.3. Rebuilding the whole index

 

如果你改变了实体到index的映射,这样就需要更新整个index。例如你要改变一个已存在的field的analyzer,你需要重建index。同样地,如果数据库被重置了(还原备份),你也需要重建index。Hibernate Search提供了两个主要策略来达到重建index的目的:

 

  • 使用FullTextSession.index()一个个地更新实体,然后对应地使用FullTextSession.flushToIndexes()方法来刷新缓存。
  • Use a MassIndexer.

 

 

6.3.1. Using flushToIndexes()

 

该策略对应使用了FullTextSession.purgeAll()或FullTextSession.index(),然而这些方法会存在内存和性能约束。为了最大性能体现,Hibernate Search捆绑了所有index操作直到commit time来执行这些操作。如果你希望添加大量的index数据,那么你需要小心内存消耗,因为所有的document保存在一个队列中直到事务提交。如果你不同期性地清空队列,你可能潜在面对一个OutOfMemoryException:清空队列可以使用fullTextSession.flushToIndexes()方法。每一次调用fullTextSession.flushToIndexes()(或事务提交),捆绑队列会应用于index。注意,当flush,所应用的改变不能roll back。

 

Example 6.4. Index rebuilding using index() and flushToIndexes()

 

Java代码 复制代码 收藏代码
  1. fullTextSession.setFlushMode(FlushMode.MANUAL);
  2. fullTextSession.setCacheMode(CacheMode.IGNORE);
  3. transaction = fullTextSession.beginTransaction();
  4. //Scrollable results will avoid loading too many objects in memory
  5. ScrollableResults results = fullTextSession.createCriteria( Email.class )
  6. .setFetchSize(BATCH_SIZE)
  7. .scroll( ScrollMode.FORWARD_ONLY );
  8. int index = 0;
  9. while( results.next() ) {
  10. index++;
  11. fullTextSession.index( results.get(0) ); //index each element
  12. if (index % BATCH_SIZE == 0) {
  13. fullTextSession.flushToIndexes(); //apply changes to indexes
  14. fullTextSession.clear(); //free memory since the queue is processed
  15. }
  16. }
  17. transaction.commit();
fullTextSession.setFlushMode(FlushMode.MANUAL);
fullTextSession.setCacheMode(CacheMode.IGNORE);
transaction = fullTextSession.beginTransaction();
//Scrollable results will avoid loading too many objects in memory
ScrollableResults results = fullTextSession.createCriteria( Email.class )
    .setFetchSize(BATCH_SIZE)
    .scroll( ScrollMode.FORWARD_ONLY );
int index = 0;
while( results.next() ) {
    index++;
    fullTextSession.index( results.get(0) ); //index each element
    if (index % BATCH_SIZE == 0) {
        fullTextSession.flushToIndexes(); //apply changes to indexes
        fullTextSession.clear(); //free memory since the queue is processed
    }
}
transaction.commit();

 

Note:hibernate.search.worker.batch_size已经被弃用,明确的API声明能提供更好的控制。

 

使用一个batch size可以保证你的应用不会out of memory:一个大的batch size,从数据库抓取数据的速度更快,不过需要更多的内存。

 

 

6.3.2. Using a MassIndexer

Hibernate Search的MassIndexer使用多个平行线程来重建index;你可以指定哪些实体需要重载或重建index。这个方法有着最优性能,但要求设置应用为maintenance模式:当MassIndexer繁忙时,不推荐查询index。

 

Example 6.5. Index rebuilding using a MassIndexer

 

Java代码 复制代码 收藏代码
  1. fullTextSession.createIndexer().startAndWait();
fullTextSession.createIndexer().startAndWait();

 

这句代码会重建index,先删除它并重新从数据库中加载所有实体。虽然使用很简单,但推荐做些调整去提高速度:有些参数需要配置。

 

Warning:在MassIndexer处理过程中,index的内容是未定义的,因此在重建过程中应该确保没有人查询index。如果有人在查询index,并不会破坏该index,只是有些结果会丢失。

 

Example 6.6. Using a tuned MassIndexer

 

Java代码 复制代码 收藏代码
  1. fullTextSession
  2. .createIndexer( User.class )
  3. .batchSizeToLoadObjects( 25 )
  4. .cacheMode( CacheMode.NORMAL )
  5. .threadsToLoadObjects( 5 )
  6. .threadsForIndexWriter( 3 )
  7. .threadsForSubsequentFetching( 20 )
  8. .progressMonitor( monitor ) //a MassIndexerProgressMonitor implementation
  9. .startAndWait();
fullTextSession
 .createIndexer( User.class )
 .batchSizeToLoadObjects( 25 )
 .cacheMode( CacheMode.NORMAL )
 .threadsToLoadObjects( 5 )
 .threadsForIndexWriter( 3 )
 .threadsForSubsequentFetching( 20 )
 .progressMonitor( monitor ) //a MassIndexerProgressMonitor implementation
 .startAndWait();

 

 

这将会重建所有的User实例(和其子类实例),使用每次查询25个对象批量处理方式,创建5个并行线程加载用户实例;这些加载的User实例是管道至20并行线程来延迟加载用户中的集合。最后,3个并行线程用于analyze文本和写入index。

 

推荐CacheMode为CacheMode.IGNORE(默认),在大多数reindexing情景,缓存是没什么作用的;你可以激活其他的CacheMode,不过这依赖于你使用的数据。如果主实体与enum-like数据相关,它或许可以提高性能。

 

Note:MassIndexer是为了提高建立索引速度而产生的,它不需要事务处理。因为它是非事务的,所以它不推荐在MassIndexer运行期间让用户执行应用。

 

其他一些影响indexing time和内存消耗:

 

  • hibernate.search.[default|<indexname>].exclusive_index_use
  • hibernate.search.[default|<indexname>].indexwriter.batch.max_buffered_docs
  • hibernate.search.[default|<indexname>].indexwriter.batch.max_merge_docs
  • hibernate.search.[default|<indexname>].indexwriter.batch.merge_factor
  • hibernate.search.[default|<indexname>].indexwriter.batch.ram_buffer_size
  • hibernate.search.[default|<indexname>].indexwriter.batch.term_index_interval
  • hibernate.search.batchbackend.concurrent_writers
之前的版本中有一个max_field_length参数,但它已经被Lucene移除,使用LimitTokenCountAnalyzer可以获得相似的效果。
 
所有.indexwriter参数是Lucene指定的,Hibernate Search只是传递这些参数。详细请看Section 3.10, “Tuning Lucene indexing performance”
 
hibernate.search.batchbackend.concurrent_writers默认是2,它表示Analysis和MassIndexing的indexWriter管道使用的线程数。MassIndexer.threadsForIndexWriter(int)覆盖这个值。
 
posted @ 2013-04-30 15:34 眉间尺之魂 阅读(...) 评论(...) 编辑 收藏