/*
* (C) Copyright 2014 Nuxeo SA (http://nuxeo.com/) and others.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Contributors:
* Delbosc Benoit
*/
package org.nuxeo.elasticsearch.work;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.nuxeo.ecm.core.api.ScrollResult;
import org.nuxeo.ecm.core.work.api.Work;
import org.nuxeo.ecm.core.work.api.WorkManager;
import org.nuxeo.runtime.api.Framework;
import org.nuxeo.runtime.transaction.TransactionHelper;
import java.util.Collections;
import java.util.List;
import static org.nuxeo.elasticsearch.ElasticSearchConstants.REINDEX_BUCKET_READ_PROPERTY;
/**
* Worker to reindex a large amount of document
*
* @since 7.1
*/
public class ScrollingIndexingWorker extends BaseIndexingWorker implements Work {
private static final Log log = LogFactory.getLog(ScrollingIndexingWorker.class);
private static final long serialVersionUID = -4507677669419340384L;
private static final String DEFAULT_BUCKET_SIZE = "500";
private static final long WARN_DOC_COUNT = 500;
protected final String nxql;
protected transient WorkManager workManager;
protected long documentCount = 0;
public ScrollingIndexingWorker(String repositoryName, String nxql) {
this.repositoryName = repositoryName;
this.nxql = nxql;
}
@Override
public String getTitle() {
return "Elasticsearch scrolling indexer: " + nxql + ", processed " + documentCount;
}
@Override
protected void doWork() {
String jobName = getSchedulePath().getPath();
if (log.isDebugEnabled()) {
log.debug(String.format("Re-indexing job: %s started, NXQL: %s on repository: %s", jobName, nxql,
repositoryName));
}
openSystemSession();
int bucketSize = getBucketSize();
ScrollResult ret = session.scroll(nxql, bucketSize, 60);
int bucketCount = 0;
boolean warnAtEnd = false;
try {
while (ret.hasResults()) {
documentCount += ret.getResultIds().size();
scheduleBucketWorker(ret.getResultIds(), false);
bucketCount += 1;
ret = session.scroll(ret.getScrollId());
TransactionHelper.commitOrRollbackTransaction();
TransactionHelper.startTransaction();
}
if (documentCount > WARN_DOC_COUNT) {
warnAtEnd = true;
scheduleBucketWorker(Collections.emptyList(), warnAtEnd);
}
} finally {
if (warnAtEnd || log.isDebugEnabled()) {
String message = String.format("Re-indexing job: %s has submited %d documents in %d bucket workers",
jobName, documentCount, bucketCount);
if (warnAtEnd) {
log.warn(message);
} else {
log.debug(message);
}
}
}
}
protected void scheduleBucketWorker(List<String> bucket, boolean isLast) {
if (bucket.isEmpty()) {
return;
}
BucketIndexingWorker subWorker = new BucketIndexingWorker(repositoryName, bucket, isLast);
getWorkManager().schedule(subWorker);
}
protected WorkManager getWorkManager() {
if (workManager == null) {
workManager = Framework.getLocalService(WorkManager.class);
}
return workManager;
}
protected int getBucketSize() {
String value = Framework.getProperty(REINDEX_BUCKET_READ_PROPERTY, DEFAULT_BUCKET_SIZE);
return Integer.parseInt(value);
}
}