昨天我們在本地啟動了 Elasticsearch,建立固定 mapping 並插入測試資料。今天的目標是:
理解並操作 match
查詢,學會用 bool
組合條件,用 terms
進行過濾(filter)
match
是最常用的全文檢索:
curl -X POST "http://localhost:9200/books/_search?pretty" \
-H 'Content-Type: application/json' \
-d '{
"query": {
"match": { "title": "golang" }
}
}'
這會透過 analyzer(分詞器)來搜尋 title
,所以即使我們存的是 "Golang 101"
,用小寫 "golang"
也能匹配。
如果改成搜尋 "elasticsearch"
,就能找到 "Elasticsearch入門"
。
實際應用裡,我們常需要多條件組合,這時就用 bool
:
curl -X POST "http://localhost:9200/books/_search?pretty" \
-H 'Content-Type: application/json' \
-d '{
"query": {
"bool": {
"must": [
{ "match": { "title": "golang" } }
],
"filter": [
{ "term": { "tags": "programming" } }
]
}
}
}'
這表示:
must
:title
必須包含 "golang"
filter
:tags
必須是 "programming"
must
會影響相關性(score),filter
不會,但能加快查詢速度。
如果我們想要「一次比對多個值」,可以用 terms
:
curl -X POST "http://localhost:9200/books/_search?pretty" \
-H 'Content-Type: application/json' \
-d '{
"query": {
"terms": {
"tags": ["golang", "search"]
}
}
}'
這會回傳所有 tags
屬於 "golang"
或 "search"
的文件。
注意:terms
適用於 keyword 欄位,如果用在 text
會失敗,因為 text
會被分詞。
我們可以在 ESSearchService
裡,加入不同查詢模式。例如:
func (es *ESSearchService) SearchByTag(ctx context.Context, tag string) ([]SearchResult, error) {
body := fmt.Sprintf(`{
"query": {
"term": { "tags": "%s" }
}
}`, tag)
return es.searchRaw(ctx, body)
}
或是寫一個支援 bool
的版本,讓 /search
API 能支援多條件。
今天我們完成了:
match
查詢(全文檢索)bool
組合 must
+ filter
terms
一次比對多個 keyword到這裡,我們的 /search
API 已經能支援更靈活的檢索。
明天,我們會處理 分頁,並從 from/size
進階到 search_after
,避免深度分頁效能問題。