mirror of
https://github.com/honeymoose/OpenSearch.git
synced 2025-02-22 12:56:53 +00:00
[DOCS] Add watcher context examples (#36565)
This commit is contained in:
parent
3bc0711b90
commit
c0368a2086
@ -1,38 +1,136 @@
|
||||
[[painless-watcher-condition-context]]
|
||||
=== Watcher condition context
|
||||
|
||||
Use a Painless script as a {xpack-ref}/condition-script.html[watcher condition]
|
||||
to test if a response is necessary.
|
||||
Use a Painless script as a {xpack-ref}/condition-script.html[watch condition]
|
||||
that determines whether to execute a watch or a particular action within a watch.
|
||||
Condition scripts return a Boolean value to indicate the status of the condition.
|
||||
|
||||
*Variables*
|
||||
|
||||
`params` (`Map`, read-only)::
|
||||
User-defined parameters passed in as part of the query.
|
||||
|
||||
`ctx['watch_id']` (`String`, read-only)::
|
||||
The id of the watch.
|
||||
|
||||
`ctx['execution_time']` (`ZonedDateTime`, read-only)::
|
||||
The start time for the watch.
|
||||
|
||||
`ctx['trigger']['scheduled_time']` (`ZonedDateTime`, read-only)::
|
||||
The scheduled trigger time for the watch.
|
||||
|
||||
`ctx['trigger']['triggered_time']` (`ZonedDateTime`, read-only)::
|
||||
The actual trigger time for the watch.
|
||||
|
||||
`ctx['metadata']` (`Map`, read-only)::
|
||||
Any metadata associated with the watch.
|
||||
|
||||
`ctx['payload']` (`Map`, read-only)::
|
||||
The accessible watch data based upon the
|
||||
{xpack-ref}/input.html[watch input].
|
||||
include::painless-watcher-context-variables.asciidoc[]
|
||||
|
||||
*Return*
|
||||
|
||||
`boolean`::
|
||||
Expects `true` if the condition is met, and `false` otherwise.
|
||||
Expects `true` if the condition is met, and `false` if it is not.
|
||||
|
||||
*API*
|
||||
|
||||
The standard <<painless-api-reference, Painless API>> is available.
|
||||
The standard <<painless-api-reference, Painless API>> is available.
|
||||
|
||||
*Example*
|
||||
|
||||
[source,Painless]
|
||||
----
|
||||
POST _watcher/watch/_execute
|
||||
{
|
||||
"watch" : {
|
||||
"trigger" : { "schedule" : { "interval" : "24h" } },
|
||||
"input" : {
|
||||
"search" : {
|
||||
"request" : {
|
||||
"indices" : [ "seats" ],
|
||||
"body" : {
|
||||
"query" : {
|
||||
"term": { "sold": "true"}
|
||||
},
|
||||
"aggs" : {
|
||||
"theatres" : {
|
||||
"terms" : { "field" : "play" },
|
||||
"aggs" : {
|
||||
"money" : {
|
||||
"sum": { "field" : "cost" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"condition" : {
|
||||
"script" :
|
||||
"""
|
||||
return ctx.payload.aggregations.theatres.buckets.stream() <1>
|
||||
.filter(theatre -> theatre.money.value < 15000 ||
|
||||
theatre.money.value > 50000) <2>
|
||||
.count() > 0 <3>
|
||||
"""
|
||||
},
|
||||
"actions" : {
|
||||
"my_log" : {
|
||||
"logging" : {
|
||||
"text" : "The output of the search was : {{ctx.payload.aggregations.theatres.buckets}}"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
----
|
||||
|
||||
<1> The Java Stream API is used in the condition. This API allows manipulation of
|
||||
the elements of the list in a pipeline.
|
||||
<2> The stream filter removes items that do not meet the filter criteria.
|
||||
<3> If there is at least one item in the list, the condition evaluates to true and the watch is executed.
|
||||
|
||||
The following action condition script controls execution of the my_log action based
|
||||
on the value of the seats sold for the plays in the data set. The script aggregates
|
||||
the total sold seats for each play and returns true if there is at least one play
|
||||
that has sold over $50,000.
|
||||
|
||||
[source,Painless]
|
||||
----
|
||||
POST _watcher/watch/_execute
|
||||
{
|
||||
"watch" : {
|
||||
"trigger" : { "schedule" : { "interval" : "24h" } },
|
||||
"input" : {
|
||||
"search" : {
|
||||
"request" : {
|
||||
"indices" : [ "seats" ],
|
||||
"body" : {
|
||||
"query" : {
|
||||
"term": { "sold": "true"}
|
||||
},
|
||||
"aggs" : {
|
||||
"theatres" : {
|
||||
"terms" : { "field" : "play" },
|
||||
"aggs" : {
|
||||
"money" : {
|
||||
"sum": { "field" : "cost" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"actions" : {
|
||||
"my_log" : {
|
||||
"condition": { <1>
|
||||
"script" :
|
||||
"""
|
||||
return ctx.payload.aggregations.theatres.buckets.stream()
|
||||
.anyMatch(theatre -> theatre.money.value > 50000) <2>
|
||||
"""
|
||||
},
|
||||
"logging" : {
|
||||
"text" : "At least one play has grossed over $50,000: {{ctx.payload.aggregations.theatres.buckets}}"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
----
|
||||
|
||||
This example uses a nearly identical condition as the previous example. The
|
||||
differences below are subtle and are worth calling out.
|
||||
|
||||
<1> The location of the condition is no longer at the top level, but is within
|
||||
an individual action.
|
||||
<2> Instead of a filter, `anyMatch` is used to return a boolean value
|
||||
|
||||
The following example shows scripted watch and action conditions within the
|
||||
context of a complete watch. This watch also uses a scripted
|
||||
<<painless-watcher-transform-context, transform>>.
|
||||
|
||||
include::painless-watcher-context-example.asciidoc[]
|
||||
|
@ -0,0 +1,157 @@
|
||||
[source,Painless]
|
||||
----
|
||||
POST _watcher/watch/_execute
|
||||
{
|
||||
"watch" : {
|
||||
"metadata" : { "high_threshold": 50000, "low_threshold": 15000 },
|
||||
"trigger" : { "schedule" : { "interval" : "24h" } },
|
||||
"input" : {
|
||||
"search" : {
|
||||
"request" : {
|
||||
"indices" : [ "seats" ],
|
||||
"body" : {
|
||||
"query" : {
|
||||
"term": { "sold": "true"}
|
||||
},
|
||||
"aggs" : {
|
||||
"theatres" : {
|
||||
"terms" : { "field" : "play" },
|
||||
"aggs" : {
|
||||
"money" : {
|
||||
"sum": { "field" : "cost" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"condition" : {
|
||||
"script" :
|
||||
"""
|
||||
return ctx.payload.aggregations.theatres.buckets.stream()
|
||||
.anyMatch(theatre -> theatre.money.value < ctx.metadata.low_threshold ||
|
||||
theatre.money.value > ctx.metadata.high_threshold)
|
||||
"""
|
||||
},
|
||||
"transform" : {
|
||||
"script":
|
||||
"""
|
||||
return [
|
||||
'money_makers': ctx.payload.aggregations.theatres.buckets.stream()
|
||||
.filter(t -> {
|
||||
return t.money.value > ctx.metadata.high_threshold
|
||||
})
|
||||
.map(t -> {
|
||||
return ['play': t.key, 'total_value': t.money.value ]
|
||||
}).collect(Collectors.toList()),
|
||||
'duds' : ctx.payload.aggregations.theatres.buckets.stream()
|
||||
.filter(t -> {
|
||||
return t.money.value < ctx.metadata.low_threshold
|
||||
})
|
||||
.map(t -> {
|
||||
return ['play': t.key, 'total_value': t.money.value ]
|
||||
}).collect(Collectors.toList())
|
||||
]
|
||||
"""
|
||||
},
|
||||
"actions" : {
|
||||
"log_money_makers" : {
|
||||
"condition": {
|
||||
"script" : "return ctx.payload.money_makers.size() > 0"
|
||||
},
|
||||
"transform": {
|
||||
"script" :
|
||||
"""
|
||||
def formatter = NumberFormat.getCurrencyInstance();
|
||||
return [
|
||||
'plays_value': ctx.payload.money_makers.stream()
|
||||
.map(t-> formatter.format(t.total_value) + ' for the play ' + t.play)
|
||||
.collect(Collectors.joining(", "))
|
||||
]
|
||||
"""
|
||||
},
|
||||
"logging" : {
|
||||
"text" : "The following plays contain the highest grossing total income: {{ctx.payload.plays_value}}"
|
||||
}
|
||||
},
|
||||
"log_duds" : {
|
||||
"condition": {
|
||||
"script" : "return ctx.payload.duds.size() > 0"
|
||||
},
|
||||
"transform": {
|
||||
"script" :
|
||||
"""
|
||||
def formatter = NumberFormat.getCurrencyInstance();
|
||||
return [
|
||||
'plays_value': ctx.payload.duds.stream()
|
||||
.map(t-> formatter.format(t.total_value) + ' for the play ' + t.play)
|
||||
.collect(Collectors.joining(", "))
|
||||
]
|
||||
"""
|
||||
},
|
||||
"logging" : {
|
||||
"text" : "The following plays need more advertising due to their low total income: {{ctx.payload.plays_value}}"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
----
|
||||
|
||||
The following example shows the use of metadata and transforming dates into a readable format.
|
||||
|
||||
[source,Painless]
|
||||
----
|
||||
POST _xpack/watcher/watch/_execute
|
||||
{
|
||||
"watch" : {
|
||||
"metadata" : { "min_hits": 10000 },
|
||||
"trigger" : { "schedule" : { "interval" : "24h" } },
|
||||
"input" : {
|
||||
"search" : {
|
||||
"request" : {
|
||||
"indices" : [ "seats" ],
|
||||
"body" : {
|
||||
"query" : {
|
||||
"term": { "sold": "true"}
|
||||
},
|
||||
"aggs" : {
|
||||
"theatres" : {
|
||||
"terms" : { "field" : "play" },
|
||||
"aggs" : {
|
||||
"money" : {
|
||||
"sum": { "field" : "cost" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"condition" : {
|
||||
"script" :
|
||||
"""
|
||||
return ctx.payload.hits.total > ctx.metadata.min_hits
|
||||
"""
|
||||
},
|
||||
"transform" : {
|
||||
"script" :
|
||||
"""
|
||||
def theDate = ZonedDateTime.ofInstant(ctx.execution_time.toInstant(), ctx.execution_time.getZone());
|
||||
return ['human_date': DateTimeFormatter.RFC_1123_DATE_TIME.format(theDate),
|
||||
'aggregations': ctx.payload.aggregations]
|
||||
"""
|
||||
},
|
||||
"actions" : {
|
||||
"my_log" : {
|
||||
"logging" : {
|
||||
"text" : "The watch was successfully executed on {{ctx.payload.human_date}} and contained {{ctx.payload.aggregations.theatres.buckets.size}} buckets"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
----
|
@ -0,0 +1,40 @@
|
||||
The following variables are available in all watcher contexts.
|
||||
|
||||
*Variables*
|
||||
|
||||
`params` (`Map`, read-only)::
|
||||
User-defined parameters passed in as part of the query.
|
||||
|
||||
`ctx['watch_id']` (`String`, read-only)::
|
||||
The id of the watch.
|
||||
|
||||
`ctx['id']` (`String`, read-only)::
|
||||
The server generated unique identifer for the run watch.
|
||||
|
||||
`ctx['metadata']` (`Map`, read-only)::
|
||||
Metadata can be added to the top level of the watch definition. This
|
||||
is user defined and is typically used to consolidate duplicate values
|
||||
in a watch.
|
||||
|
||||
`ctx['execution_time']` (`ZonedDateTime`, read-only)::
|
||||
The time the watch began execution.
|
||||
|
||||
`ctx['trigger']['scheduled_time']` (`ZonedDateTime`, read-only)::
|
||||
The scheduled trigger time for the watch. This is the time the
|
||||
watch should be executed.
|
||||
|
||||
`ctx['trigger']['triggered_time']` (`ZonedDateTime`, read-only)::
|
||||
The actual trigger time for the watch. This is the time the
|
||||
watch was triggered for execution.
|
||||
|
||||
`ctx['payload']` (`Map`, read-only)::
|
||||
The accessible watch data based upon the
|
||||
{xpack-ref}/input.html[watch input].
|
||||
|
||||
*API*
|
||||
|
||||
|
||||
The standard <<painless-api-reference, Painless API>> is available.
|
||||
|
||||
To run this example, first follow the steps in
|
||||
<<painless-context-examples, context examples>>.
|
@ -1,33 +1,11 @@
|
||||
[[painless-watcher-transform-context]]
|
||||
=== Watcher transform context
|
||||
|
||||
Use a Painless script to {xpack-ref}/transform-script.html[transform] watch
|
||||
data into a new payload for use in a response to a condition.
|
||||
|
||||
*Variables*
|
||||
|
||||
`params` (`Map`, read-only)::
|
||||
User-defined parameters passed in as part of the query.
|
||||
|
||||
`ctx['watch_id']` (`String`, read-only)::
|
||||
The id of the watch.
|
||||
|
||||
`ctx['execution_time']` (`ZonedDateTime`, read-only)::
|
||||
The start time for the watch.
|
||||
|
||||
`ctx['trigger']['scheduled_time']` (`ZonedDateTime`, read-only)::
|
||||
The scheduled trigger time for the watch.
|
||||
|
||||
`ctx['trigger']['triggered_time']` (`ZonedDateTime`, read-only)::
|
||||
The actual trigger time for the watch.
|
||||
|
||||
`ctx['metadata']` (`Map`, read-only)::
|
||||
Any metadata associated with the watch.
|
||||
|
||||
`ctx['payload']` (`Map`, read-only)::
|
||||
The accessible watch data based upon the
|
||||
{xpack-ref}/input.html[watch input].
|
||||
Use a Painless script as a {xpack-ref}/transform-script.html[watch transform]
|
||||
to transform a payload into a new payload for further use in the watch.
|
||||
Transform scripts return an Object value of the new payload.
|
||||
|
||||
include::painless-watcher-context-variables.asciidoc[]
|
||||
|
||||
*Return*
|
||||
|
||||
@ -36,4 +14,142 @@ data into a new payload for use in a response to a condition.
|
||||
|
||||
*API*
|
||||
|
||||
The standard <<painless-api-reference, Painless API>> is available.
|
||||
The standard <<painless-api-reference, Painless API>> is available.
|
||||
|
||||
*Example*
|
||||
|
||||
[source,Painless]
|
||||
----
|
||||
POST _watcher/watch/_execute
|
||||
{
|
||||
"watch" : {
|
||||
"trigger" : { "schedule" : { "interval" : "24h" } },
|
||||
"input" : {
|
||||
"search" : {
|
||||
"request" : {
|
||||
"indices" : [ "seats" ],
|
||||
"body" : {
|
||||
"query" : { "term": { "sold": "true"} },
|
||||
"aggs" : {
|
||||
"theatres" : {
|
||||
"terms" : { "field" : "play" },
|
||||
"aggs" : {
|
||||
"money" : {
|
||||
"sum": { "field" : "cost" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"transform" : {
|
||||
"script":
|
||||
"""
|
||||
return [
|
||||
'money_makers': ctx.payload.aggregations.theatres.buckets.stream() <1>
|
||||
.filter(t -> { <2>
|
||||
return t.money.value > 50000
|
||||
})
|
||||
.map(t -> { <3>
|
||||
return ['play': t.key, 'total_value': t.money.value ]
|
||||
}).collect(Collectors.toList()), <4>
|
||||
'duds' : ctx.payload.aggregations.theatres.buckets.stream() <5>
|
||||
.filter(t -> {
|
||||
return t.money.value < 15000
|
||||
})
|
||||
.map(t -> {
|
||||
return ['play': t.key, 'total_value': t.money.value ]
|
||||
}).collect(Collectors.toList())
|
||||
]
|
||||
"""
|
||||
},
|
||||
"actions" : {
|
||||
"my_log" : {
|
||||
"logging" : {
|
||||
"text" : "The output of the payload was transformed to {{ctx.payload}}"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
----
|
||||
|
||||
<1> The Java Stream API is used in the transform. This API allows manipulation of
|
||||
the elements of the list in a pipeline.
|
||||
<2> The stream filter removes items that do not meet the filter criteria.
|
||||
<3> The stream map transforms each element into a new object.
|
||||
<4> The collector reduces the stream to a `java.util.List`.
|
||||
<5> This is done again for the second set of values in the transform.
|
||||
|
||||
The following action transform changes each value in the mod_log action into a `String`.
|
||||
This transform does not change the values in the unmod_log action.
|
||||
|
||||
[source,Painless]
|
||||
----
|
||||
POST _watcher/watch/_execute
|
||||
{
|
||||
"watch" : {
|
||||
"trigger" : { "schedule" : { "interval" : "24h" } },
|
||||
"input" : {
|
||||
"search" : {
|
||||
"request" : {
|
||||
"indices" : [ "seats" ],
|
||||
"body" : {
|
||||
"query" : {
|
||||
"term": { "sold": "true"}
|
||||
},
|
||||
"aggs" : {
|
||||
"theatres" : {
|
||||
"terms" : { "field" : "play" },
|
||||
"aggs" : {
|
||||
"money" : {
|
||||
"sum": { "field" : "cost" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"actions" : {
|
||||
"mod_log" : {
|
||||
"transform": { <1>
|
||||
"script" :
|
||||
"""
|
||||
def formatter = NumberFormat.getCurrencyInstance();
|
||||
return [
|
||||
'msg': ctx.payload.aggregations.theatres.buckets.stream()
|
||||
.map(t-> formatter.format(t.money.value) + ' for the play ' + t.key)
|
||||
.collect(Collectors.joining(", "))
|
||||
]
|
||||
"""
|
||||
},
|
||||
"logging" : {
|
||||
"text" : "The output of the payload was transformed to: {{ctx.payload.msg}}"
|
||||
}
|
||||
},
|
||||
"unmod_log" : { <2>
|
||||
"logging" : {
|
||||
"text" : "The output of the payload was not transformed and this value should not exist: {{ctx.payload.msg}}"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
----
|
||||
|
||||
This example uses the streaming API in a very similar manner. The differences below are
|
||||
subtle and worth calling out.
|
||||
|
||||
<1> The location of the transform is no longer at the top level, but is within
|
||||
an individual action.
|
||||
<2> A second action that does not transform the payload is given for reference.
|
||||
|
||||
The following example shows scripted watch and action transforms within the
|
||||
context of a complete watch. This watch also uses a scripted
|
||||
<<painless-watcher-condition-context, condition>>.
|
||||
|
||||
include::painless-watcher-context-example.asciidoc[]
|
||||
|
@ -42,4 +42,4 @@ Queries that contain multiple terms calculate a separate weight for each term.
|
||||
|
||||
*API*
|
||||
|
||||
The standard <<painless-api-reference, Painless API>> is available.
|
||||
The standard <<painless-api-reference, Painless API>> is available.
|
||||
|
Loading…
x
Reference in New Issue
Block a user