Можно ли применить функцию к полю при поиске?

Я хочу выполнить Range поиск в поле даты, которое теперь сопоставлено с текстом. Проблема в том, что в этом поле уже есть данные; поэтому не рекомендуется отбрасывать индекс и воссоздавать новый index, чтобы отобразить поле как date. Поэтому я подумал о применении специальной функции к полю, чтобы выполнить поиск Range. Это возможно ?


person pheromix    schedule 27.11.2020    source источник


Ответы (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: вы можете использовать запрос сценария, в котором необходимо обработать преобразование текста в дату и применить логику диапазона.

person Nishant    schedule 27.11.2020

Конечно, можно использовать запрос сценария, но ваше текстовое поле должно иметь _ 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 для обновить все документы. Падение индекса не требуется.

Проблема с этим подходом в том, что он не повлияет на новые входящие документы. В этом случае вы либо изменяете процесс приема, чтобы также включить это новое поле даты (так что у вас было бы два поля с одинаковыми значениями по устаревшим причинам), либо вы устанавливаете конвейер приема, чтобы сделать это за вас (- ›никаких корректировок процесса приема нужный). Вот пример такого конвейера, хотя и предназначенного для несколько иной цели. Принципы те же.

person Joe Sorocin    schedule 27.11.2020