LoginSignup
1
0

Ruby on Rails で ElasticSearch をChewyで検索した際のN+1問題

Last updated at Posted at 2023-12-16

Ruby on Rails で ElasticSearch と Chewyを活用して全文検索を実装しています。

Chewyとは?

Chewy is an ODM (Object Document Mapper), built on top of the official Elasticsearch client.
https://github.com/toptal/chewy

検索した際にN+1問題がBulletで検知されました。

objects = ParentModelIndex.query(match_query).load.objects
objects.each do |obj|
 obj.child # ここの行で
end

N+1が検出されます。

GET /...
USE eager loading detected
ParentModel => [:child_model]
Add to your query: .includes([:child_model])
Call stack

ChatGPTの解決策

これをどのように対応すべきか?ChatGPTの提案は以下の通りでした。

ids = ParentModelIndex.query(match_query).load.map(&:id)
objects = ParentModel.where(id: ids).includes(:child_model)

納得いきますかこのコード? Chewy::Search::Response.objects の処理は以下の通りです。

  def objects
    @objects ||= begin
      objects = @loader.load(hits)
      if @paginator
        @paginator.call(objects)
      else
        objects
      end
    end
  end

ChatGPTの処理は劣化処理になっています。

Chewyのコードを読み解く

そこでソースコードを読み解き増すとChewy::Search::Request.loadの定義は以下の通りです。

      # Stores ORM/ODM objects loading options. Options
      # might be define per-index or be global, depends on the adapter
      # loading implementation. Also, there are 2 loading options to select
      # or exclude indexes from loading: `only` and `except` respectively.
      # Options are updated on further method calls.
      #
      # @example
      #   PlaceIndex.load(only: 'city').load(scope: -> { active })
      # @see Chewy::Search::Loader
      # @see Chewy::Search::Response#objects
      # @see Chewy::Search::Scrolling#scroll_objects
      # @param options [Hash] adapter-specific loading options
      def load(options = nil)
        modify(:load) { update!(options) }
      end

結論

以下のようにloadの際にscopeを指定してincludes してください。

ParentModelIndex.query(match_query).load(scope: -> {includes([:child_model])})
1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0