es 安裝
elasticsearch(理解爲庫) kibana(理解爲連接工具)
es 和 kibana(5601)的版本要保持一致
MySQL 對照學習 Elasticsearch(ES)
術語對照
| MySQL | Elasticsearch |
|---|---|
| database | index(索引) |
| table | type(7.x 起固定爲 _doc,8.x 徹底移除多 type) |
| row | document(文檔) |
| column | field(字段) |
| schema | mapping(映射) |
| sql | DSL(Domain Specific Language 查詢語法) |
說明:自 ES 7.x 起,一個索引只能有一個 type,名稱通常爲 _doc;8.x 中 type 概念對外基本不可見,建模時直接面向「索引 + 映射」。
核心概念速覽
- 索引(index):
- 類似數據庫中的「庫」,同一類文檔的邏輯集合,內部按分片(primary shard)和副本(replica shard)存儲。
- 文檔(document):
- 類似一行數據,JSON 對象,通過
_id唯一標識,可由 ES 自動生成或自定義。 - 字段(field):
- 文檔的屬性,類似列。字段類型影響倒排索引的建立方式和可用查詢。
- 映射(mapping):
- 類似表結構定義,聲明字段類型與索引、分詞方式等。映射一旦發佈,字段類型基本不可變更(需要重建索引並重導數據)。
- 分詞與分析器(analyzer):
- 文本如何被切分成 term 並寫入倒排索引,決定全文檢索效果(中文常用
ik_max_word/ik_smart等第三方插件)。
建模指南(對照 MySQL 思維)
- 先確定查詢維度與檢索方式,再設計字段與映射;不要照搬 MySQL 的第三範式。
- 適度冗餘、去 join 化:ES 沒有跨索引 join,查詢以單索引爲單位;複雜場景用 denormalization 或 nested/parent-child。
- 數值、時間、keyword 與 text 區分清楚:
keyword:精確匹配、聚合、排序;text:全文檢索(會分詞),不適合聚合排序;- 時間用
date,地理位置用geo_point等專用類型。
常見操作對照
- 創建索引(含映射)
SQL(建庫 / 建表 / 字段):
-- MySQL 示例
CREATE DATABASE shop;
CREATE TABLE product (
id BIGINT PRIMARY KEY,
title VARCHAR(255),
price DECIMAL(10,2),
tags JSON
);
ES(建索引 + 映射):
PUT /shop_product
{"settings": {"number_of_shards": 1, "number_of_replicas": 1},
"mappings": {
"properties": {"title": {"type": "text", "analyzer": "standard"},
"price": {"type": "double"},
"tags": {"type": "keyword"},
"createdAt": {"type": "date"}
}
}
}
- 寫入一行 / 文檔
SQL:
INSERT INTO product(id,title,price) VALUES(1,'iPhone',5999.00);
ES:
POST /shop_product/_doc/1
{
"title": "iPhone",
"price": 5999.00,
"tags": ["phone", "apple"],
"createdAt": "2025-09-18T12:00:00Z"
}
- 按主鍵查詢
SQL:
SELECT * FROM product WHERE id=1;
ES:
GET /shop_product/_doc/1
- 條件查詢(DSL vs SQL)
SQL:
SELECT id,title FROM product
WHERE price BETWEEN 3000 AND 8000 AND title LIKE '%phone%'
ORDER BY price DESC LIMIT 10 OFFSET 0;
ES:
POST /shop_product/_search
{
"from": 0,
"size": 10,
"sort": [{"price": "desc"}],
"_source": ["id","title","price"],
"query": {
"bool": {"must": [ {"match": {"title": "phone"}} ],
"filter": [{"range": {"price": {"gte": 3000, "lte": 8000}}} ]
}
}
}
- 更新與刪除
SQL:UPDATE ... WHERE id=? / DELETE FROM ... WHERE id=?
ES:
POST /shop_product/_update/1
{"doc": {"price": 5799}}
DELETE /shop_product/_doc/1
- 聚合(GROUP BY 對照)
SQL:
SELECT tags, COUNT(*) AS cnt FROM product GROUP BY tags;
ES:
POST /shop_product/_search
{
"size": 0,
"aggs": {"by_tag": {"terms": {"field": "tags"}}
}
}
索引生命週期與性能要點
- 分片數在創建索引時確定,後續只能通過重建索引調整;副本數可在線調整。
- 寫多讀少場景:降低副本、提高刷新間隔;讀多:適當增加副本、開啓緩存與合適的字段
doc_values。 - 大改映射 / 類型時採用重建索引(reindex):新索引 -> 導數據 -> 切別名。
Kibana 與端口
- Kibana 默認端口 5601,版本需與 ES 保持一致(7.x 對 7.x,8.x 對 8.x)。
- 在 Kibana Dev Tools 中可直接粘貼上面的 REST/DSL 示例執行。
我們主要是用 es 的查詢功能
GET _search?q=bobby // 會查詢所有的 index
通過 request body 來查詢
Request Body 查詢詳解
ES 支持兩種查詢方式:
- URL 參數查詢:
GET _search?q=field:value(簡單快速) - Request Body 查詢:
POST _search+ JSON body(功能強大,推薦)
爲什麼推薦 Request Body 查詢?
- 功能完整:支持複雜查詢、聚合、排序、分頁等
- 可讀性強:JSON 結構清晰,便於維護
- 性能更好:避免 URL 長度限制,支持更復雜的查詢邏輯
- 調試友好:Kibana Dev Tools 中直接粘貼執行
基礎查詢示例
- 簡單匹配查詢
POST /shop_product/_search
{
"query": {
"match": {"title": "iPhone"}
}
}
- 多條件組合查詢
POST /shop_product/_search
{
"query": {
"bool": {
"must": [{"match": {"title": "phone"}},
{"range": {"price": {"gte": 1000, "lte": 8000}}}
],
"must_not": [{"term": {"status": "discontinued"}}
],
"should": [{"match": {"tags": "apple"}}
]
}
}
}
- 精確匹配 vs 全文搜索
# 精確匹配(不分詞)POST /shop_product/_search
{
"query": {
"term": {"tags": "phone"}
}
}
# 全文搜索(會分詞)POST /shop_product/_search
{
"query": {
"match": {"title": "iPhone 15 Pro"}
}
}
- 分頁與排序
POST /shop_product/_search
{
"from": 0,
"size": 10,
"sort": [{"price": {"order": "desc"}},
{"_score": {"order": "desc"}}
],
"query": {"match_all": {}
}
}
- 指定返回字段
POST /shop_product/_search
{"_source": ["title", "price", "tags"],
"query": {"match_all": {}
}
}
- 聚合查詢(統計)
POST /shop_product/_search
{
"size": 0,
"aggs": {
"price_stats": {"stats": {"field": "price"}
},
"tags_count": {"terms": {"field": "tags", "size": 10}
},
"price_ranges": {
"range": {
"field": "price",
"ranges": [{"to": 1000},
{"from": 1000, "to": 5000},
{"from": 5000}
]
}
}
}
}
- 高亮顯示
POST /shop_product/_search
{
"query": {"match": {"title": "iPhone"}
},
"highlight": {
"fields": {"title": {}
}
}
}
常用查詢類型對照
| 需求 | SQL | ES Request Body |
|---|---|---|
| 全表掃描 | SELECT * FROM table |
{"query": {"match_all": {}}} |
| 精確匹配 | WHERE id = 1 |
{"query": {"term": {"id": 1}}} |
| 模糊匹配 | WHERE title LIKE '%phone%' |
{"query": {"match": {"title": "phone"}}} |
| 範圍查詢 | WHERE price BETWEEN 1000 AND 5000 |
{"query": {"range": {"price": {"gte": 1000, "lte": 5000}}}} |
| 多條件 AND | WHERE a=1 AND b=2 |
{"query": {"bool": {"must": [{"term": {"a": 1}}, {"term": {"b": 2}}]}}} |
| 多條件 OR | WHERE a=1 OR b=2 |
{"query": {"bool": {"should": [{"term": {"a": 1}}, {"term": {"b": 2}}]}}} |
| 分組統計 | SELECT tag, COUNT(*) FROM table GROUP BY tag |
{"aggs": {"by_tag": {"terms": {"field": "tag"}}}} |
性能優化建議
- 使用 filter 而非 query:filter 不計算相關性分數,性能更好
POST /shop_product/_search
{
"query": {
"bool": {
"filter": [{"range": {"price": {"gte": 1000}}}
]
}
}
}
- 合理使用 size:避免一次性返回大量數據
- 使用 _source 過濾:只返回需要的字段
- 緩存常用查詢:ES 會自動緩存 filter 查詢結果
POST 更新操作詳解
ES 中的更新操作有兩種方式:覆蓋更新 和部分更新,理解它們的區別很重要。
1. 覆蓋更新(PUT 方式)
特點:完全替換整個文檔,未指定的字段會被刪除
# 原始文檔
{
"id": 1,
"title": "iPhone 15",
"price": 5999,
"tags": ["phone", "apple"],
"description": " 最新款 iPhone",
"stock": 100
}
# 覆蓋更新(只保留指定的字段)PUT /shop_product/_doc/1
{
"title": "iPhone 15 Pro",
"price": 7999
}
# 更新後的文檔(description 和 stock 字段被刪除){
"id": 1,
"title": "iPhone 15 Pro",
"price": 7999
}
2. 部分更新(POST _update 方式)
特點:只更新指定字段,其他字段保持不變
# 原始文檔
{
"id": 1,
"title": "iPhone 15",
"price": 5999,
"tags": ["phone", "apple"],
"description": " 最新款 iPhone",
"stock": 100
}
# 部分更新(只更新指定字段)POST /shop_product/_update/1
{
"doc": {
"title": "iPhone 15 Pro",
"price": 7999
}
}
# 更新後的文檔(其他字段保持不變){
"id": 1,
"title": "iPhone 15 Pro",
"price": 7999,
"tags": ["phone", "apple"],
"description": " 最新款 iPhone",
"stock": 100
}
3. 高級更新操作
3.1 條件更新(upsert)
如果文檔不存在則創建,存在則更新:
POST /shop_product/_update/999
{
"doc": {
"title": " 新商品 ",
"price": 1000
},
"upsert": {
"title": " 新商品 ",
"price": 1000,
"tags": ["new"],
"created_at": "2025-01-18"
}
}
3.2 腳本更新
使用腳本進行復雜更新:
# 增加庫存
POST /shop_product/_update/1
{
"script": {
"source": "ctx._source.stock += params.increment",
"params": {"increment": 50}
}
}
# 條件更新(只有價格大於 5000 才更新)POST /shop_product/_update/1
{
"script": {"source": "if (ctx._source.price > 5000) {ctx._source.price = params.new_price}",
"params": {"new_price": 7500}
}
}
3.3 數組操作
# 添加標籤
POST /shop_product/_update/1
{
"script": {"source": "if (ctx._source.tags == null) {ctx._source.tags = [] } ctx._source.tags.add(params.tag)",
"params": {"tag": "premium"}
}
}
# 移除標籤
POST /shop_product/_update/1
{
"script": {"source": "ctx._source.tags.removeIf(item -> item == params.tag)",
"params": {"tag": "old"}
}
}
4. 批量更新
POST /shop_product/_bulk
{"update":{"_id":"1"}}
{"doc":{"price":5999}}
{"update":{"_id":"2"}}
{"doc":{"price":6999}}
{"update":{"_id":"3"}}
{"doc":{"price":7999}}
5. 更新操作對比表
| 操作方式 | 方法 | 特點 | 適用場景 |
|---|---|---|---|
| 覆蓋更新 | PUT /index/_doc/id |
完全替換文檔 | 文檔結構變化大,需要刪除字段 |
| 部分更新 | POST /index/_update/id |
只更新指定字段 | 日常業務更新,保留其他字段 |
| 條件更新 | POST /index/_update/id + upsert |
存在則更新,不存在則創建 | 不確定文檔是否存在 |
| 腳本更新 | POST /index/_update/id + script |
複雜邏輯更新 | 需要計算、條件判斷的更新 |
6. 性能注意事項
- 部分更新性能更好:只傳輸變更的字段,減少網絡開銷
- 腳本更新較慢:需要解析和執行腳本,性能相對較低
- 批量操作:大量更新時使用
_bulkAPI 提高效率 - 版本控制:ES 自動處理併發更新衝突,通過
_version字段
刪除數據操作詳解
ES 中的刪除操作有多種方式,從單個文檔刪除到整個索引刪除,理解不同場景下的刪除方法很重要。
1. 刪除單個文檔
1.1 按 ID 刪除
# 刪除指定 ID 的文檔
DELETE /shop_product/_doc/1
# 響應示例
{
"_index": "shop_product",
"_id": "1",
"_version": 2,
"result": "deleted",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
}
}
1.2 條件刪除(通過查詢)
# 刪除價格小於 1000 的所有商品
POST /shop_product/_delete_by_query
{
"query": {
"range": {
"price": {"lt": 1000}
}
}
}
# 刪除包含特定標籤的商品
POST /shop_product/_delete_by_query
{
"query": {
"term": {"tags": "discontinued"}
}
}
2. 批量刪除
2.1 使用 _bulk API
POST /shop_product/_bulk
{"delete":{"_id":"1"}}
{"delete":{"_id":"2"}}
{"delete":{"_id":"3"}}
2.2 批量條件刪除
# 刪除多個條件的商品
POST /shop_product/_delete_by_query
{
"query": {
"bool": {
"should": [{"term": {"status": "discontinued"}},
{"range": {"last_updated": {"lt": "2020-01-01"}}}
]
}
}
}
3. 刪除整個索引
# 刪除整個索引(危險操作!)DELETE /shop_product
# 響應示例
{"acknowledged": true}
4. 刪除索引中的類型(7.x 以下版本)
# 刪除索引中的特定類型(僅適用於 6.x 及以下版本)DELETE /shop_product/product_type
5. 高級刪除操作
5.1 帶版本控制的刪除
# 只有版本匹配時才刪除(防止併發刪除)DELETE /shop_product/_doc/1?version=1&version_type=external
5.2 異步刪除大量數據
# 異步刪除(適用於大量數據)POST /shop_product/_delete_by_query
{
"query": {"match_all": {}
},
"wait_for_completion": false,
"conflicts": "proceed"
}
# 響應包含任務 ID,可用於查詢刪除進度
{"task": "r1A2WoRbTwKZ516z6NEs5A:36619"}
# 查詢任務狀態
GET /_tasks/r1A2WoRbTwKZ516z6NEs5A:36619
5.3 刪除時保留快照
# 刪除前創建快照(備份)PUT /_snapshot/backup_repo/snapshot_before_delete
{
"indices": "shop_product",
"ignore_unavailable": true,
"include_global_state": false
}
# 然後執行刪除操作
POST /shop_product/_delete_by_query
{
"query": {
"range": {
"created_at": {"lt": "2020-01-01"}
}
}
}
6. 刪除操作對比表
| 刪除方式 | 方法 | 特點 | 適用場景 |
|---|---|---|---|
| 按 ID 刪除 | DELETE /index/_doc/id |
精確刪除單個文檔 | 已知文檔 ID 的刪除 |
| 條件刪除 | POST /index/_delete_by_query |
根據查詢條件刪除 | 批量刪除符合條件的文檔 |
| 批量刪除 | POST /index/_bulk |
一次刪除多個指定文檔 | 已知多個文檔 ID 的刪除 |
| 刪除索引 | DELETE /index |
刪除整個索引 | 清理測試數據或重建索引 |
| 異步刪除 | _delete_by_query + wait_for_completion:false |
不阻塞,後臺執行 | 刪除大量數據時避免超時 |
7. 刪除操作注意事項
7.1 性能考慮
# 大量刪除時使用滾動查詢提高性能
POST /shop_product/_delete_by_query
{
"query": {
"range": {
"price": {"lt": 100}
}
},
"scroll_size": 1000,
"conflicts": "proceed"
}
7.2 安全刪除
# 刪除前先查詢確認
POST /shop_product/_search
{
"query": {
"range": {
"price": {"lt": 100}
}
},
"size": 0
}
# 確認無誤後再執行刪除
POST /shop_product/_delete_by_query
{
"query": {
"range": {
"price": {"lt": 100}
}
}
}
7.3 刪除監控
# 監控刪除進度
GET /_tasks?detailed=true&actions=*delete*
# 取消刪除任務
POST /_tasks/task_id/_cancel
8. 刪除 vs 軟刪除
在實際業務中,通常使用軟刪除而不是物理刪除:
# 軟刪除:標記爲已刪除
POST /shop_product/_update/1
{
"doc": {
"deleted": true,
"deleted_at": "2025-01-18T12:00:00Z"
}
}
# 查詢時排除已刪除的文檔
POST /shop_product/_search
{
"query": {
"bool": {
"must": [{"match": {"title": "iPhone"}}
],
"must_not": [{"term": {"deleted": true}}
]
}
}
}
9. 恢復已刪除的數據
ES 刪除的數據無法直接恢復,但可以通過以下方式:
- 從快照恢復:如果之前創建了快照
- 從備份恢復:如果有數據備份
- 重新導入:從原始數據源重新導入
# 從快照恢復索引
POST /_snapshot/backup_repo/snapshot_name/_restore
{
"indices": "shop_product",
"ignore_unavailable": true,
"include_global_state": false
}
批量插入操作詳解
ES 中的批量插入是處理大量數據的高效方式,通過 _bulk API 可以一次性執行多個操作,包括插入、更新、刪除等。
1. 基礎批量插入
1.1 使用 _bulk API 插入
POST /shop_product/_bulk
{"index":{"_id":"1"}}
{"title":"iPhone 15","price":5999,"tags":["phone","apple"],"stock":100}
{"index":{"_id":"2"}}
{"title":"Samsung Galaxy","price":4999,"tags":["phone","android"],"stock":50}
{"index":{"_id":"3"}}
{"title":"MacBook Pro","price":12999,"tags":["laptop","apple"],"stock":20}
1.2 自動生成 ID 的批量插入
POST /shop_product/_bulk
{"index":{}}
{"title":"iPad Air","price":3999,"tags":["tablet","apple"],"stock":30}
{"index":{}}
{"title":"Dell XPS","price":8999,"tags":["laptop","windows"],"stock":15}
{"index":{}}
{"title":"Surface Pro","price":6999,"tags":["tablet","windows"],"stock":25}
2. 混合批量操作
POST /shop_product/_bulk
{"index":{"_id":"10"}}
{"title":" 新商品 1 ","price":1000,"tags":["new"],"stock":100}
{"update":{"_id":"1"}}
{"doc":{"price":5799}}
{"delete":{"_id":"2"}}
{"index":{"_id":"11"}}
{"title":" 新商品 2 ","price":2000,"tags":["new"],"stock":200}
3. 批量插入響應處理
# 批量操作響應示例
{
"took": 30,
"errors": false,
"items": [
{
"index": {
"_index": "shop_product",
"_id": "1",
"_version": 1,
"result": "created",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"status": 201
}
},
{
"index": {
"_index": "shop_product",
"_id": "2",
"_version": 1,
"result": "created",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"status": 201
}
}
]
}
4. 錯誤處理
4.1 檢查批量操作中的錯誤
# 包含錯誤的批量操作
POST /shop_product/_bulk
{"index":{"_id":"1"}}
{"title":" 商品 1 ","price":1000}
{"index":{"_id":"1"}} # 重複 ID,會產生錯誤
{"title":" 商品 2 ","price":2000}
# 響應中的錯誤信息
{
"took": 5,
"errors": true,
"items": [
{
"index": {
"_index": "shop_product",
"_id": "1",
"status": 201,
"result": "created"
}
},
{
"index": {
"_index": "shop_product",
"_id": "1",
"status": 409,
"error": {
"type": "version_conflict_engine_exception",
"reason": "[1]: version conflict, document already exists"
}
}
}
]
}
4.2 處理部分失敗的情況
# 使用 filter_path 只返回錯誤項
POST /shop_product/_bulk?filter_path=items.*.error
{"index":{"_id":"1"}}
{"title":" 商品 1 ","price":1000}
{"index":{"_id":"1"}}
{"title":" 商品 2 ","price":2000}
5. 性能優化
5.1 批量大小控制
# 推薦的批量大小:1000-5000 個文檔
POST /shop_product/_bulk
{"index":{"_id":"1"}}
{"title":" 商品 1 ","price":1000}
# ... 更多文檔
{"index":{"_id":"1000"}}
{"title":" 商品 1000","price":1000}
5.2 刷新策略
# 批量插入時不立即刷新(提高性能)POST /shop_product/_bulk?refresh=false
{"index":{"_id":"1"}}
{"title":" 商品 1 ","price":1000}
{"index":{"_id":"2"}}
{"title":" 商品 2 ","price":2000}
# 批量插入後手動刷新
POST /shop_product/_refresh
5.3 併發控制
# 設置批量操作的超時時間
POST /shop_product/_bulk?timeout=60s
{"index":{"_id":"1"}}
{"title":" 商品 1 ","price":1000}
6. 從文件批量導入
6.1 準備數據文件
# data.json 文件內容
{"index":{"_id":"1"}}
{"title":" 商品 1 ","price":1000,"tags":["tag1"],"stock":100}
{"index":{"_id":"2"}}
{"title":" 商品 2 ","price":2000,"tags":["tag2"],"stock":200}
{"index":{"_id":"3"}}
{"title":" 商品 3 ","price":3000,"tags":["tag3"],"stock":300}
6.2 使用 curl 導入
# 從文件批量導入
curl -X POST "localhost:9200/shop_product/_bulk" \
-H "Content-Type: application/json" \
--data-binary @data.json
7. 批量插入最佳實踐
7.1 數據預處理
# 批量插入前先創建索引和映射
PUT /shop_product
{
"settings": {
"number_of_shards": 1,
"number_of_replicas": 0
},
"mappings": {
"properties": {"title": {"type": "text", "analyzer": "standard"},
"price": {"type": "double"},
"tags": {"type": "keyword"},
"stock": {"type": "integer"}
}
}
}
7.2 分批處理大量數據
# 分批插入大量數據
POST /shop_product/_bulk
{"index":{"_id":"1"}}
{"title":" 商品 1 ","price":1000}
# ... 1000 個文檔
# 等待一段時間後繼續下一批
POST /shop_product/_bulk
{"index":{"_id":"1001"}}
{"title":" 商品 1001","price":1000}
# ... 下一批 1000 個文檔
7.3 監控批量插入進度
# 檢查索引狀態
GET /shop_product/_stats
# 檢查文檔數量
GET /shop_product/_count
# 檢查索引健康狀態
GET /_cluster/health/shop_product
8. 批量插入 vs 單個插入對比
| 操作方式 | 方法 | 性能 | 適用場景 |
|---|---|---|---|
| 單個插入 | POST /index/_doc |
較慢 | 少量數據,實時插入 |
| 批量插入 | POST /index/_bulk |
很快 | 大量數據,批量導入 |
| 混合操作 | POST /index/_bulk |
中等 | 需要同時插入、更新、刪除 |
9. 常見問題解決
9.1 內存不足
# 減少批量大小
POST /shop_product/_bulk
# 只包含 500 個文檔而不是 1000 個
9.2 超時問題
# 增加超時時間
POST /shop_product/_bulk?timeout=120s
9.3 版本衝突
# 使用 upsert 避免版本衝突
POST /shop_product/_bulk
{"update":{"_id":"1"}}
{"doc":{"price":1000},"upsert":{"title":" 商品 1 ","price":1000}}
10. 批量插入監控
# 監控批量操作性能
GET /_nodes/stats/indices/indexing
# 查看索引統計
GET /shop_product/_stats/indexing
# 監控集羣狀態
GET /_cluster/health?pretty
mget 批量獲取操作詳解
ES 中的 mget(multi-get)API 允許一次性獲取多個文檔,比單個獲取更高效,特別適合需要批量讀取數據的場景。
1. 基礎批量獲取
1.1 從同一索引獲取多個文檔
POST /shop_product/_mget
{
"docs": [{"_id": "1"},
{"_id": "2"},
{"_id": "3"}
]
}
1.2 從不同索引獲取文檔
POST /_mget
{
"docs": [{"_index": "shop_product", "_id": "1"},
{"_index": "shop_user", "_id": "100"},
{"_index": "shop_order", "_id": "200"}
]
}
1.3 指定返回字段
POST /shop_product/_mget
{
"docs": [
{
"_id": "1",
"_source": ["title", "price"]
},
{
"_id": "2",
"_source": ["title", "tags"]
}
]
}
2. 批量獲取響應處理
# mget 響應示例
{
"docs": [
{
"_index": "shop_product",
"_id": "1",
"_version": 1,
"_seq_no": 0,
"_primary_term": 1,
"found": true,
"_source": {
"title": "iPhone 15",
"price": 5999,
"tags": ["phone", "apple"],
"stock": 100
}
},
{
"_index": "shop_product",
"_id": "2",
"_version": 1,
"_seq_no": 1,
"_primary_term": 1,
"found": true,
"_source": {
"title": "Samsung Galaxy",
"price": 4999,
"tags": ["phone", "android"],
"stock": 50
}
},
{
"_index": "shop_product",
"_id": "999",
"found": false
}
]
}
3. 高級批量獲取
3.1 使用 ids 參數(簡化語法)
POST /shop_product/_mget
{"ids": ["1", "2", "3", "999"]
}
3.2 排除不需要的字段
POST /shop_product/_mget
{
"docs": [
{
"_id": "1",
"_source": {"excludes": ["description", "created_at"]
}
},
{
"_id": "2",
"_source": {"includes": ["title", "price"]
}
}
]
}
3.3 獲取存儲字段
POST /shop_product/_mget
{
"docs": [
{
"_id": "1",
"stored_fields": ["title", "price"]
}
]
}
4. 批量獲取性能優化
4.1 合理控制批量大小
# 推薦的批量大小:100-1000 個文檔
POST /shop_product/_mget
{
"ids": [
"1", "2", "3", "4", "5",
# ... 更多 ID
"100"
]
}
4.2 使用路由優化
POST /shop_product/_mget
{
"docs": [
{
"_id": "1",
"routing": "user123"
},
{
"_id": "2",
"routing": "user123"
}
]
}
5. 錯誤處理
5.1 處理不存在的文檔
POST /shop_product/_mget
{"ids": ["1", "999", "2"]
}
# 響應中包含 found: false 的文檔
{
"docs": [
{
"_index": "shop_product",
"_id": "1",
"found": true,
"_source": {...}
},
{
"_index": "shop_product",
"_id": "999",
"found": false
},
{
"_index": "shop_product",
"_id": "2",
"found": true,
"_source": {...}
}
]
}
5.2 過濾不存在的文檔
# 只返回找到的文檔
POST /shop_product/_mget?filter_path=docs._source
{"ids": ["1", "999", "2"]
}
6. 實際應用場景
6.1 購物車商品信息獲取
# 根據購物車中的商品 ID 批量獲取商品信息
POST /shop_product/_mget
{"ids": ["cart_item_1", "cart_item_2", "cart_item_3"]
}
6.2 用戶訂單詳情獲取
# 批量獲取用戶的所有訂單詳情
POST /shop_order/_mget
{
"docs": [{"_id": "order_001", "_source": ["order_id", "total", "status"]},
{"_id": "order_002", "_source": ["order_id", "total", "status"]},
{"_id": "order_003", "_source": ["order_id", "total", "status"]}
]
}
6.3 跨索引數據關聯
# 同時獲取用戶信息和用戶訂單
POST /_mget
{
"docs": [{"_index": "shop_user", "_id": "user_123", "_source": ["name", "email"]},
{"_index": "shop_order", "_id": "order_456", "_source": ["order_id", "total"]},
{"_index": "shop_product", "_id": "product_789", "_source": ["title", "price"]}
]
}
7. mget vs 單個獲取對比
| 操作方式 | 方法 | 性能 | 適用場景 |
|---|---|---|---|
| 單個獲取 | GET /index/_doc/id |
較慢 | 獲取單個文檔 |
| 批量獲取 | POST /index/_mget |
很快 | 批量獲取多個文檔 |
| 搜索獲取 | POST /index/_search |
中等 | 根據條件獲取文檔 |
8. 批量獲取最佳實踐
8.1 數據預處理
# 批量獲取前先檢查索引狀態
GET /shop_product/_stats
# 檢查文檔是否存在
GET /shop_product/_count
8.2 分批處理大量數據
# 分批獲取大量文檔
POST /shop_product/_mget
{"ids": ["1", "2", "3", "4", "5"]
# 第一批 100 個文檔
}
# 繼續下一批
POST /shop_product/_mget
{"ids": ["6", "7", "8", "9", "10"]
# 下一批 100 個文檔
}
8.3 緩存策略
# 使用緩存提高性能
POST /shop_product/_mget?preference=_local
{"ids": ["1", "2", "3"]
}
9. 常見問題解決
9.1 內存不足
# 減少批量大小
POST /shop_product/_mget
{"ids": ["1", "2", "3"] # 只獲取 3 個文檔
}
9.2 超時問題
# 增加超時時間
POST /shop_product/_mget?timeout=60s
{"ids": ["1", "2", "3"]
}
9.3 索引不存在
# 處理索引不存在的情況
POST /_mget
{
"docs": [{"_index": "shop_product", "_id": "1"},
{"_index": "non_existent_index", "_id": "2"}
]
}
10. 批量獲取監控
# 監控批量獲取性能
GET /_nodes/stats/indices/search
# 查看索引搜索統計
GET /shop_product/_stats/search
# 監控集羣狀態
GET /_cluster/health?pretty
11. 與其他批量操作結合
11.1 批量獲取 + 批量更新
# 先批量獲取
POST /shop_product/_mget
{"ids": ["1", "2", "3"]
}
# 然後批量更新
POST /shop_product/_bulk
{"update":{"_id":"1"}}
{"doc":{"stock":95}}
{"update":{"_id":"2"}}
{"doc":{"stock":45}}
{"update":{"_id":"3"}}
{"doc":{"stock":15}}
11.2 批量獲取 + 搜索
# 先搜索獲取相關文檔 ID
POST /shop_product/_search
{"query": {"match": {"tags": "phone"}},
"_source": false,
"size": 10
}
# 然後批量獲取詳細信息
POST /shop_product/_mget
{"ids": ["1", "2", "3", "4", "5"]
}
ES 的 query:{} 功能詳解
ES 中的 query 是搜索請求的核心部分,用於定義搜索條件和邏輯。query:{} 是一個空的查詢對象,通常與 match_all 結合使用。
1. query 對象基礎結構
POST /shop_product/_search
{
"query": {// 查詢條件定義在這裏}
}
2. 常用查詢類型
2.1 match_all 查詢(全表掃描)
POST /shop_product/_search
{
"query": {"match_all": {}
}
}
功能說明:
- 匹配索引中的所有文檔
- 相當於 SQL 中的
SELECT * FROM table - 常用於獲取所有數據或作爲基礎查詢
2.2 match 查詢(全文搜索)
POST /shop_product/_search
{
"query": {
"match": {"title": "iPhone"}
}
}
功能說明:
- 對指定字段進行全文搜索
- 會對查詢詞進行分詞處理
- 支持模糊匹配和相關性評分
2.3 term 查詢(精確匹配)
POST /shop_product/_search
{
"query": {
"term": {"tags": "phone"}
}
}
功能說明:
- 精確匹配,不進行分詞
- 適用於 keyword 類型字段
- 性能比 match 查詢更好
2.4 range 查詢(範圍查詢)
POST /shop_product/_search
{
"query": {
"range": {
"price": {
"gte": 1000,
"lte": 5000
}
}
}
}
功能說明:
- 對數值、日期等字段進行範圍查詢
- 支持
gte(大於等於)、gt(大於)、lte(小於等於)、lt(小於) - 常用於價格區間、時間範圍等查詢
2.5 bool 查詢(複合查詢)
POST /shop_product/_search
{
"query": {
"bool": {
"must": [{"match": {"title": "phone"}},
{"range": {"price": {"gte": 1000}}}
],
"must_not": [{"term": {"status": "discontinued"}}
],
"should": [{"match": {"tags": "apple"}}
],
"filter": [{"term": {"category": "electronics"}}
]
}
}
}
功能說明:
must:必須匹配,影響相關性評分must_not:必須不匹配,不影響評分should:應該匹配,提高相關性評分filter:必須匹配,但不影響評分,性能更好
2.6 wildcard 查詢(通配符查詢)
POST /shop_product/_search
{
"query": {
"wildcard": {
"title": {"value": "iPh*"}
}
}
}
功能說明:
- 支持
*(匹配任意字符)和?(匹配單個字符) - 性能較慢,不推薦在大量數據上使用
- 適用於模糊匹配場景
2.7 prefix 查詢(前綴查詢)
POST /shop_product/_search
{
"query": {
"prefix": {"title": "iPh"}
}
}
功能說明:
- 匹配以指定前綴開頭的文檔
- 適用於自動補全、搜索建議等場景
- 性能比 wildcard 查詢更好
2.8 fuzzy 查詢(模糊查詢)
POST /shop_product/_search
{
"query": {
"fuzzy": {
"title": {
"value": "iphone",
"fuzziness": "AUTO"
}
}
}
}
功能說明:
- 支持拼寫錯誤的容錯查詢
fuzziness參數控制容錯程度- 適用於搜索糾錯場景
3. 查詢性能優化
3.1 使用 filter 而非 query
POST /shop_product/_search
{
"query": {
"bool": {
"filter": [{"range": {"price": {"gte": 1000}}}
]
}
}
}
優勢:
- filter 不計算相關性評分,性能更好
- 結果會被緩存,重複查詢更快
- 適用於精確匹配條件
3.2 合理使用 _source 過濾
POST /shop_product/_search
{"_source": ["title", "price"],
"query": {"match_all": {}
}
}
優勢:
- 只返回需要的字段,減少網絡傳輸
- 提高查詢性能
- 降低內存使用
3.3 使用 size 控制返回數量
POST /shop_product/_search
{
"size": 10,
"query": {"match_all": {}
}
}
優勢:
- 避免一次性返回大量數據
- 提高查詢響應速度
- 減少內存消耗
4. 查詢調試技巧
4.1 使用 explain 參數
POST /shop_product/_search
{
"explain": true,
"query": {
"match": {"title": "iPhone"}
}
}
功能:
- 顯示每個文檔的評分計算過程
- 幫助理解查詢結果排序原因
- 用於查詢優化和調試
4.2 使用 profile 參數
POST /shop_product/_search
{
"profile": true,
"query": {
"bool": {
"must": [{"match": {"title": "phone"}},
{"range": {"price": {"gte": 1000}}}
]
}
}
}
功能:
- 顯示查詢執行的詳細時間信息
- 幫助識別性能瓶頸
- 用於查詢性能優化
5. 查詢最佳實踐
5.1 查詢結構優化
# 好的查詢結構
POST /shop_product/_search
{
"query": {
"bool": {
"must": [{"match": {"title": "phone"}}
],
"filter": [{"range": {"price": {"gte": 1000, "lte": 5000}}},
{"term": {"status": "active"}}
]
}
},
"sort": [{"price": "desc"}],
"size": 20
}
5.2 避免深度分頁
# 使用 search_after 替代 from/size
POST /shop_product/_search
{"query": {"match_all": {}},
"size": 100,
"sort": [{"_id": "asc"}],
"search_after": ["last_doc_id"]
}
5.3 合理使用聚合
POST /shop_product/_search
{
"size": 0,
"aggs": {
"price_stats": {"stats": {"field": "price"}
},
"tags_count": {"terms": {"field": "tags", "size": 10}
}
}
}
6. 常見查詢模式
6.1 搜索 + 過濾
POST /shop_product/_search
{
"query": {
"bool": {
"must": [{"match": {"title": " 用戶搜索詞 "}}
],
"filter": [{"term": {"category": "electronics"}},
{"range": {"price": {"gte": 1000}}}
]
}
}
}
6.2 多字段搜索
POST /shop_product/_search
{
"query": {
"multi_match": {
"query": "iPhone",
"fields": ["title^2", "description", "tags"]
}
}
}
6.3 嵌套對象查詢
POST /shop_product/_search
{
"query": {
"nested": {
"path": "reviews",
"query": {
"bool": {
"must": [{"match": {"reviews.comment": "good"}},
{"range": {"reviews.rating": {"gte": 4}}}
]
}
}
}
}
}
7. 查詢性能監控
# 監控查詢性能
GET /_nodes/stats/indices/search
# 查看慢查詢日誌
GET /_nodes/stats/indices/search?filter_path=*.search.query_time_in_millis
# 監控集羣查詢狀態
GET /_cluster/health?pretty
8. 查詢錯誤處理
8.1 處理查詢語法錯誤
# 錯誤的查詢
POST /shop_product/_search
{
"query": {
"match": {
"title": "iPhone"
// 缺少閉合括號
}
}
}
# 錯誤響應
{
"error": {
"type": "parsing_exception",
"reason": "Unexpected end-of-input"
}
}
8.2 處理字段不存在錯誤
# 查詢不存在的字段
POST /shop_product/_search
{
"query": {
"match": {"non_existent_field": "value"}
}
}
# 響應(不會報錯,但不會匹配任何文檔){
"hits": {"total": {"value": 0, "relation": "eq"},
"hits": []}
}
9. 查詢緩存策略
# 使用查詢緩存
POST /shop_product/_search
{
"query": {
"bool": {
"filter": [{"term": {"category": "electronics"}}
]
}
}
}
# 緩存會被自動使用,提高重複查詢性能
10. 總結
ES 的 query:{} 功能是搜索的核心,掌握各種查詢類型和優化技巧對於構建高性能的搜索應用至關重要:
- 基礎查詢:match_all、match、term、range
- 複合查詢:bool 查詢組合多個條件
- 性能優化:合理使用 filter、_source 過濾、size 控制
- 調試技巧:explain 和 profile 參數
- 最佳實踐:避免深度分頁、合理使用聚合、監控性能
通過合理使用這些查詢功能,可以構建出高效、準確的搜索系統。