# Combining Multiple Function Scores

**URL:** <https://discuss.elastic.co/t/combining-multiple-function-scores/183857>\
**Category:** Elasticsearch\
**Created:** [June 2, 2019, 10:13am UTC](https://discuss.elastic.co/t/combining-multiple-function-scores/183857 "2019-06-02T10:13:59Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![gidgid](https://avatars.discourse-cdn.com/v4/letter/g/b77776/32.png) [@gidgid](https://discuss.elastic.co/u/gidgid)\
**Post date:** [June 2, 2019, 10:13am UTC](https://discuss.elastic.co/t/combining-multiple-function-scores/183857/1 "2019-06-02T10:13:59Z")

</div>

I've got several different Elasticsearch function\_score but I'm not sure how to combine them

This is the test set I'm looking at (I added comments to be able to refer to specific items in the question, these comments are not actually in the index)

```
[
    { // Item 1
        "priority": 0.7,
        "classification": [
            {
                "feature": "A",
                "confidence": 0.4
            },
            {
                "feature": "C",
                "confidence": 0.3
            },
            {
                "feature": "B",
                "confidence": 0.6
            }
        ]
    },
    { // Item 2
        "priority": 0.8,
        "classification": [
            {
                "feature": "A",
                "confidence": 0.3
            },
            {
                "feature": "C",
                "confidence": 0.6
            }
        ]
    },
    { // Item 3
        "priority": 0.4,
        "classification": [
            {
                "feature": "D",
                "confidence": 0.6
            },
            {
                "feature": "C",
                "confidence": 0.8
            }
        ]
    }
]

```

Now assume I want to score items with the following weights:

- "A" with weight of 2
- "B" with weight of 3

I would like to do the following:

1. Calculate average confidence for each item only for features "A" and "B" (e.g. average confidence of 0.5 for item 1)
2. Calculate priority for each item (e.g. popularity of 0.8 item 2)
3. Calculate the sum of weights for each item feature (if item has feature "A" it receives a weight of 2, if it has feature "B" it receives a weight of 3. e.g. item 1 would receive a weight of 5 and item 2 a weight of 2)
4. Combine the different calculations into a final score (I will need to experiment a little bit with different "combine" functions)

I know how to create the function\_score for the average confidence, it would be something like this:

```
{
  "nested": {
    "path": "classification",
    "query": {
       "function_score": {
          "functions": [
              {
                  "field_value_factor": {
                      "field": "classification.confidence",
                      "missing": 0
                  },
                  "weight": 0
              }
          ],
          "query": {
              "terms": {
                  "classification.feature": [
                      "A",
                      "B"
                  ]
              }
          },
          "score_mode": "avg"
        }
    }
  }
}

```

I also know how to create the function score for the priority field, it would be something like this:

```
{
    "function_score": {
        "functions": [
            {
                "field_value_factor": {
                    "field": "popularity",
                    "missing": 0
                },
                "weight": <some-weight>
            }
        ],
        "score_mode": "sum"
    }
}

```

I think (but not sure) I know how to create the function score for the sum of feature weights (ignoring weights for features that don't match "A" or "B"). It would probably be something like this:

```
{
  "query": {
        "function_score": {
            "query": {
                "bool": {
                    "should": [
                        { "match": { "classification.feature": "A" } },
                        { "match": { "classification.feature": "B" } }
                    ]
                }
            },
            "functions": [
              {
                  "filter": { "match": { "classification.feature": "A" } },
                  "weight": 2
              },
              {
                  "filter": { "match": { "classification.feature": "B" } },
                  "weight": 3
              },
            ],
            "score_mode":"sum"
        }
    }
}

```

But I have no idea how to combine these 3 different function score (I'm currently not sure what would be the actual combine function. I will need to play with different functions and decide which one works best for me but for the question sake we can say I would like to do average on the results of my 3 function\_score)

And so my questions are:

1. Is it possible to define multiple function\_score and then define how to combine them?
2. If it's not possible to combine multiple function\_score what approach should I take in order to solve this issue? (I'm not fixated on using 3 different function\_score but not sure how to do it otherwise)
3. Although I said I want to do average on all the function\_score results I may later want to do something a  
bit more complicated like this: `score("popularity") + (score("feature-weight") * score("confidence"))` - is  
there a way to achieve this?

I'm currently testing this on ES 2.4.5 (which I know is deprecated). We are going to upgrade pretty soon anyway but:

- Is it only possible to achieve with later ES versions?
- Even if its only possible in later ES versions I would still like to know how to accomplish it (and use it after we upgrade)

Googling this didn't result in any useful information

Thanks in advance

---

<div class="post-metadata">

**Author:** ![abdon](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/abdon/32/9195_2.png) [@abdon](https://discuss.elastic.co/u/abdon)\
**Post date:** [June 2, 2019, 8:03pm UTC](https://discuss.elastic.co/t/combining-multiple-function-scores/183857/2 "2019-06-02T20:03:14Z")

</div>

I'm not sure I understand what you're trying to do. Maybe you can explain exactly what the resulting score of for example the first document would be, and how it would be calculated, so we can help you figure out how best to do that. 🙂

---

<div class="post-metadata">

**Author:** ![gidgid](https://avatars.discourse-cdn.com/v4/letter/g/b77776/32.png) [@gidgid](https://discuss.elastic.co/u/gidgid)\
**Post date:** [June 3, 2019, 7:14am UTC](https://discuss.elastic.co/t/combining-multiple-function-scores/183857/3 "2019-06-03T07:14:24Z")

</div>

You are totally right, I completely rewrote the question to make it easier to understand (hopefully)  
Let me know if there's any information needed

---

<div class="post-metadata">

**Author:** ![abdon](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/abdon/32/9195_2.png) [@abdon](https://discuss.elastic.co/u/abdon)\
**Post date:** [June 5, 2019, 7:46am UTC](https://discuss.elastic.co/t/combining-multiple-function-scores/183857/4 "2019-06-05T07:46:15Z")

</div>

Would you be open to restructuring your documents? You're currently using nested objects. While not impossible, it's hard to flexibly combine scores from different nested objects. If you would create flat documents instead, then what you're trying to do is going to be much easier.

For example, if you indexed your documents like this:

```auto
PUT my_index/doc/1
{
  "priority": 0.7,
  "classification": [
    {
      "A": 0.4
    },
    {
      "C": 0.3
    },
    {
      "B": 0.6
    }
  ]
}

PUT my_index/doc/2
{
  "priority": 0.8,
  "classification": [
    {
      "A": 0.3
    },
    {
      "C": 0.6
    }
  ]
}

PUT my_index/doc/3
{
  "priority": 0.4,
  "classification": [
    {
      "D": 0.6
    },
    {
      "C": 0.8
    }
  ]
}

```

Then all you need is a relatively straightforward [script\_score function](https://www.elastic.co/guide/en/elasticsearch/reference/2.4/query-dsl-function-score-query.html#function-script-score) to calculate the score that you want:

```auto
GET my_index/_search
{
  "query": {
    "function_score": {
      "query": {
        "match_all": {}
      },
      "functions": [
        {
          "script_score": {
            "script": "def popularity = doc['priority'].value; def feature_weight = 0.0; feature_weight += (doc['classification.A'].size() != 0 ? 2 : 0 ); feature_weight += (doc['classification.B'].size() != 0 ? 3 : 0 ); def confidence = 0.0; if (!(doc['classification.A'].size() == 0 && doc['classification.B'].size() == 0)) { confidence = (doc['classification.A'].value + doc['classification.B'].value) / (doc['classification.A'].size() + doc['classification.B'].size())}; return popularity + (feature_weight * confidence);"
          }
        }
      ]
    }
  }
}

```

(You will need to [configure `script.inline: true`](https://www.elastic.co/guide/en/elasticsearch/reference/2.4/modules-scripting.html#enable-dynamic-scripting) in your elasticsearch.yml configuration file to run inline scripts in version 2)

---

<div class="post-metadata">

**Author:** ![system](https://us1.discourse-cdn.com/elastic/original/3X/1/a/1ac57faf039f6b580b3f104ef42a2a89e41014de.png) [@system](https://discuss.elastic.co/u/system)\
**Post date:** [July 3, 2019, 7:46am UTC](https://discuss.elastic.co/t/combining-multiple-function-scores/183857/5 "2019-07-03T07:46:18Z")

</div>

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