Я хочу выполнить Range
поиск в поле даты, которое теперь сопоставлено с текстом. Проблема в том, что в этом поле уже есть данные; поэтому не рекомендуется отбрасывать индекс и воссоздавать новый index
, чтобы отобразить поле как date
. Поэтому я подумал о применении специальной функции к полю, чтобы выполнить поиск Range
. Это возможно ?
Можно ли применить функцию к полю при поиске?
Ответы (2)
Вариант 1. Обновите документы без необходимости отбрасывать и воссоздавать весь индекс.
Если для индекса включено хранилище, вы можете создать подполе с правильным типом данных. Например, если существующее имя поля - dateText
, вы можете обновить сопоставление индекса следующим образом и воспользоваться обновлением по запросу для повторного индексирования всех ваших документов.
PUT myindex/_mapping
{
"properties": {
"datetext": {
"type": "text",
"fields": {
"dateField": {
"type": "date",
"format": "yyyy-MM-dd HH:mm:ss" //<--- change this as per the data
}
}
}
}
}
Используйте обновление по запросу после обновления отображения.
POST myindex/_update_by_query?conflicts=proceed
Как только вышеуказанное будет выполнено, вы можете использовать запрос диапазона на dateText.dateField
.
Вариант 2: вы можете использовать запрос сценария, в котором необходимо обработать преобразование текста в дату и применить логику диапазона.
Конечно, можно использовать запрос сценария, но ваше текстовое поле должно иметь _ 1_ или иметь тип .keyword
(как multifield, например), чтобы сценарий имел доступ к значению поля.
После того, как об этом позаботятся, предположим, что ваше текстовое поле dateFieldAsText
содержит временные метки эпох в секундах, и вы хотите отфильтровать gte & lte с диапазонами дат, удобочитаемыми человеком. Затем мы могли бы разобрать все на миллисекунды, а затем провести простое сравнение:
{
"query": {
"script": {
"script": {
"source": """
def doc_ts_milli = Integer.parseInt(doc['dateFieldAsText'].value) * 1000L;
def df = new SimpleDateFormat("yyyy/MM/dd");
def gte_ts = df.parse(params.gte).getTime();
def lte_ts = df.parse(params.lte).getTime();
return doc_ts_milli >= gte_ts && doc_ts_milli <= lte_ts
""",
"params": {
"gte": "2020/01/01",
"lte": "2021/01/01"
}
}
}
}
}
Проблема заключается в том, что скрипты повторно инициализируются в каждом запросе (кроме случаев, когда они хранятся) и поэтому работают медленно. Поэтому лучший способ перейти сюда - обновить сопоставление с новым полем даты, а затем вызвать _reindex
для обновить все документы. Падение индекса не требуется.
Проблема с этим подходом в том, что он не повлияет на новые входящие документы. В этом случае вы либо изменяете процесс приема, чтобы также включить это новое поле даты (так что у вас было бы два поля с одинаковыми значениями по устаревшим причинам), либо вы устанавливаете конвейер приема, чтобы сделать это за вас (- ›никаких корректировок процесса приема нужный). Вот пример такого конвейера, хотя и предназначенного для несколько иной цели. Принципы те же.