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

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)

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

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

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()

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

fullTextSession.createIndexer().startAndWait();

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

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

Example 6.6. Using a tuned MassIndexer

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)覆盖这个值。

相关推荐