xref: /plugin/elasticsearch/vendor/ruflin/elastica/src/Reindex.php (revision d832d53af2a0f84c34c8d5f17c93ffaa85869e5d)
1<?php
2
3namespace Elastica;
4
5use Elastica\Query\AbstractQuery;
6use Elastica\Script\AbstractScript;
7use Elastica\Script\Script;
8
9class Reindex extends Param
10{
11    public const VERSION_TYPE = 'version_type';
12    public const VERSION_TYPE_INTERNAL = 'internal';
13    public const VERSION_TYPE_EXTERNAL = 'external';
14    public const OPERATION_TYPE = 'op_type';
15    public const OPERATION_TYPE_CREATE = 'create';
16    public const CONFLICTS = 'conflicts';
17    public const CONFLICTS_PROCEED = 'proceed';
18    public const SIZE = 'size';
19    public const QUERY = 'query';
20    public const SORT = 'sort';
21    public const SCRIPT = 'script';
22    public const SOURCE = '_source';
23    public const REMOTE = 'remote';
24    public const SLICE = 'slice';
25    public const REFRESH = 'refresh';
26    public const REFRESH_TRUE = 'true';
27    public const REFRESH_FALSE = 'false';
28    public const REFRESH_WAIT_FOR = 'wait_for';
29    public const WAIT_FOR_COMPLETION = 'wait_for_completion';
30
31    /**
32     * @deprecated since version 7.2.0, use a boolean as parameter instead.
33     */
34    public const WAIT_FOR_COMPLETION_FALSE = 'false';
35    public const WAIT_FOR_ACTIVE_SHARDS = 'wait_for_active_shards';
36    public const TIMEOUT = 'timeout';
37    public const SCROLL = 'scroll';
38    public const REQUESTS_PER_SECOND = 'requests_per_second';
39    public const PIPELINE = 'pipeline';
40    public const SLICES = 'slices';
41    public const SLICES_AUTO = 'auto';
42
43    /**
44     * @var Index
45     */
46    protected $_oldIndex;
47
48    /**
49     * @var Index
50     */
51    protected $_newIndex;
52
53    /**
54     * @var Response|null
55     */
56    protected $_lastResponse;
57
58    public function __construct(Index $oldIndex, Index $newIndex, array $params = [])
59    {
60        $this->_oldIndex = $oldIndex;
61        $this->_newIndex = $newIndex;
62
63        $this->setParams($params);
64    }
65
66    public function run(): Response
67    {
68        $body = $this->_getBody($this->_oldIndex, $this->_newIndex, $this->getParams());
69
70        $reindexEndpoint = new \Elasticsearch\Endpoints\Reindex();
71        $params = \array_intersect_key($this->getParams(), \array_fill_keys($reindexEndpoint->getParamWhitelist(), null));
72        $reindexEndpoint->setParams($params);
73        $reindexEndpoint->setBody($body);
74
75        $this->_lastResponse = $this->_oldIndex->getClient()->requestEndpoint($reindexEndpoint);
76
77        return $this->_lastResponse;
78    }
79
80    /**
81     * @param bool $value
82     */
83    public function setWaitForCompletion($value): void
84    {
85        if (\is_bool($value)) {
86            $value = $value ? 'true' : 'false';
87        } else {
88            \trigger_deprecation('ruflin/elastica', '7.2.0', 'Passing anything else than a boolean as 1st argument to "%s()" is deprecated, pass a boolean instead. It will be removed in 8.0.', __METHOD__);
89        }
90
91        $this->setParam(self::WAIT_FOR_COMPLETION, $value);
92    }
93
94    public function setWaitForActiveShards($value): void
95    {
96        $this->setParam(self::WAIT_FOR_ACTIVE_SHARDS, $value);
97    }
98
99    public function setTimeout($value): void
100    {
101        $this->setParam(self::TIMEOUT, $value);
102    }
103
104    public function setScroll($value): void
105    {
106        $this->setParam(self::SCROLL, $value);
107    }
108
109    public function setRequestsPerSecond($value): void
110    {
111        $this->setParam(self::REQUESTS_PER_SECOND, $value);
112    }
113
114    public function setScript(Script $script): void
115    {
116        $this->setParam(self::SCRIPT, $script);
117    }
118
119    public function setQuery(AbstractQuery $query): void
120    {
121        $this->setParam(self::QUERY, $query);
122    }
123
124    public function setPipeline(Pipeline $pipeline): void
125    {
126        $this->setParam(self::PIPELINE, $pipeline);
127    }
128
129    public function setRefresh(string $value): void
130    {
131        $this->setParam(self::REFRESH, $value);
132    }
133
134    public function getTaskId()
135    {
136        $taskId = null;
137        if ($this->_lastResponse instanceof Response) {
138            $taskId = $this->_lastResponse->getData()['task'] ?: null;
139        }
140
141        return $taskId;
142    }
143
144    protected function _getBody(Index $oldIndex, Index $newIndex, array $params): array
145    {
146        $body = \array_merge([
147            'source' => $this->_getSourcePartBody($oldIndex, $params),
148            'dest' => $this->_getDestPartBody($newIndex, $params),
149        ], $this->_resolveBodyOptions($params));
150
151        return $this->_setBodyScript($body);
152    }
153
154    protected function _getSourcePartBody(Index $index, array $params): array
155    {
156        $sourceBody = \array_merge([
157            'index' => $index->getName(),
158        ], $this->_resolveSourceOptions($params));
159
160        return $this->_setSourceQuery($sourceBody);
161    }
162
163    protected function _getDestPartBody(Index $index, array $params): array
164    {
165        $destBody = \array_merge([
166            'index' => $index->getName(),
167        ], $this->_resolveDestOptions($params));
168
169        // Resolves the pipeline name
170        $pipeline = $destBody[self::PIPELINE] ?? null;
171        if ($pipeline instanceof Pipeline) {
172            $destBody[self::PIPELINE] = $pipeline->getId();
173        }
174
175        return $destBody;
176    }
177
178    private function _resolveSourceOptions(array $params): array
179    {
180        return \array_intersect_key($params, [
181            self::QUERY => null,
182            self::SORT => null,
183            self::SOURCE => null,
184            self::REMOTE => null,
185            self::SLICE => null,
186        ]);
187    }
188
189    private function _resolveDestOptions(array $params): array
190    {
191        return \array_intersect_key($params, [
192            self::VERSION_TYPE => null,
193            self::OPERATION_TYPE => null,
194            self::PIPELINE => null,
195        ]);
196    }
197
198    private function _resolveBodyOptions(array $params): array
199    {
200        return \array_intersect_key($params, [
201            self::SIZE => null,
202            self::CONFLICTS => null,
203        ]);
204    }
205
206    private function _setSourceQuery(array $sourceBody): array
207    {
208        if (isset($sourceBody[self::QUERY]) && $sourceBody[self::QUERY] instanceof AbstractQuery) {
209            $sourceBody[self::QUERY] = $sourceBody[self::QUERY]->toArray();
210        }
211
212        return $sourceBody;
213    }
214
215    private function _setBodyScript(array $body): array
216    {
217        if (!$this->hasParam(self::SCRIPT)) {
218            return $body;
219        }
220
221        $script = $this->getParam(self::SCRIPT);
222
223        if ($script instanceof AbstractScript) {
224            $body = \array_merge($body, $script->toArray());
225        } else {
226            $body[self::SCRIPT] = $script;
227        }
228
229        return $body;
230    }
231}
232