相关性排序
默认情况下,结果集会按照相关性进行排序,相关性越高,排名越靠前。在Elasticsearch中相关性分值会用_score字段来给出一个浮点型的数值,所以默认情况下,结果集是以_score倒序排序的。
但是,有时候返回的_score是没有意义的,比如下面这个
{
"query": {
"bool": {
"filter": {
"term": {
"orgcode": "0120800214"
}
}
}
}
}
过滤语句与_score没有关系,但是有隐含的查询条件match_all给所有的文档的_score设置了一个确定值,也就相当于每一个文档的相关性评分是相同的。
字段值排序
下面例子中,对结果集按照时间排序,这也是最常见的场景,将最新的文档靠前,我们使用sort参数排序。
{
"query": {
"bool": {
"filter": {
"term": {
"orgcode": "0120800214"
}
}
}
},
"sort": {
"zcsj": {
"order": "desc"
}
}
}
你会发现这里有这两个不同点:
- 一、_score字段没有经过计算,因为它没有用作排序。
- 二、zcsj字段被转为毫秒来当作排序依据了
首先,在每一个结果中增加了一个sort字段,它所包含的值是用来排序的。在这个例子当中zcsj字段在内部被转成了毫秒数,即长整型数字1487088000000等同于日期字符串
2017-02-14T16:00:00.000Z。
其次就是_score和max_score都是null,计算_score是非常消耗性能的,而且通常主要用作排序–我们不是用相关性用作排序的时候,就不需要计算其相关性,如果想强制计算其相关性,可以设置track_scores为true,如下所示。
{
"query": {
"bool": {
"filter": {
"term": {
"orgcode": "0120800214"
}
}
}
},
"track_scores": "true",
"sort": {
"zcsj": {
"order": "desc"
}
}
}
默认排序
作为缩写,我们只需要指定排序的字段名称即可:
{
"query": {
"bool": {
"filter": {
"term": {
"orgcode": "0120800214"
}
}
}
},
"sort": "zcsj"
}
字段值默认以升序排序,_score默认以降序排序。
多级排序
如果我们想合并一个查询语句,并且展示所有匹配的结果集使用第一排序是zcsj,第二排序是_score。
{
"query": {
"bool": {
"filter": {
"term": {
"orgcode": "0120800214"
}
}
}
},
"sort": {
"zcsj": {
"order": "desc"
},
"_score": {
"order": "desc"
}
}
}
结果集会先用第一排序字段来排序,当用作第一字段排序的值相同时,然后再用第二排序字段来排序,以此类推。
但是_score不是多级排序必须的字段,我们可以使用几个不同的字段。
为多值字段排序
在为一个多值字段排序的时候,其实这些值本来没有固定的排序的,一个拥有多值的字段就是一个集合。
对于数字和日期而言,我们可以从多个值中取出一个来进行排序,我们可以使用min、max、avg、sum等模式,比如我们可以在likenum字段中选择最早的数字来进行排序。
{
"query": {
"match_all": {}
},
"sort": {
"likenum": {
"order": "desc",
"mode": "min"
},
"_score": {
"order": "desc"
}
}
}
多值字段字符串排序
analyzer字符串字段同时也是多值字段,在这些字段上排序往往得不到我们想要的值,比如分析一个字符"like a boy",它最终可能会得到三个值like、a、boy。例如我们想要按照第一个词首字母排序,如果第一个单词相同的话,在用第二个单词首字母排序,以此类推,可惜es在进行排序的时候 是得不到这些信息。
为了使一个String字段可以进行排序,它必须包含一个词:即完整的not_analyzer字符串,当然我们要对字段进行全文本搜索的时候还必须使用analyzer。
在_source下相同的字符串上排序两次会造成不必要的资源浪费。而我们想要的是一个字段中同时包含这两种索引方式,现在我们介绍一下在所有核心字段类型上通用的参数fields,这样我们就可以改变它的mapping
"name": {
"type": "text",
"fields":{
"raw": {
"type":"keyword"
}
}
}
改变后的多值字段mapping如下:
"name": {
"type": "text",
"fields": {
"raw": {
"type": "keyword"
}
}
}
下面附上完整的代码(直接在linux服务器上执行)
curl -u elastic -H "Content-Type: application/json" -XPUT 'http://47.100.111.22:9200/bag/' -d '
{
"settings": {
"number_of_shards": 5,
"number_of_replicas": 0
},
"mappings": {
"book": {
"properties": {
"name": {
"type": "text",
"fields":{
"raw": {
"type":"keyword"
}
}
},
"author": {
"index": "true",
"type": "keyword"
},
"price": {
"index": "true",
"type": "double"
},
"date": {
"format": "strict_date_optional_time||epoch_millis",
"type": "date"
}
}
}
}
}'
- name字段用于全文本的analyzed索引方式不变
- name.raw子字段索引方式是not_analyzer
现在改数据重建索引之后,我们可以用name来进行全文本搜索,也可以使用name.raw来进行排序,聚合。
{
"query": {
"match": {
"": "elasticsearch"
}
},
"sort": "name.raw"
}
Tip:对analyzed字段进行强制排序的话会消耗大量的内存。