Skip to content

Migrate search to Searchkick gem.#3199

Merged
simi merged 1 commit into
masterfrom
searchkick
Dec 30, 2022
Merged

Migrate search to Searchkick gem.#3199
simi merged 1 commit into
masterfrom
searchkick

Conversation

@simi

@simi simi commented Aug 27, 2022

Copy link
Copy Markdown
Contributor
  • removes elasticsearch-rails dependency not supporting opensearch
  • exactly same index is used, there is no need for reindex in production/staging

ℹ️ Once we migrate to searchkick (or fix the non-existing opensearch-rails gem problem), I can continue on upgrading tech stack at AWS to latest OpenSearch version.

@simi simi requested review from jenshenny and sonalkr132 August 27, 2022 21:26
Comment thread Gemfile
gem "unicorn", "~> 5.8.0"
gem "validates_formatting_of"
gem "elasticsearch", "~> 7.10.1"
gem "elasticsearch-api", "~> 7.10.1"

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have removed explicit api/transport requirement since we don't use it directly and it is already dependency of elasticsearch gem.

@codecov

codecov Bot commented Aug 27, 2022

Copy link
Copy Markdown

Codecov Report

Merging #3199 (4ce8dc5) into master (84ece6b) will decrease coverage by 0.06%.
The diff coverage is 100.00%.

❗ Current head 4ce8dc5 differs from pull request most recent head 6fca499. Consider uploading reports for the commit 6fca499 to get more accurate results

@@            Coverage Diff             @@
##           master    #3199      +/-   ##
==========================================
- Coverage   98.52%   98.45%   -0.07%     
==========================================
  Files         113      110       -3     
  Lines        3390     3302      -88     
==========================================
- Hits         3340     3251      -89     
- Misses         50       51       +1     
Impacted Files Coverage Δ
app/models/concerns/rubygem_searchable.rb 100.00% <100.00%> (+5.55%) ⬆️
app/models/deletion.rb 100.00% <100.00%> (ø)
app/models/gem_download.rb 100.00% <100.00%> (ø)
app/models/pusher.rb 94.17% <100.00%> (ø)
lib/elastic_searcher.rb 100.00% <100.00%> (ø)
app/controllers/api/v1/api_keys_controller.rb 94.11% <0.00%> (-5.89%) ⬇️
lib/fastly.rb 100.00% <0.00%> (ø)
app/models/user.rb 100.00% <0.00%> (ø)
app/controllers/sessions_controller.rb 100.00% <0.00%> (ø)
app/controllers/settings_controller.rb 100.00% <0.00%> (ø)
... and 4 more

Help us with your feedback. Take ten seconds to tell us how you rate us. Have a feature suggestion? Share it here.

Comment thread app/models/deletion.rb
end

def update_search_index
@version.rubygem.delay.update_document

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there any alternative to update_document in searchkick @ankane?

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not exactly the same, but there is partial reindexing.

Comment thread config/application.rb
Comment thread test/integration/advanced_search_test.rb
Comment thread test/test_helper.rb Outdated
@simi

simi commented Aug 27, 2022

Copy link
Copy Markdown
Contributor Author

@epugh @ankane thanks for the recommendation and all the work on Searchkick. Would you mind to do review as well? 🙏 I did my best to follow documentation.

Rubygem.searchkick_index.create
end

task :import_alias do

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Online async import is supported in Searchkick by default https://github.com/ankane/searchkick#parallel-reindexing, but I wasn't able to setup it locally without adding Redis dependency. Anyway since we don't need reindexing currently, I just made it simple.

In production we can call:

index = Rubygem.reindex(mode: :async)
# wait once done
Rubygem.searchkick_index.promote(index[:index_name])

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We used this task for upgrades (which required new index for backward incompatible change) or fix/add some data from our end.
Creating a new index and updating the alias allowed us to do this without downtime. Creating new index takes considerable amount of time.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As I mentioned, we can do the same and it is built in. Searchkick utilizes ActiveJob we doesn't really use currently. But I have plan to move all .delay calls to proper background jobs soon as well. For now we can do async reindexing as mentioned. Not reindexing is needed when deployed since the using index is exactly the same (checked manually via API).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For now we can do async reindexing as mentioned.

Does this work without redis? I think somewhere you commented that async needs redis.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, redis is needed just for optional progress tracking AFAIK.

@simi simi marked this pull request as ready for review August 27, 2022 21:45

@ankane ankane left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @simi, left some comments inline, but overall, looks good from a Searchkick standpoint!

Comment thread app/models/gem_download.rb Outdated
Comment thread app/models/deletion.rb
end

def update_search_index
@version.rubygem.delay.update_document

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not exactly the same, but there is partial reindexing.

