Эластичная проблема сравнения дат в документе

У меня есть эластичный индекс с тысячами таких документов.

{
    Name: John Doe,
    FirstJobStartDate: 8/9/2016,
    FirstJobEndDate:1/4/2019,
    SecondJobStartDate:7/4/2019,
    SecondJobEndDate:8/8/2020,
    ThirdJobStartDate: 1/9/2020,
}

Все остальные поля, за исключением Name и FirstJobStartDate, являются необязательными и могут как присутствовать, так и отсутствовать в документе.

Мне нужно получить 4 числа:

1) Сколько документов имеют FirstJobEndDate? Это просто

{
  "size":1,    
  "query": {
    "filtered": {
      "filter": {
        "bool": {
          "must": [
            {
              "exists": {
                "field": "FirstJobEndDate"
              }
            }
          ]
        }
      }
    }
  }
}

Теперь это становится сложным:

2) Сколько документов имеют FirstJobEndDate меньше текущей даты, и у них нет ДАЖЕ ОДНОГО из (SecondJobStartDate, SecondJobEndDate или ThirdJobStartDate)?

3) Сколько документов имеют FirstJobEndDate, а также имеют ЛЮБУЮ ОДНУ из (SecondJobStartDate, SecondJobEndDate, ThirdJobStartDate) и ЛЮБУЮ из этих дат находятся в пределах 1 года от FirstJobEndDate?

4) Сколько документов имеют FirstJobEndDate, а также имеют ЛЮБУЮ ОДНУ из (SecondJobStartDate, SecondJobEndDate, ThirdJobStartDate) и НИ ОДНА из этих дат не находится в пределах 1 года от FirstJobEndDate?

Я считаю, что это можно сделать с помощью правильного сочетания слов «должен» и «следует», но не могу найти четкого решения из-за сравнения двух дат в одном документе.

Просто для подтверждения: все даты являются допустимыми полями эластичного типа даты, а не строками.

Любая помощь будет принята с благодарностью. Эластичная версия: 2.4


person dixyantar panda    schedule 23.02.2018    source источник


Ответы (1)


Попробуйте это:

Для второго запроса:

{
  "size": 1,
  "query": {
    "bool": {
      "filter": [
        {
          "exists": {
            "field": "FirstJobEndDate"
          }
        }
      ],
      "must_not": [
        {
          "exists": {
            "field": "SecondJobStartDate"
          }
        },
        {
          "exists": {
            "field": "SecondJobEndDate"
          }
        },
        {
          "exists": {
            "field": "ThirdJobStartDate"
          }
        }
      ]
    }
  }
}

Для третьего запроса:

{
  "size": 1,
  "query": {
    "bool": {
      "filter": [
        {
          "exists": {
            "field": "FirstJobEndDate"
          }
        }
      ],
      "minimum_should_match": 1,
      "should": [
        {
          "script": {
            "script": "doc.SecondJobStartDate.date != null && doc.SecondJobStartDate.date.getMillis() - doc.FirstJobEndDate.date.getMillis() <= 31540000000"
          }
        },
        {
          "script": {
            "script": "doc.SecondJobEndDate.date != null && doc.SecondJobEndDate.date.getMillis() - doc.FirstJobEndDate.date.getMillis() <= 31540000000"
          }
        },
        {
          "script": {
            "script": "doc.ThirdJobStartDate.date != null && doc.ThirdJobStartDate.date.getMillis() - doc.FirstJobEndDate.date.getMillis() <= 31540000000"
          }
        }
      ]
    }
  }
}

Для четвертого запроса:

{
  "size": 1,
  "query": {
    "bool": {
      "filter": [
        {
          "exists": {
            "field": "FirstJobEndDate"
          }
        }
      ],
      "must_not": [
        {
          "script": {
            "script": "doc.SecondJobStartDate.date != null && doc.SecondJobStartDate.date.getMillis() - doc.FirstJobEndDate.date.getMillis() <= 31540000000"
          }
        },
        {
          "script": {
            "script": "doc.SecondJobEndDate.date != null && doc.SecondJobEndDate.date.getMillis() - doc.FirstJobEndDate.date.getMillis() <= 31540000000"
          }
        },
        {
          "script": {
            "script": "doc.ThirdJobStartDate.date != null && doc.ThirdJobStartDate.date.getMillis() - doc.FirstJobEndDate.date.getMillis() <= 31540000000"
          }
        }
      ]
    }
  }
}

Просто совет: как видите, вам нужно использовать сценарии, а это может снизить производительность. Поскольку вы заранее знаете, какие даты вы хотите сравнить, вы должны сохранить разницу дат в дополнительных скалярных полях, которые впоследствии можно будет легко сравнить с range запросами.

person Val    schedule 23.02.2018
comment
Спасибо Вал. Это очень помогает. Я пробовал запросы, и они работают. Единственная проблема в том, что скрипт возвращает true, даже если поле не существует. Скажем, например, у меня нет ThirdJobStartDate, тогда условие «следует» возвращает true, потому что NA - X ‹ 1 год. - person dixyantar panda; 23.02.2018
comment
Дублируйте, пожалуйста, смотрите комментарий выше. - person dixyantar panda; 23.02.2018
comment
Я добавил нулевую проверку, попробуйте еще раз - person Val; 23.02.2018
comment
Если больше ничего не осталось, вы можете закрыть этот вопрос, спасибо. - person Val; 19.03.2018