Rails
Elasticsearch
AmazonElasticsearchService

朝起きたらAmazon Elasticsearchから取得した検索結果でJson Parse Errorが起きた件

More than 1 year has passed since last update.

前日まで普通に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」 がデフォルトの設定らしい。