Skip to content

Instantly share code, notes, and snippets.

@darklow
Last active May 31, 2022 05:25
Show Gist options
  • Star 19 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save darklow/7132077 to your computer and use it in GitHub Desktop.
Save darklow/7132077 to your computer and use it in GitHub Desktop.
ElasticSearch custom sort, based on provided ids array order. Original code from here: http://damienalexandre.fr/post/elasticsearch-ids-query-order Rewritten to new "function_score" syntax Note: You need to remove \n new lines from "script" field in order to get it work.
q = {
"query": {
"function_score": {
"boost_mode": "replace",
"query": {
"ids": {
"values": [
50,
80,
44,
12
]
}
},
"script_score": {
"params": {
"ids": [
50,
80,
44,
12
]
},
"script": """
count = ids.size();
id = org.elasticsearch.index.mapper.Uid.idFromUid(doc['_uid'].value);
for (i = 0; i < count; i++) {
if (id == ids[i]) { return count - i; }
}""",
}
}
},
"size": 20,
"from": 0
}
@vi-hipvan
Copy link

vi-hipvan commented Oct 31, 2016

{
  "query": {
    "function_score": {
      "boost_mode": "replace",
      "query": {
        "ids": {
          "values":  [50, 80, 44, 12]
        }
      },
      "functions": [
         {  
          "filter": {
            "term": { "id": 50 }
          },
          "weight" : 4
     },
     {  
          "filter": {
            "term": { "id": 80 }
          },
          "weight" : 3
     },
     {  
          "filter": {
            "term": { "id": 44 }
          },
          "weight" : 1
     },
     {  
          "filter": {
            "term": { "id": 12 }
          },
          "weight" : 0
     }
       ]
    }
  },
  "_source": ["id"],
  "size": 20,
  "from": 0
}

@santhoshdevadiga
Copy link

@vi-hipvan
I used API which you told to get the results. It worked for the small set of numbers(till 100k) but if the array size is more than 500k then function block in API will increase and my ES server is going down.

I have following queries
Do we have any other way to solve this problem?
Can we use the script in ES API to solve this problem? if yes how to do that?

Please help me to solve this problem

Thanks in advance.

@sravanthi17
Copy link

I have the similar problem, where I want to boost certain set of documents providing an array of id's. Is there a solution using functional score as asked above ?

@darklow
Copy link
Author

darklow commented Nov 5, 2017

Not 1:1 example, but you adjust to IDS as well, this is how I boosted certain items on top of others, while maintaining default sort as well (for ES 5.4+):

{
   "query": {
      "function_score": {
         "query": {
           "match_all": {}
         },
         "boost_mode": "replace",
         "script_score": {
            "script": {
               "params": {
                  "important_tags": ["tag1", "tag2, "tag3"]
               },
               "source": "params.important_tags.indexOf(doc['tag'].value) > -1 ? 10 : 0"
            }
         }
      }
   },
   "sort" : [
       "_score",
        { "defaultOrderField" : "desc" }
    ]
}

@nelsoneldoro
Copy link

According with Elasticsearch Reference [6.6]

{
   "query":{
      "function_score":{
         "boost_mode":"replace",
         "query":{
            "bool":{
               "filter":{
                  "ids":{
                     "values":[
                        50,
                        80,
                        44,
                        12
                     ]
                  }
               }
            }
         },
         "script_score":{
            "script":{
               "params":{
                  "ids":[
                     50,
                     80,
                     44,
                     12
                  ]
               },
               "source":"params.ids.length - params.ids.indexOf(doc['_id'].value)"
            }
         }
      }
   },
   "size":20,
   "from":0
}

@sonureddoorz
Copy link

I am achieving my result using script but I want alternate solution for this. Please help....
I have the similar problem, but I want to boost certain set of documents using functional score :

My current code

{
.
.
.
"sort": [
    {
      "_script": {
        "type": "number",
        "script": {
          "lang": "painless",
          "source": "double pscore = 0;for(id in params.boost_ids){if(params._source.midoffice_master_id == id){pscore = -999999999;}}return pscore;",
          "params": {
            "boost_ids": [
              90,
              687,
              333,
              756
            ]
          }
        }
      }
    },
    {
      "_geo_distance": {
        "location": {
          "lat": -8.4095178,
          "lon": 115.188916
        },
        "order": "asc"
      }
    }
  ]
.
.
.
.
.
}

@terrynguyen255
Copy link

"script_score": {
  "params": {
    "ids": [
        50,
        80,
        44,
        12
    ]
  },
  "script": """
    count = ids.size();
    id    = org.elasticsearch.index.mapper.Uid.idFromUid(doc['_uid'].value);
    for (i = 0; i < count; i++) {
      if (id == ids[i]) { return count - i; }
     }""",
}

This doesn't work in my case.

I update it to:

sort: {
  _script: {
    type: 'number',
    script: {
      lang: 'painless',
      params: {
        ids: [4,8,2,4,8,16],
      },
      source: `
        int idsCount = params.ids.size();
        def id = doc['slug.keyword'].value;
        int foundIdx = params.ids.indexOf(id);
        return foundIdx > -1 ? foundIdx: idsCount + 1;
      `
    }
  }
}

hope it helps someone

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment