How to retrieve a field value from inner_hits filtered object


(pungent) #1

In my mapping document, I have one of the nested object as follows

"availabilities":{                      
  "type": "nested",                     
  "dynamic": "strict",                      
  "properties": {                     
    "start":                        { "type": "date",   "format": "yyyy-MM-dd"  },
    "end":                          { "type": "date",   "format": "yyyy-MM-dd"  },
    "age":                          { "type": "integer"                         }
  }                     
}

I have a long DSL query, in which one of the filters is:

{
  "nested": {
    "path": "availabilities",
    "inner_hits" : {
      "size": 1,
      "name": "selected_availabilities"
    },
    "query": {
      "bool": {
        "must": [
          {
            "range": {
              "availabilities.start": {
                "gte": "2016-10-08",
                "lte": "2016-10-08"
              }
            }
          },
          {
            "range": {
              "availabilities.end": {
                "gte": "2016-10-17",
                "lte": "2016-10-17"
              } 
            }
          }
        ]
      }
    }
  }
}

I am trying to use inner_hits to get the selected availabilities object and that returns something like this:

{
  "took": 5,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "failed": 0
  },
  "hits": {
    "total": 1,
    "max_score": 6000,
    "hits": [
      {
        "_index": "listings_v1",
        "_type": "listing",
        "_id": "228527",
        "_score": 6000,
        "_source": {
          ...my fields....
          ...my fields....
          ...my fields....
          ...my fields....
          ...availabilities has nested objects.....
        },
        "inner_hits": {
          "selected_availabilities": {
            "hits": {
              "total": 1,
              "max_score": 1.4142135,
              "hits": [
                {
                  "_type": "listing",
                  "_id": "228527",
                  "_nested": {
                    "field": "availabilities",
                    "offset": 3
                  },
                  "_score": 1.4142135,
                  "_source": {
                    "start": "2016-10-08",
                    "end": "2016-10-17",
                    "age": 23
                  }
                }
              ]
            }
          }
        }
      }
    ]
  }
}

My goal is to use one of the fileds from the selected object in the inner_hits for the calculation of the score.
Since availabilities object may have multiple object, but there will ALWAYS be only one matching my search criteria. SO this is what I have as my query:

function_score": {
  "query": {},
  "score_mode": "sum",
  "boost_mode": "replace"
  "functions": [
    {
      "script_score": {
        "params": {
          "move_in_date_boost": -1350,
          "desired_move_in_date": "2016-11-03"
        },
        "script": "return (inner_hits['selected_availabilities']['hits']['hits'][0]['_source']['age']);" 
      }
    },
    {
      ....more functions...
    }
  ]
}

But when I use above script, I get the following error:

{
  "took": 239,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 4,
    "failed": 1,
    "failures": [
      {
        "shard": 0,
        "index": "xyz_v1",
        "node": "5645yDwf345we234236w",
        "reason": {
          "type": "script_exception",
          "reason": "failed to run inline script [return (inner_hits['selected_availabilities']['hits']['hits'][0]['_source']['age']);] using lang [groovy]",
          "caused_by": {
            "type": "missing_property_exception",
            "reason": "missing_property_exception: No such property: inner_hits for class: 572da4fc5f5e591a0d7cfec2cde0c998b550b1f4"
          }
        }
      }
    ]
  },
  "hits": {
    "total": 0,
    "max_score": null,
    "hits": []
  }
}

How to get selected_availabilities age field in score calculation? Any help will be highly appreciated.


(Bryan Warner) #2

Trying to do something similar and getting the same error - i.e. missing_property_exception: No such property: inner_hits for class...

Are you not able to access inner_hits from scripts the same way you can access _source, _score, etc.? I see the field inner_hits present on the returned results from ES (just like above), and even put in extra null checks to only access it in my script if it was present, but didn't make any difference

Any feedback would be appreciated


#3

I was struggling with this as well as I needed to boost my query score as a function of a field within inner hits. Per the following post, inner hits are not accessible within scripts:

Bummer.

However, I managed to find a solution to my problem by using a nested query with a function score query inside it computing the score contribution of the nested hit.

For example, if you have the following mapping:

{
    "properties": {
        "field": {
            "type": "nested",
            "properties": {
                 "nested_field": {
                     "type": "text"
                 },
                 "nested_field_score": {
                     "type": "float"
                 }
            }
        }
    }
}

Then you can do the following nested query:

{
    "query": {
        "nested": {
            "path": "field",
            "query": {
                "function_score": {
                    "query": {
                        "match": {
                            "field.nested_field": "<match text>"
                        }
                    }
                },
                "script_score": {
                    "script": "doc['field.nested_field_score'].value"
                }
            }
        }
    }
}

You can then wrap this in a bool query and match non-nested fields along-side nested fields, each contributing a computed score.

This doesn't solve all issues with not having access to inner hits but worked well in my case.


(Spencer De Mars) #4

Thanks this was a big help!