🔧 阿川の電商水電行
Shopify 顧問、維護與客製化
💡
小任務 / 單次支援方案
單次處理 Shopify 修正/微調
⭐️
維護方案
每月 Shopify 技術支援 + 小修改 + 諮詢
🚀
專案建置
Shopify 功能導入、培訓 + 分階段交付

Elasticsearch 避坑指南:我在專案中總結的 14 條實用經驗

剛開始接觸 Elasticsearch 時,我覺得它就像個黑盒子——數據往裡一扔,查詢語句一寫,結果就出來了。直到負責公司核心業務的搜尋模組後,我才發現這個黑盒子裡面藏著無數需要注意的細節。

今天就把我在實際專案中積累的 ES 使用經驗分享給大家,主要從索引設計字段類型查詢優化集群管理架構設計這幾個方面來展開。

20251102-4.jpg

索引設計:從基礎到進階

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_001orders_064,每個索引包含部分商家的數據,然後再根據商戶ID指定routing key。

請根據業務數據量業務要求,選擇最適合的分片拆分規則routing key路由算法,同時不要因為拆分不合理,導致ES節點中存在大量分片。

ES默認單節點分片最大值為1000(7.0版本後),可以參考ES官方建議,堆內存分片數量維持大約1:20的比例


字段類型:選擇比努力重要

4. Text vs Keyword:理解它們的本質區別

曾經有個坑:用戶手機號用 text 類型存儲,結果搜尋完整的手機號卻搜不到。原來 text 類型會被分詞,13800138000 可能被拆成 13800138000 等片段。

正確做法

  • 需要分詞搜尋的用 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 這樣的大廠,也都對分頁做了限制,這不僅是技術考量,更是用戶體驗的最優選擇。

技術方案(僅在確實無法避免時考慮):

  • 淺分頁:使用 from/size,適合前幾頁的常規分頁
  • Scroll:適合大數據量導出,但需要維護 scroll_id 和歷史快照,對伺服器資源消耗較大
  • search_after:基於上一頁最後一條記錄進行分頁,但無法跳轉任意頁面,且頻繁查詢會增加伺服器壓力

需要強調的是,這些技術方案都存在各自的局限性,業務設計上的規避始終是最佳選擇


集群管理:保障穩定運行

9. 索引生命週期:自動化運維

日誌數據的特點是源源不斷,如果不加管理,磁碟很快就會被撐滿。

我的做法

  • 按天創建索引(如 log_20231201)
  • 設置保留策略(保留7天或30天)
  • 結合模板自動化管理

10. 準實時性:理解刷新機制

很多新手會困惑:為什麼數據寫入後不能立即搜尋?

原理ES 默認 1 秒刷新一次索引,這是為了在即時性和寫入性能之間取得平衡。

調整建議

  • 實時性要求高:保持 1s
  • 寫入量大:適當調大 refresh_interval

補充說明:如果需要更新後立即能查詢到,通常有兩種方案:

  1. 讓前端直接展示剛提交的數據,等下一次調用介面時再查詢 ES
  2. 更新後,前端延遲 1.5 秒後再查詢

關鍵點:業務需求不一定都要後端實現,可以結合前端一起考量解決方案。

11. 內存配置:32G 限制的真相

為什麼 ES 官方建議不要超過 32G 內存?

技術原因:Java 的壓縮指針技術在 32G 以內有效,超過這個限制會浪費大量內存。

實踐建議:單個節點配置約50%內存,留出部分給操作系統。


架構設計:合理的分工協作

12. ES 與資料庫:各司其職

曾經試圖在 ES 裡存儲完整的業務數據,結果遇到數據一致性問題。

現在的方案

  • ES:存儲搜尋條件和文檔 ID
  • 資料庫:存儲完整業務數據
  • 查詢:ES 找 ID,資料庫取詳情

好處:既享受 ES 的搜尋能力,又保證數據的強一致性。

13. 嵌套對象:保持數據關聯性

處理商品規格這類陣列數據時,用普通的 object 類型會導致數據扁平化,破壞對象間的關聯。

解決方案:使用 nested 類型,保持陣列內對象的獨立性,確保查詢結果的準確性。

14. 副本配置:讀寫平衡的藝術

副本可以提升查詢能力,但也不是越多越好。

經驗值

  • 大多數場景:1 個副本足夠
  • 高查詢壓力:可適當增加
  • 注意:副本越多,寫入壓力越大

寫在最後

這些經驗都是在解決實際問題中慢慢積累的。就像修路一樣,開始可能只是簡單鋪平,隨著車流量的增加,需要不斷優化——設置紅綠燈、劃分車道、建立立交橋。使用 ES 也是同樣的道理,隨著業務的發展,需要不斷調整和優化。

最大的體會是:理解原理比記住命令更重要。只有明白了為什麼這樣設計,才能在遇到新問題時找到合適的解決方案。

如果有人問我:"ES 怎麼才能用得更好?"我的回答是:"先理解業務場景,再選擇技術方案。就像我們之前做的模糊搜尋,不是簡單地用 wildcard,而是根據 ES 版本選擇最優解。"

技術的價值不在於多複雜,而在於能否優雅地解決實際問題。與大家共勉。


原文出處:https://juejin.cn/post/7569959427879567370


精選技術文章翻譯,幫助開發者持續吸收新知。

共有 0 則留言


精選技術文章翻譯,幫助開發者持續吸收新知。
🏆 本月排行榜
🥇
站長阿川
📝14   💬4   ❤️5
474
🥈
我愛JS
📝1   💬4   ❤️2
49
🥉
酷豪
1
評分標準:發文×10 + 留言×3 + 獲讚×5 + 點讚×1 + 瀏覽數÷10
本數據每小時更新一次
🔧 阿川の電商水電行
Shopify 顧問、維護與客製化
💡
小任務 / 單次支援方案
單次處理 Shopify 修正/微調
⭐️
維護方案
每月 Shopify 技術支援 + 小修改 + 諮詢
🚀
專案建置
Shopify 功能導入、培訓 + 分階段交付