一、概述

默认情况下,结果集会按照相关性进行排序 – 相关性越高,排名越靠前。为了使结果可以按照相关性进行排序,我们需要一个相关性的值。在ElasticSearch的查询结果中, 相关性分值会用_score字段来给出一个浮点型的数值,所以默认情况下,结果集以_score进行倒序排列.

二、Es中排序使用

2.1 简单排序

例如下面的按照创建时间的倒序排序。

GET example/docs/_search
{
  "query": {
    "match_all": {}
  },
  "sort": [
    {
      "createTime": {
        "order": "desc"
      }
    }
  ]
}

#按照创建时间降序 -> 简化成
GET example/docs/_search
{
  "query": {
    "match_all": {}
  },
  "sort": [
    {
      "createTime": "desc"
    }
  ]
}

#按照创建时间升序
GET example/docs/_search
{
  "query": {
    "match_all": {}
  },
  "sort": [
    {
      "createTime": "asc"
    }
  ]
}

#按照创建时间升序 -> 简化成
GET example/docs/_search
{
  "query": {
    "match_all": {}
  },
  "sort": [
    "createTime"
  ]
}

order选项可以具有以下值:

asc: 升序排列

desc: 降序排列

在_score上排序时,该顺序默认为desc;在其他任何内容上排序时,该顺序默认为asc.

2.2 排序模式选项

Elasticsearch支持按数组或多值字段排序。模式选项控制选择哪个数组值对它所属的文档进行排序。模式选项可以具有以下值:

min: 选择最低值

max: 选择最高值

sum: 使用所有值的总和作为排序值。仅适用于基于数字的数组字段

avg: 使用所有值的平均值作为排序值。仅适用于基于数字的数组字段

median: 使用所有值的中位数作为排序值。仅适用于基于数字的数组字段

示例使用

PUT example/docs/1?refresh
{
    "product": "chocolate",
    "price": [20, 10, 7]
}

#查询示例
GET example/docs/_search
{
    "query": {
        "match_all": {}
    },
    "sort": [
        {
            "price": {
                "order": "asc",
                "mode": "avg"
            }
        }
    ]
}

2.3 嵌套对象中排序

Elasticsearch还支持按一个或多个嵌套对象内部的字段排序。“按嵌套字段排序”支持具有以下属性的嵌套排序选项:

  • path

定义要在哪个嵌套对象上排序。实际的排序字段必须是此嵌套对象内的直接字段。当按嵌套字段排序时,此字段是必填字段

  • filter

嵌套路径内的内部对象应与其匹配的过滤器,以便通过排序将其字段值考虑在内。常见的情况是在嵌套的过滤器或查询中重复查询/过滤器。默认情况下,没有nested_filter处于活动状态

  • nested

与顶级嵌套相同,但适用于当前嵌套对象内的另一个嵌套路径

注意:在Elasticsearch 6.1版本之前。不推荐使用nested_path和nested_filter选项,而推荐使用上面的选项

GET example/docs/_search
{
    "query": {
        "match_all": {}
    },
    "sort": [
        {
            "items.goodPrice": {
                "order": "asc",
                "mode": "max",
                "nested": {
                    "path": "items"
                }
            }
        }
    ]
}

上面的例子中,items是一个嵌套类型的字段。需要指定嵌套路径;否则,Elasticsearch不知道需要捕获哪些嵌套级别的排序值。

下面是多级嵌套的例子。代码仅做参考:

POST example/docs/_search
{
   "query": {
      "nested": {
         "path": "parent",
         "query": {
            "bool": {
                "must": {"range": {"parent.age": {"gte": 21}}},
                "filter": {
                    "nested": {
                        "path": "parent.child",
                        "query": {"match": {"parent.child.name": "matt"}}
                    }
                }
            }
         }
      }
   },
   "sort" : [
      {
         "parent.child.age" : {
            "mode" :  "min",
            "order" : "asc",
            "nested": {
               "path": "parent",
               "filter": {
                  "range": {"parent.age": {"gte": 21}}
               },
               "nested": {
                  "path": "parent.child",
                  "filter": {
                     "match": {"parent.child.name": "matt"}
                  }
               }
            }
         }
      }
   ]
}

嵌套排序支持按脚本排序和按地理位置距离排序。

此外还有地理距离排序、脚本字段排序这种比较高级的方式。感兴趣的同学可以自己研究下。

脚本排序的示例如下

POST example/docs/_search
{
    "query" : {
        "match_all" : {}
    },
    "sort" : {
        "_script" : {
            "type" : "number",
            "script" : {
                "lang": "painless",
                "source": "doc[orderAmount].value * params.factor",
                "params" : {
                    "factor" : 1.1
                }
            },
            "order" : "desc"
        }
    }
}

注意

排序时,Elasticsearch会将相关的排序字段值加载到内存中。这意味着每个分片应该有足够的内存来容纳它们。对于字符串的类型,不应是分词或标记的的字段。对于数字类型,如果可能,建议将类型显式设置为较窄的类型(如short,integer和float)

在实际开发中,真正使用ElasticSearch来搜索时,通常还是使用score来打分,来实现相关性高的记录在前,相关性低的记录在后。而架构也远远不止按照权重划分来打分,有可能我们的搜索权重是动态的,这时知识图谱的知识就会映入我们的眼帘,感兴趣的同学可以深入的了解和学习下。

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