这个想法是,给定排序列表[3, 1, 2],您应该为 3 返回较小的分数,为 1 返回较大的分数,最后为 2 返回最大的分数。您可以考虑的最简单的函数是从数组元素到其索引的函数.例如,对于 3,您应该返回 0,对于 1 1 和对于 2 2。
具体来说,您需要一个可能如下所示的函数:
def myList = [3, 1, 2];
// Declares a map literal
Map m= [:];
// Generate from [3, 1, 2] the mapping { 3 = 0.0, 1 = 1.0, 2 = 2.0 }
def i = 0;
for (x in myList) {
m[x] = (double)i++;
}
// Extract the xId from the document
def xId = (int)doc['xId'].value;
// Return the mapped value, e.g., for 3 return 0
return m[xId];
显然,您可以通过将地图作为参数直接传递给脚本here 来提高性能。
在这种情况下,脚本简化为:
def xId = doc['xId'].value.toString();
return params.m[xId];
完整示例
索引数据
POST _bulk
{"index": { "_index": "test", "_id": 1}}
{"xId": 1}
{"index": { "_index": "test", "_id": 2}}
{"xId": 2}
{"index": { "_index": "test", "_id": 3}}
{"xId": 3}
{"index": { "_index": "test", "_id": 4}}
{"another_field": "hello"}
使用列表方法的完整示例:
GET test/_search
{
"query": {
"terms": {
"xId": [3, 1, 2]
}
},
"sort": {
"_script": {
"type": "number",
"script": {
"lang": "painless",
"params": {
"list": [3, 1, 2]
},
"source": """
Map m= [:];
def i = 0;
for (x in params.list) {
m[x] = (double)i++;
}
def xId = (int)doc['xId'].value;
m[xId];
"""
},
"order": "asc"
}
}
}
地图方法的完整示例
GET test/_search
{
"sort": {
"_script": {
"type": "number",
"script": {
"lang": "painless",
"params": {
"list": [3, 1, 2],
"map": {
"3": 0.0,
"1": 1.0,
"2": 2.0
}
},
"source": """
def xId = doc['xId'].value.toString();
params.map[xId];
"""
},
"order": "asc"
}
},
"query": {
"terms": {
"xId": [3, 1, 2]
}
}
}
最后说明
- 脚本被简化,因为有一个术语查询保证只考虑具有 id 并且存在于地图中的文档。如果不是这种情况,则应处理缺少 xId 和 map 中缺少 key 的情况。
- 您应该小心使用类型。实际上,当您从存储的文档中检索字段时,会使用索引类型检索它,例如,xId 存储为 long 并检索为 long。在第二个示例中,映射是从字符串到双精度的,因此 xId 在用作映射中的键之前会转换为字符串。