2
votes

I have different types indexed in elastic search. but, if I want to boost my results on some selected types then what should I do? I could use type filter in boosting query, but type filter allows me only one type to be used in filter. I need results to be boosted on the basis of multiple types.

Example: I have Person, Event, Location data indexed in elastic search where Person, Location and Event are my types.

I am searching for keyword 'London' in all types but i want Person and Event type records to be boosted than Location.

How could I achieve the same?

2

2 Answers

2
votes

One of the ways of getting the desired functionality is by wrapping your query inside a bool query and then make use of the should clause, in order to boost certain documents

Small example:

POST test/person
{
  "title": "london elise moore"
}

POST test/event
{
  "title" : "london is a great city"
}

Without boost:

GET test/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "title": "london"
          }
        }
      ]
    }
  }
}

With the following response:

"hits": {
    "total": 2,
    "max_score": 0.2972674,
    "hits": [
      {
        "_index": "test",
        "_type": "person",
        "_id": "AVVx621GYvUb9aQn6r5X",
        "_score": 0.2972674,
        "_source": {
          "title": "london elise moore"
        }
      },
      {
        "_index": "test",
        "_type": "event",
        "_id": "AVVx63LrYvUb9aQn6r5Y",
        "_score": 0.26010898,
        "_source": {
          "title": "london is a great city"
        }
      }
    ]
  }

And now with the added should clause:

GET test/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "title": "london"
          }
        }
      ],
      "should": [
        {
          "term": {
            "_type": {
              "value": "event",
              "boost": 2
            }
          }
        }
      ]
    }
  }
}

Which gives back the following response:

"hits": {
    "total": 2,
    "max_score": 1.0326607,
    "hits": [
      {
        "_index": "test",
        "_type": "event",
        "_id": "AVVx63LrYvUb9aQn6r5Y",
        "_score": 1.0326607,
        "_source": {
          "title": "london is a great city"
        }
      },
      {
        "_index": "test",
        "_type": "person",
        "_id": "AVVx621GYvUb9aQn6r5X",
        "_score": 0.04235228,
        "_source": {
          "title": "london elise moore"
        }
      }
    ]
  }

You could even leave out the extra boost in the should clause, cause if the should clause matches it will boost the result :)

Hope this helps!

0
votes

I see two ways of doing that using that but both is using scripts 1. using sorting

POST c1_1/_search
{
  "from": 0,
  "size": 10,
  "sort": [
    {
      "_script": {
        "order": "desc",
        "type": "number",
        "script": "double boost = 1; if(doc['_type'].value == 'Person') { boost *= 2 }; if(doc['_type'].value == 'Event') { boost *= 3}; return _score * boost; ",
        "params": {}
      }
    },
    {
      "_score": {}
    }
  ],
  "query": {
    "bool": {
      "should": [
        {
          "query_string": {
            "query": "*",
            "default_operator": "and"
          }
        }
      ],
      "minimum_should_match": "1"
    }
  }
}

Second option Using function score.

POST c1_1/_search
{
  "from": 0,
  "size": 10,
  "query": {
    "function_score": {
      "query": {
        "bool": {
          "should": [
            {
              "query_string": {
                "query": "*",
                "default_operator": "and"
              }
            }
          ],
          "minimum_should_match": "1"
        }
      },
      "script_score": {
        "script": "_score * (doc['_type'].value == 'Person' || doc['_type'].value == 'Event'? 2 : 1)"
      }
    }
  }
}