I am trying to solve a problem using painless. I need to find number of customers who ate any of the specified food items within specified date range and with frequency . The code works on 6.0 but breaks on 6.3.
Below is my Mapping
PUT myindex
{
"settings": {
"index": {
"number_of_shards": 2
}
},
"mappings": {
"customer": {
"dynamic": "strict",
"properties": {
"customerName": {
"type": "keyword"
},
"customerRegion": {
"type": "keyword"
},
"dateOfBirthYear": {
"type": "date",
"format": "yyyy"
},
"foods": {
"properties": {
"dates": {
"type": "date",
"index": false,
"store": true,
"ignore_malformed": true,
"format": "yyyy-MM-dd"
},
"datesCount": {
"type": "integer",
"index": false,
"store": true
},
"foodRowKey": {
"type": "keyword",
"index": false,
"store": true
} } } } } } }
Data is :
PUT myindex/customer/1?refresh=true
{
"customerName" : "Batman",
"customerRegion": "N California",
"dateOfBirthYear" :"1977",
"foods":[{
"foodRowKey": "Chicken",
"datesCount": 2,
"dates": ["2016-06-20"]
},{
"foodRowKey": "Soup",
"datesCount": 3,
"dates": ["2016-04-18", "2016-04-19", "2016-04-20"]
},{
"foodRowKey": "Dessert",
"datesCount": 3,
"dates": ["2016-06-20"]
}]
}
PUT myindex/customer/2?refresh=true
{
"customerName" : "Keenu Reeves",
"customerRegion": "N California",
"dateOfBirthYear" :"1987",
"foods":[{
"foodRowKey": "Soup",
"datesCount": 1,
"dates": ["2016-06-20"]
},{
"foodRowKey": "Dessert",
"datesCount": 2,
"dates": ["2016-06-21","2016-08-12"]
},{
"foodRowKey": "Burger",
"datesCount": 2,
"dates": ["2016-06-20","2016-09-2"]
}]
}
Query is :
GET myindex/_search
{
"size" : 1000,
"query" : {
"bool" : {
"filter" : [
{
"bool" : { "must":[{ "script" : {
"script" : {
"lang": "painless",
"source" : "def fromDt = LocalDate.parse(params.fromDate); def toDt = LocalDate.parse(params.toDate); def rowKeys = params._fields[params.rowKeyField].values; def dates = params._fields[params.dateField].values; def dateCounts = params._fields[params.dateCountField].values; def interestingDates = new HashSet(); def datesCtr = 0; if (dateCounts.size() < params.min_occurs) { return (false); } for (int ctr = 0; ctr < rowKeys.size(); ctr++) { if (params.rowKey.contains(rowKeys.get(ctr))) { def matchingDates = dates.subList(datesCtr, datesCtr + dateCounts.get(ctr).intValue()); if (matchingDates.size() < params.min_occurs) { break; } for (int ctr1 = 0; ctr1 < matchingDates.size(); ctr1++) { def dt = LocalDate.parse(matchingDates.get(ctr1)); if (dt.isAfter(toDt)) { break; } else if (dt.isAfter(fromDt) && dt.isBefore(toDt)) { interestingDates.add(dt); } else if (dt.equals(fromDt) || dt.equals(toDt)) { interestingDates.add(dt); } } if (interestingDates.size() >= params.min_occurs && ChronoUnit.DAYS.between(Collections.min(interestingDates), Collections.max(interestingDates)) >= params.gapDays) { return (true); } } datesCtr += dateCounts.get(ctr).intValue(); }",
"params" : {
"fromDate" : "2016-04-01",
"dateCountField" : "foods.datesCount",
"min_occurs" : 2,
"rowKeyField" : "foods.foodRowKey",
"toDate" : "2016-06-30",
"dateField" : "foods.dates",
"rowKey" : [
"Soup","Dessert"],
"gapDays" : 0
}
},
"boost" : 1.0
} }]} }]}}}
Below is the error stack trace
"failures": [
{
"shard": 1,
"index": "myindex",
"node": "NZXRtCJDRxOpaYk-dvD3FA",
"reason": {
"type": "script_exception",
"reason": "runtime error",
"script_stack": [
"rowKeys = params._fields[params.rowKeyField].values; def ",
" ^---- HERE"
],
"script": "def fromDt = LocalDate.parse(params.fromDate); def toDt = LocalDate.parse(params.toDate); def rowKeys = params._fields[params.rowKeyField].values; def dates = params._fields[params.dateField].values; def dateCounts = params._fields[params.dateCountField].values; def interestingDates = new HashSet(); def datesCtr = 0; if (dateCounts.size() < params.min_occurs) { return (false); } for (int ctr = 0; ctr < rowKeys.size(); ctr++) { if (params.rowKey.contains(rowKeys.get(ctr))) { def matchingDates = dates.subList(datesCtr, datesCtr + dateCounts.get(ctr).intValue()); if (matchingDates.size() < params.min_occurs) { break ; } for (int ctr1 = 0; ctr1 < matchingDates.size(); ctr1++) { def dt = LocalDate.parse(matchingDates.get(ctr1)); if (dt.isAfter(toDt)) { break; } else if (dt.isAfter(fromDt) && dt.isBefore(toDt)) { interestingDates.add(dt); } else if (dt.equals(fromDt) || dt.equals(toDt)) { interestingDates.add(dt); } } if (interestingDates.size() >= params.min_occurs && ChronoUnit.DAYS.between(Collections.min(interestingDates), Collections.max(interestingDates)) >= params.gapDays) { return (true); } } datesCtr += dateCounts.get(ctr).intValue(); }",
"lang": "painless",
"caused_by": {
"type": "null_pointer_exception",
"reason": null } } } ]