What is the difference between should and boost final score calculation? - elasticsearch

I'm a little confused about what is the difference between should and boost final score calculation
when a bool query has a must clause, the should clauses act as a boost factor, meaning none of them have to match but if they do, the relevancy score for that document will be boosted and thus appear higher in the result.
so,if we have:
one query which contains must and should clauses
vs
second query which contains must clause and boosting clause
Is there a difference ?
when you recommend to use must and should vs must and boosting clauses in a query ?

You can read the documentation of boolean query here, there is huge difference in the should and boost.
Should and must both contributes to the _score of the document, and as mentioned in the above documentation, follows the
The bool query takes a more-matches-is-better approach, so the score from each matching must or should clause will be added together to provide the final _score for each document.
While boost is a parameter, using which you can increase the weight according to your value, let me explain that using an example.
Index sample docs
POST _doc/1
{
"brand" : "samsung",
"name" : "samsung phone"
}
POST _doc/2
{
"brand" : "apple",
"name" : "apple phone"
}
Boolean Query using should without boost
{
"query": {
"bool": {
"should": [
{
"match": {
"name": {
"query": "apple"
}
}
},
{
"match": {
"brand": {
"query": "apple"
}
}
}
]
}
}
}
Search result showing score
"max_score": 1.3862942,
Now in same query use boost of factor 10
{
"query": {
"bool": {
"should": [
{
"match": {
"name": {
"query": "apple"
}
}
},
{
"match": {
"brand": {
"query": "apple",
"boost": 10 --> Note additional boost
}
}
}
]
}
}
}
Query result showing boost
"max_score": 7.624619, (Note considerable high score)
In short, when you want to boost a particular document containing your query term, you can additionally pass the boost param and it will be on top of the normal score calculated by should or must.

Related

Elasticsearch - Impact of adding Boost to query

I have a very simple Elastic query mentioned below.
{
"query": {
"bool": {
"must": [
{
"bool": {
"minimum_should_match": 1,
"should": [
{
"match": {
"tag": {
"query": "Audience: PRO Brand: Samsung",
"boost": 3,
"operator": "and"
}
}
},
{
"match": {
"tag": {
"query": "audience: PRO brand samsung",
"boost": 2,
"operator": "or"
}
}
}
]
}
}
]
}
}
}
I want to know if I add a boost in the query, will there be any performance impact because of this, and also will boosting help if you have a very large data set, where the occurrence of a search word is common.
Elasticsearch adds boost param with default value, IMO giving different value won't make much difference in the performance, but you should be able to measure it yourself.
Reg. your second question, adding boost definitely makes sense where the occurrence of your search words are common, this will help you to find the relevant document. for example: suppose you are searching for query in a index containing Elasticsearch posts(query will be very common on Elasticsearch posts), but you want the give more weight to documents which have tag elasticsearch-query. Adding boosts in this case, will provide you more relevant results.

Elasticsearch Boolean query with Constant score wrapper

When using elasticsearch-7 I'm confused by es compound queries syntax.
Though reading es documents repeatedly but i just find standard syntax of Boolean or Constant score seperately.
As it illuminate,i understand what is 'query context' and what is 'filter context'.But when combining these two query type in a single query i don't know what it mean.
Let's see a example:
GET /classes_test/_search
{
"size": "21",
"query": {
"constant_score": {
"filter": {
"bool": {
"must": [
{
"match": {
"class_name": "29386556"
}
}
],
"should": [
{
"term": {
"master": "7033560"
}
},
{
"term": {
"assistant": "7033560"
}
},
{
"term": {
"students": "7033560"
}
}
],
"minimum_should_match": 1,
"must_not": [
{
"term": {
"class_id": 0
}
}
],
"filter": [
{
"term": {
"class_status": "1"
}
}
]
}
}
}
}
}
This query can be executed and response well.Each item in response content has a '_score' value with 1.0.
So,is it mean that the sub bool query as a entirety is in a filter context though it has a 'must' and 'should'?
Also i found boolean query can have a constant score sub query.
Why es allow these syntax but has no more words to explain?
If you use a constant_score query, you'll never get scores different than 1.0, unless you specify boost parameters in which case the score will match those.
If you need scoring you obviously need to ditch constant_score.
In your case, your match query on class_name cannot yield any other score than 1 or 0 since this is basically a yes/no filter, not a matching based on full-text search.
To sum up, all your query executes in a filter context (hence score 0 or 1) since you don't rely on full-text search. So you get scoring whenever you use full-text search, not because you use a match query. In your case, you can merge all must constraints into filter, it won't make any difference since you only have filters (yes/no matches) and no full-text search.

Elasticsearch how to replace "terms" query?

