月度归档:2015年12月

Elasticsearch 多字段评分排序

有这样一个需求: 展示一个用户列表, 有头像的优先展示, 有认证的优先展示, 有相册的优先展示, 同时拥有这些条件越多的则优先级更高, 第二排序条件是注册时间逆序.

通常是用条件进行过滤, 但往往是将不符合的条件数据去掉了, 而不是将其排在后面. 而对于多个条件时, 过滤更无能为力.

自定义脚本, 进行多字段评分排序, 可以很方便可以实现:

1. 写入配置文件, 开启script支持, 并重启Elasticsearch

script.groovy.sandbox.enabled: true

script.inline: on
script.indexed: on
script.search: on
script.engine.groovy.inline.aggs: on
script.engine.groovy.inline.search: on

2. 创建索引

PUT /users
{
  "mappings": {
    "list" : {
      "properties": {
        "Name": {
          "type": "string",
          "analyzer": "standard",
          "index": "analyzed"
        },
        "HasAvatar": {
          "type": "long"
        },
        "HasAlbum": {
          "type": "long"
        },
        "HasAuth": {
          "type": "long"
        },
        "RegTime": {
          "type": "date",
          "format": "yyyy-MM-dd HH:mm:ss"
        }
      }
    }
  }
}

3. 添加测试数据

POST /users/list/_bulk
{"index": {"_id": 1}}
{"Name": "Allen", "HasAvatar": 1, "HasAlbum": 1, "HasAuth": 1, "RegTime": "2015-12-01 00:00:00"}
{"index": {"_id": 2}}
{"Name": "Burnell", "HasAvatar": 0, "HasAlbum": 0, "HasAuth": 0, "RegTime": "2015-11-02 00:00:00"}
{"index": {"_id": 3}}
{"Name": "Chasel", "HasAvatar": 0, "HasAlbum": 0, "HasAuth": 0, "RegTime": "2015-11-22 00:00:00"}
{"index": {"_id": 4}}
{"Name": "Eden", "HasAvatar": 1, "HasAlbum": 0, "HasAuth": 1, "RegTime": "2015-12-02 00:00:00"}
{"index": {"_id": 5}}
{"Name": "Ford", "HasAvatar": 1, "HasAlbum": 1, "HasAuth": 0, "RegTime": "2015-12-03 00:00:00"}
{"index": {"_id": 6}}
{"Name": "Gordon", "HasAvatar": 1, "HasAlbum": 0, "HasAuth": 0, "RegTime": "2015-12-04 00:00:00"}

4. 按条件搜索

GET /users/list/_search
{
  "sort": [{
    "_script": {
      "script": "doc['HasAvatar'].value  + doc['HasAlbum'].value + doc['HasAuth'].value",
      "type": "number",
      "order": "desc"
    },
    "RegTime":{"order": "desc"}
  }]
}

看看结果是不是符合预期:

{
   "took": 8,
   "timed_out": false,
   "_shards": {
      "total": 5,
      "successful": 5,
      "failed": 0
   },
   "hits": {
      "total": 6,
      "max_score": null,
      "hits": [
         {
            "_index": "users",
            "_type": "list",
            "_id": "1",
            "_score": null,
            "_source": {
               "Name": "Allen",
               "HasAvatar": 1,
               "HasAlbum": 1,
               "HasAuth": 1,
               "RegTime": "2015-12-01 00:00:00"
            },
            "sort": [
               3,
               1448928000000
            ]
         },
         {
            "_index": "users",
            "_type": "list",
            "_id": "5",
            "_score": null,
            "_source": {
               "Name": "Ford",
               "HasAvatar": 1,
               "HasAlbum": 1,
               "HasAuth": 0,
               "RegTime": "2015-12-03 00:00:00"
            },
            "sort": [
               2,
               1449100800000
            ]
         },
         {
            "_index": "users",
            "_type": "list",
            "_id": "4",
            "_score": null,
            "_source": {
               "Name": "Eden",
               "HasAvatar": 1,
               "HasAlbum": 0,
               "HasAuth": 1,
               "RegTime": "2015-12-02 00:00:00"
            },
            "sort": [
               2,
               1449014400000
            ]
         },
         {
            "_index": "users",
            "_type": "list",
            "_id": "6",
            "_score": null,
            "_source": {
               "Name": "Gordon",
               "HasAvatar": 1,
               "HasAlbum": 0,
               "HasAuth": 0,
               "RegTime": "2015-12-04 00:00:00"
            },
            "sort": [
               1,
               1449187200000
            ]
         },
         {
            "_index": "users",
            "_type": "list",
            "_id": "3",
            "_score": null,
            "_source": {
               "Name": "Chasel",
               "HasAvatar": 0,
               "HasAlbum": 0,
               "HasAuth": 0,
               "RegTime": "2015-11-22 00:00:00"
            },
            "sort": [
               0,
               1448150400000
            ]
         },
         {
            "_index": "users",
            "_type": "list",
            "_id": "2",
            "_score": null,
            "_source": {
               "Name": "Burnell",
               "HasAvatar": 0,
               "HasAlbum": 0,
               "HasAuth": 0,
               "RegTime": "2015-11-02 00:00:00"
            },
            "sort": [
               0,
               1446422400000
            ]
         }
      ]
   }
}

字段评分还能根据不同需要给予权重, 同样可以用于带搜索词的情况中, 只需要设置好对应的评分权重即可.