简体   繁体   中英

How to boost certain documents if the search query contains a certain term/text in elastic

If the search query contains fruits I want to boost the products from a certain category?

{
  "query": {
    "bool": {
      "should": [
        { 
          "constant_score": {
            "boost":   2,
            "filter": { 
              "term": { "categories": "3" }
            }
          }
        }
      ]
    }
  }
}

I have the above query, which gives a constant score to items with the category 3 , I want to apply this constant score/boosting/increase relevancy only when a certain text (for example fruits ) is present in the search term.

Sample elasticsearch document

{
   "id" : 1231,
   "name" : {
       "ar" : "Arabic fruit name",
       "en" : "english fruit name"
   }
   "categories" : [3,1,3] // category ids because the same product is shown in multiple categories
}

How do I achieve this? I use elasticsearch 7.2

Original answer:

{
  "query": {
    "bool": {
      "should": [
        {
          "constant_score": {
            "boost": 2,
            "filter": {
              "bool": {
                "filter": [
                  {
                    "term": {
                      "categories": "3"
                    }
                  }
                ],
                "should": [
                  {
                    "match": {
                      "name.ar": "fruit"
                    }
                  },
                  {
                    "match": {
                      "name.en": "fruit"
                    }
                  }
                ],
                "minimum_should_match": 1
              }
            }
          }
        }
      ]
    }
  }
}

If i understand correctly what you're looking for. Btw, I suggest using "match_phrase" instead of "match" if you want to match "fruit name" exactly and not "fruit" or "name"

Update: (based on the comment) In that case i'd suggest reorganizing your schema in the following manner:

"item": {
  "properties": {
    "name": {
      "type": ["string"]
    },
    "language": {
      "type": ["string"]
    }
  }
}

So your sample would become:

{
   "id" : 1231,
   "item" : [
      {"name": "Arabic fruit name", "language": "ar"}
      {"name": "english fruit name", "language": "en"}
   ],
   "categories" : [3,1,3]
}

And then you can match against "item.name"

Why? Because the way ElasticSearch indexes (at least, by default) is to flatten your the array, so internally it looks like ["Arabic fruit name", "english fruit name"]

With your original sample, two different fields are created in the schema (name.ar and name.en), which is actually not a great design if you need to scale

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM