Sort script in painless

I'm trying to sort results on query which is run using multiple indexes/type

In some types I have nested 'revisions' which have title, in some I don't have revisions just title. Title has raw field.
I just want to use revisions.title.raw when revisions exists and title.raw when don't

this is my query:

{
   "query":{
      "bool":{
         "must":[
            {
               "match_all":{

               }
            }
         ]
      }
   },
   "sort":{
      "_script":{
         "script":{
            "lang":"painless",
            "inline":"doc['revisions'] === null ? doc['title'].raw.value : doc['revisions.title'].raw.value"
         },
         "type":"string",
         "order":"asc"
      }
   },
   "size":10,
   "from":"0"
}

and I get error:

{
   "error":{
      "root_cause":[
         {
            "type":"script_exception",
            "reason":"runtime error",
            "script_stack":[
               "org.elasticsearch.search.lookup.LeafDocLookup.get(LeafDocLookup.java:80)",
               "doc['revisions'] === null ? doc['title'].raw.value : doc['revisions.title'].raw.value",
               "    ^---- HERE"
            ],
            "script":"doc['revisions'] === null ? doc['title'].raw.value : doc['revisions.title'].raw.value",
            "lang":"painless"
         }
      ],
      "type":"search_phase_execution_exception",
      "reason":"all shards failed",
      "phase":"query",
      "grouped":true,
      "failed_shards":[
         {
            "shard":0,
            "index":"cdk",
            "node":"oGUf1cVDRaGrOQD3d0IUog",
            "reason":{
               "type":"script_exception",
               "reason":"runtime error",
               "script_stack":[
                  "org.elasticsearch.search.lookup.LeafDocLookup.get(LeafDocLookup.java:80)",
                  "doc['revisions'] === null ? doc['title'].raw.value : doc['revisions.title'].raw.value",
                  "    ^---- HERE"
               ],
               "script":"doc['revisions'] === null ? doc['title'].raw.value : doc['revisions.title'].raw.value",
               "lang":"painless",
               "caused_by":{
                  "type":"illegal_argument_exception",
                  "reason":"No field found for [revisions] in mapping with types []"
               }
            }
         }
      ],
      "caused_by":{
         "type":"script_exception",
         "reason":"runtime error",
         "script_stack":[
            "org.elasticsearch.search.lookup.LeafDocLookup.get(LeafDocLookup.java:80)",
            "doc['revisions'] === null ? doc['title'].raw.value : doc['revisions.title'].raw.value",
            "    ^---- HERE"
         ],
         "script":"doc['revisions'] === null ? doc['title'].raw.value : doc['revisions.title'].raw.value",
         "lang":"painless",
         "caused_by":{
            "type":"illegal_argument_exception",
            "reason":"No field found for [revisions] in mapping with types []"
         }
      }
   },
   "status":500
}

I try to use containsKey function like this:

doc.containsKey('revisions') ? doc.revisions.title.raw.value : doc.title.raw.value

But I get:

          ^---- HERE"],"script":"doc.containsKey('revisions') ? doc.revisions.title.raw.value : doc.title.raw.value","lang":"painless","caused_by":{"type":"illegal_argument_exception","reason":"No field found for [title] in mapping with types []"}}},"status":500}

but my mappings are fine:

I have:

"properties": {
        "title": {
            "type": "text",
            "boost": 10.0,
            "fields": {
              "first": {
                "type": "text",
                "analyzer": "first",
                "fielddata": true
              },
              "raw": {
                "type": "keyword"
              }
            },

or

"properties": {
          "revisions": {
            "type": "nested",
            "properties": {
              "title": {
                "type": "text",
                "boost": 10.0,
                "fields": {
                  "first": {
                    "type": "text",
                    "analyzer": "first",
                    "fielddata": true
                  },
                  "raw": {
                    "type": "keyword"
                  }
                },
                "analyzer": "cz"
              }
            }
          },

Fields that have a . in their name need to be looked up like doc['revisions.title.raw'] and doc['title.raw'] because doc is an accessor for doc values rather than your source document.

Yes this is part of my problem.

When I do:
"inline":"doc.containsKey('revisions') ? doc['revisions.title.raw'] : doc['title.raw']"
One of my index is success.
But the weird thing is that other one will fail with:

{
   "error":{
      "root_cause":[
         {
            "type":"script_exception",
            "reason":"runtime error",
            "script_stack":[
               "org.elasticsearch.search.lookup.LeafDocLookup.get(LeafDocLookup.java:80)",
               "doc.containsKey('revisions') ? doc['revisions.title.raw'] : doc['title.raw']",
               "                                                                ^---- HERE"
            ],
            "script":"doc.containsKey('revisions') ? doc['revisions.title.raw'] : doc['title.raw']",
            "lang":"painless"
         }
      ],
      "type":"search_phase_execution_exception",
      "reason":"all shards failed",
      "phase":"query",
      "grouped":true,
      "failed_shards":[
         {
            "shard":0,
            "index":"cdk",
            "node":"oGUf1cVDRaGrOQD3d0IUog",
            "reason":{
               "type":"script_exception",
               "reason":"runtime error",
               "script_stack":[
                  "org.elasticsearch.search.lookup.LeafDocLookup.get(LeafDocLookup.java:80)",
                  "doc.containsKey('revisions') ? doc['revisions.title.raw'] : doc['title.raw']",
                  "                                                                ^---- HERE"
               ],
               "script":"doc.containsKey('revisions') ? doc['revisions.title.raw'] : doc['title.raw']",
               "lang":"painless",
               "caused_by":{
                  "type":"illegal_argument_exception",
                  "reason":"No field found for [title.raw] in mapping with types [competence]"
               }
            }
         }
      ],
      "caused_by":{
         "type":"script_exception",
         "reason":"runtime error",
         "script_stack":[
            "org.elasticsearch.search.lookup.LeafDocLookup.get(LeafDocLookup.java:80)",
            "doc.containsKey('revisions') ? doc['revisions.title.raw'] : doc['title.raw']",
            "                                                                ^---- HERE"
         ],
         "script":"doc.containsKey('revisions') ? doc['revisions.title.raw'] : doc['title.raw']",
         "lang":"painless",
         "caused_by":{
            "type":"illegal_argument_exception",
            "reason":"No field found for [title.raw] in mapping with types [competence]"
         }
      }
   },
   "status":500
}

But when I do:
"inline":"doc.containsKey('revisions') ? doc['revisions.title.raw'] : doc['revisions.title.raw']"
It will be success. So how I understand it is that doc.containsKey('revisions') will be false even when key revisions exists, that doesn't make sense and should fail this way.

If revisions is an object field then it won't be in doc at all because doc is a view of doc values fields, not the internal structure of the document.

1 Like

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