Skip to content

Commit 4ffc503

Browse files
committed
Change the default serializer to the json gem for 4.0.0-beta.5
Historically, the `json` gem that is default from ruby has been somewhat slow compared to other available implementations like the `oj` gem. Gems like `multi_json` exist to allow people to choose which backend they want to use. For example, to use `oj`, one has to simply add it to their gemfile and then use `MultiJson.load` and it will automatically use the `oj` gem. Over the last few months there has been some great work to make the default `json` implementation in ruby more performant. In the following script, `json` used to be 1.5x times slower, now it is 1.4x times faster compared to `oj`: <details><summary>Benchmark</summary> <p> ```rb require "bundler/inline" gemfile do source 'https://rubygems.org' gem 'json' gem 'multi_json' gem 'oj' gem 'benchmark-ips' end # https://github.com/ruby/json/blob/3e025f76d77e323b30f6f6d2d8d06e787d497a0c/benchmark/data/twitter.json data = File.read("twitter.json") pp MultiJson.adapter Benchmark.ips do |x| x.report("json") do JSON.parse(data) end x.report("multi_json") do MultiJson.load(data) end x.compare! end ``` ``` ruby 3.4.2 (2025-02-15 revision d2930f8e7a) +PRISM [x86_64-linux] Warming up -------------------------------------- json 56.000 i/100ms multi_json 42.000 i/100ms Calculating ------------------------------------- json 570.026 (± 5.3%) i/s (1.75 ms/i) - 2.856k in 5.025704s multi_json 417.460 (± 2.4%) i/s (2.40 ms/i) - 2.100k in 5.033273s Comparison: json: 570.0 i/s multi_json: 417.5 i/s - 1.37x slower ``` </p> </details> You can read more about this work on the blog of the person who is responsible for these improvements here: https://byroot.github.io/ruby/json/2024/12/15/optimizing-ruby-json-part-1.html. It is 7 parts and contains many other benchmarks and interesting information. So, at this moment using `multi_json` is actually making things worse (if `oj` is in the gemfile) because it considers `oj` to be the preferable option. `multi_json` is in maintenance mode as per a maintainer intridea/multi_json#198 (comment) and not recommended anymore for new projects. There has also been no release in the last 5 years (but to be fair, last year there were many commits made by a different person, so not entirely a dead project). Anyways, I do not think there is any value in shipping with support for `multi_json` today anymore. If for some reason people want to use a different parser, they can easily accomplish this by implementing a custom serializer. So, for `opensearch-ruby` 4 I want to default to just using the `json` gem instead. Signed-off-by: Earlopain <14981592+Earlopain@users.noreply.github.com>
1 parent 8b47089 commit 4ffc503

File tree

13 files changed

+25
-20
lines changed

13 files changed

