#php #laravel #elasticsearch
#php #laravel #elasticsearch
Вопрос:
Я использую elasticsearch
in my laravel
-app и пытаюсь использовать range
-query . У меня есть массив компаний, в которых в разные периоды было разное количество сотрудников, но меня интересует только самый новый период, который в данном случае означает последний элемент массива employees .
итак, в основном массив выглядит так:
"company" => [
"name" => "some company",
"company_number" => "1234567",
"status" => "normal",
"employees" => [
"period_1" => [
"amount" => 10
],
"period_2" => [
"amount" => 15
],
"period_3" => [
"amount" => 24
],
etc etc...
]
]
итак, во внешнем интерфейсе вы можете ввести минимальное и максимальное значение для поиска компаний с определенным количеством сотрудников. Затем в моем контроллере я делаю это:
"query":{
"bool": {
"should" : [
{ "match" : { "company.status" : "normal" },
{
"range": {
"company.employees": { // I WANT THE LAST ITEM FROM THIS ARRAY
"gte": "'. $min . '",
"lt" : "'.$max .'"
}
}
}
]
}
}
Это в основном работает, но, конечно, не дает мне последнюю запись массива employees.
Как я могу это решить? Пожалуйста, помогите…
Обновить
хорошо, теперь я добавил код, который был предложен:
"query": {
"bool": {
"should" : [
{ "match" : { "company.status" : "normal" },
{
"range": {
"company.employees": { // I WANT THE LAST ITEM FROM THIS ARRAY
"gte": "'. $min . '",
"lt" : "'.$max .'"
}
}
}
]
},
"script": {
"source": """
def period_keys = new ArrayList(ctx._source.company.employees.keySet());
Collections.sort(period_keys);
Collections.reverse(period_keys);
def latest_period = period_keys[0];
def latest_amount = ctx._source.company.employees[latest_period].amount;
ctx._source.company.current_employees = ["period": latest_period, "amount": latest_amount];
"""
}
}
}
Но я получаю сообщение об ошибке: Unexpected character ('{' (code 123)): was expecting comma to separate Object entries
…
Поскольку я все еще учусь, я должен сказать, я понятия не имею, что происходит, и сообщения об ошибках от Elasticsearch ужасны.
В любом случае, у кого-нибудь есть подсказка? Заранее спасибо
Ответ №1:
Поиск чего-то подобного во время выполнения довольно сложен и недостаточно оптимизирован. Вот альтернатива.
Я предполагаю, что количество сотрудников данной компании меняется не так часто — это означает, что когда они меняются (т. Е. Вы Обновляете этот документ), Вы можете запустить следующий _update_by_query
скрипт, чтобы получить информацию о сотрудниках за последний период и сохранить ее на уровне компании, оставив раздел сотрудников нетронутым:
POST companies_index/_update_by_query
{
"query": {
"match_all": {}
},
"script": {
"source": """
def period_keys = new ArrayList(ctx._source.company.employees.keySet());
Collections.sort(period_keys);
Collections.reverse(period_keys);
def latest_period = period_keys[0];
def latest_amount = ctx._source.company.employees[latest_period].amount;
ctx._source.company.current_employees = ['period': latest_period, 'amount': latest_amount];
"""
}
}
Однострочный:
POST companies_index/_update_by_query
{"query":{"match_all":{}},"script":{"source":" def period_keys = new ArrayList(ctx._source.company.employees.keySet());n Collections.sort(period_keys);n Collections.reverse(period_keys);n n def latest_period = period_keys[0];n def latest_amount = ctx._source.company.employees[latest_period].amount;n n ctx._source.company.current_employees = ['period': latest_period, 'amount': latest_amount];"}}
Обратите внимание, что когда приведенный выше запрос пуст, скрипт будет применяться ко всем документам в вашем индексе. Но, конечно, вы могли бы ограничить это только одной компанией.
После этого вызова ваши документы будут выглядеть следующим образом:
{
"company" : {
"company_number" : "1234567",
"name" : "some company",
"current_employees" : { <---
"period" : "period_3",
"amount" : 24
},
"employees" : {
...
},
...
}
}
и запрос диапазона сверху становится проще простого:
...
"range": {
"company.current_employees.amount": { <--
"gte": "'. $min . '",
"lt" : "'.$max .'"
}
...
Кстати, я также предположил, что ключи периода могут быть отсортированы в алфавитном порядке, но если они содержат даты, скрипту потребуется корректировка в виде компаратора для анализа даты.
Комментарии:
1. Хм,
script
вещь возвращаетсяUnexpected character ('"' (code 34)): was expecting comma to separate Object entries
… :-/2. Обновите мой ответ — тройные кавычки можно использовать только в kibana; в противном случае их нужно экранировать…
3. Странно. Вы уверены, что запустили один лайнер?
4. Да, а также «скрипт» должен быть внутри «запроса»…
5. Нет, потому что это
_update_by_query
не_search
так.