Comment thread app/models/concerns/rubygem_searchable.rb Outdated
Comment thread lib/tasks/elasticsearch.rake Outdated
Comment thread test/helpers/es_helper.rb Outdated
Comment thread test/test_helper.rb Outdated
Comment thread app/models/pusher.rb
end
Delayed::Job.enqueue Indexer.new, priority: PRIORITIES[:push]
rubygem.delay.index_document
rubygem.delay.reindex

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fwiw, delay.reindex isn't tested in Searchkick (the recommended approach is reindex(mode: :async))

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This just calls rubygem.reindex in backround job. That should be safe.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't use ActiveJob for now, but I have plan to migrate from delay job being used directly to ActiveJob. Once done, we can move to reindex(mode: :async) if I understand it well.

Comment thread app/models/concerns/rubygem_searchable.rb Outdated
@ankane

ankane commented Aug 28, 2022

Copy link
Copy Markdown

Also, forgot to mention Searchkick has built-in Rake tasks for reindexing, you might be able to remove elasticsearch.rake.

rake searchkick:reindex:all
# or
rake searchkick:reindex CLASS=Rubygem

@simi simi force-pushed the searchkick branch 4 times, most recently from 432dcff to 87a70e3 Compare September 10, 2022 22:15
@simi

simi commented Sep 10, 2022

Copy link
Copy Markdown
Contributor Author

@ankane would you mind to do another review round once you have some spare time 🙏?

@ankane

ankane commented Sep 11, 2022

Copy link
Copy Markdown

Hey @simi, looks great!

While not needed with the current code (since it only calls response), you may want to pass load: false to searchkick_search calls to ensure records won't get loaded from the DB if someones tries to use a different method on results in the future. https://github.com/ankane/searchkick/#results

@simi

simi commented Oct 29, 2022

Copy link
Copy Markdown
Contributor Author

This is ready from my side @sonalkr132 @jenshenny. Next step would be to merge and test on staging.

Comment thread Gemfile.lock
@@ -482,10 +480,7 @@ DEPENDENCIES
delayed_job
delayed_job_active_record
elasticsearch (~> 7.10.1)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we have plans to remove this? I am guessing we can't upgrade our cluster as long as we have this in out gemfile.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, plan is to move to OpenSearch gems once this lands to production.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you please elaborate on the order of changes?

  • deploy this to prod
  • replace elasticsearch in gemfile with opensearch (does opensearch gem work with ES cluster)
  • upgrade ES cluster engine in staging to opensearch

Is this the plan?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Once this will be merged, deployed to staging and considered safe to deploy to production, we can deploy to production.

After that my plan is to open other PR moving out of elasticsearch gem (migrate to opensearch). That can be merged and tested on staging as well. There is no need for upgrade of ES cluster.

And again after some time we can finally upgrade ES cluster engine. First I would like to try on staging to see if any downtime is needed and get some estimate on time needed for upgrade in general and repeat in production. If I understand it well, application works well without ES. The only problem could be unindexed changes. We can track gems recently changed (during maintenance window) and explicitly ask for reindex for those.

That's my initial plan.

@jenshenny jenshenny left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @simi! I added a couple of comments but generally it looks good to me.

Comment thread lib/tasks/elasticsearch.rake
Comment thread test/helpers/es_helper.rb Outdated
Comment thread test/unit/rubygem_searchable_test.rb Outdated
Comment thread lib/tasks/elasticsearch.rake
@simi simi requested review from jenshenny and removed request for ankane November 5, 2022 00:15

@jenshenny jenshenny left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚀

@simi

simi commented Nov 16, 2022

Copy link
Copy Markdown
Contributor Author

I have tested this on staging (manually deploying this branch in there). Everything works well with no needed for reindexing. I have tested reindexing as well.

  • rake task

ℹ️ this wipes the index first so search is affected by this

time kubectl exec -it deploy/unicorn -n rubygems-staging --context rubygems -- bin/rake searchkick:reindex CLASS=Rubygem
Defaulted container "unicorn" out of: unicorn, nginx
** [Honeybadger] Initializing Honeybadger Error Tracker for Ruby. Ship it! version=5.0.2 framework=rails level=1 pid=32
Reindexing Rubygem...
Reindex successful

real    40m21,265s
user    0m1,088s
sys     0m0,490s
  • manual async

ℹ️ is needed to be merged #3266 for this

ℹ️ this is not affecting search functionality

# schedule reindex in batches using ActiveJob
index = Rubygem.reindex(mode: :async)
#=> {:index_name=>"rubygems-staging_20221113223835766"}

# check progress
Delayed::Backend::ActiveRecord::Job.where(queue: 'searchkick').count
#=> 175

# switch
Rubygem.searchkick_index.promote(index[:index_name])
#=> {"acknowledged"=>true}

@simi

simi commented Nov 16, 2022

Copy link
Copy Markdown
Contributor Author

I think this is ready for merge.

- removes elasticsearch-rails dependency not supporting opensearch
@simi simi merged commit 01ee51b into master Dec 30, 2022
@simi simi deleted the searchkick branch December 30, 2022 22:07
@rubygems-org-shipit rubygems-org-shipit Bot temporarily deployed to staging December 30, 2022 23:06 Inactive
@rubygems-org-shipit rubygems-org-shipit Bot temporarily deployed to production December 30, 2022 23:10 Inactive
@deivid-rodriguez

Copy link
Copy Markdown
Contributor

🙌

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants