/* * Licensed to Elasticsearch under one or more contributor * license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright * ownership. Elasticsearch licenses this file to you 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. */ package org.elasticsearch.index.reindex; import org.elasticsearch.action.Action; import org.elasticsearch.action.ActionListener; import org.elasticsearch.action.search.SearchRequest; import org.elasticsearch.client.Client; import org.elasticsearch.index.mapper.UidFieldMapper; import org.elasticsearch.search.builder.SearchSourceBuilder; import org.elasticsearch.search.slice.SliceBuilder; import org.elasticsearch.tasks.TaskId; import org.elasticsearch.tasks.TaskManager; /** * Helps parallelize reindex requests using sliced scrolls. */ class BulkByScrollParallelizationHelper { private BulkByScrollParallelizationHelper() {} public static <Request extends AbstractBulkByScrollRequest<Request>> void startSlices(Client client, TaskManager taskManager, Action<Request, BulkByScrollResponse, ?> action, String localNodeId, ParentBulkByScrollTask task, Request request, ActionListener<BulkByScrollResponse> listener) { TaskId parentTaskId = new TaskId(localNodeId, task.getId()); for (final SearchRequest slice : sliceIntoSubRequests(request.getSearchRequest(), UidFieldMapper.NAME, request.getSlices())) { // TODO move the request to the correct node. maybe here or somehow do it as part of startup for reindex in general.... Request requestForSlice = request.forSlice(parentTaskId, slice); ActionListener<BulkByScrollResponse> sliceListener = ActionListener.wrap( r -> task.onSliceResponse(listener, slice.source().slice().getId(), r), e -> task.onSliceFailure(listener, slice.source().slice().getId(), e)); client.execute(action, requestForSlice, sliceListener); } } /** * Slice a search request into {@code times} separate search requests slicing on {@code field}. Note that the slices are *shallow* * copies of this request so don't change them. */ static SearchRequest[] sliceIntoSubRequests(SearchRequest request, String field, int times) { SearchRequest[] slices = new SearchRequest[times]; for (int slice = 0; slice < times; slice++) { SliceBuilder sliceBuilder = new SliceBuilder(field, slice, times); SearchSourceBuilder slicedSource; if (request.source() == null) { slicedSource = new SearchSourceBuilder().slice(sliceBuilder); } else { if (request.source().slice() != null) { throw new IllegalStateException("Can't slice a request that already has a slice configuration"); } slicedSource = request.source().copyWithNewSlice(sliceBuilder); } slices[slice] = new SearchRequest() .source(slicedSource) .searchType(request.searchType()) .indices(request.indices()) .types(request.types()) .routing(request.routing()) .preference(request.preference()) .requestCache(request.requestCache()) .scroll(request.scroll()) .indicesOptions(request.indicesOptions()); } return slices; } }