Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Boost if result begin with the word

I use Elasticsearch to search with autocompletion with an ngram filter. I need to boost a result if it starts with the search keyword.

My query is simple :

"query": {
   "match": {
      "query": "re",
      "operator": "and"
   }
}

And this is my results :

  • Restaurants
  • Couture et retouches
  • Restauration rapide

But I want them like this :

  • Restaurants
  • Restauration rapide
  • Couture et retouches

How can I boost a result starting with the keyword?

In case it can helps, here is my mapping :

{
    "settings": {
        "analysis": {
            "analyzer": {
                "partialAnalyzer": {
                    "type": "custom",
                    "tokenizer": "ngram_tokenizer",
                    "filter": ["asciifolding", "lowercase"]
                },
                "searchAnalyzer": {
                    "type": "custom",
                    "tokenizer": "standard",
                    "filter": ["asciifolding", "lowercase"]
                }
            },

            "tokenizer": {
                "ngram_tokenizer": {
                    "type": "edge_ngram",
                    "min_gram": "1",
                    "max_gram": "15",
                    "token_chars": [ "letter", "digit" ]
                }
            }
        }
    },

    "mappings": {
        "place": {
            "properties": {
                "name": {
                    "type": "string",
                    "index_analyzer": "partialAnalyzer",
                    "search_analyzer": "searchAnalyzer",
                    "term_vector": "with_positions_offsets"
                }
            }
        }
    }
}

Regards,

like image 523
Raphaël Malié Avatar asked Mar 14 '23 04:03

Raphaël Malié


1 Answers

How about this idea, not 100% sure of it as it depends on the data I think:

  • create a sub-field in your name field that should be analyzed with keyword analyzer (pretty much staying as is)
  • change the query to be a bool with shoulds
  • one should is the query you have now
  • the other should is a match with phrase_prefix on the sub-field.

The mapping:

{
  "settings": {
    "analysis": {
      "analyzer": {
        "partialAnalyzer": {
          "type": "custom",
          "tokenizer": "ngram_tokenizer",
          "filter": [
            "asciifolding",
            "lowercase"
          ]
        },
        "searchAnalyzer": {
          "type": "custom",
          "tokenizer": "standard",
          "filter": [
            "asciifolding",
            "lowercase"
          ]
        },
        "keyword_lowercase": {
          "type": "custom",
          "tokenizer": "keyword",
          "filter": [
            "asciifolding",
            "lowercase"
          ]
        }
      },
      "tokenizer": {
        "ngram_tokenizer": {
          "type": "edge_ngram",
          "min_gram": "1",
          "max_gram": "15",
          "token_chars": [
            "letter",
            "digit"
          ]
        }
      }
    }
  },
  "mappings": {
    "place": {
      "properties": {
        "name": {
          "type": "string",
          "index_analyzer": "partialAnalyzer",
          "search_analyzer": "searchAnalyzer",
          "term_vector": "with_positions_offsets",
          "fields": {
            "as_is": {
              "type": "string",
              "analyzer": "keyword_lowercase"
            }
          }
        }
      }
    }
  }
}

The query:

{
  "query": {
    "bool": {
      "should": [
        {
          "match": {
            "name": {
              "query": "re",
              "operator": "and"
            }
          }
        },
        {
          "match": {
            "name.as_is": {
              "query": "re",
              "type": "phrase_prefix"
            }
          }
        }
      ]
    }
  }
}
like image 129
Andrei Stefan Avatar answered Mar 23 '23 12:03

Andrei Stefan