これをモデル化する 1 つの方法は、親/子ドキュメントを使用することです。ルーム ドキュメントは親ドキュメントになり、空き時間ドキュメントは子ドキュメントになります。部屋ごとに、部屋が利用可能な日付ごとに 1 つの空室状況ドキュメントがあります。次に、クエリ時に、検索間隔内の日付ごとに 1 つの空室状況の子ドキュメントを持つ親ルームをクエリできます (バラバラの場合でも)。
部屋が予約されるとすぐに、予約された日付ごとに対応する子ドキュメントを削除する必要があることに注意してください。
これを試してみましょう。最初にインデックスを作成します。
PUT /rooms
{
"mappings": {
"room": {
"properties": {
"room_num": {
"type": "integer"
}
}
},
"availability": {
"_parent": {
"type": "room"
},
"properties": {
"date": {
"type": "date",
"format": "date"
},
"available": {
"type": "boolean"
}
}
}
}
}
次に、いくつかのデータを追加します
POST /rooms/_bulk
{"_index": { "_type": "room", "_id": 233}}
{"room_num": 233}
{"_index": { "_type": "availability", "_id": "20160701", "_parent": 233}}
{"date": "2016-07-01"}
{"_index": { "_type": "availability", "_id": "20160702", "_parent": 233}}
{"date": "2016-07-02"}
{"_index": { "_type": "availability", "_id": "20160704", "_parent": 233}}
{"date": "2016-07-04"}
{"_index": { "_type": "availability", "_id": "20160705", "_parent": 233}}
{"date": "2016-07-05"}
{"_index": { "_type": "availability", "_id": "20160707", "_parent": 233}}
{"date": "2016-07-07"}
{"_index": { "_type": "availability", "_id": "20160708", "_parent": 233}}
{"date": "2016-07-08"}
最後に、クエリを開始できます。まず、 で利用可能な部屋を見つけたいとしましょう2016-07-01
:
POST /rooms/room/_search
{
"query": {
"has_child": {
"type": "availability",
"query": {
"term": {
"date": "2016-07-01"
}
}
}
}
}
=> result: room 233
2016-07-01
では、 ~から空室のあるお部屋を探してみましょう。2016-07-03
POST /rooms/room/_search
{
"query": {
"bool": {
"minimum_should_match": 3,
"should": [
{
"has_child": {
"type": "availability",
"query": {
"term": {
"date": "2016-07-01"
}
}
}
},
{
"has_child": {
"type": "availability",
"query": {
"term": {
"date": "2016-07-02"
}
}
}
},
{
"has_child": {
"type": "availability",
"query": {
"term": {
"date": "2016-07-03"
}
}
}
}
]
}
}
}
=> Result: No rooms
2016-07-01
ただし、 ~から利用可能な部屋を検索すると、2016-07-02
部屋 233 が表示されます。
POST /rooms/room/_search
{
"query": {
"bool": {
"minimum_should_match": 2,
"should": [
{
"has_child": {
"type": "availability",
"query": {
"term": {
"date": "2016-07-01"
}
}
}
},
{
"has_child": {
"type": "availability",
"query": {
"term": {
"date": "2016-07-02"
}
}
}
}
]
}
}
}
=> Result: Room 233
2016-07-01
from to 2016-07-02
+ from 2016-07-04
toなど、互いに素な区間を検索することもできます。2016-07-05
POST /rooms/room/_search
{
"query": {
"bool": {
"minimum_should_match": 4,
"should": [
{
"has_child": {
"type": "availability",
"query": {
"term": {
"date": "2016-07-01"
}
}
}
},
{
"has_child": {
"type": "availability",
"query": {
"term": {
"date": "2016-07-02"
}
}
}
},
{
"has_child": {
"type": "availability",
"query": {
"term": {
"date": "2016-07-04"
}
}
}
},
{
"has_child": {
"type": "availability",
"query": {
"term": {
"date": "2016-07-05"
}
}
}
}
]
}
}
}
=> Result: Room 233
などなど...重要なポイントは、has_child
空室状況を確認する必要がある日付ごとに 1 つのクエリを追加し、確認minimum_should_match
する日付の数を設定することです。
アップデート
もう 1 つのオプションはscript
filterを使用することですが、1 億のドキュメントがあるため、それほどうまくスケーリングできるかどうかはわかりません。
このシナリオでは、元の設計を維持できます (最初の設計ではマッピングに不要なフィールドが多すぎるため、2 番目の設計が望ましい)、クエリは次のようになります。
POST /rooms/room/_search
{
"query": {
"bool": {
"filter": {
"script": {
"script": {
"inline": "def dates = doc.availability.sort(false); from = Date.parse('yyyy-MM-dd', from); to = Date.parse('yyyy-MM-dd', to); def days = to - from; def fromIndex = doc.availability.values.indexOf(from.time); def toIndex = doc.availability.values.indexOf(to.time); return days == (toIndex - fromIndex)",
"params": {
"from": "2016-07-01",
"to": "2016-07-04"
}
}
}
}
}
}
}