Hibernate Search:防止批量插入期间的高内存使用量

时间:2014-05-08 17:09:47

标签: java batch-processing hibernate-search

在使用自动索引执行批量插入时,Hibernate Search会创建数百万个org.apache.lucene.document.Field实例,这些实例都会保留在内存中直到事务完成。

由于我没有设法使用任何HS选项进行修复,并且我不想刷新未指定的事务,我想在批处理之前暂停自动索引,然后手动更新索引。为此我设置了以下选项:

 hibernateProperties.put("hibernate.search.default.indexBase", "path/to/index");
 hibernateProperties.put("hibernate.search.model_mapping", searchMappingFactory.createSearchMapping());
 hibernateProperties.put("hibernate.search.autoregister_listeners", false);

我用以下方法编写自定义FullTextIndexEventListener:

@Override
public void onPostInsert(PostInsertEvent event) {
    if (!isPaused) {
         super.onPostDelete(event);
    }
}

我使用自定义集成商集成了它:

@Component
public class HibernateEventIntegrator {  

    @Autowired
    private SessionFactoryImpl sessionFactory;
    @Autowired
    private SearchIndexEventListener searchIndexEventListener;  

    @PostConstruct
    public void integrate() {
         EventListenerRegistry listenerRegistry = sessionFactory.getServiceRegistry().getService(EventListenerRegistry.class);
         listenerRegistry.appendListeners(EventType.POST_INSERT, searchIndexEventListener);
         //... and so for all events like in HibernateSearchIntegrator
         searchIndexEventListener.initialize(sessionFactory.getProperties());
    }
}

但是,在这种情况下,不会读取映射,就好像没有索引任何实体一样,它们只能由本机HS集成商看到。

我也试过使用带有跳过动作的拦截器,但它似乎不是一个很好的解决方案。

是否有任何解决方案可以在不完全切换到手动索引的情况下以编程方式暂停自动索引?

2 个答案:

答案 0 :(得分:1)

Hibernate Search不提供这样的功能。另请参阅https://hibernate.atlassian.net/browse/HSEARCH-168https://hibernate.atlassian.net/browse/HSEARCH-387

一种解决方法是使用两个单独的SessionFactories,一个启用事件处理,另一个禁用事件处理。然后,您将根据用例从正确的工厂打开会话。

答案 1 :(得分:1)

我们解决了自定义TransactionalWorker,使其刷新,这样在给定的操作数量后释放内存。这就是我期望的worker.batch_size,在代码之下:

public class TransactionalFlushingWorker extends TransactionalWorker {

private static final int INDEX_BATCH_SIZE = 2000;

private final AtomicInteger indexingWithoutFlushCounter = new AtomicInteger();

public void performWork(Work<?> work, TransactionContext transactionContext) {
    super.performWork(work, transactionContext);
    if (indexingWithoutFlushCounter.incrementAndGet() > INDEX_BATCH_SIZE) {
        flushWorks(transactionContext);
    }
}

public void flushWorks(TransactionContext transactionContext) {
    indexingWithoutFlushCounter.set(0);
    super.flushWorks(transactionContext);
}
}

注册:

hibernateProperties.put("hibernate.search.worker.scope", TransactionalFlushingWorker.class.getName());