Skip to content

Commit 98955eb

Browse files
committed
Add Elasticsearch 9.x support
Elasticsearch 9.x introduced breaking changes to the elasticsearch-ruby client gem that prevent Chewy from working with ES 9 clusters: 1. The scroll API now requires scroll_id nested under a body: key ({scroll: '1m', body: {scroll_id: '...'}}) rather than as a top-level parameter. Without this, scroll requests raise an ArgumentError in elasticsearch-ruby 9.x. 2. API responses are now wrapped in Elasticsearch::API::Response objects instead of returning raw hashes/arrays. Code that calls .map or other Enumerable methods directly on responses (e.g. cat.indices) must now call .body first to access the underlying data. 3. The '_type' field was removed from search responses in ES 7+ and the elasticsearch-ruby 9.x client no longer includes it. All references to '_type' have been removed: mock response helpers, EVERFIELDS, wrapper accessors, and documentation examples. 4. The elasticsearch Ruby gem at version 9.x sends a compatible-with=9 header that ES 8.x servers reject. CI matrix entries that test against ES 8.x must pin the gem to ~> 8.14. Changes: - Widen elasticsearch gem dependency from < 9.0 to < 10.0 - Restructure perform_scroll to nest scroll_id under body:, which is compatible with both elasticsearch-ruby 8.x and 9.x - Access .body on cat.indices response in the drop_indices test helper - Remove '_type' from Minitest and RSpec mock response helpers, EVERFIELDS, Index::Wrapper accessors, and README examples - Remove obsolete '_parent' from EVERFIELDS - Add elasticsearch version matrix to CI (9.3.1 default with 8.15.0 spot-checks) using dynamic service container images - Pin elasticsearch gem to ~> 8.14 in CI for ES 8.x matrix entries - Add Ruby 3.4 / Rails 8.0 / ES 8.15.0 CI matrix entry - Add scroll body format assertion in scrolling specs - Expand migration guide with code examples, gem pinning guidance, corrected URLs, and more detailed upgrade steps - Consolidate CHANGELOG entries into single item with sub-bullets - Default docker-compose ES image to 9.3.1 - Bump version to 9.0.0
1 parent 680080a commit 98955eb

17 files changed

Lines changed: 98 additions & 24 deletions

File tree

.github/workflows/ruby.yml

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,21 @@ jobs:
2727
matrix:
2828
ruby: [ '3.2', '3.3', '3.4', '4.0' ]
2929
gemfile: [rails.7.2.activerecord, rails.8.0.activerecord, rails.8.1.activerecord]
30-
name: ${{ matrix.ruby }}-${{ matrix.gemfile }}
30+
elasticsearch: ['9.3.1']
31+
include:
32+
- ruby: '3.2'
33+
gemfile: rails.7.2.activerecord
34+
elasticsearch: '8.15.0'
35+
es_gem_constraint: '~> 8.14'
36+
- ruby: '3.4'
37+
gemfile: rails.8.0.activerecord
38+
elasticsearch: '8.15.0'
39+
es_gem_constraint: '~> 8.14'
40+
- ruby: '4.0'
41+
gemfile: rails.8.1.activerecord
42+
elasticsearch: '8.15.0'
43+
es_gem_constraint: '~> 8.14'
44+
name: ${{ matrix.ruby }}-${{ matrix.gemfile }}-es${{ matrix.elasticsearch }}
3145

3246
env:
3347
BUNDLE_GEMFILE: gemfiles/${{ matrix.gemfile }}.gemfile
@@ -45,7 +59,7 @@ jobs:
4559
--health-timeout 5s
4660
--health-retries 5
4761
elasticsearch:
48-
image: docker.elastic.co/elasticsearch/elasticsearch:8.15.0
62+
image: docker.elastic.co/elasticsearch/elasticsearch:${{ matrix.elasticsearch }}
4963
ports:
5064
- '9250:9200'
5165
env:
@@ -65,6 +79,9 @@ jobs:
6579
with:
6680
ruby-version: ${{ matrix.ruby }}
6781
bundler-cache: true
82+
- name: Pin elasticsearch gem for ES 8.x
83+
if: matrix.es_gem_constraint
84+
run: echo "gem 'elasticsearch', '${{ matrix.es_gem_constraint }}'" >> $BUNDLE_GEMFILE
6885
- name: Tests
6986
run: bundle exec rspec
7087

CHANGELOG.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,17 @@
11
# Changelog
22

