目錄
Elasticsearch查詢分類
葉子查詢
全文檢索查詢
match查詢
multi_match查詢
精確查詢
term查詢
range查詢
復雜查詢
bool查詢簡單應用
bool查詢實現排序和分頁
bool查詢實現高亮
場景分析
問題思考
解決方案
?search_after方案(推薦)
point in time方案
方案比較
Elasticsearch查詢分類
Elasticsearch的查詢可以分為兩大類:
葉子查詢(Leaf query clauses):一般是在特定的字段里查詢特定值,屬于簡單查詢,很少單獨使用。
復合查詢(Compound query clauses):以邏輯方式組合多個葉子查詢或者更改葉子查詢的行為方式。
葉子查詢
全文檢索查詢
用分詞器對用戶輸入搜索條件先分詞,得到詞條,然后再利用倒排索引搜索詞條。
match查詢
可以以一個分詞,例如"GB"得到所有name中帶“GB”的數據
# match查詢所有
GET /items/_search
{"query": {"match": {"name": "GB"}}
}
實現效果如下:(總共有17條數據中name有“GB”)
multi_match查詢
與match
類似的還有multi_match
,區別在于可以同時對多個字段搜索,而且多個字段都要滿足,語法示例:
GET /items/_search
{"query": {"multi_match": {"query": "電腦","fields": ["name", "category"]}}
}
實現效果如下:(即name和brand都必須帶“電腦”)
精確查詢
不對用戶輸入搜索條件分詞,根據字段內容精確值匹配。但只能查找keyword、數值、日期、boolean類型的字段。
term查詢
# term查詢所有
GET /items/_search
{"query": {"term": {"brand": {"value": "Dell"}}}
}
實現效果如下:(不在對搜索條件分詞)
range查詢
# range查詢所有
GET /items/_search
{"query": {"range": {"price": {"gte": 10000,"lte": 200000}}}
}
實現效果如下:(對price范圍查詢: 10000<查詢值<200000)
復雜查詢
bool查詢簡單應用
GET /items/_search
{"query": {"bool": {"must": [{"match": {"name": "GB"}}],"filter": [{"term": {"brand": "Apple"}},{"range": {"price": {"gte": 100000,"lte": 2000000}}}]}}
}
實現效果如下:(name中要有“GB”,brand中有“Apple”,且100000<查詢值<2000000)
bool查詢實現排序和分頁
GET /items/_search
{"query": {"match_all": {}},"sort": [{"price": {"order": "desc"},"sold": {"order": "asc"}}],"from": 0,"size": 5
}
實現效果解讀:查詢所有數據,先以price降序排序,price相同,以sold升序排序,一頁五條。
bool查詢實現高亮
我們在百度,京東搜索時,關鍵字會變成紅色,比較醒目,這叫高亮顯示。
事實上elasticsearch已經提供了給搜索關鍵字加標簽的語法,無需我們自己編碼。
GET /items/_search
{"query": {"match": {"name": "手機"}},"highlight": {"fields": {"name": {}}}
}
實現效果如下:(給手機加上了<em>標簽)
場景分析
問題思考
- elasticsearch的數據一般會采用分片存儲,也就是把一個索引中的數據分成N份,存儲到不同節點上。這種存儲方式比較有利于數據擴展,但給分頁帶來了一些麻煩。
- 比如一個索引庫中有100000條數據,分別存儲到4個分片,每個分片25000條數據。現在每頁查詢10條,查詢第99頁。
- 實現思路來分析,肯定是將所有數據排序,找出前1000名,截取其中的990~1000的部分。但問題來了,我們如何才能找到所有數據中的前1000名呢?
- 要知道每一片的數據都不一樣,第1片上的第900~1000,在另1個節點上并不一定依然是900~1000名。所以我們只能在每一個分片上都找出排名前1000的數據,然后匯總到一起,重新排序,才能找出整個索引庫中真正的前1000名。
解決方案
?search_after方案(推薦)
search_after
提供了一種基于上一次查詢結果中最后一個文檔的排序值來“繼續”下一頁的方式。這要求每次查詢都必須帶上前一次查詢結果中的排序值,從而避免了深度分頁的問題。
GET /_search
{"size": 10,"query": {"match": {"title": "elasticsearch"}},"search_after": [123456], // 上一個查詢結果中的排序值"sort": [{"_id": "desc"}]
}
point in time方案
從Elasticsearch 7.10版本開始引入的point in time
功能,提供了比scroll(一個過時的方案,官方棄用)
更靈活的方式來遍歷結果集。與scroll
不同,point in time
不會自動關閉搜索上下文,而是需要顯式地關閉它,這樣可以在一定程度上減少資源消耗。
POST /my-index/_pit?keep_alive=1m
{}GET /_search
{"size": 10,"query": {"match": {"title": "elasticsearch"}},"pit": {"id": "wmx3UmRBY1VnVUJqQlNvMzZQRVhBQT09LS1RY1hZRkRBPT0=","keep_alive": "1m"},"sort": [{"_id": "asc"}]
}
方案比較
search_after
?是解決前端深度分頁的最佳選擇,因為它效率高且易于實現。(簡單)
point in time
?提供了更細粒度的控制,特別適合長時間運行的數據處理任務,并有助于優化資源管理。