* * @see https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-update-settings.html * @see https://www.elastic.co/guide/en/elasticsearch/reference/current/index-modules-merge.html */ class Settings { public const DEFAULT_REFRESH_INTERVAL = '1s'; public const DEFAULT_NUMBER_OF_REPLICAS = 1; public const DEFAULT_NUMBER_OF_SHARDS = 1; /** * Response. * * @var Response Response object */ protected $_response; /** * Stats info. * * @var array Stats info */ protected $_data = []; /** * Index. * * @var BaseIndex Index object */ protected $_index; /** * Construct. * * @param BaseIndex $index Index object */ public function __construct(BaseIndex $index) { $this->_index = $index; } /** * Returns the current settings of the index. * * If param is set, only specified setting is return. * 'index.' is added in front of $setting. * * @param string $setting OPTIONAL Setting name to return * * @throws ClientException * @throws ConnectionException * @throws ResponseException * * @return array|int|string|null Settings data * * @see https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-update-settings.html */ public function get(string $setting = '', bool $includeDefaults = false) { $queryParameters = [ 'include_defaults' => $includeDefaults, ]; $requestData = $this->request([], Request::GET, $queryParameters)->getData(); $data = \reset($requestData); if (empty($data['settings']) || empty($data['settings']['index'])) { // should not append, the request should throw a ResponseException throw new NotFoundException('Index '.$this->getIndex()->getName().' not found'); } $settings = $data['settings']['index']; $defaults = $data['defaults']['index'] ?? []; $settings = \array_merge($defaults, $settings); if (!$setting) { // return all array return $settings; } if (isset($settings[$setting])) { return $settings[$setting]; } if (false !== \strpos($setting, '.')) { // translate old dot-notation settings to nested arrays $keys = \explode('.', $setting); foreach ($keys as $key) { if (isset($settings[$key])) { $settings = $settings[$key]; } else { return null; } } return $settings; } return null; } /** * Returns a setting interpreted as a bool. * * One can use a real bool, int(0), int(1) to set bool settings. * But Elasticsearch stores and returns all settings as strings and does * not normalize bool values. This method ensures a bool is returned for * whichever string representation is used like 'true', '1', 'on', 'yes'. * * @param string $setting Setting name to return * * @throws ClientException * @throws ConnectionException * @throws ResponseException */ public function getBool(string $setting): bool { $data = $this->get($setting); return 'true' === $data || '1' === $data || 'on' === $data || 'yes' === $data; } /** * Sets the number of replicas. * * @param int $replicas Number of replicas * * @throws ClientException * @throws ConnectionException * @throws ResponseException * * @return Response Response object */ public function setNumberOfReplicas(int $replicas): Response { return $this->set(['number_of_replicas' => $replicas]); } /** * Returns the number of replicas. * * If no number of replicas is set, the default number is returned * * @throws ClientException * @throws ConnectionException * @throws ResponseException * * @return int The number of replicas */ public function getNumberOfReplicas(): int { return $this->get('number_of_replicas') ?? self::DEFAULT_NUMBER_OF_REPLICAS; } /** * Returns the number of shards. * * If no number of shards is set, the default number is returned * * @throws ClientException * @throws ConnectionException * @throws ResponseException * * @return int The number of shards */ public function getNumberOfShards(): int { return $this->get('number_of_shards') ?? self::DEFAULT_NUMBER_OF_SHARDS; } /** * Sets the index to read only. * * @param bool $readOnly (default = true) * * @throws ClientException * @throws ConnectionException * @throws ResponseException */ public function setReadOnly(bool $readOnly = true): Response { return $this->set(['blocks.read_only' => $readOnly]); } /** * @throws ClientException * @throws ConnectionException * @throws ResponseException */ public function getReadOnly(): bool { return $this->getBool('blocks.read_only'); } /** * @throws ClientException * @throws ConnectionException * @throws ResponseException */ public function getBlocksRead(): bool { return $this->getBool('blocks.read'); } /** * @param bool $state OPTIONAL (default = true) * * @throws ClientException * @throws ConnectionException * @throws ResponseException */ public function setBlocksRead(bool $state = true): Response { return $this->set(['blocks.read' => $state]); } /** * @throws ClientException * @throws ConnectionException * @throws ResponseException */ public function getBlocksWrite(): bool { return $this->getBool('blocks.write'); } /** * @param bool $state OPTIONAL (default = true) * * @throws ClientException * @throws ConnectionException * @throws ResponseException */ public function setBlocksWrite(bool $state = true): Response { return $this->set(['blocks.write' => $state]); } /** * @throws ClientException * @throws ConnectionException * @throws ResponseException */ public function getBlocksMetadata(): bool { // When blocks.metadata is enabled, reading the settings is not possible anymore. // So when a cluster_block_exception happened it must be enabled. try { return $this->getBool('blocks.metadata'); } catch (ResponseException $e) { if ('cluster_block_exception' === $e->getResponse()->getFullError()['type']) { return true; } throw $e; } } /** * Set to true to disable index metadata reads and writes. * * @param bool $state OPTIONAL (default = true) * * @throws ClientException * @throws ConnectionException * @throws ResponseException */ public function setBlocksMetadata(bool $state = true): Response { return $this->set(['blocks.metadata' => $state]); } /** * Sets the index refresh interval. * * Value can be for example 3s for 3 seconds or * 5m for 5 minutes. -1 to disabled refresh. * * @param string $interval Duration of the refresh interval * * @throws ClientException * @throws ConnectionException * @throws ResponseException * * @return Response Response object */ public function setRefreshInterval(string $interval): Response { return $this->set(['refresh_interval' => $interval]); } /** * Returns the refresh interval. * * If no interval is set, the default interval is returned * * @throws ClientException * @throws ConnectionException * @throws ResponseException * * @return string Refresh interval */ public function getRefreshInterval(): string { return $this->get('refresh_interval') ?? self::DEFAULT_REFRESH_INTERVAL; } /** * Sets the specific merge policies. * * To have this changes made the index has to be closed and reopened * * @param string $key Merge policy key (for ex. expunge_deletes_allowed) * @param int|string $value * * @throws ClientException * @throws ConnectionException * @throws ResponseException * * @see https://www.elastic.co/guide/en/elasticsearch/reference/current/index-modules-merge.html */ public function setMergePolicy(string $key, $value): Response { $this->_index->close(); $response = $this->set(['merge.policy.'.$key => $value]); $this->_index->open(); return $response; } /** * Returns the specific merge policy value. * * @param string $key Merge policy key (for ex. expunge_deletes_allowed) * * @throws ClientException * @throws ConnectionException * @throws ResponseException * * @return int|string * * @see https://www.elastic.co/guide/en/elasticsearch/reference/current/index-modules-merge.html */ public function getMergePolicy(string $key) { $settings = $this->get(); return $settings['merge']['policy'][$key] ?? null; } /** * Can be used to set/update settings. * * @param array $data Arguments * * @throws ClientException * @throws ConnectionException * @throws ResponseException * * @return Response Response object */ public function set(array $data): Response { return $this->request($data, Request::PUT); } /** * Returns the index object. * * @return BaseIndex Index object */ public function getIndex(): BaseIndex { return $this->_index; } /** * Updates the given settings for the index. * * With elasticsearch 0.16 the following settings are supported * - index.term_index_interval * - index.term_index_divisor * - index.translog.flush_threshold_ops * - index.translog.flush_threshold_size * - index.translog.flush_threshold_period * - index.refresh_interval * - index.merge.policy * - index.auto_expand_replicas * * @param array $data OPTIONAL Data array * @param string $method OPTIONAL Transfer method (default = \Elastica\Request::GET) * * @throws ClientException * @throws ConnectionException * @throws ResponseException * * @return Response Response object */ public function request(array $data = [], string $method = Request::GET, array $queryParameters = []): Response { $path = '_settings'; if ($data) { $data = ['index' => $data]; } return $this->getIndex()->request($path, $method, $data, $queryParameters); } }