Skip to content

Instantly share code, notes, and snippets.

@darklow
Last active May 31, 2022 05:25
Show Gist options
  • Select an option

  • Save darklow/7132077 to your computer and use it in GitHub Desktop.

Select an option

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

vi-hipvan commented Oct 31, 2016

Copy link
Copy Markdown
{
  "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
Copy Markdown

@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
Copy Markdown

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

darklow commented Nov 5, 2017

Copy link
Copy Markdown
Author

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
Copy Markdown

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
Copy Markdown

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
Copy Markdown
"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