优秀的编程知识分享平台

网站首页 > 技术文章 正文

Elasticsearch三种分页如何选择以及数据排序

nanyue 2024-10-14 11:34:42 技术文章 5 ℃

与关系型数据一样,在面对大量数据时,我们是需要对数据进行分页和排序的

一.elasticsearch数据分页

1.传统from+size分页

(1)用法

  • from表示从第几条数据开始。
  • size表示每页显示多少条数据
GET <indexName>/_search  
{  
  "query": {  
    "match_all": {}  
  },  
  "from": 0,  // 起始偏移量  
  "size": 10  // 每页显示的结果数  
}

(2)适用场景

传统的PC端可随意跳转的分页

(3)优缺点:

优点:可以向前或向后翻页,可以跳转到任意页码上

缺点:

  • 受限于max_result_window参数,默认最多只能查看10000条数据,如果随意调整这个配置,可能会造成OOM
  • 页码越大,内存和CPU开销越大,查询越慢

2.通过类似于游标的scroll实现全量非实时数据分页

(1)用法

  • scroll: 指定快照时间有效期
  • scroll_id: 类似于游标的的ID
GET merchant_order/_search/scroll?scroll=1m&scroll_id=cXVlcnlBbmRGZXRjaDsxOzg4NDg2OTpTQzRmWWkwQ1Q1bUlwMjc0WmdIX2ZnOzA
{
     
  "query": {  
    "match_all": {}  
  },  
  "sort": [  
    {  
      "id": "asc"  // 排序字段和排序方式ASC、DESC  
    }  
  ]  
}

注:本次响应返回的scroll_id作为下次查询的scroll_id查询参数

(2)适用场景

  • 需要查询全量数据(如展出数据等)
  • 对实时性要求要求不太严格的

(3)优缺点

优点:可以查询全量数据,总数不受max_result_window参数影响

缺点:

  • 因为它类似于一个快照数据,并不是实时数据,如果对实时性要求比较高,则不适合
  • srcoll_id 的存在会耗费大量的资源来保存一份当前查询结果集映像,并且会占用文件描述符,用完后需要手动清理

3.通过search after实现实时数据分页

分页的方式是根据上一页的最后一条数据来确定下一页的位置,同时在分页请求的过程中,如果有索引数据的增删改查,这些变更也会实时的反映到游标上。但是需要注意,因为每一页的数据依赖于上一页最后一条数据,所以无法跳页请求。

  • 场景:APP分页

第一页:

GET merchant_order/_search
{
    "size": 10,
    "query": {
        "term" : {
            "did" : 519390
        }
    },
    "sort": [
        {"date": "asc"},
        {"_id": "desc"}
    ]
}

后页的分页:

GET merchant_order/_search
{
    "size": 10,
    "query": {
        "match" : {
            "name" : "折刀"
        }
    },
    "search_after": [10.2, "2024-06-16 18:00:15"],
    "sort": [
        {"price": "asc"},
        {"update_time": "desc"}
    ]
}
  • 要求:
    • 它必须先要指定排序(因为一定要按排序记住坐标)
    • 必须从第一页开始搜起
    • 从第一页开始以后每次都带上search_after
  • 优缺点:
  • 优点:可以查询全量数据,而且可以保证实时
  • 缺点:不能随意跳转翻页

二.elasticsearch 数据排序

elasticsearch中,是通过sort子句来实现排序的,其主要格式为:

GET <indexName>/_search  
{  
  "query": {  
    "match_all": {}  
  },  
  "sort": [  
    {  
      "sortField": "desc"  // 排序字段和排序方式ASC、DESC  
    }  
  ]  
}
  • sortField即为要排序的字段,另外一种是:
GET <indexName>/_search  
{  
  "query": {  
    "match_all": {}  
  },  
  "sort": [  
    {  
      "sortField": {
        "order":"desc"
      }
    }  
  ]  
}

1.按指定字段排序

GET steam_item_730/_search
{  
  "query": {  
    "match_all": {}  
  },  
  "sort": [  
    {  
      "price":"asc"
    },
    {
      "update_time":"desc"
    }
  ]  
}

本例中是按价格字段升序排列,然后再按更新时间倒序

2.特殊字段排序

  • 通过元数据字段进行排序,如
GET steam_item_730/_search  
{  
  "query": {  
    "term_id": {
        "app_id":730
    }  
  },  
  "sort": [  
    {  
      "_id":"desc"
    }  
  ]  
}
  • 通过和分_score这个字段来排序
GET steam_item_730/_search  
{  
  "query": {  
    "match": {
        "name":"久经沙场"
    }  
  },  
  "sort": [  
    {  
      "_score":"desc"
    }  
  ]  
}

上例中通过关键词搜索,并按照匹配相关性得分倒序排序

3.通过脚本实现自定义排序

GET merchant_order/_search  
{  
  "query": {  
    "match": {
        "name":"久经沙场"
    }  
  },  
  "sort": [  
    {  
      "_script": {
          "type": "number",
          "script": {
            "source": "if (doc['status'] == 'waiting_payment') {return 10;} else if (doc['status'] == 'cancel') {return 1;} else { return 5;}",
            "lang": "painless"
          },
          "order": "desc"
        }
    }  
  ]  
}

上例中,通过脚本实现自定义的排序(如果订单状态为未支付,则优先级最高; 取消状态,优化级最低,其他优先级中等)

  • type: 脚本结果的类型
  • script: 脚本主内容
    • source : 脚本文本内容
    • lang: 脚本语言
  • order: 排序方式
最近发表
标签列表