I have a query just like this:
{
"script": {
"script": {
"lang": "painless",
"params": {
"maxPrice": 1000000,
"minPrice": 50,
"now": "{{now}}"
},
"source": "(doc['selling_price'].value == 0 && doc['normal_price'].value >= params.minPrice && doc['normal_price'].value <= params.maxPrice) || (doc['selling_price'].value > 0 && doc['selling_price'].value >= params.minPrice && doc['selling_price'].value <= params.maxPrice && params.now <= doc['selling_price_end_time'].value.getMillis() && params.now >= doc['selling_price_start_time'].value.getMillis())"
}
}
}
When I trying to put minPrice and maxPrice into parameters in a template just like now like this :
"params": {
"maxPrice": "{{maxPrice}}",
"minPrice": "{{minPrice}}",
"now": "{{now}}"
},
Then when I run :
{
"id": "my_template",
"params": {
"query_all": "My goi",
"maxPrice": 100000000,
"minPrice": 50,
"now": 1421427600000,
I received this:
"failures": [
{
"shard": 4,
"index": "dev_index_sku_list",
"node": "jSpDqKHwSMeWsUxxoD9-5w",
"reason": {
"type": "script_exception",
"reason": "runtime error",
"script_stack": [
"(doc['selling_price'].value == 0 && doc['normal_price'].value >= params.minPrice && doc['normal_price'].value <= params.maxPrice) || (doc['selling_price'].value > 0 && doc['selling_price'].value >= params.minPrice && doc['selling_price'].value <= params.maxPrice &&
Ridiculously, when I set up now as a parameter it works, but not for the case for minPrice and maxPrice:
The logic behind the source is:
Our data have:
NormalPrice: 200 #this is the normal price
SellingPrice: 100 #this is actually the promotion price
selling_price_start_time: "2020-01-01" #duration of promotion price
selling_price_end_time: "2020-01-30"
The logic:
if selling_price != 0 and now in the promotion time then filter within minPrice and maxPrice
else then filter by normalPrice within minPrice and maxPrice
Currently working on version 7 of elasticSearch
Related
I am able to categorize various error like this ---
But i want to send email to groups based on error message.
Something like ---
when error ie "key"= "Response status code does not indicate success Service Unavailable" ---send email to group 1 [user1#gmail.com,user2#gmail.com,user3#gmail.com]
when error ie "key"= "Response status code does not indicate success Gateway" ---send email to group 2 [user4#gmail.com,user5#gmail.com,user6#gmail.com]
I have done upto this much ---
"actions": {
"send_email": {
"throttle_period_in_millis": 300000,
"condition": {
"script": {
"source": " def status = false; for(int i=0; i<ctx.payload.failure_request.aggregations.categories.buckets.length;i++) {if(ctx.payload.failure_request.aggregations.categories.buckets[i].key.contains('Response status code does not indicate success')) {status = true}} return status ",
"lang": "painless"
}
},
"email": {
"profile": "standard",
"to": [
"avinash.singh1#spglobal.com"
],
"subject": "{{ctx.metadata.email_subject}}",
"body": {
"html": "Error Found: <ul> {{ctx.payload.aggregations.categories.buckets.length}}"
}
}
}
}
Even Email is going to the given email when condition is pass ie when key contains that message.
But I want to send email based on message match for specific group at one go.
can any one help me on this if we have something in painless language to write logic like case statement.
Appreciate your help in advance.
These is my advice, I hope that can help you.
solution one: match with a string
"actions": {
"email_group_one" : {
"condition": {
"script": {
"source": "def status = ctx.payload.failure_request.aggregations.categories.buckets; if (status.size() == 0) return false; return hosts.stream().anyMatch(p -> p.key == 'Response status code does not indicate success Service Unavailable');"
"lang": "painless"
}
},
"email" : {
"to" : ["user1#gmail.com","user2#gmail.com","user3#gmail.com"],
"subject" : "YOUR SUBJEC",
"body" : {
"html": "YOUR HTML CODE"
}
}
},
"email_group_two" : {
"condition": {
"script": {
"source": "def status = ctx.payload.failure_request.aggregations.categories.buckets; if (status.size() == 0) return false; return hosts.stream().anyMatch(p -> p.key == 'Response status code does not indicate success Gateway');"
"lang": "painless"
}
},
"email" : {
"to" : ["user4#gmail.com","user5#gmail.com","user5#gmail.com"],
"subject" : "YOUR SUBJECT",
"body" : {
"html": "YOUR HTML CODE"
}
}
}
}
solution two: match with multiple values like a,b,c and d
"actions": {
"email_group_one" : {
"condition": {
"script": {
"source": "def myArray= ['a', 'b', 'c', 'd'];def status = ctx.payload.failure_request.aggregations.categories.buckets; if (status.size() == 0) return false; return hosts.stream().anyMatch(p -> p.key in myArray);"
"lang": "painless"
}
},
"email" : {
"to" : ["user1#gmail.com","user2#gmail.com","user3#gmail.com"],
"subject" : "YOUR SUBJEC",
"body" : {
"html": "YOUR HTML CODE"
}
}
},
"email_group_two" : {
"condition": {
"script": {
"source": "def myArray= ['e', 'f', 'g', 'h'];def status = ctx.payload.failure_request.aggregations.categories.buckets; if (status.size() == 0) return false; return hosts.stream().anyMatch(p -> p.key in myArray);"
"lang": "painless"
}
},
"email" : {
"to" : ["user4#gmail.com","user5#gmail.com","user5#gmail.com"],
"subject" : "YOUR SUBJECT",
"body" : {
"html": "YOUR HTML CODE"
}
}
}
}
the code has not been tested, you may have syntax errors.
i need help with finding and replacing a string from all the indexes and replace it with another string. I wanna change my attribut libelle when his value is 'Vol, Incendie' to 'Vol et incendie'.
here is my elasticJson example :
"devisdata": [
{
"nameWhoMadeIt": " ADMIN admin",
"Garanties": [
{
"libelle": "Vol, incendie",
"id": 2
},
{
"libelle": "bdg",
"id": 2
},
]
},
{
"nameWhoMadeIt": " ADMIN admin",
"Garanties": [
{
"libelle": "Vol, incendie",
"id": 2
},
{
"libelle": "bdg",
"id": 2
},
]
},
]
}
and here is my request :
{
"script": {
"source": "for (int i=0; i <= ctx._source.devisdata.length; i++) {
for (int j=0; j <= ctx._source.devisdata[i].Garanties.length; j++) {
if(ctx._source.devisdata[i].Garanties[j].libelle == 'Vol, Incendie') {
ctx._source.devisdata[i].Garanties[j].libelle = params.value; break
}
}
}",
"lang": "painless",
"params": {
"value": "Vol et incendie"
}
}
}
I find the answer, i just went out of the array. i only needed to do < not <=.
is there a better way to do this without looping ??
I am using painless script in ES and encountering a null pointer exception, here is my script and also I have added the response for better understanding, I use ES v7.3.
POST test_script/_update/1
{
"scripted_upsert": true,
"script": {
"lang": "painless",
"source": "int getBrowsersObjectIndex(def x, def y){for (int i = 0; i < x.length; i++) {if (x[i].deviceType == y.deviceType) {if (x[i].osName == y.osName) {if(x[i].browserName == y.browserName) {return i}}}}return -1} int getDevicesObjectIndex(def x, def y){for (int i = 0; i < x.length; i++) {if (x[i].deviceId == y.deviceId) {if (x[i].appName == y.appName) {if (x[i].appNameSpace == y.appNameSpace){return i}}}}return -1}if (!ctx._source.containsKey('browsers')) {ctx._source['browsers'] = []}if (!ctx._source.containsKey('devices')) {ctx._source['devices'] = []}for (int index = 0; index < params.iterate.length; index++) {if (params.iterate[index].browserObject) {int browserIndex = getBrowsersObjectIndex(ctx._source.browsers, params.iterate[index].browserObject);if (browserIndex >= 0) {ctx._source.browsers.remove(browserIndex);}ctx._source.browsers.add(params.iterate[index].browserObject);}if (params.iterate[index].deviceObject) {int deviceIndex = getDevicesObjectIndex(ctx._source.devices, params.iterate[index].deviceObject);if (deviceIndex >= 0) {ctx._source.devices.remove(deviceIndex);}ctx._source.devices.add(params.iterate[index].deviceObject);}}",
"params": {
"iterate": [
{
"deviceObject": {
"deviceId": "162c04e48832e338",
"appName": "test_app",
"appNameSpace": "com.test",
"appBuild": 55,
"appVersion": "4.6.3",
"deviceName": "OP4B80L1",
"manufacturer": "OPPO",
"model": "CPH1937",
"networkCarrier": "Jio",
"os": "Android",
"platform": "Android",
"timezone": "Asia/Kolkata",
"version": "10"
}
},
{
"browserObject": {
"deviceType": "mobile",
"osName": "Android",
"browserName": "Chrome",
"osVersion": 10,
"browserVersion": "80.0.3987.99"
}
}
]
}
},
"upsert": {}
}
Error is:
{
"error": {
"root_cause": [
{
"type": "remote_transport_exception",
"reason": "[connecto][192.168.36.235:9300][indices:data/write/update[s]]"
}
],
"type": "illegal_argument_exception",
"reason": "failed to execute script",
"caused_by": {
"type": "script_exception",
"reason": "runtime error",
"script_stack": [
"if (params.iterate[index].browserObject) {int ",
" ^---- HERE"
],
"script": "int getBrowsersObjectIndex(def x, def y){for (int i = 0; i < x.length; i++) {if (x[i].deviceType == y.deviceType) {if (x[i].osName == y.osName) {if(x[i].browserName == y.browserName) {return i}}}}return -1} int getDevicesObjectIndex(def x, def y){for (int i = 0; i < x.length; i++) {if (x[i].deviceId == y.deviceId) {if (x[i].appName == y.appName) {if (x[i].appNameSpace == y.appNameSpace){return i}}}}return -1}if (!ctx._source.containsKey('browsers')) {ctx._source['browsers'] = []}if (!ctx._source.containsKey('devices')) {ctx._source['devices'] = []}for (int index = 0; index < params.iterate.length; index++) {if (params.iterate[index].browserObject) {int browserIndex = getBrowsersObjectIndex(ctx._source.browsers, params.iterate[index].browserObject);if (browserIndex >= 0) {ctx._source.browsers.remove(browserIndex);}ctx._source.browsers.add(params.iterate[index].browserObject);}if (params.iterate[index].deviceObject) {int deviceIndex = getDevicesObjectIndex(ctx._source.devices, params.iterate[index].deviceObject);if (deviceIndex >= 0) {ctx._source.devices.remove(deviceIndex);}ctx._source.devices.add(params.iterate[index].deviceObject);}}",
"lang": "painless",
"caused_by": {
"type": "null_pointer_exception",
"reason": null
}
}
},
"status": 400
}
Seems like the error is in the if statement where I am checking if either of browserObject or deviceObject exists inside the iterate array of objects.
You need to perform an explicit null-check, i.e.
if (params.iterate[index].browserObject != null)
Besides, in Kibana Dev Tools, you can use triple quotes """ to properly format your code so it's more legible and easier to read/maintain:
POST test_script/_update/1
{
"scripted_upsert": true,
"script": {
"lang": "painless",
"source": """
int getBrowsersObjectIndex(def x, def y){
for (int i = 0; i < x.length; i++) {
if (x[i].deviceType == y.deviceType) {
if (x[i].osName == y.osName) {
if(x[i].browserName == y.browserName) {
return i
}
}
}
}
return -1
}
int getDevicesObjectIndex(def x, def y){
for (int i = 0; i < x.length; i++) {
if (x[i].deviceId == y.deviceId) {
if (x[i].appName == y.appName) {
if (x[i].appNameSpace == y.appNameSpace){
return i
}
}
}
}
return -1
}
if (!ctx._source.containsKey('browsers')) {
ctx._source['browsers'] = []
}
if (!ctx._source.containsKey('devices')) {
ctx._source['devices'] = []
}
for (int index = 0; index < params.iterate.length; index++) {
if (params.iterate[index].browserObject != null) {
int browserIndex = getBrowsersObjectIndex(ctx._source.browsers, params.iterate[index].browserObject);
if (browserIndex >= 0) {
ctx._source.browsers.remove(browserIndex);
}
ctx._source.browsers.add(params.iterate[index].browserObject);
}
if (params.iterate[index].deviceObject != null) {
int deviceIndex = getDevicesObjectIndex(ctx._source.devices, params.iterate[index].deviceObject);
if (deviceIndex >= 0) {
ctx._source.devices.remove(deviceIndex);
}
ctx._source.devices.add(params.iterate[index].deviceObject);
}
}
""",
"params": {
"iterate": [
{
"deviceObject": {
"deviceId": "162c04e48832e338",
"appName": "test_app",
"appNameSpace": "com.test",
"appBuild": 55,
"appVersion": "4.6.3",
"deviceName": "OP4B80L1",
"manufacturer": "OPPO",
"model": "CPH1937",
"networkCarrier": "Jio",
"os": "Android",
"platform": "Android",
"timezone": "Asia/Kolkata",
"version": "10"
}
},
{
"browserObject": {
"deviceType": "mobile",
"osName": "Android",
"browserName": "Chrome",
"osVersion": 10,
"browserVersion": "80.0.3987.99"
}
}
]
}
},
"upsert": {}
}
I want to update a field with a new value depending on its previous value. E.g: if field 'set' values are either 'aaa' or 'bbb', I want to provide a list of new values so that, say, 'aaa' becomes 'ccc' and 'bbb' becomes 'ddd'.
This query is were I am stuck:
POST my_index/_update_by_query?conflicts=proceed
{
"query": {
"terms": {"set.keyword": ["aaa", "bbb"]}
},
"script": {
"inline": "ctx._source.set = 'ccc'; ctx._source.set = 'ddd';"
}
}
Instead of getting different updated values ('ccc' or 'ddd' depending on which was the previous value), all values are updated to 'ddd'. I suspect it is updating all values twice.
Using Val's query below, I get the following output:
{
"error": {
"root_cause": [
{
"type": "script_exception",
"reason": "runtime error",
"script_stack": [
"ctx._source.set = ctx._source.set.stream().map(elem -> {\n ",
" ^---- HERE"
],
"script": " ctx._source.set = ctx._source.set.stream().map(elem -> {\n if (params[elem] != null) {\n return params[elem];\n } else {\n return elem;\n }\n }).collect(Collectors.toList());",
"lang": "painless"
}
],
"type": "script_exception",
"reason": "runtime error",
"script_stack": [
"ctx._source.set = ctx._source.set.stream().map(elem -> {\n ",
" ^---- HERE"
],
"script": " ctx._source.set = ctx._source.set.stream().map(elem -> {\n if (params[elem] != null) {\n return params[elem];\n } else {\n return elem;\n }\n }).collect(Collectors.toList());",
"lang": "painless",
"caused_by": {
"type": "illegal_argument_exception",
"reason": "Unable to find dynamic method [stream] with [0] arguments for class [java.lang.String]."
}
},
"status": 500
}
Mapping does not explicitly mention 'set' field:
MY_MAPPING = '''{
"mappings": {
"data_type": {
"properties": {
"delivered": {
"type": "date",
"format": "yyyy-MM-dd"
},
"requested": {
"type": "date",
"format": "yyyy-MM-dd"
},
"location": {
"type": "geo_point"
}
}
}
}
}'''
Taking a look at my index, I have 'set' as a searchable string and 'set.keyword', also a string, that is searchable and aggregatable.
I would do it like this:
POST my_index/_update_by_query?conflicts=proceed
{
"query": {
"terms": {"set.keyword": ["aaa", "bbb"]}
},
"script": {
"source": """
def currentSet = ctx._source.set;
ctx._source.set = (params[currentSet] != null) ? params[currentSet] : currentSet;
""",
"params": {
"aaa": "ccc",
"bbb": "ddd"
}
}
}
In other terms, the script will iterate over the set array and for each element, it will return whatever new value is in the params hash for a given old value, or the old value itself if there's no new value.
If your set is ["aaa", "bbb", "xxx"] then after updating your index, it would contain ["ccc", "ddd", "xxx"]
I am using update_by_query with the following body:
POST /documents/_update_by_query
{
"script":{
"source":"for(int i = 0;i < ctx._source.fields.size();i++){for (int j = 0; j < params.field_uid.size();j++){ if(params.field_uid[j].type == \"group\" ){ } else{ if(ctx._source.fields[i].uid == params.field_uid[j].uid){ ctx._source.fields.remove(i);} } }}",
"params":{
"field_uid":[{"uid":"number","type":"number"},{"uid":"test","type":"group"}]
}
},
"query": {
"term": {
"name": "test"
}
}
}
It is giving me like Extraneous if statement. Here is the error message I got :
{
"error": {
"root_cause": [
{
"type": "script_exception",
"reason": "compile error",
"script_stack": [
"... s.field_uid.size();j++){ if(params.field_uid[j].ty ...",
" ^---- HERE"
],
"script": "for(int i = 0;i < ctx._source.fields.size();i++){for (int j = 0; j < params.field_uid.size();j++){ if(params.field_uid[j].type == 100 ){ } else{ if(ctx._source.fields[i].uid == params.field_uid[j].uid){ ctx._source.fields.remove(i);} } }}",
"lang": "painless"
}
],
"type": "script_exception",
"reason": "compile error",
"script_stack": [
"... s.field_uid.size();j++){ if(params.field_uid[j].ty ...",
" ^---- HERE"
],
"script": "for(int i = 0;i < ctx._source.fields.size();i++){for (int j = 0; j < params.field_uid.size();j++){ if(params.field_uid[j].type == 100 ){ } else{ if(ctx._source.fields[i].uid == params.field_uid[j].uid){ ctx._source.fields.remove(i);} } }}",
"lang": "painless",
"caused_by": {
"type": "illegal_argument_exception",
"reason": "Extraneous if statement."
}
},
"status": 500
}
Can anyone help me into this?
What is wrong here?
The if statement written is not doing any operation and is irrelevant as a result ES is throwing extraneous if statement error.
Remove it and update the condition accordingly as below.
for(int i = 0;i < ctx._source.fields.size();i++){ for (int j = 0;j <
params.field_uid.size();j++){ if(params.field_uid[j].type != \"group\"
&& ctx._source.fields[i].uid == params.field_uid[j].uid){
ctx._source.fields.remove(i);}}}