欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Elasticsearch(039):es中搜索之排序

程序员文章站 2022-07-05 14:26:23
...

一、概述

默认情况下,结果集会按照相关性进行排序 – 相关性越高,排名越靠前。为了使结果可以按照相关性进行排序,我们需要一个相关性的值。在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来打分,来实现相关性高的记录在前,相关性低的记录在后。而架构也远远不止按照权重划分来打分,有可能我们的搜索权重是动态的,这时知识图谱的知识就会映入我们的眼帘,感兴趣的同学可以深入的了解和学习下。