3+
## 9.0.0 (unreleased)
4+
5+
### New Features
6+
7+
### Changes
8+
9+
* [#1009](https://github.com/toptal/chewy/pull/1009): **(Breaking)** Add Elasticsearch 9.x support while retaining ES 8.x compatibility. The `elasticsearch` gem dependency now allows `>= 8.14, < 10.0`. ([@mattmenefee][])
10+
* The `search_query.chewy` notification payload for scroll requests now nests `scroll_id` under `body:` (i.e. `{scroll: '1m', body: {scroll_id: '...'}}` instead of `{scroll: '1m', scroll_id: '...'}`). Update any application code that subscribes to scroll notification payloads.
11+
* `'_type' => '_doc'` has been removed from mock response helpers in `Chewy::Minitest::Helpers` and `Chewy::Rspec::Helpers` to match actual ES response format (ES 7+ no longer returns `_type`).
12+
13+
### Bugs Fixed
14+
315
## 8.0.2 (unreleased)
416

517
### Changes

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ Chewy is compatible with MRI 3.2-4.0.
5353

5454
| Chewy version | Elasticsearch version |
5555
| ------------- | ---------------------------------- |
56+
| 9.0.x | 8.x, 9.x |
5657
| 8.0.x | 8.x |
5758
| 7.2.x | 7.x |
5859
| 7.1.x | 7.x |
@@ -220,7 +221,6 @@ end
220221
},
221222
"_data":{
222223
"_index":"users",
223-
"_type":"_doc",
224224
"_id":"1",
225225
"_score":0.9808291,
226226
"_source":{

chewy.gemspec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ Gem::Specification.new do |spec|
1818
spec.require_paths = ['lib']
1919

2020
spec.add_dependency 'activesupport', '>= 7.2'
21-
spec.add_dependency 'elasticsearch', '>= 8.14', '< 9.0'
21+
spec.add_dependency 'elasticsearch', '>= 8.14', '< 10.0'
2222
spec.add_dependency 'elasticsearch-dsl'
2323
spec.metadata['rubygems_mfa_required'] = 'true'
2424
end

docker-compose.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
services:
22
elasticsearch_test:
3-
image: "docker.elastic.co/elasticsearch/elasticsearch:${ES_VERSION:-8.15.0}"
3+
image: "docker.elastic.co/elasticsearch/elasticsearch:${ES_VERSION:-9.3.1}"
44
environment:
55
- bootstrap.memory_lock=${ES_MEMORY_LOCK:-false}
66
- "ES_JAVA_OPTS=-Xms${TEST_ES_HEAP_SIZE:-500m} -Xmx${TEST_ES_HEAP_SIZE:-500m}"

lib/chewy/index/wrapper.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ def ==(other)
3939
end
4040
end
4141

42-
%w[_id _type _index].each do |name|
42+
%w[_id _index].each do |name|
4343
define_method name do
4444
_data[name]
4545
end

lib/chewy/minitest/helpers.rb

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,6 @@ def mock_elasticsearch_response_sources(index, hits, &block)
9696
'hits' => hits.each_with_index.map do |hit, i|
9797
{
9898
'_index' => index.index_name,
99-
'_type' => '_doc',
10099
'_id' => hit[:id] || (i + 1).to_s,
101100
'_score' => 3.14,
102101
'_source' => hit

lib/chewy/rspec/helpers.rb

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@ def mock_elasticsearch_response_sources(index, hits)
3939
'hits' => hits.each_with_index.map do |hit, i|
4040
{
4141
'_index' => index.index_name,
42-
'_type' => '_doc',
4342
'_id' => (i + 1).to_s,
4443
'_score' => 3.14,
4544
'_source' => hit

lib/chewy/search/request.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ class Request
1818
include Scoping
1919
include Scrolling
2020
UNDEFINED = Class.new.freeze
21-
EVERFIELDS = %w[_index _type _id _parent _routing].freeze
21+
EVERFIELDS = %w[_index _id _routing].freeze
2222
DELEGATED_METHODS = %i[
2323
query filter post_filter knn order reorder docvalue_fields
2424
track_scores track_total_hits request_cache explain version profile
@@ -936,7 +936,7 @@ def find(*ids)
936936

937937
# Returns and array of values for specified fields.
938938
# Uses `source` to restrict the list of returned fields.
939-
# Fields `_id`, `_type`, `_routing` and `_index` are also supported.
939+
# Fields `_id`, `_routing` and `_index` are also supported.
940940
#
941941
# @overload pluck(field)
942942
# If single field is passed - it returns and array of values.

lib/chewy/search/scrolling.rb

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -128,9 +128,10 @@ def scroll_objects(**options, &block)
128128

129129
private
130130

131-
def perform_scroll(body)
132-
ActiveSupport::Notifications.instrument 'search_query.chewy', notification_payload(request: body) do
133-
Chewy.client.scroll(body)
131+
def perform_scroll(scroll:, scroll_id:)
132+
request = {scroll: scroll, body: {scroll_id: scroll_id}}
133+
ActiveSupport::Notifications.instrument 'search_query.chewy', notification_payload(request: request) do
134+
Chewy.client.scroll(request)
134135
end
135136
end
136137
end

0 commit comments

Comments
 (0)