brunch

You can make anything
by writing

C.S.Lewis

by 홍진우 Jun 11. 2017

[Rails] 불필요한 검색 인덱싱 줄이기

 elasticsearch-rails Gem에서 일어나는 인덱싱 줄이기

Rails 환경에서 full-text 검색을 위해 elasticsearch를 사용하고 있는데, 계속 찜찜하게 묵혀두고 있던 채무가 있었다. 모든 API 요청당 elasticsearch 인덱싱이 한 번씩 일어난다는 점이었다. 문제는 아래와 같이 일어난다.


1. Rails 프로젝트에서 회원 관리를 위해 Devise Gem을 사용 중이다.

2. Devise Gem에서는 기본적으로 로그인 시에 last_sign_in_at 등 최근 로그인 기록을 업데이트한다.

3. elasticsearch-rails는 모델이 업데이트될 때마다 변경 사항을 적용하기 위해 인덱싱을 실행한다.

4. 대부분의 API 요청에는 토큰을 검사하기 때문에 User의 로그인 기록이 업데이트되고 불필요한 인덱싱이 실행된다.



https://github.com/elastic/elasticsearch-rails/tree/master/elasticsearch-model


class Article < ActiveRecord::Base  include Elasticsearch::Model  

    after_commit on: [:create] do    

        __elasticsearch__.index_document if self.published?  

    end  


    after_commit on: [:update] do    

        __elasticsearch__.update_document if self.published?  

    end 


     after_commit on: [:destroy] do    

         __elasticsearch__.delete_document if self.published?  

    end

end



elasticsearch-model Gem에서 제공하는 ReadMe 에 위와 같은 샘플 코드가 있기 때문에 그대로 적용해서 생긴 문제인데, 인덱싱이 필요 없는 attributes가 업데이트되었을 때에는 인덱싱이 실행되지 않도록 수정되어야 한다.


Rails에는 ActiveModel::Dirty라는 아주 편리한 기능이 있는데 모델의 변경 사항을 추적해주는 기능이다. 아래 코드를 보면 어떤 역할인지 바로 이해될 것이다.



person.name = 'Bob'

person.changed?       # => true

person.name_changed?  # => true

person.name_changed?(from: nil, to: "Bob") # => true

person.name_was       # => nil

person.name_change    # => [nil, "Bob"]

person.name = 'Bill'

person.name_change    # => [nil, "Bill"]



처음에 시도했던 방식은 #changes라는 메써드를 사용해서 모델의 변경사항을 추적하는 것이었는데, after_commit callback은 이미 저장된 이후이기 때문에 #changes 메써드로는 어떤 attributes가 변경되었는지 알 수 없었다.


그래서 #previous_changes이라는 메써드를 사용해야 했다. 이미 저장이 완료되었기 때문에 이전의 변경 사항을 불러와야 하기 때문이었다.



after_commit :elastic_update, on: [:update], if: proc { |record|

    # 변경된 attributes 중 인덱싱이 필요한 attributes가 있을 때만 인덱싱을 실행한다.

    (record.previous_changes.keys - no_index_attrs).count > 0

}


# 인덱싱을 하지 않을 attributes의 어레이

def no_index_attrs

   ['updated_at', 'sign_in_count', 'current_sign_in_at', 'last_sign_in_at', 'current_sign_in_ip', 'last_sign_in_ip']

end



위의 코드처럼 수정해서 불필요한 인덱싱을 없앨 수 있다.

매거진의 이전글 irb 한글 입력 문제 해결
브런치는 최신 브라우저에 최적화 되어있습니다. IE chrome safari