Combine two function_score queries in dis_max


(Pavel) #1

Hello! I would like to make a query with two subqueries, each of them has it's own scoring based on function_score with script. For example, this subquery

 {
                     "query":{
                        "function_score":{
                           "query":{
                              "bool":{
                                 "filter":[
                                    {
                                       "term":{
                                          "rooms_count":3
                                       }
                                    },
                                    {
                                       "term":{
                                          "addresses":"d76255c8-3173-4db5-a39b-badd3ebdf851"
                                       }
                                    },
                                    {
                                       "exists":{
                                          "field":"zhk_id"
                                       }
                                    }
                                 ]
                              }
                           },
                           "script_score":{
                              "script":"1 * doc['price'].value/100000"
                           },
                           "boost_mode":"replace"
                        }
                     }
                  }

works fine, and it's score is based on price (about 190 points). But if I try to combine two subquieries in dis_max query, function_score is not working and I get scores about 1 point.
Explanation for each subquery looks like this

"value": 100.9416, "description": "script score function, computed with script:"[script: 1 * doc['price'].value/100000, type: inline, lang: null, params: {}]" and parameters:
{}",
for dis_max query like
"value": 1, "description": "ConstantScore(function score (#rooms_count: #addresses:d76255c8-3173-4db5-a39b-badd3ebdf851 #ConstantScore(_field_names:zhk_id),function=script[script: 1 * doc['price'].value/100000, type: inline, lang: null, params: {}])), product of:",`

Can anybody tell me, how to combine function_score queries properly?

My full dis_max query on pastebin


(Daniel Mitterdorfer) #2

Hi @bender268,

based on what I see here everything is fine. Maybe there is some problem in your data?

Here is a complete example based on Elasticsearch 5.1.1 (just replace the keyword field with a not_analyzed string field if you use ES 2.x):

DELETE /immo

PUT /immo
{
    "mappings": {
        "flat": {
            "properties": {
                "address": {
                    "type": "keyword"
                },
                "rooms": {
                    "type": "integer"
                },
                "price": {
                    "type": "float"
                }
            }
        }
    }
}

# Create a few matching (and also non-matching flats)

POST /immo/flat
{
    "address": "Munich",
    "rooms": 3,
    "price": "500000",
    "zhk_id": 42
}

POST /immo/flat
{
    "address": "Munich",
    "rooms": 1,
    "price": "200000",
    "zhk_id": 43
}

POST /immo/flat
{
    "address": "Munich",
    "rooms": 3,
    "price": "700000"
}

POST /immo/flat
{
    "address": "Munich",
    "rooms": 3,
    "price": "800000"
}

POST /immo/flat
{
    "address": "Munich",
    "rooms": 3,
    "price": "700000",
    "zhk_id": 48
}

POST /immo/flat
{
    "address": "Munich",
    "rooms": 3,
    "price": "336000",
    "zhk_id": 88
}

If I run a slightly modified version of your query (adapted to the simplified example and the 5.x syntax):

GET /immo/flat/_search
{
   "query": {
      "dis_max": {
         "queries": [
            {
               "function_score": {
                  "query": {
                     "bool": {
                        "filter": [
                           {
                              "term": {
                                 "rooms": 3
                              }
                           },
                           {
                              "term": {
                                 "address": "Munich"
                              }
                           },
                           {
                              "bool": {
                                 "must_not": {
                                    "exists": {
                                       "field": "zhk_id"
                                    }
                                 }
                              }
                           }
                        ]
                     }
                  },
                  "script_score": {
                     "script": "doc['price'].value / 100000"
                  },
                  "boost_mode": "replace"
               }
            },
            {
               "function_score": {
                  "query": {
                     "bool": {
                        "filter": [
                           {
                              "term": {
                                 "rooms": 3
                              }
                           },
                           {
                              "term": {
                                 "address": "Munich"
                              }
                           },
                           {
                              "exists": {
                                 "field": "zhk_id"
                              }
                           }
                        ]
                     }
                  },
                  "script_score": {
                     "script": "doc['price'].value / 100000"
                  },
                  "boost_mode": "replace"
               }
            }
         ]
      }
   }
}

I get reasonable scores:

{
   "took": 6,
   "timed_out": false,
   "_shards": {
      "total": 5,
      "successful": 5,
      "failed": 0
   },
   "hits": {
      "total": 5,
      "max_score": 8,
      "hits": [
         {
            "_index": "immo",
            "_type": "flat",
            "_id": "AVlvVc1FYSS4vzD5IS5l",
            "_score": 8,
            "_source": {
               "address": "Munich",
               "rooms": 3,
               "price": "800000"
            }
         },
         {
            "_index": "immo",
            "_type": "flat",
            "_id": "AVlvVdtgYSS4vzD5IS5m",
            "_score": 7,
            "_source": {
               "address": "Munich",
               "rooms": 3,
               "price": "700000",
               "zhk_id": 48
            }
         },
         {
            "_index": "immo",
            "_type": "flat",
            "_id": "AVlvVcIuYSS4vzD5IS5k",
            "_score": 7,
            "_source": {
               "address": "Munich",
               "rooms": 3,
               "price": "700000"
            }
         },
         {
            "_index": "immo",
            "_type": "flat",
            "_id": "AVlvVaXZYSS4vzD5IS5i",
            "_score": 5,
            "_source": {
               "address": "Munich",
               "rooms": 3,
               "price": "500000",
               "zhk_id": 42
            }
         },
         {
            "_index": "immo",
            "_type": "flat",
            "_id": "AVlvViw9YSS4vzD5IS5n",
            "_score": 3.36,
            "_source": {
               "address": "Munich",
               "rooms": 3,
               "price": "336000",
               "zhk_id": 88
            }
         }
      ]
   }
}

By the way, I don't think you need dis_max for the query as you posted it but I guess the original one is more complex which is why you want to use it.

Daniel


(Pavel) #3

Thank you very much, @danielmitterdorfer!!!

I repeated your query and it worked!

After that, I found that in my query, there was an extra "query" keyword before "function_score".
I removed it and BINGO! it's all working!

I really appreciate your help, this problem cost me 3 days!

Thank you again!!!

Correct query is:

    {
   "query":{
      "dis_max":{
         "queries":[
        {
                        "function_score":{
                           "query":{
                              "bool":{
                                 "filter":[
                                    {
                                       "term":{
                                          "rooms_count":3
                                       }
                                    },
                                    {
                                       "term":{
                                          "addresses":"d76255c8-3173-4db5-a39b-badd3ebdf851"
                                       }
                                    },
                                    {
                                       "missing":{
                                          "field":"zhk_id"
                                       }
                                    }
                                 ]
                              }
                           },
                           "script_score":{
                              "script":"1 * doc['price'].value/100000"
                           },
                           "boost_mode":"replace"
                        }
                  },
        {
                        "function_score":{
                           "query":{
                              "bool":{
                                 "filter":[
                                    {
                                       "term":{
                                          "rooms_count":3
                                       }
                                    },
                                    {
                                       "term":{
                                          "addresses":"d76255c8-3173-4db5-a39b-badd3ebdf851"
                                       }
                                    },
                                    {
                                       "exists":{
                                          "field":"zhk_id"
                                       }
                                    }
                                 ]
                              }
                           },
                           "script_score":{
                              "script":"1 * doc['price'].value/100000"
                           },
                           "boost_mode":"replace"
                        }
                     }
         ]
      }
   }
}

(Daniel Mitterdorfer) #4

Hi @bender268,

glad I could help you. :slight_smile:

Daniel


(system) #5

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