# Расчет даты в watcher

**URL:** <https://discuss.elastic.co/t/watcher/202524>\
**Category:** Вопросы на русском языке\
**Created:** [October 7, 2019, 12:15pm UTC](https://discuss.elastic.co/t/watcher/202524 "2019-10-07T12:15:59Z")\
**Posts on this page:** 12\
**Page:** 1

<div class="post-metadata">

**Author:** ![kurdit](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/kurdit/32/54994_2.png) [@kurdit](https://discuss.elastic.co/u/kurdit)\
**Post date:** [October 7, 2019, 12:16pm UTC](https://discuss.elastic.co/t/watcher/202524/1 "2019-10-07T12:16:00Z")

</div>

Добрый день!

Делаю watcher. В ответ на запрос watcher`a из elastic в таком формате выводятся два поля с датами:

- формат @timestamp - 2019-10-06T2 0:06:59.140Z
- формат @buildTimestamp - 2019-10-06T20:06:58.237Z

Мне необходимо вычислить разницу между этими двумя датами в миллисекундах (я так понимаю это делается в поле transform?)

Что для этого необходимо ?

---

<div class="post-metadata">

**Author:** ![Igor\_Motov](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/igor_motov/32/45193_2.png) [@Igor\_Motov](https://discuss.elastic.co/u/Igor_Motov)\
**Post date:** [October 7, 2019, 1:08pm UTC](https://discuss.elastic.co/t/watcher/202524/2 "2019-10-07T13:08:41Z")

</div>

Зависит от того, как вы эти даты получаете в watcher.

---

<div class="post-metadata">

**Author:** ![kurdit](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/kurdit/32/54994_2.png) [@kurdit](https://discuss.elastic.co/u/kurdit)\
**Post date:** [October 7, 2019, 1:20pm UTC](https://discuss.elastic.co/t/watcher/202524/3 "2019-10-07T13:20:31Z")

</div>

отсюда:

```
  "hits": {
      "hits": [
        {
          "_index": "job",
          "_type": "_doc",
          "_source": {
              "@timestamp": "2019-10-06T20:06:24.580Z",
              "@buildTimestamp": "2019-10-06T20:06:23.479Z",
              "source": "dev",
              "projectName": "dev",
              "type": "job"

```

.....

---

<div class="post-metadata">

**Author:** ![Igor\_Motov](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/igor_motov/32/45193_2.png) [@Igor\_Motov](https://discuss.elastic.co/u/Igor_Motov)\
**Post date:** [October 7, 2019, 1:49pm UTC](https://discuss.elastic.co/t/watcher/202524/4 "2019-10-07T13:49:51Z")

</div>

То есть как строки? Тогда как-то так:

```auto
DELETE test

PUT test/_doc/1
{
  "@timestamp": "2019-10-06T20:06:24.580Z",
  "@buildTimestamp": "2019-10-06T20:06:23.479Z",
  "foo": "bar"
}

PUT _watcher/watch/log_error_watch
{
  "trigger": {
    "schedule": {
      "interval": "2s"
    }
  },
  "input": {
    "search": {
      "request": {
        "indices": [
          "test"
        ],
        "body": {
          "query": {
            "match": {
              "foo": "bar"
            }
          },
          "size": 1
        }
      }
    }
  },
  "transform": {
    "script": {
      "source": """
        Instant timestamp = Instant.parse( ctx.payload.hits.hits[0]['_source']['@timestamp']);
        Instant buildTimestamp = Instant.parse( ctx.payload.hits.hits[0]['_source']['@buildTimestamp']);
        return ['diff': Duration.between(buildTimestamp, timestamp).toMillis()];
      """,
      "lang": "painless"
    }
  },
  "actions": {
    "log_error": {
      "logging": {
        "text": """The diff = {{ctx.payload.diff}}ms"""
      }
    }
  }
}

```

---

<div class="post-metadata">

**Author:** ![kurdit](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/kurdit/32/54994_2.png) [@kurdit](https://discuss.elastic.co/u/kurdit)\
**Post date:** [October 7, 2019, 2:33pm UTC](https://discuss.elastic.co/t/watcher/202524/5 "2019-10-07T14:33:14Z")

</div>

Игорь, спасибо, но есть нюанс:  
у нас есть массив и несколько документов (с разными "\_source"), которые необходимо обрабатывать и указывать в {{ctx.payload.diff}}, который у каждого будет свой.

---

<div class="post-metadata">

**Author:** ![Igor\_Motov](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/igor_motov/32/45193_2.png) [@Igor\_Motov](https://discuss.elastic.co/u/Igor_Motov)\
**Post date:** [October 8, 2019, 4:35pm UTC](https://discuss.elastic.co/t/watcher/202524/6 "2019-10-08T16:35:51Z")

</div>

К сожалению, понять все нюансы по 2 строчкам описания очень сложно. Если вы приведете подробный пример, вроде того, как я привел в своем ответе, который учитывает все ваши нюансы, то я вам с удовольствием помогу разобраться.

Скрипты в transform пишутся на языке [painless](https://www.elastic.co/guide/en/elasticsearch/painless/current/index.html). Там есть доступ к всех хитам через `ctx.payload.hits.hits` - это список, то есть `ctx.payload.hits.hits[0]['_source']` - это все значение первого документа, `ctx.payload.hits.hits[1]['_source']` - второго и т.д.

---

<div class="post-metadata">

**Author:** ![kurdit](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/kurdit/32/54994_2.png) [@kurdit](https://discuss.elastic.co/u/kurdit)\
**Post date:** [October 9, 2019, 8:11am UTC](https://discuss.elastic.co/t/watcher/202524/7 "2019-10-09T08:11:16Z")

</div>

Прошу прощения за неполный вопрос! Вот код ватчера (постарался привести его в более читаемый вид):

```
{
  "trigger": {....}
  },
  "input": {
    "search": {
      "request": {
        "search_type": "query_then_fetch",
        "indices": [
          "web*"
        ],
        "rest_total_hits_as_int": true,
        "body": {
          "size": 5,
          "query": {
            "bool": {
              "must": [
                {
                  "query_string": {
                    "analyze_wildcard": true,
                    "fields": [
                      "projectName.keyword"
                    ],
                    "query": "domain.ru"
                  }
                }
              ],
              "filter": {
                "range": {
                  "@timestamp": {
                    "gte": "{{ctx.trigger.scheduled_time}}||-30m",
                    "lte": "{{ctx.trigger.scheduled_time}}",
                    "format": "strict_date_optional_time||epoch_millis"
                  }
                }
              }
            }
          }
        }
      }
    }
  },
  "condition": {
    "script": {
      "source": "if (ctx.payload.hits.total >= params.threshold) { return true; } return false;",
      "lang": "painless",
      "params": {
        "threshold": 1
      }
    }
  },
  "actions": {
    "telegram": {.............},
        "body": "chat_id=-1234567890&text=
		
		Дата: {{ctx.payload.human_date}}%0A\n
		{{#ctx.payload.aggregations}}
		Название: {{_source.projectName}}%0A\n
		Время старта: {{ctx.payload.new_date}}%0A\n
		Заняло времени (s): {{ctx.payload.duration}}%0A\n
		{{/ctx.payload.aggregations}}"
      }
    }
  },
  "transform": {
    "script": {
      "source": "DateFormat dateFormat = new SimpleDateFormat(\"yyyy-MM-dd HH:mm:ss z\"); dateFormat.setTimeZone(TimeZone.getTimeZone(\"Europe/Moscow\")); Date date = new Date(); ctx.execution_time = dateFormat.format(date); for (bucket in ctx.payload.hits.hits) {bucket.timestamp = bucket._source['@timestamp']; bucket.buildTimestamp = bucket._source['@buildTimestamp']; def dateString = ctx.payload.hits.hits[0]['_source']['@buildTimestamp']; def inputFormat = new SimpleDateFormat(\"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'\"); def myDate = inputFormat.parse(dateString); def outputFormat = new SimpleDateFormat(\"yyyy-MM-dd HH:mm:ss z\"); ctx.new_date = outputFormat.format(myDate);} Instant timestamp = Instant.parse(ctx.payload.hits.hits[0]['_source']['@timestamp']); Instant buildTimestamp = Instant.parse(ctx.payload.hits.hits[0]['_source']['@buildTimestamp']); return ['new_date': ctx.new_date, 'human_date': ctx.execution_time, 'aggregations': ctx.payload.hits.hits, 'duration': Duration.between(buildTimestamp, timestamp).toMillis()]",
      "lang": "painless",
      "params": {
        "threshold": 1
      }
    }
  }
}

```

Есть проблема с выводом {{ctx.payload.new\_date}} для нескольких документов.У них new\_date разный (т.е. в каждом документе есть @buildTimestamp с разными значениями).

---

<div class="post-metadata">

**Author:** ![Igor\_Motov](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/igor_motov/32/45193_2.png) [@Igor\_Motov](https://discuss.elastic.co/u/Igor_Motov)\
**Post date:** [October 9, 2019, 9:39am UTC](https://discuss.elastic.co/t/watcher/202524/8 "2019-10-09T09:39:51Z")

</div>

Вы не могли бы изменить мой пример, так чтобы он более отражал вашу ситуацию, и вы не могли бы описать, что конкретно требуется вывести.

---

<div class="post-metadata">

**Author:** ![kurdit](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/kurdit/32/54994_2.png) [@kurdit](https://discuss.elastic.co/u/kurdit)\
**Post date:** [October 9, 2019, 10:21am UTC](https://discuss.elastic.co/t/watcher/202524/9 "2019-10-09T10:21:57Z")

</div>

Исправил Ваш код:

```
{
  "trigger": {
    "schedule": {
      "interval": "2s"
    }
  },
  "input": {
    "search": {
      "request": {
        "search_type": "query_then_fetch",
        "indices": [
          "web*"
        ],
        "rest_total_hits_as_int": true,
        "body": {
          "size": 5,
          "query": {
            "bool": {
              "must": [
                {
                  "query_string": {
                    "analyze_wildcard": true,
                    "fields": [
                      "projectName.keyword"
                    ],
                    "query": "domain.ru"
                  }
                }
              ],
              "filter": {
                "range": {
                  "@timestamp": {
                    "gte": "{{ctx.trigger.scheduled_time}}||-30m",
                    "lte": "{{ctx.trigger.scheduled_time}}",
                    "format": "strict_date_optional_time||epoch_millis"
                  }
                }
              }
            }
          }
        }
      },
   "condition": {
    "script": {
      "source": "if (ctx.payload.hits.total >= params.threshold) { return true; } return false;",
      "lang": "painless",
      "params": {
        "threshold": 1
      }
    }
  },
  "transform": {
    "script": {
      "source": "
	  DateFormat dateFormat = new SimpleDateFormat(\"yyyy-MM-dd HH:mm:ss z\"); 
	  dateFormat.setTimeZone(TimeZone.getTimeZone(\"Europe/Moscow\")); 
	  Date date = new Date(); ctx.execution_time = dateFormat.format(date); 
	  for (bucket in ctx.payload.hits.hits) 
	  {
		  bucket.timestamp = bucket._source['@timestamp']; 
		  bucket.buildTimestamp = bucket._source['@buildTimestamp']; 
		  def dateString = ctx.payload.hits.hits[0]['_source']['@buildTimestamp']; 
		  def inputFormat = new SimpleDateFormat(\"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'\"); 
		  def myDate = inputFormat.parse(dateString); 
		  def outputFormat = new SimpleDateFormat(\"yyyy-MM-dd HH:mm:ss z\"); 
		  ctx.new_date = outputFormat.format(myDate);
		} 
		  
	  Instant timestamp = Instant.parse(ctx.payload.hits.hits[0]['_source']['@timestamp']); 
	  Instant buildTimestamp = Instant.parse(ctx.payload.hits.hits[0]['_source']['@buildTimestamp']); 
	  return 
	   [
		 'new_date': ctx.new_date, 
		 'human_date': ctx.execution_time, 
	     'aggregations': ctx.payload.hits.hits, 
	     'diff': Duration.between(buildTimestamp, timestamp).toMillis()
	    ]",
      "lang": "painless",
      "params": {
        "threshold": 1
      }
    }
  },
  "actions": {
    "telegram": {.............},
        "body": "chat_id=-1234567890&text=
		Дата: {{ctx.payload.human_date}}%0A\n
		{{#ctx.payload.aggregations}}
		Название: {{_source.projectName}}%0A\n
		Время старта: {{ctx.payload.new_date}}%0A\n
		Заняло времени (s): {{ctx.payload.duration}}%0A\n
		{{/ctx.payload.aggregations}}"
      }
    }
  }
}

```

Требуется получить в action в "body " {{ctx.payload.new\_date}} для нескольких документов. У них он разный - т.е. в каждом документе есть поле @buildTimestamp с разными датой и временем.

@buildTimestamp по трансформации равен ctx.new\_date, который "вытащили" так:

def **dateString** = ctx.payload.hits.hits[0]['\_source'][' **@buildTimestamp**'];  
def **myDate** = inputFormat.parse( **dateString** );  
ctx.new\_date = outputFormat.format( **myDate** )

---

<div class="post-metadata">

**Author:** ![Igor\_Motov](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/igor_motov/32/45193_2.png) [@Igor\_Motov](https://discuss.elastic.co/u/Igor_Motov)\
**Post date:** [October 9, 2019, 10:51am UTC](https://discuss.elastic.co/t/watcher/202524/10 "2019-10-09T10:51:47Z")

</div>

> Исправил Ваш код:

Проблема в том, что у меня нет ваших данных, нет вашего маппинга и нет ключа telegram, чтобы протестировать решение. Поэтому я и привел пример, в котором есть все необходимое - данные и watcher с logging action. Мой пример может запустить кто угодно - он не требует никаких дополнительных установок. Я поэтому и хотел продолжить на моем примере.

В вашем случае, надо все поставить в цикл и возвращать массив дат.

---

<div class="post-metadata">

**Author:** ![kurdit](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/kurdit/32/54994_2.png) [@kurdit](https://discuss.elastic.co/u/kurdit)\
**Post date:** [October 9, 2019, 2:21pm UTC](https://discuss.elastic.co/t/watcher/202524/11 "2019-10-09T14:21:41Z")

</div>

В нашем случае, все надо поставить в цикл и возвращать массив из переменных diff и buildTimestamp с форматированием.  
У нас есть скрипт из трансформа, в выводе которого diff мы получаем общий для всех элементов возвращаемых данных, а он должен быть для каждого элемента свой.

```
"source": 
    "DateFormat dateFormat = new SimpleDateFormat(\"yyyy-MM-dd HH:mm:ss z\"); 
	dateFormat.setTimeZone(TimeZone.getTimeZone(\"Europe/Moscow\")); 
	Date date = new Date(); ctx.execution_time = dateFormat.format(date); 
	for (bucket in ctx.payload.hits.hits) 
	{
		  bucket.timestamp = bucket._source['@timestamp']; 
		  bucket.buildTimestamp = bucket._source['@buildTimestamp']; 
		  def dateString = ctx.payload.hits.hits[0]['_source']['@buildTimestamp']; 
		  def inputFormat = new SimpleDateFormat(\"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'\"); 
		  def myDate = inputFormat.parse(dateString); 
		  def outputFormat = new SimpleDateFormat(\"yyyy-MM-dd HH:mm:ss z\"); 
		  ctx.new_date = outputFormat.format(myDate);
	  } 
	Instant timestamp = Instant.parse(ctx.payload.hits.hits[0]['_source']['@timestamp']); 
	Instant buildTimestamp = Instant.parse(ctx.payload.hits.hits[0]['_source']['@buildTimestamp']); 
	return [
      'new_date': ctx.new_date, 
	  'human_date': ctx.execution_time, 
	  'aggregations': ctx.payload.hits.hits, 
	  'diff': Duration.between(buildTimestamp, timestamp).toMillis() ]",

```

Плюс к этому, нам надо отформатировать вывод поля buildTimestamp в цикле, так же для каждого документа в массиве по отдельности.  
Как это сделать?

---

<div class="post-metadata">

**Author:** ![system](https://us1.discourse-cdn.com/elastic/original/3X/1/a/1ac57faf039f6b580b3f104ef42a2a89e41014de.png) [@system](https://discuss.elastic.co/u/system)\
**Post date:** [November 6, 2019, 2:21pm UTC](https://discuss.elastic.co/t/watcher/202524/12 "2019-11-06T14:21:43Z")

</div>

This topic was automatically closed 28 days after the last reply. New replies are no longer allowed.
