Search code examples
elasticsearchscoring

elasticsearch: Add weight for each match of array


I want to add a weight for each match (instead of adding a weight once if one of those matched):

Having docs like this:

[{
    "username": "xyz",
    "categories": [
        {
            "category.id": 1
        },
        {
            "category.id": 2
        }
    ]
}, {
    "username": "xyz2",
    "categories": [
        {
            "category.id": 1
        }
    ]
}]

And currently, I have this query:

{
    "query": {
        "filtered": {
            "query": {
                "function_score": {
                    "query": {
                        "bool": {}
                    },
                    "score_mode": "sum",
                    "boost_mode": "sum",
                    "functions": [
                        {
                            "weight": 1.1,
                            "filter": {
                                "terms": {
                                    "category.id": [
                                        1,
                                        2
                                    ]
                                }
                            }
                        }
                    ]
                }
            },
            "filter": {
                "bool": {
                    "must_not": [
                        {
                            "terms": {
                                "_id": [
                                    8
                                ]
                            }
                        }
                    ]
                }
            }
        }
    },
    "from": 0,
    "size": 30
}

With this query, both entries would receive a single weight of 1.1, but I want the first entry to get 2 * 1.1 because 2 categories are matched. How could I achieve that?

EDIT: Sorry, I missed to add elastic search version. It's 1.7.2.


Solution

  • This might be a bit cumbersome, since for multiple IDs that query will need to have multiple statements, but I don't think there is any other way. Also, notice that your field referencing is not complete - it should be categories.category.id to be correct. Also, be careful when upgrading with dots in field names. This changed in some releases over time.

    {
      "query": {
        "filtered": {
          "query": {
            "function_score": {
              "query": {
                "match_all": {}
              },
              "score_mode": "sum",
              "boost_mode": "sum",
              "functions": [
                {
                  "weight": 1.1,
                  "filter": {
                    "term": {
                      "categories.category.id": 1
                    }
                  }
                },
                {
                  "weight": 1.1,
                  "filter": {
                    "term": {
                      "categories.category.id": 2
                    }
                  }
                }
              ]
            }
          },
          "filter": {
            "bool": {
              "must_not": [
                {
                  "terms": {
                    "_id": [
                      8
                    ]
                  }
                }
              ]
            }
          }
        }
      },
      "from": 0,
      "size": 30
    }