当发送查询命令到ElasticSearch中,返回的文档集合默认会按照计算出来的文档打分排序(已经在本章的 Lucene的默认打分算法 一节中讲到)。这通常是用户希望的:结果集中的第一个文档就是查询命令想要的文档。然而,有的时候我们希望改变这种排序。这很简单,因为我们已经用过了单个字符串类型的数据。让我们看如下的样例:
{
"query" : {
"terms" : {
"title" : [ "crime", "front", "punishment" ],
"minimum_match" : 1
}
},
"sort" : [
{ "section" : "desc" }
]
}
上面的查询会返回所有title域中至少存在一个上述term的文档,并且会基于section域对文档排序。 我们也通过在sort中添加missing属性来处理当section 域没有值时的排序方式。例如,上面的查询语句中sort部分应该定义如下:
{ "section" : { "order" : "asc", "missing" : "_last" }}
{
"query" : {
"match_all" : {}
},
"sort" : [
{"release_dates" : { "order" : "asc", "mode" : "min" }}
]
}
注意在我们的例子中,query部分是冗余的,基于上是默认值,因此下面的例子中我们会省略这一部分。在本例中,ElasticSearch会选择每个文档中release_dates域中的最小值,然后基于该值对文档排序。mode参数能够设置如下的值:
{
"mappings": {
"poi": {
"properties": {
"country": { "type": "string" },
"loc": { "type": "geo_point" }
}
}
}
}
接下来有一条简单的数据,如下:
{ "country": "UK", "loc": ["51.511214,-0.119824", "53.479251,
-2.247926", "53.962301,-1.081884"] }
我们的查询命令也很简单,如下:
{
"sort": [{
"_geo_distance": {
"loc": "51.511214,-0.119824",
"unit": "km",
"mode" : "min"
}
}]
}
可以看到上面的例子中,我们只有一个包含多个地理坐标点的文档。接下来基于该文档执行上面的查询命令,返回结果如下:
{
"took" : 21,
"timed_out" : false,
"_shards" : {
"total" : 5,
"successful" : 5,
"failed" : 0
},
"hits" : {
"total" : 1,
"max_score" : null,
"hits" : [ {
"_index" : "map",
"_type" : "poi",
"_id" : "1",
"_score" : null, "_source" : {
"country": "UK", "loc": ["51.511214,-0.119824",
"53.479251,-2.247926", "53.962301,-1.081884"] }
,
"sort" : [ 0.0 ]
} ]
}
}
可以看到,该查询命令的结果集中sort部分如下:"sort" : [ 0.0 ]。这是因为查询命令中的坐标点与文档中的一个坐标点是一样的。如果用户修改mode属性值为max,结果会变得不一样,高亮的部分就会变成:"sort" : [ 280.4459406165739 ]。
ElasticSearch 0.90.1版本引入了在mode属性中使用avg来对地理距离排序的功能。
{
"country": "PL", "cities": { "name": "Cracow", "votes": {
"users": "A" }}
}
{
"country": "EN", "cities": { "name": "York", "votes": [{"users":
"B"}, { "users": "C" }]}
}
{
"country": "FR", "cities": { "name": "Paris", "votes": {
"users": "D"} }
}
可以看到,内嵌对象一层套一层,而且有些文档中还包含多值域(例如:多个votes)。 接下来关注如下的查询命令:
{
"sort": [{ "cities.votes.users": { "order": "desc", "mode":
"min" }}]
}
上面的查询命令会使文档按照users中的最小值升序排序。但是,如果使用object类型的subdocument,可以简化查询命令如下:
{
"sort": [{ "users": { order: "desc", mode: "min" }}]
}
之所以可以简化查询是因为使用object类型时,整个object的结构在存储时可以作为一个单独的Lucene文档来存储。如果使用内嵌类型,ElasticSearch需要更精确的域信息,因为这些文档实际上各自是独立的Lucene 文档。有时使用nested_path属性会更方便,比如查询命令写成下面的样子:
{
"sort": [{ "users": { "nested_path": "cities.votes", "order":
"desc", "mode": "min" }}]
}
请注意,用户还可以使用nested_filter参数,该参数只能用于内嵌文档中(明确标识为内嵌文档)。幸亏有这个参数,才使得用户可以在业务中使用从排序结果中排序文档的过滤器,而非从结果集中过滤文档的过滤器。