Elasticsearch の日付検索を検証
どうも!昨日に引き続き Elasticsearch の入門ネタです。
以前の記事で書きましたが、検索エンジンである Apache Solr では日付の扱いが上手く行かず、実プロジェクトで痛い目にあったことがありました。Solr の場合、日付は UTC でしか扱うことができない、DBの trunc のように年月日のみで検索することができない、といった2点にやられたのですが、詳しくはこちらのエントリをごらんください。
Solrでよく勘違いしそうな仕様3点+1 - よしだのブログ
じゃあ、Elasticsearchってどうよということで、検証しました。中身は同じ Lucene だしなーと思っていたのですが、結論から書くとしっかり処理できます!
- ISO表記が扱えるので、UTC以外のタイムゾーンにも対応している!
- trunc に当たる検索が可能。年だけで、月だけといった指定で検索ができる。
スキーママッピング設定
dynamic mapping は使わず、明示的にマッピング*1を指定しました。format はISOフォーマット用である date_optional_timeを、明示的に指定しました。一つだけですが。。
{ "mappings":{ sample:{ properties:{ "mdate":{"type":"date","store":"yes","format":"date_optional_time"} } } } }
なお、日付は色々なフォーマットがあると思います。例えば、スラッシュで区切る、ハイフンで区切る、月/日/年の順番になっている、年が2桁などなど様々です。Elasticsearch は、多くのフォーマットに対応できるよに JODA というライブラリを内部で使用してパースします。
指定できるフォーマットの一覧はこちら。
http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/mapping-date-format.html
JODA はこちら。
http://joda-time.sourceforge.net/
データを投入
ISOフォーマットに従い、JSTの+09:00を指定して登録しました。特にエラーも出ず、入れることができました。
{ "mdate":"2007-06-30T21:10+09:00" }
確認
入れたそのままの値が返されて、ちょっと予想外。てっきり、内部的にはエポックセカンドに変換されるはずだから、何も指定しないとUTCで返ってくるのかと思いましたが。まあ、この方式なら、特に複数のタイムゾーンを扱うケースでは変に迷うようなことはなくなるからいいかもしれません。
{ "_index": "tztest", "_type": "sample", "_id": "1", "_version": 1, "found": true, "_source": { "mdate": "2007-06-30T21:10+09:00" } }
検索
いくつかのパターンで試してみました。いずれも range を指定して、絞り込むパターンです。
ISO表記のクエリ。ちゃんとヒットする。ちなみに、fromは "grater than equals"、toは "less than equals" です。なお、to の値を9分に変更するとヒットしないことが確認できました。
{ "query":{ "range":{ "mdate":{ "from":"2007-06-30T00:00:00Z", "to":"2007-06-30T12:10:00Z" } } } }
次に、trunc が可能か検証。日にちの指定だけにまるめる形で検索しましたが、想定通りにヒットしました。ちゃんと trunc できる!
もっと短く、月まで、年まで、といった指定も可能。その場合、省略された値は最小値が内部的に補完して、検索しているようです。なので "2007-06-30" は "2007-06-30T00:00:00Z" として扱われます。
{ "query":{ "range":{ "mdate":{ "from":"2007-06-30", "to":"2007-07-01" } } } }
あの苦戦した日々は何だったのかと思うぐらい、ちゃんと動きました。
*1:要するにスキーマのこと。