よしだのブログ

サブタイトルはありません。

Elasticsearch の日付検索を検証

f:id:yoshi0309:20140423001602p:plain

どうも!昨日に引き続き 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:要するにスキーマのこと。