vendor/ruflin/elastica/src/Index.php line 546

Open in your IDE?
  1. <?php
  2. namespace Elastica;
  3. use Elastica\Bulk\ResponseSet;
  4. use Elastica\Exception\Bulk\ResponseException as BulkResponseException;
  5. use Elastica\Exception\ClientException;
  6. use Elastica\Exception\ConnectionException;
  7. use Elastica\Exception\InvalidException;
  8. use Elastica\Exception\NotFoundException;
  9. use Elastica\Exception\ResponseException;
  10. use Elastica\Index\Recovery as IndexRecovery;
  11. use Elastica\Index\Settings as IndexSettings;
  12. use Elastica\Index\Stats as IndexStats;
  13. use Elastica\Query\AbstractQuery;
  14. use Elastica\ResultSet\BuilderInterface;
  15. use Elastica\Script\AbstractScript;
  16. use Elasticsearch\Endpoints\AbstractEndpoint;
  17. use Elasticsearch\Endpoints\DeleteByQuery;
  18. use Elasticsearch\Endpoints\Get as DocumentGet;
  19. use Elasticsearch\Endpoints\Index as IndexEndpoint;
  20. use Elasticsearch\Endpoints\Indices\Alias;
  21. use Elasticsearch\Endpoints\Indices\Aliases\Update;
  22. use Elasticsearch\Endpoints\Indices\Analyze;
  23. use Elasticsearch\Endpoints\Indices\Cache\Clear;
  24. use Elasticsearch\Endpoints\Indices\ClearCache;
  25. use Elasticsearch\Endpoints\Indices\Close;
  26. use Elasticsearch\Endpoints\Indices\Create;
  27. use Elasticsearch\Endpoints\Indices\Delete;
  28. use Elasticsearch\Endpoints\Indices\DeleteAlias;
  29. use Elasticsearch\Endpoints\Indices\Exists;
  30. use Elasticsearch\Endpoints\Indices\Flush;
  31. use Elasticsearch\Endpoints\Indices\ForceMerge;
  32. use Elasticsearch\Endpoints\Indices\GetAlias;
  33. use Elasticsearch\Endpoints\Indices\GetMapping;
  34. use Elasticsearch\Endpoints\Indices\Mapping\Get as MappingGet;
  35. use Elasticsearch\Endpoints\Indices\Open;
  36. use Elasticsearch\Endpoints\Indices\PutSettings;
  37. use Elasticsearch\Endpoints\Indices\Refresh;
  38. use Elasticsearch\Endpoints\Indices\Settings\Put;
  39. use Elasticsearch\Endpoints\Indices\UpdateAliases;
  40. use Elasticsearch\Endpoints\OpenPointInTime;
  41. use Elasticsearch\Endpoints\UpdateByQuery;
  42. /**
  43. * Elastica index object.
  44. *
  45. * Handles reads, deletes and configurations of an index
  46. *
  47. * @author Nicolas Ruflin <spam@ruflin.com>
  48. * @phpstan-import-type TCreateQueryArgsMatching from Query
  49. */
  50. class Index implements SearchableInterface
  51. {
  52. /**
  53. * Index name.
  54. *
  55. * @var string Index name
  56. */
  57. protected $_name;
  58. /**
  59. * Client object.
  60. *
  61. * @var Client Client object
  62. */
  63. protected $_client;
  64. /**
  65. * Creates a new index object.
  66. *
  67. * All the communication to and from an index goes of this object
  68. *
  69. * @param Client $client Client object
  70. * @param string $name Index name
  71. */
  72. public function __construct(Client $client, string $name)
  73. {
  74. $this->_client = $client;
  75. $this->_name = $name;
  76. }
  77. /**
  78. * Return Index Stats.
  79. *
  80. * @return IndexStats
  81. */
  82. public function getStats()
  83. {
  84. return new IndexStats($this);
  85. }
  86. /**
  87. * Return Index Recovery.
  88. *
  89. * @return IndexRecovery
  90. */
  91. public function getRecovery()
  92. {
  93. return new IndexRecovery($this);
  94. }
  95. /**
  96. * Sets the mappings for the current index.
  97. *
  98. * @param Mapping $mapping MappingType object
  99. * @param array $query querystring when put mapping (for example update_all_types)
  100. */
  101. public function setMapping(Mapping $mapping, array $query = []): Response
  102. {
  103. return $mapping->send($this, $query);
  104. }
  105. /**
  106. * Gets all mappings for the current index.
  107. *
  108. * @throws ClientException
  109. * @throws ConnectionException
  110. * @throws ResponseException
  111. */
  112. public function getMapping(): array
  113. {
  114. // TODO: Use only GetMapping when dropping support for elasticsearch/elasticsearch 7.x
  115. $endpoint = \class_exists(GetMapping::class) ? new GetMapping() : new MappingGet();
  116. $response = $this->requestEndpoint($endpoint);
  117. $data = $response->getData();
  118. // Get first entry as if index is an Alias, the name of the mapping is the real name and not alias name
  119. $mapping = \array_shift($data);
  120. return $mapping['mappings'] ?? [];
  121. }
  122. /**
  123. * Returns the index settings object.
  124. *
  125. * @return IndexSettings
  126. */
  127. public function getSettings()
  128. {
  129. return new IndexSettings($this);
  130. }
  131. /**
  132. * @param array|string $data
  133. *
  134. * @return Document
  135. */
  136. public function createDocument(string $id = '', $data = [])
  137. {
  138. return new Document($id, $data, $this);
  139. }
  140. /**
  141. * Uses _bulk to send documents to the server.
  142. *
  143. * @param Document[] $docs Array of Elastica\Document
  144. * @param array $options Array of query params to use for query. For possible options check es api
  145. *
  146. * @throws ClientException
  147. * @throws ConnectionException
  148. * @throws ResponseException
  149. * @throws BulkResponseException
  150. * @throws InvalidException
  151. *
  152. * @see https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-bulk.html
  153. */
  154. public function updateDocuments(array $docs, array $options = []): ResponseSet
  155. {
  156. foreach ($docs as $doc) {
  157. $doc->setIndex($this->getName());
  158. }
  159. return $this->getClient()->updateDocuments($docs, $options);
  160. }
  161. /**
  162. * Update entries in the db based on a query.
  163. *
  164. * @param AbstractQuery|array|Query|string|null $query Query object or array
  165. * @phpstan-param TCreateQueryArgsMatching $query
  166. *
  167. * @param AbstractScript $script Script
  168. * @param array $options Optional params
  169. *
  170. * @see https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-update-by-query.html
  171. *
  172. * @throws ClientException
  173. * @throws ConnectionException
  174. * @throws ResponseException
  175. */
  176. public function updateByQuery($query, AbstractScript $script, array $options = []): Response
  177. {
  178. $endpoint = new UpdateByQuery();
  179. $q = Query::create($query)->getQuery();
  180. $body = [
  181. 'query' => \is_array($q) ? $q : $q->toArray(),
  182. 'script' => $script->toArray()['script'],
  183. ];
  184. $endpoint->setBody($body);
  185. $endpoint->setParams($options);
  186. return $this->requestEndpoint($endpoint);
  187. }
  188. /**
  189. * Adds the given document to the search index.
  190. *
  191. * @throws ClientException
  192. * @throws ConnectionException
  193. * @throws ResponseException
  194. */
  195. public function addDocument(Document $doc): Response
  196. {
  197. $endpoint = new IndexEndpoint();
  198. if (null !== $doc->getId() && '' !== $doc->getId()) {
  199. $endpoint->setId($doc->getId());
  200. }
  201. $options = $doc->getOptions(
  202. [
  203. 'consistency',
  204. 'op_type',
  205. 'parent',
  206. 'percolate',
  207. 'pipeline',
  208. 'refresh',
  209. 'replication',
  210. 'retry_on_conflict',
  211. 'routing',
  212. 'timeout',
  213. ]
  214. );
  215. $endpoint->setBody($doc->getData());
  216. $endpoint->setParams($options);
  217. $response = $this->requestEndpoint($endpoint);
  218. $data = $response->getData();
  219. // set autogenerated id to document
  220. if ($response->isOk() && (
  221. $doc->isAutoPopulate() || $this->getClient()->getConfigValue(['document', 'autoPopulate'], false)
  222. )) {
  223. if (isset($data['_id']) && !$doc->hasId()) {
  224. $doc->setId($data['_id']);
  225. }
  226. $doc->setVersionParams($data);
  227. }
  228. return $response;
  229. }
  230. /**
  231. * Uses _bulk to send documents to the server.
  232. *
  233. * @param array|Document[] $docs Array of Elastica\Document
  234. * @param array $options Array of query params to use for query. For possible options check es api
  235. *
  236. * @throws ClientException
  237. * @throws ConnectionException
  238. * @throws ResponseException
  239. * @throws BulkResponseException
  240. * @throws InvalidException
  241. *
  242. * @return ResponseSet
  243. *
  244. * @see https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-bulk.html
  245. */
  246. public function addDocuments(array $docs, array $options = [])
  247. {
  248. foreach ($docs as $doc) {
  249. $doc->setIndex($this->getName());
  250. }
  251. return $this->getClient()->addDocuments($docs, $options);
  252. }
  253. /**
  254. * Get the document from search index.
  255. *
  256. * @param int|string $id Document id
  257. * @param array $options options for the get request
  258. *
  259. * @throws NotFoundException
  260. * @throws ClientException
  261. * @throws ConnectionException
  262. * @throws ResponseException
  263. */
  264. public function getDocument($id, array $options = []): Document
  265. {
  266. $endpoint = new DocumentGet();
  267. $endpoint->setId($id);
  268. $endpoint->setParams($options);
  269. $response = $this->requestEndpoint($endpoint);
  270. $result = $response->getData();
  271. if (!isset($result['found']) || false === $result['found']) {
  272. throw new NotFoundException('doc id '.$id.' not found');
  273. }
  274. if (isset($result['fields'])) {
  275. $data = $result['fields'];
  276. } elseif (isset($result['_source'])) {
  277. $data = $result['_source'];
  278. } else {
  279. $data = [];
  280. }
  281. $doc = new Document($id, $data, $this->getName());
  282. $doc->setVersionParams($result);
  283. return $doc;
  284. }
  285. /**
  286. * Deletes a document by its unique identifier.
  287. *
  288. * @see https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-delete.html
  289. *
  290. * @throws ClientException
  291. * @throws ConnectionException
  292. * @throws ResponseException
  293. */
  294. public function deleteById(string $id, array $options = []): Response
  295. {
  296. if (!\trim($id)) {
  297. throw new NotFoundException('Doc id "'.$id.'" not found and can not be deleted');
  298. }
  299. $endpoint = new \Elasticsearch\Endpoints\Delete();
  300. $endpoint->setId(\trim($id));
  301. $endpoint->setParams($options);
  302. return $this->requestEndpoint($endpoint);
  303. }
  304. /**
  305. * Deletes documents matching the given query.
  306. *
  307. * @param AbstractQuery|array|Query|string|null $query Query object or array
  308. * @phpstan-param TCreateQueryArgsMatching $query
  309. *
  310. * @param array $options Optional params
  311. *
  312. * @see https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-delete-by-query.html
  313. *
  314. * @throws ClientException
  315. * @throws ConnectionException
  316. * @throws ResponseException
  317. */
  318. public function deleteByQuery($query, array $options = []): Response
  319. {
  320. $query = Query::create($query)->getQuery();
  321. $endpoint = new DeleteByQuery();
  322. $endpoint->setBody(['query' => \is_array($query) ? $query : $query->toArray()]);
  323. $endpoint->setParams($options);
  324. return $this->requestEndpoint($endpoint);
  325. }
  326. /**
  327. * Opens a Point-in-Time on the index.
  328. *
  329. * @see: https://www.elastic.co/guide/en/elasticsearch/reference/current/point-in-time-api.html
  330. *
  331. * @throws ClientException
  332. * @throws ConnectionException
  333. * @throws ResponseException
  334. */
  335. public function openPointInTime(string $keepAlive): Response
  336. {
  337. $endpoint = new OpenPointInTime();
  338. $endpoint->setParams(['keep_alive' => $keepAlive]);
  339. return $this->requestEndpoint($endpoint);
  340. }
  341. /**
  342. * Deletes the index.
  343. *
  344. * @throws ClientException
  345. * @throws ConnectionException
  346. * @throws ResponseException
  347. */
  348. public function delete(): Response
  349. {
  350. return $this->requestEndpoint(new Delete());
  351. }
  352. /**
  353. * Uses the "_bulk" endpoint to delete documents from the server.
  354. *
  355. * @param Document[] $docs Array of documents
  356. *
  357. * @throws ClientException
  358. * @throws ConnectionException
  359. * @throws ResponseException
  360. * @throws BulkResponseException
  361. * @throws InvalidException
  362. *
  363. * @see https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-bulk.html
  364. */
  365. public function deleteDocuments(array $docs): ResponseSet
  366. {
  367. foreach ($docs as $doc) {
  368. $doc->setIndex($this->getName());
  369. }
  370. return $this->getClient()->deleteDocuments($docs);
  371. }
  372. /**
  373. * Force merges index.
  374. *
  375. * Detailed arguments can be found here in the ES documentation.
  376. *
  377. * @param array $args Additional arguments
  378. *
  379. * @see https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-forcemerge.html
  380. *
  381. * @throws ClientException
  382. * @throws ConnectionException
  383. * @throws ResponseException
  384. */
  385. public function forcemerge($args = []): Response
  386. {
  387. $endpoint = new ForceMerge();
  388. $endpoint->setParams($args);
  389. return $this->requestEndpoint($endpoint);
  390. }
  391. /**
  392. * Refreshes the index.
  393. *
  394. * @see https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-refresh.html
  395. *
  396. * @throws ClientException
  397. * @throws ConnectionException
  398. * @throws ResponseException
  399. */
  400. public function refresh(): Response
  401. {
  402. return $this->requestEndpoint(new Refresh());
  403. }
  404. /**
  405. * Creates a new index with the given arguments.
  406. *
  407. * @see https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-create-index.html
  408. *
  409. * @param array $args Additional arguments to pass to the Create endpoint
  410. * @param array|bool $options OPTIONAL
  411. * bool=> Deletes index first if already exists (default = false).
  412. * array => Associative array of options (option=>value)
  413. *
  414. * @throws InvalidException
  415. * @throws ClientException
  416. * @throws ConnectionException
  417. * @throws ResponseException
  418. *
  419. * @return Response Server response
  420. */
  421. public function create(array $args = [], $options = null): Response
  422. {
  423. if (null === $options) {
  424. if (\func_num_args() >= 2) {
  425. \trigger_deprecation('ruflin/elastica', '7.1.0', 'Passing null as 2nd argument to "%s()" is deprecated, avoid passing this argument or pass an array instead. It will be removed in 8.0.', __METHOD__);
  426. }
  427. $options = [];
  428. } elseif (\is_bool($options)) {
  429. \trigger_deprecation('ruflin/elastica', '7.1.0', 'Passing a bool as 2nd argument to "%s()" is deprecated, pass an array with the key "recreate" instead. It will be removed in 8.0.', __METHOD__);
  430. $options = ['recreate' => $options];
  431. } elseif (!\is_array($options)) {
  432. throw new \TypeError(\sprintf('Argument 2 passed to "%s()" must be of type array|bool|null, %s given.', __METHOD__, \is_object($options) ? \get_class($options) : \gettype($options)));
  433. }
  434. $endpoint = new Create();
  435. $invalidOptions = \array_diff(\array_keys($options), $allowedOptions = \array_merge($endpoint->getParamWhitelist(), [
  436. 'recreate',
  437. ]));
  438. if (1 === $invalidOptionCount = \count($invalidOptions)) {
  439. throw new InvalidException(\sprintf('"%s" is not a valid option. Allowed options are "%s".', \implode('", "', $invalidOptions), \implode('", "', $allowedOptions)));
  440. }
  441. if ($invalidOptionCount > 1) {
  442. throw new InvalidException(\sprintf('"%s" are not valid options. Allowed options are "%s".', \implode('", "', $invalidOptions), \implode('", "', $allowedOptions)));
  443. }
  444. if ($options['recreate'] ?? false) {
  445. try {
  446. $this->delete();
  447. } catch (ResponseException $e) {
  448. // Index can't be deleted, because it doesn't exist
  449. }
  450. }
  451. unset($options['recreate']);
  452. $endpoint->setParams($options);
  453. $endpoint->setBody($args);
  454. return $this->requestEndpoint($endpoint);
  455. }
  456. /**
  457. * Checks if the given index exists ans is created.
  458. *
  459. * @throws ClientException
  460. * @throws ConnectionException
  461. * @throws ResponseException
  462. */
  463. public function exists(): bool
  464. {
  465. $response = $this->requestEndpoint(new Exists());
  466. return 200 === $response->getStatus();
  467. }
  468. /**
  469. * {@inheritdoc}
  470. */
  471. public function createSearch($query = '', $options = null, ?BuilderInterface $builder = null): Search
  472. {
  473. $search = new Search($this->getClient(), $builder);
  474. $search->addIndex($this);
  475. $search->setOptionsAndQuery($options, $query);
  476. return $search;
  477. }
  478. /**
  479. * {@inheritdoc}
  480. */
  481. public function search($query = '', $options = null, string $method = Request::POST): ResultSet
  482. {
  483. $search = $this->createSearch($query, $options);
  484. return $search->search('', null, $method);
  485. }
  486. /**
  487. * {@inheritdoc}
  488. */
  489. public function count($query = '', string $method = Request::POST): int
  490. {
  491. $search = $this->createSearch($query);
  492. return $search->count('', false, $method);
  493. }
  494. /**
  495. * Opens an index.
  496. *
  497. * @see https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-open-close.html
  498. *
  499. * @throws ClientException
  500. * @throws ConnectionException
  501. * @throws ResponseException
  502. */
  503. public function open(): Response
  504. {
  505. return $this->requestEndpoint(new Open());
  506. }
  507. /**
  508. * Closes the index.
  509. *
  510. * @see https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-open-close.html
  511. *
  512. * @throws ClientException
  513. * @throws ConnectionException
  514. * @throws ResponseException
  515. */
  516. public function close(): Response
  517. {
  518. return $this->requestEndpoint(new Close());
  519. }
  520. /**
  521. * Returns the index name.
  522. */
  523. public function getName(): string
  524. {
  525. return $this->_name;
  526. }
  527. /**
  528. * Returns index client.
  529. */
  530. public function getClient(): Client
  531. {
  532. return $this->_client;
  533. }
  534. /**
  535. * Adds an alias to the current index.
  536. *
  537. * @param bool $replace If set, an existing alias will be replaced
  538. *
  539. * @see https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-aliases.html
  540. *
  541. * @throws ClientException
  542. * @throws ConnectionException
  543. * @throws ResponseException
  544. */
  545. public function addAlias(string $name, bool $replace = false): Response
  546. {
  547. $data = ['actions' => []];
  548. if ($replace) {
  549. $status = new Status($this->getClient());
  550. foreach ($status->getIndicesWithAlias($name) as $index) {
  551. $data['actions'][] = ['remove' => ['index' => $index->getName(), 'alias' => $name]];
  552. }
  553. }
  554. $data['actions'][] = ['add' => ['index' => $this->getName(), 'alias' => $name]];
  555. // TODO: Use only UpdateAliases when dropping support for elasticsearch/elasticsearch 7.x
  556. $endpoint = \class_exists(UpdateAliases::class) ? new UpdateAliases() : new Update();
  557. $endpoint->setBody($data);
  558. return $this->getClient()->requestEndpoint($endpoint);
  559. }
  560. /**
  561. * Removes an alias pointing to the current index.
  562. *
  563. * @see https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-aliases.html
  564. *
  565. * @throws ClientException
  566. * @throws ConnectionException
  567. * @throws ResponseException
  568. */
  569. public function removeAlias(string $name): Response
  570. {
  571. // TODO: Use only DeleteAlias when dropping support for elasticsearch/elasticsearch 7.x
  572. $endpoint = \class_exists(DeleteAlias::class) ? new DeleteAlias() : new Alias\Delete();
  573. $endpoint->setName($name);
  574. return $this->requestEndpoint($endpoint);
  575. }
  576. /**
  577. * Returns all index aliases.
  578. *
  579. * @throws ClientException
  580. * @throws ConnectionException
  581. * @throws ResponseException
  582. *
  583. * @return string[]
  584. */
  585. public function getAliases(): array
  586. {
  587. // TODO: Use only GetAlias when dropping support for elasticsearch/elasticsearch 7.x
  588. $endpoint = \class_exists(GetAlias::class) ? new GetAlias() : new Alias\Get();
  589. $endpoint->setName('*');
  590. $responseData = $this->requestEndpoint($endpoint)->getData();
  591. if (!isset($responseData[$this->getName()])) {
  592. return [];
  593. }
  594. $data = $responseData[$this->getName()];
  595. if (!empty($data['aliases'])) {
  596. return \array_keys($data['aliases']);
  597. }
  598. return [];
  599. }
  600. /**
  601. * Checks if the index has the given alias.
  602. */
  603. public function hasAlias(string $name): bool
  604. {
  605. return \in_array($name, $this->getAliases(), true);
  606. }
  607. /**
  608. * Clears the cache of an index.
  609. *
  610. * @see https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-clearcache.html
  611. *
  612. * @throws ClientException
  613. * @throws ConnectionException
  614. * @throws ResponseException
  615. */
  616. public function clearCache(): Response
  617. {
  618. // TODO: Use only ClearCache when dropping support for elasticsearch/elasticsearch 7.x
  619. $endpoint = \class_exists(ClearCache::class) ? new ClearCache() : new Clear();
  620. // TODO: add additional cache clean arguments
  621. return $this->requestEndpoint($endpoint);
  622. }
  623. /**
  624. * Flushes the index to storage.
  625. *
  626. * @see https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-flush.html
  627. *
  628. * @throws ClientException
  629. * @throws ConnectionException
  630. * @throws ResponseException
  631. */
  632. public function flush(array $options = []): Response
  633. {
  634. $endpoint = new Flush();
  635. $endpoint->setParams($options);
  636. return $this->requestEndpoint($endpoint);
  637. }
  638. /**
  639. * Can be used to change settings during runtime. One example is to use it for bulk updating.
  640. *
  641. * @param array $data Data array
  642. *
  643. * @see https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-update-settings.html
  644. *
  645. * @throws ClientException
  646. * @throws ConnectionException
  647. * @throws ResponseException
  648. */
  649. public function setSettings(array $data): Response
  650. {
  651. // TODO: Use only PutSettings when dropping support for elasticsearch/elasticsearch 7.x
  652. $endpoint = \class_exists(PutSettings::class) ? new PutSettings() : new Put();
  653. $endpoint->setBody($data);
  654. return $this->requestEndpoint($endpoint);
  655. }
  656. /**
  657. * Makes calls to the elasticsearch server based on this index.
  658. *
  659. * @param string $path Path to call
  660. * @param string $method Rest method to use (GET, POST, DELETE, PUT)
  661. * @param array|string $data Arguments as array or encoded string
  662. *
  663. * @throws ClientException
  664. * @throws ConnectionException
  665. * @throws ResponseException
  666. */
  667. public function request(string $path, string $method, $data = [], array $queryParameters = []): Response
  668. {
  669. $path = $this->getName().'/'.$path;
  670. return $this->getClient()->request($path, $method, $data, $queryParameters);
  671. }
  672. /**
  673. * Makes calls to the elasticsearch server with usage official client Endpoint based on this index.
  674. *
  675. * @throws ClientException
  676. * @throws ConnectionException
  677. * @throws ResponseException
  678. */
  679. public function requestEndpoint(AbstractEndpoint $endpoint): Response
  680. {
  681. $cloned = clone $endpoint;
  682. $cloned->setIndex($this->getName());
  683. return $this->getClient()->requestEndpoint($cloned);
  684. }
  685. /**
  686. * Run the analysis on the index.
  687. *
  688. * @param array $body request body for the `_analyze` API, see API documentation for the required properties
  689. * @param array $args Additional arguments
  690. *
  691. * @see https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-analyze.html
  692. *
  693. * @throws ClientException
  694. * @throws ConnectionException
  695. * @throws ResponseException
  696. */
  697. public function analyze(array $body, $args = []): array
  698. {
  699. $endpoint = new Analyze();
  700. $endpoint->setBody($body);
  701. $endpoint->setParams($args);
  702. $data = $this->requestEndpoint($endpoint)->getData();
  703. // Support for "Explain" parameter, that returns a different response structure from Elastic
  704. // @see: https://www.elastic.co/guide/en/elasticsearch/reference/current/_explain_analyze.html
  705. if (isset($body['explain']) && $body['explain']) {
  706. return $data['detail'];
  707. }
  708. return $data['tokens'];
  709. }
  710. /**
  711. * Update document, using update script.
  712. *
  713. * @see https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-update.html
  714. *
  715. * @param AbstractScript|Document $data Document or Script with update data
  716. * @param array $options array of query params to use for query
  717. */
  718. public function updateDocument($data, array $options = []): Response
  719. {
  720. if (!($data instanceof Document) && !($data instanceof AbstractScript)) {
  721. throw new \InvalidArgumentException('Data should be a Document or Script');
  722. }
  723. if (!$data->hasId()) {
  724. throw new InvalidException('Document or Script id is not set');
  725. }
  726. return $this->getClient()->updateDocument($data->getId(), $data, $this->getName(), $options);
  727. }
  728. }