elasticsearch-rails的更新回调处理令人疑惑不解

在使用elasticsearch-rails时,出现了更新后无法在Elasticsearch中反映的问题,以下是我当时查找到的备忘。

看一下elasticsearch-rails的问题,

    • #5

 

    • #37

 

    • #52

 

    • #125

 

    #182

经过讨论,截至2014-12-08,似乎已经确定了以下实施方案。

# https://github.com/elasticsearch/elasticsearch-rails/blob/master/elasticsearch-model/lib/elasticsearch/model/indexing.rb#L338

def update_document(options={})
  if changed_attributes = self.instance_variable_get(:@__changed_attributes)
    attributes = if respond_to?(:as_indexed_json)
      self.as_indexed_json.select { |k,v| changed_attributes.keys.map(&:to_s).include? k.to_s }
    else
      changed_attributes
    end

    client.update(
      { index: index_name,
        type:  document_type,
        id:    self.id,
        body:  { doc: attributes } }.merge(options)
    )
  else
    index_document(options)
  end
end

根据 @__changed_attributes 和 as_indexed_json 进行对照,确认哪些属性已经更新,如果没有更新则使用 @__changed_attributes 进行处理。而 @__changed_attributes 是什么呢,

# https://github.com/elasticsearch/elasticsearch-rails/blob/4a61f1786696045561864567e0921db9b318aeaa/elasticsearch-model/lib/elasticsearch/model/proxy.rb#L62

before_save do |i|
  i.__elasticsearch__.instance_variable_set(:@__changed_attributes,
                                            Hash[ i.changes.map { |key, value| [key, value.last] } ])
end if respond_to?(:before_save) && instance_methods.include?(:changed_attributes)

在执行save之前,before_save将在ActiveModel::Dirty中设置并保存实体的值。

换句话说,在执行before_save之后改变的属性不会被检测到更新,因此如果在其他before_save中修改了属性,该属性就不会被更新。
before_save的执行顺序遵循Rails回调函数综述文章中的规定,如果有多个相同的before_save指定,它们将按照从上到下的顺序执行,因此,我认为最好将Elasticsearch::Model和Elasticsearch::Model::Callbacks都放在最后include进来。

require 'elasticsearch/model'

class Article < ActiveRecord::Base

  before_save :update_pv_count

  def update_pv_count
    self.pv_count += 1
    true
  end

  ...

  include Elasticsearch::Model
  include Elasticsearch::Model::Callbacks
end

我认为之所以采用这种实现是为了实现只更新更新的属性并使其与Elasticsearch保持同步的节省资源的实现,但在运营中,由于需要频繁覆盖as_indexed_json函数,我认为这种通用处理方式并不能解决问题。顺便提一下,在第5个问题中,

after_update -> {
  __elasticsearch__.index_document
}

所以,有一些人正常地進行更新處理。

广告
将在 10 秒后关闭
bannerAds