+25
-20
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
1818
### Changed
1919
- Restructured the API methods and modules to be more efficient and intuitive ([261](https://github.com/opensearch-project/opensearch-ruby/pull/261))
2020
- Moved ignore-404-on-deletion feature into the client options ([#277](https://github.com/opensearch-project/opensearch-ruby/pull/277))
21+
- Changed the default json serializer from `multi_json` to the `json` gem ([#290](https://github.com/opensearch-project/opensearch-ruby/pull/290))
2122
### Removed
2223
- Removed support for Ruby 2.x ([261](https://github.com/opensearch-project/opensearch-ruby/pull/261))
2324
- Removed the ability to ignore any error code by passing the `ignore: Array<error_code>` to each API method invocation ([#277](https://github.com/opensearch-project/opensearch-ruby/pull/277))

UPGRADING.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ Major versions of OpenSearch introduce breaking changes that require careful upg
77
- The lesser-known ability to ignore any error code by passing the `ignore: Array<error_code>` to each API method invocation is deemed unnecessary and dangerous. This feature has been removed in OpenSearch Ruby 4.
88
- The ability to pass an `opaque_id` parameter into an API method invocation to set the value of the `X-Opaque-Id` header has been removed. The user should now set the `X-Opaque-Id` header as part of the `headers` parameter in the API method invocation directly.
99
- OpenSearch Ruby 4 received a major refactor to remove middle-man `perform_request` methods. While this does not affect the vast majority of use cases, applications or wrappers that rely on these methods should be updated. For more information, check the `How the perform_request method is invoked` section of this [PR](https://github.com/opensearch-project/opensearch-ruby/pull/261).
10+
- The default serializer was switched from `multi_json` to the `json` gem. If you want to still use `multi_json`, you can easily achieve it by implementing a [custom serializer](guides/transport_options.md#serializer-implementations).
1011
## Upgrade to OpenSearch Ruby 3
1112
In Version 3 of the OpenSearch Ruby client, we have added the `api` and `transport` modules as the core components of the gem, instead of treating them as separate gems that are required by the `opensearch-ruby` gem. This removes the confusions around compatibility between the ruby client, its legacy dependencies, and the OpenSearch cluster.
1213

api_generator/lib/templates/api.mustache

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ module OpenSearch
1111
{{/global_query_params}}
1212
]).freeze
1313

14-
DEFAULT_SERIALIZER = MultiJson
14+
DEFAULT_SERIALIZER = Transport::Transport::Serializer::JSON.new
1515

1616
def self.serializer
1717
settings[:serializer] || DEFAULT_SERIALIZER

guides/transport_options.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -383,7 +383,7 @@ You can write your own transport implementation easily, by including the {OpenSe
383383

384384
### Serializer Implementations
385385

386-
By default, the [MultiJSON](http://rubygems.org/gems/multi_json) library is used as the serializer implementation, and it will pick up the "right" adapter based on gems available.
386+
By default, the [json](https://rubygems.org/gems/json) library is used as the serializer implementation.
387387

388388
The serialization component is pluggable, though, so you can write your own by including the {OpenSearch::Transport::Transport::Serializer::Base} module, implementing the required contract, and passing it to the client as the `serializer_class` or `serializer` parameter.
389389

lib/opensearch/api.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ module API
1919
'filter_path' # Used to reduce the response. This parameter takes a comma-separated list of filters. It supports using wildcards to match any field or part of a field’s name. You can also exclude fields with "-".
2020
]).freeze
2121

22-
DEFAULT_SERIALIZER = MultiJson
22+
DEFAULT_SERIALIZER = Transport::Transport::Serializer::JSON.new
2323

2424
def self.serializer
2525
settings[:serializer] || DEFAULT_SERIALIZER

lib/opensearch/transport.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,11 @@
2727
require 'uri'
2828
require 'time'
2929
require 'timeout'
30-
require 'multi_json'
30+
require 'json'
3131
require 'faraday'
3232

3333
require 'opensearch/transport/transport/loggable'
34-
require 'opensearch/transport/transport/serializer/multi_json'
34+
require 'opensearch/transport/transport/serializer/json'
3535
require 'opensearch/transport/transport/sniffer'
3636
require 'opensearch/transport/transport/response'
3737
require 'opensearch/transport/transport/errors'

lib/opensearch/transport/transport/base.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ module Base
3737
DEFAULT_RELOAD_AFTER = 10_000 # Requests
3838
DEFAULT_RESURRECT_AFTER = 60 # Seconds
3939
DEFAULT_MAX_RETRIES = 3 # Requests
40-
DEFAULT_SERIALIZER_CLASS = Serializer::MultiJson
40+
DEFAULT_SERIALIZER_CLASS = Serializer::JSON
4141
SANITIZED_PASSWORD = '*' * rand(1..14)
4242

4343
attr_reader :hosts, :options, :connections, :counter, :last_request_at, :protocol

lib/opensearch/transport/transport/serializer/multi_json.rb renamed to lib/opensearch/transport/transport/serializer/json.rb

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,21 +38,25 @@ def initialize(transport = nil)
3838
end
3939
end
4040

41-
# A default JSON serializer (using [MultiJSON](http://rubygems.org/gems/multi_json))
41+
# A default JSON serializer (using [json](http://rubygems.org/gems/json))
4242
#
43-
class MultiJson
43+
class JSON
4444
include Base
4545

4646
# De-serialize a Hash from JSON string
4747
#
4848
def load(string, options = {})
49-
::MultiJson.load(string, options)
49+
::JSON.parse(string, options)
5050
end
5151

5252
# Serialize a Hash to JSON string
5353
#
5454
def dump(object, options = {})
55-
::MultiJson.dump(object, options)
55+
if options.delete(:pretty)
56+
::JSON.pretty_generate(object, options)
57+
else
58+
::JSON.generate(object, options)
59+
end
5660
end
5761
end
5862
end

lib/opensearch/version.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,5 +25,5 @@
2525
# under the License.
2626

2727
module OpenSearch
28-
VERSION = '4.0.0-beta.4'.freeze
28+
VERSION = '4.0.0-beta.5'.freeze
2929
end

opensearch-ruby.gemspec

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,5 +66,4 @@ Gem::Specification.new do |s|
6666

6767
s.add_dependency 'faraday', '>= 1.0', '< 3'
6868
s.add_dependency "logger"
69-
s.add_dependency 'multi_json', '>= 1.0'
7069
end

0 commit comments

Comments
 (0)