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