如何在ElasticSearch中按数组大小对项目进行排序?

时间:2015-10-20 12:50:34

标签: elasticsearch

我有300万件具有这种结构的物品:

{
    "id": "some_id",
    "title": "some_title",
    "photos": [
        {...},
        {...},
        ...
    ]
}

某些项目可能包含空photos字段:

{
    "id": "some_id",
    "title": "some_title",
    "photos": []
}

我想按照照片的数量排序,导致没有照片的元素出现在列表的末尾。

我有一个有效的解决方案,但300万件物品的速度非常慢:

GET myitems/_search
{
   "filter": {
      ...some filters...
   },
   "sort": [
      {
          "_script": {
              "script": "_source.photos.size()",
              "type": "number",
              "order": "desc"
          }
      }
   ]
}

此查询执行55秒。如何优化此查询?

2 个答案:

答案 0 :(得分:0)

正如评论中所建议的那样,添加一个包含照片数量的新字段将是最佳选择。有一种方法可以使用update by query plugin实现此而无需重新编制索引所有数据。

基本上,在安装插件后,您可以运行以下查询,所有文档都将获得该新字段。但是,请确保索引过程还填充新文档中的新字段:

curl -XPOST 'localhost:9200/myitems/_update_by_query' -d '{
    "query" : {
        "match_all" : {}
    },
    "script" : "ctx._source.nb_photos = ctx._source.photos.size();"
}'

运行完毕后,您只需使用以下内容对结果进行排序:

"sort": {"nb_photos": "desc"}

注意:要使此插件正常工作,需要scripting enabled,因为您可以使用排序脚本,所以已经是您的情况,但我只是为了完整性而提到这一点。

答案 1 :(得分:0)

使用Transform指令解决了问题。现在我有一个映射:

PUT /myitems/_mapping/lol
{
    "lol" : {
        "transform": {
            "lang": "groovy",
            "script": "ctx._source['has_photos'] = ctx._source['photos'].size() > 0"
        },
        "properties" : {
            ... fields ...
            "photos" : {"type": "object"},
            "has_photos": {"type": "boolean"}
            ... fields ...
        }
    }
}

现在我可以通过照片存在对项目进行排序:

GET /test/_search
{
    "sort": [
        {
            "has_photos": {
               "order": "desc"
            }
        }
    ]
}

不幸的是,这将导致完全重新索引。