相关性排序

默认情况下,结果集会按照相关性进行排序,相关性越高,排名越靠前。在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"
    }
  }
}

你会发现这里有这两个不同点:

ES 时间字符串排序 es将结果按时间排序_字符串

  • 一、_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"
    }
  }
}

ES 时间字符串排序 es将结果按时间排序_字段_02

多值字段字符串排序

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字段进行强制排序的话会消耗大量的内存。