概要
elasticsearchの_idカラムは指定しないと適当に一意のidが振られるが、それだと更新、削除の時に不便なので、なるべく自分で指定したい。で、今回テーブルのidの値でない値を_idにしたのだが、elasticsearch-modelでうまく動かなかったので、どうやったのかをメモとして残す
やった事
複数のDBに同じ名前のテーブルがあって、それらを一つのElasticsearchに突っ込む時に「_id」に何をセットするか注意が必要。、対象のテーブルのidカラムの値を入れようと思っても、値が重複してしまうのでidカラムの値ではなく違う値をセットする。
で、例えば以下のようにする
result = es.client.bulk(
index: 'hogehoge_index',
type: es.document_type,
body: entries.map { |entry| { index: { _id: "dbNum#{どのdbのデータかわかるようにするid}id#{entry.id}", data: entry.as_indexed_json } } },
refresh: true,
)
こうやって_idの値を違うテーブルのidと違うようにしたが、今度は検索がうまく動かない。どうしてかなと思ってデバッグする。
$ bundle open elasticsearch-model
でこちらのコード見て「あ!!そうか!」という発見。
def records
sql_records = klass.where(klass.primary_key => ids)
# 以下省略
end
もしかしてここのidsは・・・と思ってids
を見に行ったら、こちらに書いてあるように
module Elasticsearch
module Model
module Response
class Records
def ids
response.response['hits']['hits'].map { |hit| hit['_id'] }
end
end
end
end
end
やっぱり_idの値を見ている。という事でこちらの処理を上書きしました。
module Elasticsearch
module Model
module Response
class Records
def ids
response.response['hits']['hits'].
map { |hit| hit['_source'] }.
map { |source| source['id'] }
end
end
end
end
end
これで「やったー」と思ったら、今度はsortがおかしい。あれと思い、さっき見てたrecordsメソッドをもう一度見ると、ここに書いてあるように、ここでも_idを見ている
@records.sort_by { |record| hits.index { |hit| hit['_id'].to_s == record.id.to_s } }
なので、こっちも
@records.sort_by { |record| hits.index { |hit| hit['_source']['id'].to_s == record.id.to_s } }
となるようにして、改善した方を使うように変更。
これで無事検索できて、ソートも問題なくできるようになった。
めでたし、めでたし。