小数据量场景下MongoDB与ElasticSearch实现Faceted Search选型咨询
问题
我有一个需要在WebApp中构建Faceted Search Navigation的需求,以虚构的鞋类销售电商站点为例,为简化逻辑,鞋类商品可按Brand、Color、Category三个维度筛选,Faceted导航样式如下:
Brand(10): =========== Nike(6) Puma(2) Adidas(2) Color(10): =========== Red(4) Blue(2) White(4) Category(10): ============= Sneakers(3) Running(3) Climbing(3)
若同时对Brand和Color应用筛选条件,不会移除全部Brand和Color的可选筛选项,选项更新规则如下:
- Brand维度:移除与已选Color不匹配的筛选选项
- Color维度:移除与已选Brand不匹配的筛选选项
- Category维度:移除与已选Brand、Color均不匹配的筛选选项
预选方案
方案1 - Elastic Search/OpenSearch
我尝试基于Elastic Search构建数据模型与查询实现该需求,索引Schema与查询逻辑完全匹配公开技术博客中给出的标准分面搜索方案。
但我认为使用OpenSearch的主要限制在于:我当前的数据量仅约1MB,远期最大规模也仅为10GB。按照AWS官方文档给出的公式计算,最小存储需求为10GB x 2 x 1.45 = 29 GB。如果当前拆分3个shard,每个shard仅存储约300KB数据,ES官方文档提到过小的shard会占用大量CPU和内存资源。
请问这是否属于真实缺陷?是否有人遇到过小shard尺寸导致的CPU性能问题?
方案2 - MongoDB
我尝试采用和ES相同的文档结构建模,公开技术博客也推荐了这类通用索引构建方案。但MongoDB存在的问题是,当同时应用多个筛选条件时可能出现index intersection问题,影响查询性能。公开技术博客解释了Index intersection问题。请问MongoDB facets能否解决该问题?如果可以,同时应用多个过滤条件时的查询性能表现如何?
请问结合我的数据规模,哪个数据库更适合该场景?ES、MongoDB及其他可选方案各有哪些优缺点?
解答
方案1疑问澄清
你提到的小shard占用过多资源的问题是真实存在的,但仅在集群shard总数过百、单shard大小低于1GB的大规模部署场景下才会有明显感知,你的场景完全可以通过配置规避:
- 10GB以内的数据不需要拆分3个shard,使用单主分片+1个副本分片即可,单shard大小在5GB左右完全符合ES官方推荐的最优区间,即使当前只有1MB数据,单节点单shard的CPU和内存消耗可以忽略
- 你计算的29GB是生产环境高可用配置的冗余要求,如果是低流量、非核心业务场景,可以直接关闭副本,或选用AWS Serverless版OpenSearch,按实际请求量计费,不用预先采购存储资源,成本极低
方案2疑问澄清
MongoDB的$facet聚合完全可以满足你的分面统计需求,你担心的索引交集问题可以通过提前预建复合索引完全规避,不需要依赖MongoDB的自动索引交集能力:
- 针对你常用的筛选组合(Brand+Color、Brand+Category、Color+Category)提前创建对应的复合索引,
$facet下的三个统计管道可以直接命中索引,10GB级别的数据查询延迟基本稳定在100ms以内,完全满足Web端交互需求 - 即使不做额外优化,你的数据量极小,哪怕是全表扫描也不会有明显的性能问题
选型建议
结合你的数据规模,可以按未来需求灵活选择:
- 若未来计划扩展全文搜索、模糊匹配、权重排序、同义词搜索等功能,直接选OpenSearch/ES,小数据量下成本和性能都不是瓶颈,功能扩展性更强
- 若你当前已经在用MongoDB作为主力业务库,不想额外引入新的技术栈,直接用MongoDB
$facet即可,完全满足现有需求 - 还有更轻量的可选方案:如果远期商品规模不超过10万,可以直接把全量商品的维度数据缓存到应用内存或Redis中,直接在内存中做筛选统计,延迟可以控制在10ms以内,几乎没有额外运维成本
内容的提问来源于stack exchange,提问作者user8622082

