MST

星途 面试题库

面试题:ElasticSearch在复杂聚合场景下如何优化搜索结果折叠

在一个包含大量商品信息的ElasticSearch索引中,文档包含 'brand'(品牌)、'price'(价格)、'rating'(评分)等字段。现在需要按照 'brand' 进行折叠,并且在每个品牌下,筛选出价格前10%且评分大于4分的商品,同时要保证查询性能。阐述实现该需求的详细步骤及可能用到的ElasticSearch特性,并分析可能存在的性能瓶颈及优化方向。
25.5万 热度难度
数据库ElasticSearch

知识考点

AI 面试

面试题答案

一键面试

实现步骤

  1. 桶聚合(Terms Aggregation):使用 terms 聚合按照 brand 进行分组,即折叠操作。
{
    "aggs": {
        "by_brand": {
            "terms": {
                "field": "brand",
                "size": 10000
            }
        }
    }
}

这里 size 可根据实际品牌数量调整,确保能获取所有品牌。

  1. 子聚合 - 过滤(Filter Aggregation):在每个品牌桶内,使用 filter 聚合筛选评分大于4分的商品。
{
    "aggs": {
        "by_brand": {
            "terms": {
                "field": "brand",
                "size": 10000
            },
            "aggs": {
                "high_rating": {
                    "filter": {
                        "range": {
                            "rating": {
                                "gt": 4
                            }
                        }
                    }
                }
            }
        }
    }
}
  1. 子聚合 - Top Hits 结合 Percentiles Bucket Aggregation
    • 先使用 percentiles_bucket 聚合计算出价格前10% 的阈值。
    • 再用 top_hits 聚合根据阈值筛选出价格前10% 的商品。
{
    "aggs": {
        "by_brand": {
            "terms": {
                "field": "brand",
                "size": 10000
            },
            "aggs": {
                "high_rating": {
                    "filter": {
                        "range": {
                            "rating": {
                                "gt": 4
                            }
                        }
                    },
                    "aggs": {
                        "price_threshold": {
                            "percentiles_bucket": {
                                "field": "price",
                                "percents": [90]
                            }
                        },
                        "top_products": {
                            "top_hits": {
                                "sort": [
                                    {
                                        "price": {
                                            "order": "desc"
                                        }
                                    }
                                ],
                                "size": 10000,
                                "script": {
                                    "source": "doc['price'].value >= params.threshold",
                                    "params": {
                                        "threshold": 0
                                    }
                                }
                            },
                            "aggs": {
                                "set_threshold": {
                                    "bucket_script": {
                                        "buckets_path": {
                                            "threshold": "price_threshold>90.0"
                                        },
                                        "script": "params.threshold"
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}

这里 top_hitssize 可根据实际情况调整,确保能获取足够多商品来筛选前10%。

可能用到的ElasticSearch特性

  1. 聚合(Aggregation):包括 terms 聚合用于分组,filter 聚合用于筛选条件,percentiles_bucket 聚合用于计算百分位数,top_hits 聚合用于获取符合条件的文档。
  2. 脚本(Scripting):在 top_hits 聚合中使用脚本,根据计算出的价格阈值筛选商品。

性能瓶颈及优化方向

  1. 性能瓶颈

    • 数据量过大:大量商品信息可能导致聚合计算量巨大,尤其是在计算百分位数和筛选文档时。
    • 深分页问题:如果 top_hitssize 设置过大,可能会导致深分页问题,影响性能。
    • 脚本计算:脚本计算会增加额外的 CPU 开销。
  2. 优化方向

    • 数据预处理:在数据写入 ElasticSearch 时,可以对数据进行一些预处理,如计算并存储价格区间等信息,减少实时计算量。
    • 分页优化:采用滚动(Scroll)或者搜索后下一页(Search After)的方式代替深分页,减少内存和性能消耗。
    • 缓存:对于一些不经常变化的品牌数据,可以使用缓存来减少 ElasticSearch 的查询压力。
    • 硬件优化:如果可能,增加服务器资源,如 CPU、内存等,以提高 ElasticSearch 的处理能力。