HasseWilson
HasseWilson

Reputation: 169

Elasticsearch - give negative boost to documents without a certain field

I'm working on a query, the basic filtered multi match query is working as planned, it returns the documents i want.

The issue is that a want to boost results which have a certain string field with ex. 0.5, or in this example give results which don't have this field 'traded_as' a negative boost of 1.0.

Cannot get the filter - boost - must - exists/missing to work as i want.

It this the correct approach on this issue?

Using elasticsearch 1.5.2

{
"query": {
    "filtered": {
        "query": {
           "multi_match": {
               "query": "something",
               "fields": ["title", "url", "description"]
           }
        },
        "filter": {
           "bool": {
                "must": {
                    "missing": {
                        "field": "marked_for_deletion"
                    }
                }
            }
        }
    }
},
"boosting": {
    "positive": {
        "filter": {
            "bool": {
                "must": {
                    "exists": {
                        "field": "traded_as"                            
                    }
                }
            }
        }
    },
    "negative": {
        "filter": {
           "bool": {
                "must": {
                    "missing": {
                        "field": "traded_as"
                    }
                }
            }
        }
    },
    "negative_boost": 1.0
}
}

Upvotes: 7

Views: 8957

Answers (1)

Julien C.
Julien C.

Reputation: 966

You cannot have the desired result. As stated in the doc for boosting query :

Unlike the "NOT" clause in bool query, this still selects documents that contain undesirable terms, but reduces their overall score.

{
  "query": {
    "boosting": {
      "positive": [{
        "filtered": {
          "query": {
            "multi_match": {
              "query": "something",
              "fields": ["title", "url", "description"]
            }
          },
          "filter": {
            "bool": {
              "must": [{
                "missing": {
                  "field": "marked_for_deletion"
                }
              }]
            }
          }
        }
      }],
      "negative": [{
        "filtered": {
          "filter": {
            "missing": {
              "field": "traded_as"
            }
          }
        }
      }],
      "negative_boost": 1.0
    }
  }
}

So you'll still have some irrelevant documents, but matching documents will have a better score. You won't have any boost on traded_as presence that way. For this you should have a look at function score http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-function-score-query.html#_using_function_score

You would have something like

{
  "query": {
    "function_score": {
      "query": {
        "filtered": {
          "query": {
            "multi_match": {
              "query": "something",
              "fields": ["title", "url", "description"]
            }
          },
          "filter": {
            "bool": {
              "must": {
                "missing": {
                  "field": "marked_for_deletion"
                }
              }
            }
          }
        }
      },
      "functions": [{
        "filter": {
          "exists": {
            "field": "traded_as"
          }
        },
        "boost_factor": 2
      }, {
        "filter": {
          "missing": {
            "field": "traded_as"
          }
        },
        "boost_factor": 0.5
      }],
      "score_mode": "first",
      "boost_mode": "multiply"
    }
  }
}

Upvotes: 2

Related Questions