Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Elasticsearch layered ordering

I would like to be able to return typeahead items in a certain order. For example, search for Para should return:

 Paracetamol

 Parafin

 LIQUID PARAFFIN

 ISOMETHEPTENE WITH PARACETAMOL

1) The suggestions that begin with the search term para should be ordered at the top and in alphabetical order

2) The rest of the items should appear below and also in alphabetical order

Is this possible with Elasticsearch?

Update

What if I wanted the output to be like this:

 Paracetamol

 Parafin

 Amber Paraffin

 ISOMETHEPTENE WITH PARACETAMOL

 LIQUID PARAFFIN

So all the terms that contain the prefix are at the top and everything else in alphabetical order.

like image 390
Imran Azad Avatar asked Feb 17 '26 20:02

Imran Azad


1 Answers

This is my suggestion (also, you need to enable scripting):

PUT /test
{
  "settings": {
    "analysis": {
      "analyzer": {
        "autocomplete": {
          "type": "custom",
          "tokenizer": "standard",
          "filter": [
            "standard",
            "lowercase",
            "ngram"
          ]
        },
        "search_ngram": {
          "type": "custom",
          "tokenizer": "keyword",
          "filter": "lowercase"
        }
      },
      "filter": {
        "ngram": {
          "type": "ngram",
          "min_gram": 2,
          "max_gram": 15
        }
      }
    }
  },
  "mappings": {
    "test": {
      "properties": {
        "text": {
          "type": "string",
          "index_analyzer": "autocomplete",
          "search_analyzer": "search_ngram",
          "index_options": "positions",
          "fields": {
            "not_analyzed_sorting": {
              "type": "string",
              "index": "not_analyzed"
            }
          }
        }
      }
    }
  }
}

POST test/test/_bulk
{"index":{"_id":1}}
{"text":"Paracetamol"}
{"index":{"_id":2}}
{"text":"Paracetamol xxx yyy zzz"}
{"index":{"_id":3}}
{"text":"Parafin"}
{"index":{"_id":4}}
{"text":"LIQUID PARAFFIN"}
{"index":{"_id":5}}
{"text":"ISOMETHEPTENE WITH PARACETAMOL"}

GET /test/test/_search
{
  "query": {
    "match": {
      "text": "Para"
    }
  },
  "sort": [
    {
      "_script": {
        "type": "number",
        "script": "termInfo=_index[field_to_search].get(term_to_search.toLowerCase(),_POSITIONS);if (termInfo) {for(pos in termInfo){return pos.position}};return 0;",
        "params": {
          "term_to_search": "Para",
          "field_to_search": "text"
        },
        "order": "asc"
      }
    },
    {
      "text.not_analyzed_sorting": {
        "order": "asc"
      }
    }
  ]
}

UPDATE

For your updated question, even if I would have preferred to have another post, use the following query:

{
  "query": {
    "match": {
      "text": "Para"
    }
  },
  "sort": [
    {
      "_script": {
        "type": "number",
        "script": "termInfo=_index[field_to_search].get(term_to_search.toLowerCase(),_POSITIONS);if (termInfo) {for(pos in termInfo){if (pos.position==0) return pos.position; else return java.lang.Integer.MAX_VALUE}};return java.lang.Integer.MAX_VALUE;",
        "params": {
          "term_to_search": "Para",
          "field_to_search": "text"
        },
        "order": "asc"
      }
    },
    {
      "text.not_analyzed_sorting": {
        "order": "asc"
      }
    }
  ]
}
like image 87
Andrei Stefan Avatar answered Feb 21 '26 15:02

Andrei Stefan