Elasticsearch script - Extraneous if statement - elasticsearch

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);}}}

Related

Find and replace String in elasticSearch using loop

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 ??

Null pointer exception in ES painless script?

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": {}
}

How to put parameters in query.script.script.params?

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

ElasticSearch and Groovy scripting with "\n"

I have next query :
{
"script": " for (int i = 0; i < ctx._source.sample.size(); i++) {boolean f = false;if (ctx._source.sample[j].id == sample.id) {ctx._source.sample[j].c_rg = sample.c_rg;f=true;break;}}\nif(!f){ctx._source.sample.add(sample);}}",
"params": {
"sample":
{
"id": "GM033438",
"c_rg": [{"start":"69082","end":"70000"}]
}
}
}
I have this error :
"type": "script_exception",
"reason": "failed to compile groovy script",
"caused_by": {
"type": "multiple_compilation_errors_exception",
"reason": "startup failed:\n1dfd396b94db7321e5b5c14fbb1bfc21983608e6: 2: expecting EOF, found '}' # line 2, column 40.\n if(!f){ctx._source.sample.add(sample);}}\n ^\n\n1 error\n"
}
seems that I have a problem with "\n" ... but I have no idea about solve it... thanks!
The error message states: expecting EOF, found '}'
At this place:
if(!f){ctx._source.sample.add(sample);}}
(last } is not needed)

Scripted field to count array length

I have the following document:
{
"likes": {
"data": [
{
"name": "a"
},
{
"name": "b"
},
{
"name": "c"
}
]
}
}
I'm trying to run an update_by_query that will add a field called 'like_count' with the number of array items inside likes.data
It's important to know that not all of my documents have the likes.data object.
I've tried this:
POST /facebook/post/_update_by_query
{
"script": {
"inline": "if (ctx._source.likes != '') { ctx._source.like_count = ctx._source.likes.data.length }",
"lang": "painless"
}
}
But getting this error message:
{
"type": "script_exception",
"reason": "runtime error",
"script_stack": [
"ctx._source.like_count = ctx._source.likes.data.length }",
" ^---- HERE"
],
"script": "if (ctx._source.likes != '') { ctx._source.like_count = ctx._source.likes.data.length }",
"lang": "painless"
}
Try ctx._source['likes.data.name'].length
According to https://www.elastic.co/guide/en/elasticsearch/reference/current/nested.html, the object array in ES is flattened to
{
"likes.data.name" :["a", "b", "c"]
}
The object array datatype we thought is Nest datatype.
Try this
ctx._source['likes']['data'].size()

Resources