笔记|ElasticSearch|ES 翻页性能优化方法

查询语法层面的优化方法

1. 如只文档的 doc_ic,则可配置 "_source": false

如果我们只需要文档的 doc_id 而不需要文档 _source 中的任何字段,那么则可以添加配置 "_source": false。此时,ES 将只需要执行查询的 query 阶段而不需要执行 fetch 阶段,从而极大地加快查询速度。

修改前:

GET /my-index-000001/_search?
{
    
    
    "query": {
    
    
        "match_all": {
    
    }
    },
    "_source": ""
}

修改后:

GET /my-index-000001/_search?
{
    
    
    "query": {
    
    
        "match_all": {
    
    }
    },
    "_source": false
}

2. 将 query 查询改为 filter 过滤语句

使用 FilterContext 代替 QueryConext,因为 filter 查询子句的性能优于 query 查询子句,filter 查询子句不需要计算相关性的分值而 query 查询子句需要计算相关性的分支,filter 查询子句的结果可以缓存。

修改前:

GET /my-index-000001/_search?
{
    
    
    "query": {
    
    
        "term": {
    
    
            "field_name": "field_value"
        }
    }
}

修改后:

GET /my-index-000001/_search?
{
    
    
    "query": {
    
    
        "bool": {
    
    
            "filter": {
    
    
                "term": {
    
    
                    "field_name": "field_value"
                }
            }
        }
    }
}

3. 在不超时的前提下,增加每次 scroll 获取的记录数

我们可以通过增加 size,使每一次 scroll 返回更多数据,从而减少查询的 query、fetch、response 各阶段的次数,提高效率。但需要注意增大超时时间,以避免因为每次 scroll 将返回更多数据而超时。

修改前:

GET /my-index-000001/_search?
{
    
    
    "query": {
    
    
        "match_all": {
    
    }
    },
    "size": 1000
}

修改后:

GET /my-index-000001/_search?
{
    
    
    "query": {
    
    
        "match_all": {
    
    }
    },
    "size": 10000
}

4. 在 scroll 查询中按 _doc 排序

在 ElasticSearch 的官方文档中,说明了 _doc 表示按索引顺序排序,是最高效的排序方法。如果不关心返回文档的顺序的话,那么就应按 _doc 进行排序以提高查询性能。这在 scroll 时格外有效。

文档地址:https://www.elastic.co/guide/en/elasticsearch/reference/8.6/sort-search-results.html

修改前:

{
    
    
    "query": {
    
    
        "bool": {
    
    
            "filter": {
    
    
                "term": {
    
    
                    "field_name": "field_value"
                }
            }
        }
    }
}

修改后:

{
    
    
    "query": {
    
    
        "bool": {
    
    
            "filter": {
    
    
                "term": {
    
    
                    "field_name": "field_value"
                }
            }
        }
    },
    "sort": ["_doc"]
}

5. 减少不需要的查询字段(使用 _source 筛选)

通过减少不需要的字段,可以有效地减少查询的 fetch 阶段的耗时。

修改前:

GET /my-index-000001/_search?
{
    
    
    "query": {
    
    
        "match_all": {
    
    }
    }
}

修改后:

GET /my-index-000001/_search?
{
    
    
    "query": {
    
    
        "match_all": {
    
    }
    },
    "_source": ["need-field-1", "need-field-2"]
}

6. 避免使用模糊匹配

7. 使用 filter_path 过滤返回结果

通过添加 filter_path,可以减少网络 IO 占用。需要注意,如果使用 scroll 的话,需要保留 _scroll_id 字段。

文档地址:https://www.elastic.co/guide/en/elasticsearch/reference/8.7/common-options.html#common-options-response-filtering

8. scroll scan(2.1 版本前)

在 2.1 版本后已不支持。

9. search after

经过测试,在 7.10.2 版本环境下,在不使用 PIT 时:使用 _doc 排序时,search after 的全量查询速度与 scroll 的全量查询速度似乎基本相同,但可能会导致漏掉少量数据;使用 _id 排序时,search after 的全量查询速度比 scroll 的全量查询速度明显更慢?(以上测试结果与部分文章结果不一致,尚待继续分析)

文档地址:https://www.elastic.co/guide/en/elasticsearch/reference/8.7/paginate-search-results.html#search-after

response = es_client.search(
        index="my-index-0001",
        size=10000,
        body={
    
    "query": {
    
    ...}, "sort": ["_doc"]}
    )
    while response["hits"]["hits"]:
        last = None
        for item in response["hits"]["hits"]:
            last = item["sort"]
            # ...... 处理逻辑
        response = es_client.search(
            index="my-index-0001",
            size=10000,
            body={
    
    "query": {
    
    ...}, "search_after": last, "sort": ["_doc"]}
        )

10. search after + PIT(并发方法)

在 7.10 版本添加到 X-Pack 中;在 7.11 版本被添加。

文档地址:https://www.elastic.co/guide/en/elasticsearch/reference/8.7/point-in-time-api.html

11. slice scroll(并发方法)

通过 slice scroll 可以支持并发 scroll。

但是如果没有合适的字段作为 slice field 的话,如切片(slice)数量超过索引的分片数(shards),则 ES 则需要较长 O ( N ) O(N) O(N) 的时间复杂度和空间复杂度来完成拆分,需要当已进行相当比例的查询后才能完成这个过程。经过测试,在 7.10.2 版本环境下,在 slice 数量超过 shards 数量时,约需查询约 60% - 70% 后 ES 才能完成拆分过程,在完成拆分前,所有进程 scroll 的速度之和与单进程 scroll 的速度基本相同。

文档地址:https://www.elastic.co/guide/en/elasticsearch/reference/8.7/paginate-search-results.html#slice-scroll

索引设计方面的优化方法

1. 将字符串格式字段改为数字或日期格式

因为索引方式的原因,使得:对于字符串类型的字段,range 过滤时效率很低;而对于数字和日期类型字段,range 过滤时效率很高。所以,如果某个字段的含义就是数字或日期,那么则不应使用字符串类型存储。

2. 降低嵌套层级

可以通过将深层嵌套(例如 "field-1": {"field-1-1": 1, "field-1-2": 2})的字段拉平,减少嵌套层级。

3. 减少 refresh 频率

如果对搜索的时效性要求不高,则可以将 refresh 的周期延长,减少刷新次数,但同时也意味着需要更高的内存占用。

4. 减少副本数量

以降低可用性为代价,减少副本数量,提高写索引的速度。

猜你喜欢

转载自blog.csdn.net/Changxing_J/article/details/130139631