疑問文

PythonとかRubyについて、疑問や学びをまとめる場所

勉強しないと。しないと。

【翻訳】Elasticsearchにおけるマッピングの更新

背景

オープンソース検索エンジンといえばSolr!というイメージで、Solrしか使ったことがなかったんですが、作りたいアプリケーションの都合で今回はElasticsearchを使ってみることにしました。わからないことばかりでTwitterでぼやいてたんですが

f:id:nanakenashi:20150925233710p:plain

まさかのアドバイスを頂いてすごく嬉しかったので、該当箇所を翻訳してみました。

オリジナル

Elasticsearch: The Definitive Guide Mapping
https://www.elastic.co/guide/en/elasticsearch/guide/current/mapping-intro.html#updating-a-mapping


翻訳

マッピングの更新

最初にインデックスを作成するときには、タイプに対してマッピングを指定することができる。あるいは新しく定義するタイプに対して後からマッピングを追加(また、既存のタイプのマッピングを更新)することができる。このとき、/_mappingエンドポイントを利用する。

既存のマッピングに対しては、「追加」することはできるが、「変更」することはできない。もしマッピングに対して既にフィールドが存在するのなら、そのフィールドにはデータがインデックスされているだろう。フィールドのマッピングを変更するのなら、既にインデックスされているデータは間違いとなり、適切に検索できなくなる。

新しいフィールドを追加するためにマッピングを更新することはできるが、既存のフィールドをanalyzedからnot_analyzedに変更することはできない。

マッピングを指定する2つの方法をデモで示すために、まずはgbインデックスを削除する。

DELETE /gb

そして新しいインデックスを作成する。ここではenglishアナライザを利用するtweetフィールドを指定する。

PUT /gb 
{
  "mappings": {
    "tweet" : {
      "properties" : {
        "tweet" : {
          "type" :    "string",
          "analyzer": "english"
        },
        "date" : {
          "type" :   "date"
        },
        "name" : {
          "type" :   "string"
        },
        "user_id" : {
          "type" :   "long"
        }
      }
    }
  }
}

ここではマッピングと共にインデックスを作成している。

その後で、not_analyzedなテキストフィールドであるtagフィールドをtweetマッピングに追加する。ここでは_mappingエンドポイントを利用する。

PUT /gb/_mapping/tweet
{
  "properties" : {
    "tag" : {
      "type" :    "string",
      "index":    "not_analyzed"
    }
  }
}

このとき、既存のフィールドの全ての定義をもう一度列挙する必要はない(既に変更はできないため)。新しく追加するフィールドは、既存のマッピングにマージされる。


まとめ

太字と下線で強調した部分がすべてで、既にドキュメントを追加したなら後から変更するのは難しい。DBのテーブル定義なんかだと中のデータ入れ替えとかもっと面倒だし、そもそもきっちり想定をして設計するのが重要なんだと思います。

余談

マッピングの変更のたびに再インデックスが必要なら、本番環境のシステムも毎回止めないといけないのかというのが一番の疑問だったんですが、ドキュメントでも言及されてました。

Changing Mapping with Zero Downtime | Elastic

すんごいタイムリーな記事も。
techlife.cookpad.com

インデックスにエイリアスを貼る機能を使って、裏で新しく作りなおしたインデックスと入れ替えることで実現するようです。マスターとスレーブを駆使してごにょごにょ切り替えたりはしなくていいのね。