ElasticSearch学习笔记之十九 多字段排序和字符串排序

  • 排序
  • 多级排序
  • 字符串排序


排序

为了按照相关性来排序,需要将相关性表示为一个数值。在 Elasticsearch 中, 相关性得分 由一个浮点数进行表示,并在搜索结果中通过 _score 参数返回, 默认排序是 _score 降序。

新建索引映射

PUT tweet
{
  "mappings": {
    "tweet": {
      "properties": {
          "about": {
            "type": "text"
          },
          "comments": {
            "type": "nested", 
            "properties": {
              "content": {
                "type": "text"
              },
              "date": {
                "type": "date"
              },
              "user_id": {
                "type": "long"
              }
            }
          },
          "date": {
            "type": "date"
          },
          "name": {
            "type": "text",
            "fields": {
              "keyword": {
                "type": "keyword",
                "ignore_above": 256
              }
            }
          },
          "topic": {
            "type": "text"
          },
          "tweet": {
            "type": "text"
          },
          "user_id": {
            "type": "long"
          }
      }
    }
  }
}

插入数据

PUT tweet/tweet/1
{
    "tweet":    "What is Elasticsearch?",
    "date":     "2014-09-14",
    "name":     "Mary Jones",
    "about":["es","elasticsearch"],
    "topic":"elasticsearch",
    "user_id":  1,
    "comments": [
      {
        "content":  "very good",
        "date":  "2014-09-14",
        "user_id":  1
      },
      {
        "content":  "good question",
        "date":  "2014-09-15",
        "user_id":  2
      }
    ]
}
PUT tweet/tweet/2
{
    "tweet":    "How can we study Elasticsearch?",
    "date":     "2014-09-18",
    "name":     "Mary Jones",
    "about":["es","elasticsearch"],
    "topic":"elasticsearch",
    "user_id":  1,
    "comments": [
      {
        "content":  "very good",
        "date":  "2014-09-18",
        "user_id":  1
      },
      {
        "content":  "good question",
        "date":  "2014-10-15",
        "user_id":  2
      }
    ]
}
PUT tweet/tweet/3
{
    "tweet":    "How can we manage Elasticsearch?",
    "date":     "2014-10-18",
    "name":     "Tom Foxs",
    "about":["es","elasticsearch"],
    "topic":"elasticsearch",
    "user_id":  2,
    "comments": [
      {
        "content":  "do not know",
        "date":  "2014-09-14",
        "user_id":  3
      },
      {
        "content":  "good question",
        "date":  "2014-09-15",
        "user_id":  2
      }
    ]
}

此时假设我们希望看到按照时间的排序,来查询数据

GET tweet/tweet/_search
{
  "sort": [
    {
      "date": {
        "order": "desc"
      }
    }
  ]
}

结果如下:

Java实现es多个字段的排序 es多字段排序sort_Java实现es多个字段的排序

  • 文档返回时多出来了sort 它包含了我们用于排序的值。
  • _score 不被计算, 因为它并没有用于排序。
  • date 字段的值表示为自 epoch (January 1, 1970 00:00:00 UTC)以来的毫秒数,通过 sort字段的值进行返回。

_scoremax_score 字段都是 null 。计算 _score 的花销巨大,通常仅用于排序;这里 我们并不根据相关性排序,所以记录 _score 是没有意义的。如果无论如何你都要计算 _score , 你可以将 track_scores 参数设置为 true

相关性查询

GET tweet/tweet/_search
{
  "query": {
    "match": {
      "name": "jones"
    }
  }
}

查询结果如下:

Java实现es多个字段的排序 es多字段排序sort_排序_02

多级排序

假定我们想要结合使用 date_score 进行查询,并且匹配的结果首先按照日期排序,然后按照相关性排序:

GET tweet/tweet/_search
{
  "query": {
    "match": {
      "name": "jones"
    }
  },
    "sort": [
    {
      "date": {
        "order": "desc"
      }
    },
    {
      "_score":{
        "order": "desc"
      }
    }
  ]
}

排序条件的顺序是很重要的。结果首先按第一个条件排序,仅当结果集的第一个 sort 值完全相同时才会按照第二个条件进行排序,以此类推。

字符串排序

以全文 analyzed 字段排序会消耗大量的内存。

如果你想分析一个字符串,如 fine old art , 这包含 3 项。我们很可能想要按第一项的字母排序,然后按第二项的字母排序,诸如此类,但是 Elasticsearch 在排序过程中没有这样的信息。

你可以使用 minmax 排序模式(默认是 min ),但是这会导致排序以 art 或是 old ,任何一个都不是所希望的。

为了以字符串字段进行排序,这个字段应仅包含一项: 整个 not_analyzed 字符串。 但是我们仍需要 analyzed 字段,这样才能以全文进行查询

一个简单的方法是用两种方式对同一个字符串进行索引,这将在文档中包括两个字段: analyzed 用于搜索, not_analyzed 用于排序

但是保存相同的字符串两次在 source 字段是浪费空间的。 我们真正想要做的是传递一个 _单字段 但是却用两种方式索引它。所有的 _core_field 类型 (strings, numbers, Booleans, dates) 接收一个 fields 参数

该参数允许你转化一个简单的映射如我们上面为名字创建的映射:

"name": {
            "type": "text",
            "fields": {
              "keyword": {
                "type": "keyword",
                "ignore_above": 256
              }
            }
          }

对应检索

GET tweet/tweet/_search
{
  "query": {
    "match": {
      "name": "jones"
    }
  },
    "sort": [
    {
      "name.keyword": {
        "order": "asc"
      }
    },
    {
      "_score":{
        "order": "desc"
      }
    }
  ]
}