Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ Please mark backwards incompatible changes with an exclamation mark at the start
when `active_support/core_ext/string` hadn't been loaded.

### Added
- The `#force_merge` method to the `Elasticsearch::Index` class. This method
starts a Forced Segment Merge on the index.
- The `#totals` method to `Elasticsearch::Stats::Index`, this gives the caller
access to the index's total metrics.
- The `Elasticsearch::Stats::Index::Totals` class. The class contains information
Expand Down
1 change: 1 addition & 0 deletions lib/jay_api/elasticsearch/errors.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
require_relative 'errors/query_execution_failure'
require_relative 'errors/query_execution_timeout'
require_relative 'errors/search_after_error'
require_relative 'errors/writable_index_error'

module JayAPI
module Elasticsearch
Expand Down
13 changes: 13 additions & 0 deletions lib/jay_api/elasticsearch/errors/writable_index_error.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# frozen_string_literal: true

require_relative '../../errors/error'

module JayAPI
module Elasticsearch
module Errors
# An error to be raised when an attempt is made to perform force_merge
# over an index which hasn't been set to be read-only.
class WritableIndexError < ::JayAPI::Errors::Error; end
end
end
end
24 changes: 24 additions & 0 deletions lib/jay_api/elasticsearch/index.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

require_relative 'indexable'
require_relative 'indices/settings'
require_relative 'errors/writable_index_error'

module JayAPI
module Elasticsearch
Expand Down Expand Up @@ -57,6 +58,29 @@ def settings
# DO NOT MEMOIZE! Leave it to the caller.
::JayAPI::Elasticsearch::Indices::Settings.new(client.transport_client, index_name)
end

# Starts a Forced Segment Merge process on the index.
#
# ⚠️ For big indexes this process can take a very long time, make sure to
# adjust the timeout when creating the client.
# @param [Boolean] only_expunge_deletes Specifies whether the operation
# should only remove deleted documents.
# @raise [JayAPI::Elasticsearch::Errors::WritableIndexError] If the index
# is writable (hasn't been set to read-only).
# @return [Hash] A +Hash+ with the result of the index merging process,
# it looks like this:
#
# { "_shards" => { "total" => 10, "successful" => 10, "failed" => 0 } }
def force_merge(only_expunge_deletes: nil)
unless settings.blocks.write_blocked?
raise ::JayAPI::Elasticsearch::Errors::WritableIndexError,
"Write block for '#{index_name}' has not been enabled. " \
"Please enable the index's write block before performing a segment merge"
end

params = { index: index_name, only_expunge_deletes: }.compact
client.transport_client.indices.forcemerge(**params)
end
end
end
end
129 changes: 129 additions & 0 deletions spec/jay_api/elasticsearch/index_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,135 @@
end
end

describe '#force_merge' do
subject(:method_call) { index.force_merge(**method_params) }

let(:method_params) { {} }

let(:write_blocked?) { true }

let(:blocks) do
instance_double(
JayAPI::Elasticsearch::Indices::Settings::Blocks,
write_blocked?: write_blocked?
)
end

let(:settings) do
instance_double(
JayAPI::Elasticsearch::Indices::Settings,
blocks: blocks
)
end

let(:request_result) do
{ '_shards' => { 'total' => 10, 'successful' => 10, 'failed' => 0 } }
end

let(:indices_client) do
instance_double(
Elasticsearch::API::Indices::IndicesClient,
forcemerge: request_result
)
end

before do
allow(JayAPI::Elasticsearch::Indices::Settings).to receive(:new).and_return(settings)
allow(transport_client).to receive(:indices).and_return(indices_client)
end

context 'when the fetching of the settings raises an HTTP error' do
let(:error) do
[
Elasticsearch::Transport::Transport::Errors::RequestTimeout,
'408 - Timed out'
]
end

before do
allow(blocks).to receive(:write_blocked?).and_raise(*error)
end

it 're-raises the error' do
expect { method_call }.to raise_error(*error)
end
end

context 'when the fetching of the settings raises a KeyError' do
let(:error) { [KeyError, 'key not found: "blocks"'] }

before do
allow(blocks).to receive(:write_blocked?).and_raise(*error)
end

it 're-raises the error' do
expect { method_call }.to raise_error(*error)
end
end

context 'when the index is not in read-only mode' do
let(:write_blocked?) { false }

it 'raises a WritableIndexError' do
expect { method_call }.to raise_error(
JayAPI::Elasticsearch::Errors::WritableIndexError,
"Write block for 'elite_unit_tests' has not been enabled. " \
"Please enable the index's write block before performing a segment merge"
)
end
end

context "when 'only_expunge_deletes' is omitted" do
it 'starts a Force Merge process for the index, with no additional parameters' do
expect(indices_client).to receive(:forcemerge).with(index: 'elite_unit_tests')
method_call
end
end

context "when 'only_expunge_deletes' set to false" do
let(:method_params) { super().merge(only_expunge_deletes: false) }

it 'starts a Force Merge process for the index, with only_expunge_deletes set to false' do
expect(indices_client).to receive(:forcemerge)
.with(index: 'elite_unit_tests', only_expunge_deletes: false)

method_call
end
end

context "when 'only_expunge_deletes' set to true" do
let(:method_params) { super().merge(only_expunge_deletes: true) }

it 'starts a Force Merge process for the index, with only_expunge_deletes set to true' do
expect(indices_client).to receive(:forcemerge)
.with(index: 'elite_unit_tests', only_expunge_deletes: true)

method_call
end
end

context 'when the Force Merge API call fails' do
let(:error) do
[
Elasticsearch::Transport::Transport::Errors::Forbidden,
'408 - You do not have permissions to perform this action'
]
end

before do
allow(indices_client).to receive(:forcemerge).and_raise(*error)
end

it 're-raises the error' do
expect { method_call }.to raise_error(*error)
end
end

it 'returns the Hash with the result of the request' do
expect(method_call).to be(request_result)
end
end

describe '#queue_size' do
subject(:method_call) { index.queue_size }

Expand Down