package pl.allegro.tech.search.elasticsearch.tools.reindex; import org.elasticsearch.client.Client; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import pl.allegro.tech.search.elasticsearch.tools.reindex.connection.ElasticDataPointer; import pl.allegro.tech.search.elasticsearch.tools.reindex.connection.ElasticSearchClientFactory; import pl.allegro.tech.search.elasticsearch.tools.reindex.connection.ElasticSearchQuery; import pl.allegro.tech.search.elasticsearch.tools.reindex.process.IndexingComponent; import pl.allegro.tech.search.elasticsearch.tools.reindex.process.IndexingProcessBuilder; import pl.allegro.tech.search.elasticsearch.tools.reindex.process.ProcessConfiguration; import pl.allegro.tech.search.elasticsearch.tools.reindex.process.ProcessExecutor; import pl.allegro.tech.search.elasticsearch.tools.reindex.process.ProcessSynchronizer; import pl.allegro.tech.search.elasticsearch.tools.reindex.process.QueryComponentBuilder; import pl.allegro.tech.search.elasticsearch.tools.reindex.process.QueryProcess; import pl.allegro.tech.search.elasticsearch.tools.reindex.query.QuerySegmentation; import pl.allegro.tech.search.elasticsearch.tools.reindex.statistics.ReindexingSummary; import java.util.Arrays; import java.util.stream.IntStream; class ReindexInvoker { private static final Logger LOGGER = LoggerFactory.getLogger(ReindexInvoker.class); private ProcessSynchronizer processSynchronizer; private ProcessExecutor processExecutor; public ReindexInvoker(int querySegmentCount) { processExecutor = new ProcessExecutor(querySegmentCount); processSynchronizer = new ProcessSynchronizer(querySegmentCount); } public static ReindexingSummary invokeReindexing(ElasticDataPointer sourcePointer, ElasticDataPointer targetPointer, QuerySegmentation segmentation) { ReindexInvoker reindexInvoker = new ReindexInvoker(segmentation.getSegmentsCount()); LOGGER.info("Starting"); ReindexingSummary summary = reindexInvoker.run(sourcePointer, targetPointer, segmentation); LOGGER.info("Ended"); return summary; } public ReindexingSummary run(ElasticDataPointer sourcePointer, ElasticDataPointer targetPointer, QuerySegmentation segmentation) { Client sourceClient = ElasticSearchClientFactory.createClient(sourcePointer); Client targetClient = ElasticSearchClientFactory.createClient(targetPointer); if (indexExists(sourceClient, sourcePointer.getIndexName())) { startQueriesProcesses(sourceClient, sourcePointer, segmentation); startUpdatesProcesses(targetClient, targetPointer); processSynchronizer.waitForProcessesToEnd(); } releaseResources(sourceClient, targetClient); processSynchronizer.logStats(); return processSynchronizer.getReindexingSummary(); } private boolean indexExists(Client sourceClient, String indexName) { return sourceClient.admin().indices().prepareExists(indexName).get().isExists(); } private void startUpdatesProcesses(Client client, ElasticDataPointer targetPointer) { IntStream.range(0, ProcessConfiguration.getInstance().getUpdateThreadsCount()).forEach( i -> processExecutor.startProcess( IndexingProcessBuilder.builder() .setIndexingComponent(new IndexingComponent(client)) .setDataPointer(targetPointer) .setProcessSynchronizer(processSynchronizer) .build()) ); } private void startQueriesProcesses(Client client, ElasticDataPointer sourcePointer, QuerySegmentation segmentation) { IntStream.range(0, segmentation.getSegmentsCount()) .mapToObj( i -> QueryComponentBuilder.builder() .setClient(client) .setDataPointer(sourcePointer) .setSegmentationField(segmentation.getFieldName()) .setBound(segmentation.getThreshold(i)) .setQuery(segmentation.getQuery()) .createQueryComponent() ).map( queryComponent -> new QueryProcess(processSynchronizer, queryComponent) ).forEach( processExecutor::startProcess ); } private void releaseResources(Client sourceClient, Client targetClient) { processExecutor.finishProcessing(); refreshTargetIndex(targetClient); disconnectElasticsearchClients(sourceClient, targetClient); } private void refreshTargetIndex(Client targetClient) { targetClient.admin().indices().prepareRefresh().get(); } private void disconnectElasticsearchClients(Client... clients) { Arrays.asList(clients) .forEach(Client::close); } }