ES是一個開源的高擴展的分布式全文檢索引擎
在項目已有mysql增刪改查的情況下,新增kafka,es流程
用戶新增/修改商家(寫MySQL)
↓
Kafka 生產者發送商家數據消息
↓
Kafka 消費者監聽消息 → 寫入 Elasticsearch
↓
前端搜索商家時 → 查詢 Elasticsearch(不是 MySQL)
這個 Kafka + Elasticsearch 的寫入同步 + 搜索解耦架構 是目前絕大多數中大型互聯網企業的標準做法
一、為什么不能只查 MySQL而引入es查詢?
傳統做法的問題:
比如你在前端搜索商家名稱“李大壯”,如果查的是 MySQL:
SELECT * FROM merchant WHERE name LIKE '%李大壯%' OR description LIKE '%李大壯%' LIMIT 10;
問題:
- 慢:LIKE + 多字段模糊查詢在數據量大時性能非常差;
- 不智能:MySQL 的模糊匹配不支持分詞、不支持排序打分;
- 不靈活:無法實現“相關度排序”“拼音搜索”“短語匹配”等搜索場景。
所以,企業通常引入 Elasticsearch(簡稱 ES)來替代 MySQL 作為 搜索引擎。
二、為什么 MySQL 改動不直接同步到 Elasticsearch,而是先發 Kafka?
這是你最關鍵的問題:為什么加一層 Kafka?
原因一:解耦系統,避免寫 ES 出錯影響主業務
-
如果你直接在寫 MySQL 后同時寫 ES,那么:
- 如果 ES 掛了、網絡抖動、接口異常等,會導致整個商家創建流程失敗;
- Kafka 相當于消息緩沖器 + 解耦層,即便 ES 掛了,Kafka 消息還能繼續收集,等恢復后繼續消費。
原因二:可支持異步、并發、大吞吐處理
- Kafka 是高吞吐分布式系統,支持水平擴展(通過分區);
- 消費者可以并行處理,批量寫入 ES,系統更加穩定、可擴展。
原因三:可拓展更多下游系統,不只是 Elasticsearch
未來你可能還需要這些:
- 同步商家數據到 Redis 緩存(做秒級展示);
- 觸發推送服務(比如新商家上線通知);
- 同步用戶畫像系統、數據倉庫。
如果有 Kafka,你只需要新增一個消費者;
如果沒有 Kafka,你要改源代碼、邏輯復雜,非常不利于維護。
三、流程總結:企業為什么這樣做?
階段 | 系統 | 作用 |
---|---|---|
1 | MySQL | 業務主庫,負責存儲真實、結構化的數據 |
2 | Kafka | 消息中間件,做異步解耦、緩沖和流式處理 |
3 | Elasticsearch | 專用于搜索,支持全文檢索、相關度評分等搜索功能 |
4 | 前端 | 直接查 ES,提升搜索速度、支持搜索功能增強 |
四、圖示結構(簡化):
用戶操作前端↓后端寫 MySQL(商家表)↓┌────→ Kafka ←────┐│ │Kafka Consumer │(可以多個系統消費)↓ ↓
ElasticSearch Redis/OLAP等其他系統↓
前端搜索
es查詢使用案例
query := map[string]interface{}{// DSL 查詢主體"query": map[string]interface{}{"bool": map[string]interface{}{ // bool 組合查詢(企業中常用)"must": []interface{}{ // must 表示“必須匹配”的條件,全部滿足才返回map[string]interface{}{"multi_match": map[string]interface{}{ // 多字段模糊匹配"query": in.Keyword, // 用戶輸入的搜索關鍵詞(如“口腔”)"fields": []string{"name", "business", "address"},"type": "most_fields", // type: most_fields → 各字段各自打分后相加,適合字段內容差異大;另一個選項 cross_fields 更適合字段語義接近。},},},"filter": filters, // 精準過濾器(如按省市區篩選,不能容忍模糊匹配)"should": []interface{}{ // 加分項,提升命中相關性map[string]interface{}{"match_phrase": map[string]interface{}{ "name": in.Keyword, // 要求關鍵詞“完整連續地”出現在 name 中才能加分(如“牙科診所”)},},map[string]interface{}{"match_phrase": map[string]interface{}{"business": in.Keyword, // business 完整短語匹配},},},// 注:should 不設置 minimum_should_match 時,不滿足不會過濾掉,只是不加分},},// 分頁設置"from": (in.Page - 1) * in.PerPage, // 從第幾條開始取數據(起始位置)"size": in.PerPage, // 每頁返回多少條// 排序設置"sort": []interface{}{map[string]interface{}{"order_score": "desc", // 業務字段排序:order_score 是你在 merchant 映射里定義的字段,值越大代表權重越高。// 通常用于控制:優質商家排前面(如人工打分、運營配置)},},
}// -----------------
// 構造查詢DSL// DSL:Domain-Specific Language(領域特定語言)// 這里表示一段用于構建或解析 Elasticsearch 查詢語句的邏輯query := map[string]interface{}{"query": map[string]interface{}{"bool": map[string]interface{}{"must": []interface{}{map[string]interface{}{"multi_match": map[string]interface{}{ // multi_match 該字段使得查詢支持不同類型的匹配模式// type 參數控制多字段匹配的方式,主要有兩種:"query": in.Keyword,"fields": []string{"name", "business", "address"},"type": "most_fields", // 1.most_fields:把多個字段匹配結果 分開 算分,最后相加// 2.cross_fields:把多個字段 和在一起 匹配(適合同一個詞,可能出現在name和business這種的情況)// 分數(score):Elasticsearch內部計算的相關度分值,用于衡量文檔與查詢的匹配程度,// 數值越大說明匹配越好,搜索結果排序默認會根據這個分數降序排列。},},},"filter": filters,// 其中should字段,主要作用是在滿足上述條件下,增加相關度,縮小搜索范圍。"should": []interface{}{ // should:表示“或”關系,滿足should中條件的文檔會被加分,提高其相關度排序,// 但文檔不一定非要滿足should中的條件才能匹配整個查詢(除非設置minimum_should_match)。// 下面2map的效果:如果傳入的name和business是能完全匹配的,則會獲得更高的相關度評分。map[string]interface{}{"match_phrase": map[string]interface{}{ // match_phrase 是短語匹配,要求查詢詞,是順序的不拆分的,否則匹配失敗。"name": in.Keyword,},},map[string]interface{}{"match_phrase": map[string]interface{}{"business": in.Keyword,},},},},},"from": (in.Page - 1) * in.PerPage,"size": in.PerPage,"sort": []interface{}{ // 按照評分排序map[string]interface{}{"order_score": "desc"}, // 降序},}
https://github.com/0voice