LoginSignup
9
8

More than 5 years have passed since last update.

[解決] Amazon ES(Elasticsearch Service)を使ってみたら、POSTとquery-stringが共存できなくて困った件

Last updated at Posted at 2015-10-02

表題通りなんですが。ちょっとハマりました。

elasticsearch-api 本体側が修正されました

Karelさんが教えてくれた! Thank you karel!

type パラメータを bulk api の呼び出し側で削除するような対応が行われたようです。これで不格好な workaround を抹消できて、俺ハッピー。

transport_options で Content-Type 指定することで回避できました

@xend 様にコメントで教えていただきました。Clientのコンストラクタで transport_options を指定することで対応できるようです。うーむ。jsonで送信するのであれば application/x-www-form-urlencoded でなぜ送る…。(2015/10/7追記)

以下ハマったのと workaround の経緯

$ curl mysearch.ap-southeast-1.es.amazonaws.com/_search/? -X POST -d '{}'

HTTP/1.1 403 Forbidden
Content-Type: application/json
Server: Jetty(8.1.12.v20130726)
x-amzn-RequestId: **********************
Content-Length: 135
Connection: keep-alive

{"message":"When Content-Type:application/x-www-form-urlencoded, URL cannot include query-string parameters (after '?'): '/_search/?'"}

ContentType が x-www-form-urlencoded だった場合、query-string が含まれたURLだと403でエラーになります (>_<!!

マジで?

これが問題になったのは、elasticsearch-railsを使ってバルクインサートしてる箇所であり。

調べて見ると、elasticsearch-api の bulk アクション(これ)が type パラメータを query-string として渡しているのが原因であろうと思われた。というかそれが上の制約と衝突してるのは間違いない。

ということで取り急ぎ type だけを特別扱いするように残念すぎるモンキーパッチを用意。

[ec2-user:~/my_rails_app]$ cat config/initializers/elasticsearch_patch.rb

# type を valid_params から除外する
module Elasticsearch
  module API
    module Actions
      def bulk(arguments={})
        valid_params = [
          :consistency,
          :refresh,
          :replication,
#         :type,
          :timeout ]

        method = HTTP_POST
        path   = Utils.__pathify Utils.__escape(arguments[:index]), Utils.__escape(arguments[:type]), '_bulk'

        params = Utils.__validate_and_extract_params arguments, valid_params
        body   = arguments[:body]

        if body.is_a? Array
          payload = Utils.__bulkify(body)
        else
          payload = body
        end
        perform_request(method, path, params, payload).body
      end
    end
  end
end

最初 elasticsearch-rails のバージョンが 1.7系だからじゃないかとか、Amazon ESのElasticsearchが1.5.2だからなんじゃねーかとかいろいろ疑ったのだが、空振りでした。

http://docs.aws.amazon.com/elasticsearch-service/latest/developerguide/aes-limits.html こことか参照すると、Parameters in HTTP POST requests が、The service ignores parameters passed in URLs for HTTP POST requests signed with Signature Version 4.とか書かれているので突破する方法はあるのかもしれない。が、手作業で署名したアクセスを作ってみても Response body: {"message":"Credential should be scoped to correct service: 'es'. "} とか言われてしまうので手詰まり感がある。Admin権限持ってるのにー。

かくして、上のようなパッチを置くことになってしまった。本当に反省している。しかし elasticsearch-api の方の不適切な挙動って感じでもないので、難しいところです。このやりかただと refresh とか consistency とか timeout とか指定できないし。うーん。

9
8
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
8