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