Ответ 1
Вам не нужны скопления для этого:
Это критерии сортировки:
- Расстояние ASC (company.location)
- Рейтинг DESC (company.rating_value)
- Скорое будущее Доступность ASC (company.employee.availability.start)
Если вы проигнорируете № 3, вы можете запустить относительно простой корпоративный запрос:
GET /companies/company/_search
{
"query": { "match_all" : {} },
"sort": {
"_script": {
"params": {
"lat": 51.5186,
"lon": -0.1347
},
"lang": "groovy",
"type": "number",
"order": "asc",
"script": "doc['location'].distanceInMiles(lat,lon)"
},
"rating_value": { "order": "desc" }
}
}
# 3 сложно, потому что вам нужно спуститься и найти доступность (компания > сотрудник > доступность) для каждой компании, ближайшей к моменту запроса, и использовать эта продолжительность как третий критерий сортировки.
Мы собираемся использовать запрос function_score
на уровне внука, чтобы получить разницу во времени между временем запроса и каждой доступностью в хит _score
. (Тогда мы будем использовать _score
как третий критерий сортировки).
Чтобы достичь внуков, нам нужно использовать запрос has_child
внутри запроса has_child
.
Для каждой компании мы хотим, чтобы скорейший доступный Сотрудник (и, конечно же, их ближайшая доступность). Elasticsearch 2.0 предоставит нам "score_mode": "min"
для таких случаев, но пока, поскольку мы ограничены "score_mode": "max"
, мы сделаем внука _score
обратным разнице во времени.
"function_score": {
"filter": {
"range": {
"start": {
"gt": "2014-12-22T10:34:18+01:00"
}
}
},
"functions": [
{
"script_score": {
"lang": "groovy",
"params": {
"requested": "2014-12-22T10:34:18+01:00",
"millisPerHour": 3600000
},
"script": "1 / ((doc['availability.start'].value - new DateTime(requested).getMillis()) / millisPerHour)"
}
}
]
}
Итак, теперь _score
для каждого внука (Доступность) будет 1 / number-of-hours-until-available
(чтобы мы могли использовать максимальное обратное время до тех пор, пока оно не будет доступно для каждого сотрудника, а максимальное взаимное (ly?) доступный сотрудник на компанию).
Объединяя все вместе, мы продолжаем запрашивать компанию, но используем company > employee > availabilty для создания _score
для использования в качестве # 3 критерий сортировки:
GET /companies/company/_search
{
"query": {
"has_child" : {
"type" : "employee",
"score_mode" : "max",
"query": {
"has_child" : {
"type" : "availability",
"score_mode" : "max",
"query": {
"function_score": {
"filter": {
"range": {
"start": {
"gt": "2014-12-22T10:34:18+01:00"
}
}
},
"functions": [
{
"script_score": {
"lang": "groovy",
"params": {
"requested": "2014-12-22T10:34:18+01:00",
"millisPerHour": 3600000
},
"script": "1/((doc['availability.start'].value - new DateTime(requested).getMillis()) / millisPerHour)"
}
}
]
}
}
}
}
}
},
"sort": {
"_script": {
"params": {
"lat": 51.5186,
"lon": -0.1347
},
"lang": "groovy",
"type": "number",
"order": "asc",
"script": "doc['location'].distanceInMiles(lat,lon)"
},
"rating_value": { "order": "desc" },
"_score": { "order": "asc" }
}
}