前日まで普通にAmazonElasticsearchの検索が使えたのに、朝急に
MultiJson::ParseError: 822: unexpected token at '�'
というエラーが頻発したので、その対処方法の共有です。
環境
- Amazon Elasticsearch
- Elasticsearch(ver2系、5系)
- elasticsearch-rails-5.0.4
事象
Elasticsearchから返ってきたjsonをparseしてエラー。
何が起きたのか?
以下確認手順を記載。
調査
- エラー発生箇所に「binding.pry」を入れてそもそもどんなjsonデータをparseしようとしてエラーになっているのか調査
bundle open elasticsearch-transport
でエラーが起きていた箇所を確認。pryを使ってjsonの中身を確認
elasticsearch-transport-5.0.4/lib/elasticsearch/transport/transport/serializer/multi_json.rb
module Elasticsearch
module Transport
module Transport
module Serializer
# An abstract class for implementing serializer implementations
#
module Base
# @param transport [Object] The instance of transport which uses this serializer
#
def initialize(transport=nil)
@transport = transport
end
end
# A default JSON serializer (using [MultiJSON](http://rubygems.org/gems/multi_json))
#
class MultiJson
include Base
# De-serialize a Hash from JSON string
#
def load(string, options={})
::MultiJson.load(string, options) <<<<< ここのstringの中身を確認
end
# Serialize a Hash to JSON string
#
def dump(object, options={})
::MultiJson.dump(object, options)
end
end
end
end
end
end
- 中身をみるとjsonデータでなく、何かエンコーディングされたような形式ものになっていた
- なぜそうなったのか・・・。AmazonElasticsearchの仕様変更でgzip形式返すようになった。
対応
Elasticsearchの接続を行っていた箇所に以下のような修正を追加
Elasticsearch::Client.new(
hosts: hosts,
randomize_hosts: true,
request_timeout: 10,
reload_connections: false,
sniffer_timeout: 3,
reload_on_failure: false,
transport_options: { headers: {
content_type: 'application/json',
"Accept-Encoding": "" <<<<< ここを追加
}
},
log: true
) do |f|
f.request :aws_signers_v4,
credentials: Aws::Credentials.new(ENV['AWS_ACCESS_KEY_ID'], ENV['AWS_SECRET_ACCESS_KEY']),
service_name: 'es',
region: 'ap-northeast-1'
f.adapter Faraday.default_adapter
end
こちらを参考にしました。
<追記> 自分が忘れないようにするためのメモ: elasticsearch-railsの方でHttp通信で使っているfaradayは「Accept-Encoding: gzip」 がデフォルトの設定らしい。