Elasticsearch项目中哪些避坑经验总结的14条实用技巧最关键?

摘要:如果有人问我:'ES 怎么才能用得更好?'我的回答是:'先理解业务场景,再选择技术方案。技术的价值不在于多复杂,而在于能否优雅地解决实际问题。与大家共勉。'
刚开始接触 Elasticsearch 时,我觉得它就像个黑盒子——数据往里一扔,查询语句一写,结果就出来了。直到负责公司核心业务的搜索模块后,我才发现这个黑盒子里面藏着无数需要注意的细节。 今天就把我在实际项目中积累的 ES 使用经验分享给大家,主要从索引设计、字段类型、查询优化、集群管理和架构设计这几个方面来展开。 索引设计:从基础到进阶 1. 索引别名(alias):为变更留条后路 刚开始做项目时,我习惯直接用索引名。直到有一次需要修改字段类型,才发现 ES 不支持直接修改映射,也不支持修改主分片数,必须重建索引。(**新增字段是可以的) 解决方案很简单:使用索引别名。业务代码中永远使用别名,重建索引时只需要切换别名的指向,整个过程用户无感知。 这就好比给索引起了个"外号",里面怎么换内容都不影响外面的人称呼它。 2. Routing 路由:让查询更精准 在做 SaaS 电商系统时,我发现查询某个商家的订单数据特别慢。原来,默认情况下ES根据文档ID的哈希值分配分片,导致同一个商家的数据分散在不同分片上。 优化方案:使用商家 ID 作为 routing key,存储和查询数据时指定routing key。这样,同一个商家的所有数据都会存储在同一个分片上。 效果对比: 优化前:查询要扫描所有分片(比如3个分片都要查) 优化后:只需要查1个分片 结果:查询速度直接翻倍,资源消耗还更少 3. 分片拆分:应对数据增长 当单个索引数据量持续增长时,单纯增加分片数并不是最佳方案。 我的经验是: 业务索引:单个分片控制在 10-30GB 搜索索引:10GB 以内更合适 日志索引:可以放宽到 20-50GB 对于 SaaS 系统,ES单索引数据较大,且存在“超级大商户”,导致数据倾斜严重时,可以按商家ID%64取模进行索引拆分,比如 orders_001 到 orders_064,每个索引包含部分商家的数据,然后再根据商户ID指定routing key。 请根据业务数据量和业务要求,选择最适合的分片拆分规则 和routing key路由算法,同时不要因为拆分不合理,导致ES节点中存在大量分片。 ES默认单节点分片最大值为1000(7.0版本后),可以参考ES官方建议,堆内存分片数量维持大约1:20的比例 字段类型:选择比努力重要 4. Text vs Keyword:理解它们的本质区别 曾经有个坑:用户手机号用 text 类型存储,结果搜索完整的手机号却搜不到。原来 text 类型会被分词,13800138000 可能被拆成 138、0013、8000 等片段。 正确做法: 需要分词搜索的用 text(如商品描述) 需要精确匹配的用 keyword(如订单号、手机号),适合 term、terms 等精确查询 效果:keyword 类型的 term 查询速度更快,存储空间更小 5. 多字段映射(multi-fields):按需使用不浪费 ES 默认会为 text 字段创建 keyword 子字段,但这并不总是必要的。 我的选择: 确定字段需要精确匹配和聚合时:启用 multi-fields 只用于全文搜索时:禁用 multi-fields 好处:节省存储空间,提升写入速度 6. 排序字段:选对类型提升性能 用 keyword 字段做数值排序是个常见误区。比如价格排序,100 会排在 99 前面,因为它是按字符串顺序比较的。 推荐做法: 数值排序:用 long、integer 类型 时间排序:用 date 类型 提升效果:排序速度提升明显,内存占用也更少 查询优化:平衡速度与精度 7. 模糊查询:了解正确的打开方式 在 ES 7.9 之前,wildcard 查询是个性能陷阱。它基于正则表达式引擎,前导通配符会导致全量词项扫描。 现在的方案: ES7.9+:使用 wildcard 字段类型 优势:底层使用优化的 n-gram + 二进制 doc value 机制,性能提升显著 提示:ES7.9前后版本wildcard的具体介绍,可以参考我的上一篇文章 《与产品经理的“模糊”对决:Elasticsearch实现MySQL LIKE '%xxx%'》 8. 分页查询:避免深度分页的坑 产品经理曾要求实现"无限滚动",我展示了深度分页的性能数据后,大家达成共识:业务层面避免深度分页才是根本解决方案。就像淘宝、Google 这样的大厂,也都对分页做了限制,这不仅是技术考量,更是用户体验的最优选择。
阅读全文