Using Elasticsearch before version 6 the following query returned hits based on similarity to the query. Now in ES 6+ this returns hit based on whether they match any part of the query, all with the same score. This change breaks the rest of the more complicated query (not shown).
How can I get hit scores that match the older ES 5- for the following query
{
"query": {
"bool": {
"should": [
{
"terms": {
"some_field_name": [
"iPad Pro",
"iPhone 8"
]
}
}
]
}
}
}
In ES 5 this returns hits scored higher for matching all terms and lower for matching less. In ES 6+ this returns hits with only scores = 1 and so they are ranked with no regards to how many matched terms there were.
For instance a hit that has both terms is ranked higher in ES 5:
"_score": 0.87546873, when 2 of 4 terms match
"_score": 0.60353506, when 2 of 5 terms match
"_score": 0.13353139, when 1 of 4 terms match
This is much like the desired "cosine" similarity that we need (understood that this is not precisely how scores are created).
What query will return the same scores as ES 5 does for above query. In other words, what is the ES 6 equivalent query?
Note: Just posting it as a draft suggestion since discussion in comments is getting longer and clumsy.
UPDATE: Just checked both the methods I suggested and both seem to give similar scoring. Please try these methods and see if the scores you get are of any relevance to you.
I get that it doesn't work for terms but I suggested to replace it with either multiple "term" filter which also has a boost parameter or else replace it with "term_set" query and set required_matches param to "1" since we want the "or" behaviour.
1) Using terms_set query:
{
"query": {
"bool": {
"should": [
{
"terms_set": {
"some_field_name": {
"terms" : ["iPad Pro", "iPhone 8"],
"minimum_should_match_script": {
"source": "1"
}
}
}
}
]
}
}
}
2) Using multiple term filters instead of single terms filter:
{
"query": {
"bool": {
"should": [
{
"term": {
"some_field_name": "iPad Pro"
}
},
{
"term": {
"some_field_name": "iPhone 8"
}
}
]
}
}
}
If you were using boost in terms, then you should apply same boost in each of term blocks.

How to boost individual documents

I have a pretty complex query and now I want to boost some documents that fulfill some criteria. I have the following simplified document structure and I try to give some documents a boost based on the id, genre, tag.
{
"id": 123,
"genres": ["ACTION", "DRAMA"],
"tags": ["For kids", "Romantic", "Nature"]
}
What I want to do is for example
id: 123 boost: 5
genres: ACTION boost: 3
tags: Romantic boost: 0.2
and boost all documents that are contained in my query and fit the criteria but I don't want to filter them out. So query clause boosting is not of any help I guess.
Edit: To make if easier to understand what I want to achieve (not sure if it is possible with elasticsearch, no is also a valid answer).
I want to search with a query and get a result set. In this set I want to boost some documents. But I don't want to enlarge the result set or filter it. The boost should be independent from the query.
For example I search for a specific tag and want to boost all documents with category 'ACTION' in the result set. But I don't want all documents with category 'ACTION' in the result set and also I don't want only documents with the specific tag AND category 'ACTION'.
I think you need to have Dynamic boosting during query time.
The first matches the id title with boost and second one matches the 'genders' ACTION.
{
"query": {
"bool": {
"should": [
{
"match": {
"title": {
"query": "id",
"boost": 5
}
}
},
{
"match": {
"content": "Action"
}
}
]
}
}
}
If you want to have multi_match match based on your query:
{
"multi_match" : {
"query": "some query terms here",
"fields": [ "id^5", "genders^3", "tags^0.2" ]
}
}
Note: the ^5 means boost for the title.
Edit:
Maybe you are asking for different types of multi_match queries (at least for ES 5.x) from the ES reference guide:
best_fields
(default) Finds documents which match any field, but uses
the _score from the best field. See best_fields.
most_fields
Finds documents which match any field and combines the _score from
each field. See most_fields.
cross_fields
Treats fields with the same analyzer as though they were one big
field. Looks for each word in any field. See cross_fields.
phrase
Runs a match_phrase query on each field and combines the _score from
each field. See phrase and phrase_prefix.
phrase_prefix
Runs a match_phrase_prefix query on each field and combines the _score
from each field. See phrase and phrase_prefix.
More at: ES 5.4 ElasticSearch reference
I found a solution and it was pretty simple. I use a boosting query. I now just nest the different boosting criteria with and my original query is now the base query.
https://www.elastic.co/guide/en/elasticsearch/reference/2.3/query-dsl-boosting-query.html
For example:
{
"query": {
"boosting": {
"positive": {
"boosting": {
"positive": {
"match": {
"director": "Spielberg"
}
},
"negative": {
"term": {
"genres": "DRAMA"
}
},
"negative_boost": 1.3
}
},
"negative": {
"term": {
"tags": "Romantic"
}
},
"negative_boost": 1.2
}
}
}

Function_score using score_mode inside a bool query as max but working like sum?

I am using function_score so that i can use its score_mode as maximum score of the bool query i am using actually i have two boolean query inside should now i want the score of the document to be the maximum score among both queries my code is given below but when i am passing a string for matching both then scores are being added not be taken maximum can anyone please tell me how can i acheive that.
"function_score": {
"boost_mode": "max",
"score_mode": "max",
"query": {
bool: {
"disable_coord": true,
"should": [
{
bool: {
"disable_coord": true,
"must": [
{
"constant_score": { // here i am using this because to remove tf/idf factors from my scoring
boost: 1.04,
"query": {
query_string: {
query: location_search,
fields: ['places_city.city'],
// boost: 1.04
}
}
}
}
]
}
},
{
"constant_score": { // here i am using this because to remove tf/idf factors from my scoring
boost: 1,
"query": {
"fuzzy_like_this" : {
"fields" : ["places_city.city"],
"like_text" : "bangaloremn",
"prefix_length": 3,
"fuzziness": 2
}
}
}
}
], "minimum_should_match": 1
}
}
}
Yes boolean query takes a sum by design. If you want the maximum score of two queries, you ought to look at the dismax query. Dismax is designed to pick a "winner".
Roughly speaking, this would look like
{"query":
"dismax": {
"queries": [
{ /* your first constant_score query above */},
{/* your second constant_score query from above */}
]
}
}
Unfortunately, function score query doesn't have a great way of operating on more than one text query at a time. See this question. If you want to do any complex math with the scores of multiple queries, Solr actually has a lot more flexibility in this area.

Resources