前言
個(gè)人在學(xué)習(xí)的過(guò)程中,感覺(jué)比較吃力的地方有如下:
- 語(yǔ)法結(jié)構(gòu)比較陌生
- 沒(méi)有中文文檔, 只能看英文
- 其他博客也比較少介紹語(yǔ)法結(jié)構(gòu)。比如說(shuō),為什么查詢(xún)中會(huì)出現(xiàn)
query
關(guān)鍵詞
閱讀對(duì)象
有ES入門(mén)基礎(chǔ),且想進(jìn)一步學(xué)習(xí)ES基本操作的朋友
閱讀導(dǎo)航
系列上一篇文章:《【ES專(zhuān)題】ElasticSearch快速入門(mén)》
系列下一篇文章:《【ES專(zhuān)題】ElasticSearch搜索進(jìn)階》
官方文檔地址:ES官方使用文檔-英文
前置知識(shí)
- 理解ES的核心概念,最最重要的是【索引】和【文檔】
- 了解基本的索引、文檔操作
- 了解RESTFul風(fēng)格
數(shù)據(jù)準(zhǔn)備
為了方便后面的查詢(xún)演示,我們先在ES中創(chuàng)建/es_db
索引,并創(chuàng)建一些文檔。
#指定ik分詞器
PUT /es_db
{
"settings" : {
"index" : {
"analysis.analyzer.default.type": "ik_max_word"
}
}
}
# 創(chuàng)建文檔,指定id
PUT /es_db/_doc/1
{
"name": "張三",
"sex": 1,
"age": 25,
"address": "廣州天河公園",
"remark": "java developer"
}
PUT /es_db/_doc/2
{
"name": "李四",
"sex": 1,
"age": 28,
"address": "廣州荔灣大廈",
"remark": "java assistant"
}
PUT /es_db/_doc/3
{
"name": "王五",
"sex": 0,
"age": 26,
"address": "廣州白云山公園",
"remark": "php developer"
}
PUT /es_db/_doc/4
{
"name": "趙六",
"sex": 0,
"age": 22,
"address": "長(zhǎng)沙橘子洲",
"remark": "python assistant"
}
PUT /es_db/_doc/5
{
"name": "張龍",
"sex": 0,
"age": 19,
"address": "長(zhǎng)沙麓谷企業(yè)廣場(chǎng)",
"remark": "java architect assistant"
}
PUT /es_db/_doc/6
{
"name": "趙虎",
"sex": 1,
"age": 32,
"address": "長(zhǎng)沙麓谷興工國(guó)際產(chǎn)業(yè)園",
"remark": "java architect"
}
PUT /es_db/_doc/7
{
"name": "李虎",
"sex": 1,
"age": 32,
"address": "廣州番禺節(jié)能科技園",
"remark": "java architect"
}
PUT /es_db/_doc/8
{
"name": "張星",
"sex": 1,
"age": 32,
"address": "武漢東湖高新區(qū)未來(lái)智匯城",
"remark": "golang developer"
}
筆記正文
一、ES高級(jí)查詢(xún)Query DSL
1.1 基本介紹
就跟Mysql有自己的查詢(xún)語(yǔ)言一樣,ES作為一款優(yōu)秀的分布式文檔存儲(chǔ)和【搜索引擎】,它也有自己的查詢(xún)語(yǔ)言。即:Query DSL(查詢(xún)Domain Specific Language),查詢(xún)領(lǐng)域?qū)S谜Z(yǔ)言。Query DSL是利用RESTfull風(fēng)格API傳遞JSON格式的請(qǐng)求體(RequestBody)數(shù)據(jù)與ES進(jìn)行交互,這種方式的豐富查詢(xún)語(yǔ)法讓ES檢索變得更強(qiáng)大,更簡(jiǎn)潔。
上面高亮處是否有似曾像是的感覺(jué)?我第一眼覺(jué)得,這不跟做http請(qǐng)求差不多嘛。基于ES是Java寫(xiě)的,我嚴(yán)重懷疑…
Elasticsearch 提供了基于 JSON 的完整查詢(xún) DSL(查詢(xún)領(lǐng)域特定語(yǔ)言)來(lái)定義查詢(xún)。在ES的Query DSL中,大體可以分為兩類(lèi):葉查詢(xún)子句(我更喜歡叫:簡(jiǎn)單查詢(xún))以及復(fù)合查詢(xún)子句(復(fù)雜查詢(xún))。
總的來(lái)說(shuō),ES支持很多種查詢(xún)方式,所以,在后面的舉例中我不會(huì)全部都介紹一遍,而只是把我們工作中【據(jù)說(shuō)】可能比較常用的大概介紹一遍。(畢竟我自己也沒(méi)有生產(chǎn)使用經(jīng)驗(yàn))
在DSL中,所有的查詢(xún)都以下面這種范式開(kāi)頭:
比如下面的語(yǔ)法示例:
GET /index_name/_doc/_search
{
"query": {
json請(qǐng)求體數(shù)據(jù)
}
}
# 可以簡(jiǎn)寫(xiě)成下面的
GET /index_name/_search
{
"query": {
json請(qǐng)求體數(shù)據(jù)
}
}
# 查詢(xún)指定字段則是如下
GET /index_name/_search
{
"query": {
"field_name": {
json請(qǐng)求體數(shù)據(jù)
}
}
}
來(lái)個(gè)簡(jiǎn)單的使用示例:
#無(wú)條件查詢(xún),默認(rèn)返回10條數(shù)據(jù)
GET /es_db/_search
{
"query":{
"match_all":{}
}
}
然后,再給個(gè)返回圖解給大家稍微看看字段是什么意思。
1.2 簡(jiǎn)單查詢(xún)之——match-all(匹配所有)
語(yǔ)法格式如下:
GET /index_name/_search
{
"query":{
"match_all":{}
}
}
值得注意的是,使用match_all,匹配所有文檔,默認(rèn)只會(huì)返回10條數(shù)據(jù)。因?yàn)?code>_search查詢(xún)默認(rèn)采用的是【分頁(yè)查詢(xún)】,每頁(yè)記錄數(shù)size的默認(rèn)值為10。如果想顯示更多數(shù)據(jù),指定size。
簡(jiǎn)單的使用示例如下:
GET /es_db/_search
等同于
GET /es_db/_search
{
"query": {
"match_all": {}
}
}
1.2.1 返回源數(shù)據(jù)_source
_source
關(guān)鍵字: 是一個(gè)數(shù)組,在數(shù)組中用來(lái)指定展示那些字段。語(yǔ)法格式我就不貼了,直接看時(shí)使用示例就行了,如下:
# 返回指定字段
GET /es_db/_search
{
"query": {
"match_all": {}
},
"_source": ["name","address"]
}
#在查詢(xún)中過(guò)濾
#不查看源數(shù)據(jù),僅查看元字段
{
"_source": false,
"query": {
...
}
}
#只看以obj.開(kāi)頭的字段(其實(shí)這里就是通配符)
{
"_source": "obj.*",
"query": {
...
}
}
1.2.2 返回指定條數(shù)size
size
關(guān)鍵字: 指定查詢(xún)結(jié)果中返回指定條數(shù)。 默認(rèn)返回值10條
學(xué)到這里的時(shí)候我有點(diǎn)懵,為啥這里不以下劃線開(kāi)頭_size,?。。?!太沒(méi)規(guī)范了吧
GET /es_db/_search
{
"query": {
"match_all": {}
},
"size": 100
}
1.2.3 分頁(yè)查詢(xún)from&size
size
:顯示應(yīng)該返回的結(jié)果數(shù)量,默認(rèn)是 10from
:顯示應(yīng)該跳過(guò)的初始結(jié)果數(shù)量,默認(rèn)是 0
from 關(guān)鍵字用來(lái)指定起始返回位置,和size關(guān)鍵字連用可實(shí)現(xiàn)分頁(yè)效果
跟Mysql中的limit很像,原理也是
GET /es_db/_search
{
"query": {
"match_all": {}
},
"from": 0,
"size": 5
}
1.2.4 指定字段排序sort
注意:會(huì)讓得分失效
GET /es_db/_search
{
"query": {
"match_all": {}
},
"sort": [
{
"age": "desc"
}
]
}
#排序,分頁(yè)
GET /es_db/_search
{
"query": {
"match_all": {}
},
"sort": [
{
"age": "desc"
}
],
"from": 10,
"size": 5
}
1.3 簡(jiǎn)單查詢(xún)之——Term-Level Queries(術(shù)語(yǔ)級(jí)別查詢(xún),精確匹配)
術(shù)語(yǔ)級(jí)別查詢(xún)(Term-Level Queries)指的是:搜索內(nèi)容不經(jīng)過(guò)文本分析直接用于文本匹配,這個(gè)過(guò)程類(lèi)似于數(shù)據(jù)庫(kù)的SQL查詢(xún),搜索的對(duì)象大多是索引的非text類(lèi)型字段。Elasticsearch 中的一些術(shù)語(yǔ)級(jí)別查詢(xún)示例包括 term、terms 和 range 查詢(xún)。
不經(jīng)過(guò)文本分析是指:不對(duì)查詢(xún)語(yǔ)句分詞了,輸入什么就拿什么去【索引文檔】中匹配
1.3.1 Term query術(shù)語(yǔ)查詢(xún)(詞項(xiàng)查詢(xún))
術(shù)語(yǔ)查詢(xún)直接返回包含搜索內(nèi)容的文檔,常用來(lái)查詢(xún)索引中某個(gè)類(lèi)型為keyword的文本字段,類(lèi)似于SQL的【=】查詢(xún),使用十分普遍。
注意:最好不要對(duì)text字段使用term查詢(xún),因?yàn)閠ext字段會(huì)被分詞,這樣做既沒(méi)有意義,還很有可能什么也查不到。
另外,term大家不知道還熟悉否?這不就是ES概念中的【詞項(xiàng)】嘛,所以我更喜歡稱(chēng)呼Term Query為【詞項(xiàng)查詢(xún)】。理論上來(lái)說(shuō),ES所有文檔的source皆為詞項(xiàng),只不過(guò)有一種比較特殊的情況是:text
類(lèi)型的字段會(huì)先被分詞成多個(gè)【詞項(xiàng)】寫(xiě)入倒排索引中。所以,對(duì)text
類(lèi)型的字段做【詞項(xiàng)查詢(xún)】的時(shí)候要注意【分詞】的情況了。(查詢(xún)字符串不分詞,但是文檔記錄在被寫(xiě)入的時(shí)候已經(jīng)被分詞了)
接下來(lái)我們來(lái)三個(gè)查詢(xún)給大家演示一下,詞項(xiàng)查詢(xún)的效果。
查詢(xún)一:精確匹配,查找age為28的記錄
# 對(duì)bool,日期,數(shù)字,結(jié)構(gòu)化的文本可以利用term做精確匹配
# term 精確匹配
GET /es_db/_search
{
"query": {
"term": {
"age": {
"value": 28
}
}
}
}
根據(jù)我們前面的演示數(shù)據(jù),age=28
的數(shù)據(jù)即:李四。查詢(xún)結(jié)果如下:
查詢(xún)二:對(duì)text字段查詢(xún)
GET /es_db/_search
{
"query":{
"term": {
"address": {
"value": "廣州白云"
}
}
}
}
大家思考下,上面的查詢(xún)有數(shù)據(jù)嘛?畢竟我們?cè)跍?zhǔn)備數(shù)據(jù)中id==3
的王五
地址就是廣州白云山公園
。
哈,答案是沒(méi)有的。因?yàn)槲覀兊?code>es_db索引使用的分詞器為ik_max_word
,最細(xì)粒度的拆分。我們來(lái)看看這個(gè)分詞器下的拆分結(jié)果:
看,沒(méi)有我們查詢(xún)的廣州白云
詞項(xiàng),所以查找無(wú)數(shù)據(jù)返回。
查詢(xún)?nèi)和ㄟ^(guò)keyword對(duì)text字段精確查詢(xún)
# 采用term精確查詢(xún), 查詢(xún)字段映射類(lèi)型為keyword
GET /es_db/_search
{
"query":{
"term": {
"address.keyword": {
"value": "廣州白云山公園"
}
}
}
}
結(jié)果如下:
在ES中,Term查詢(xún),對(duì)輸入不做分詞。會(huì)將輸入作為一個(gè)整體,在倒排索引中查找準(zhǔn)確的詞項(xiàng),并且使用相關(guān)度算分公式為每個(gè)包含該詞項(xiàng)的文檔進(jìn)行相關(guān)度算分。
可以通過(guò)Constant Score
操作將查詢(xún)轉(zhuǎn)換成一個(gè)Filtering
,避免算分,并利用緩存,提高性能。
- 將Query 轉(zhuǎn)成 Filter,忽略TF-IDF計(jì)算,避免相關(guān)性算分的開(kāi)銷(xiāo)
- Filter可以有效利用緩存
GET /es_db/_search
{
"query": {
"constant_score": {
"filter": {
"term": {
"address.keyword": "廣州白云山公園"
}
}
}
}
}
term處理多值字段時(shí)(數(shù)組),term查詢(xún)是包含,不是等于。
POST /employee/_bulk
{"index":{"_id":1}}
{"name":"小明","interest":["跑步","籃球"]}
{"index":{"_id":2}}
{"name":"小紅","interest":["跳舞","畫(huà)畫(huà)"]}
{"index":{"_id":3}}
{"name":"小麗","interest":["跳舞","唱歌","跑步"]}
POST /employee/_search
{
"query": {
"term": {
"interest.keyword": {
"value": "跑步"
}
}
}
}
1.3.2 Terms Query多術(shù)語(yǔ)查詢(xún)
Terms query用于在指定字段上匹配多個(gè)詞項(xiàng)(terms)。它會(huì)精確匹配指定字段中包含的任何一個(gè)詞項(xiàng)。
POST /es_db/_search
{
"query": {
"terms": {
"remark.keyword": ["java assistant", "java architect"]
}
}
}
1.3.3 exists query是否存在字段查詢(xún)
在Elasticsearch中可以使用exists進(jìn)行查詢(xún),以判斷文檔中是否存在對(duì)應(yīng)的字段。
注意:這里是判斷【字段】是否存在,而不是文檔數(shù)據(jù)
#查詢(xún)索引庫(kù)中存在remarks字段的文檔數(shù)據(jù)
GET /es_db/_search
{
"query": {
"exists":
{
"field": "remark"
}
}
}
1.3.4 ids query——id數(shù)組查詢(xún)
ids
關(guān)鍵字 : 值為數(shù)組類(lèi)型,用來(lái)根據(jù)一組id獲取多個(gè)對(duì)應(yīng)的文檔
GET /es_db/_search
{
"query": {
"ids": {
"values": [1,2]
}
}
}
1.3.5 range query范圍查詢(xún)
range
:范圍關(guān)鍵字。它的取值如下:
- gte 大于等于
- lte 小于等于
- gt 大于
- lt 小于
- now 當(dāng)前時(shí)間
POST /es_db/_search
{
"query": {
"range": {
"age": {
"gte": 25,
"lte": 28
}
}
}
}
#日期范圍比較
DELETE /product
POST /product/_bulk
{"index":{"_id":1}}
{"price":100,"date":"2021-01-01","productId":"XHDK-1293"}
{"index":{"_id":2}}
{"price":200,"date":"2022-01-01","productId":"KDKE-5421"}
GET /product/_mapping
GET /product/_search
{
"query": {
"range": {
"date": {
"gte": "now-2y"
}
}
}
}
1.3.6 prefix query前綴查詢(xún)
它會(huì)對(duì)分詞后的文檔數(shù)據(jù)term進(jìn)行前綴搜索。
- 它不會(huì)分析要搜索的字符串,傳入的前綴就是想要查找的前綴
- 默認(rèn)狀態(tài)下,前綴查詢(xún)不做相關(guān)度分?jǐn)?shù)計(jì)算,它只是將所有匹配的文檔返回,然后賦予所有相關(guān)分?jǐn)?shù)值為1。它的行為更像是一個(gè)過(guò)濾器而不是查詢(xún)。兩者實(shí)際的區(qū)別就是過(guò)濾器是可以被緩存的,而前綴查詢(xún)不行
prefix的原理:需要遍歷所有倒排索引,并比較每個(gè)term是否以所指定的前綴開(kāi)頭
GET /es_db/_search
{
"query": {
"prefix": {
"address": {
"value": "廣州"
}
}
}
}
1.3.7 wildcard query通配符查詢(xún)
通配符查詢(xún):工作原理和prefix相同,只不過(guò)它不是只比較開(kāi)頭,它能支持更為復(fù)雜的匹配模式。
通配符,大家都不陌生
GET /es_db/_search
{
"query": {
"wildcard": {
"address": {
"value": "*白*"
}
}
}
}
1.3.8 fuzzy query模糊查詢(xún)
在實(shí)際的搜索中,我們有時(shí)候會(huì)打錯(cuò)字,從而導(dǎo)致搜索不到。在Elasticsearch中,我們可以使用fuzziness屬性來(lái)進(jìn)行模糊查詢(xún),從而達(dá)到搜索有錯(cuò)別字的情形。
fuzzy 查詢(xún)會(huì)用到兩個(gè)很重要的參數(shù),fuzziness,prefix_length
-
fuzziness
:表示輸入的關(guān)鍵字通過(guò)幾次操作可以轉(zhuǎn)變成為ES庫(kù)里面的對(duì)應(yīng)field的字段- 操作是指:新增一個(gè)字符,刪除一個(gè)字符,修改一個(gè)字符,每次操作可以記做編輯距離為1;
- 如【中文集團(tuán)】到【中威集團(tuán)】編輯距離就是1,只需要修改一個(gè)字符;如果fuzziness值在這里設(shè)置成2,會(huì)把編輯距離為2的【東東集團(tuán)】也查出來(lái)(所謂距離,可以理解為,
允許錯(cuò)誤的字?jǐn)?shù)
) - 該參數(shù)默認(rèn)值為0,即不開(kāi)啟模糊查詢(xún); fuzzy 模糊查詢(xún) 最大模糊錯(cuò)誤必須在0-2之間
-
prefix_length
:表示限制輸入關(guān)鍵字和ES對(duì)應(yīng)查詢(xún)field的內(nèi)容開(kāi)頭的前n個(gè)字符必須完全匹配,不允許錯(cuò)別字匹配;- 如這里等于1,則表示開(kāi)頭的字必須匹配,不匹配則不返回;
- 默認(rèn)值也是0;
- 加大prefix_length的值可以提高效率和準(zhǔn)確率。
GET /es_db/_search
{
"query": {
"fuzzy": {
"address": {
"value": "白運(yùn)山",
"fuzziness": 1
}
}
}
}
1.4 簡(jiǎn)單查詢(xún)之——Full Text Queries(全文檢索)
全文檢索查詢(xún)(Full Text Queries)和術(shù)語(yǔ)級(jí)別查詢(xún)(Term-Level Queries)是 Elasticsearch 中搜索和檢索數(shù)據(jù)的兩種不同方法。
全文檢索查詢(xún)旨在基于相關(guān)性搜索和匹配文本數(shù)據(jù)。這些查詢(xún)會(huì)對(duì)輸入的文本進(jìn)行分析,將其拆分為詞項(xiàng)(單個(gè)單詞),并執(zhí)行諸如分詞、詞干處理和標(biāo)準(zhǔn)化等操作。lasticsearch 中的一些全文檢索查詢(xún)示例包括match、match_phrase 和 multi_match 查詢(xún)。
全文檢索的關(guān)鍵特點(diǎn):
- 對(duì)輸入的文本進(jìn)行分析,并根據(jù)分析后的詞項(xiàng)進(jìn)行搜索和匹配。全文檢索查詢(xún)會(huì)對(duì)輸入的文本進(jìn)行分析,將其拆分為詞項(xiàng),并基于這些詞項(xiàng)進(jìn)行搜索和匹配操作
- 以相關(guān)性為基礎(chǔ)進(jìn)行搜索和匹配。全文檢索查詢(xún)使用相關(guān)性算法來(lái)確定文檔與查詢(xún)的匹配程度,并按照相關(guān)性進(jìn)行排序。相關(guān)性可以基于詞項(xiàng)的頻率、權(quán)重和其他因素來(lái)計(jì)算
- 全文檢索查詢(xún)適用于包含自由文本數(shù)據(jù)的字段(text類(lèi)型),例如文檔的內(nèi)容、文章的正文或產(chǎn)品描述等
對(duì)于match查詢(xún),其底層邏輯的概述:
- 分詞:首先,輸入的查詢(xún)文本會(huì)被分詞器進(jìn)行分詞。分詞器會(huì)將文本拆分成一個(gè)個(gè)詞項(xiàng)(terms),如單詞、短語(yǔ)或特定字符。分詞器通常根據(jù)特定的語(yǔ)言規(guī)則和配置進(jìn)行操作。
- 倒排索引:ES使用倒排索引來(lái)加速搜索過(guò)程。倒排索引是一種數(shù)據(jù)結(jié)構(gòu),它將詞項(xiàng)映射到包含這些詞項(xiàng)的文檔。每個(gè)詞項(xiàng)都有一個(gè)對(duì)應(yīng)的倒排列表,其中包含了包含該詞項(xiàng)的所有文檔的引用。
- 匹配計(jì)算:一旦查詢(xún)被分詞,ES將根據(jù)查詢(xún)的類(lèi)型和參數(shù)計(jì)算文檔與查詢(xún)的匹配度。對(duì)于match查詢(xún),ES將比較查詢(xún)的詞項(xiàng)與倒排索引中的詞項(xiàng),并計(jì)算文檔的相關(guān)性得分。相關(guān)性得分衡量了文檔與查詢(xún)的匹配程度。
- 結(jié)果返回:根據(jù)相關(guān)性得分,ES將返回最匹配的文檔作為搜索結(jié)果。搜索結(jié)果通常按照相關(guān)性得分進(jìn)行排序,以便最相關(guān)的文檔排在前面。
1.4.1 match query匹配查詢(xún)
match在匹配時(shí)會(huì)對(duì)所查找的關(guān)鍵詞進(jìn)行分詞,然后按分詞匹配查找。
match支持以下參數(shù):
- query : 指定匹配的值
- operator : 匹配條件類(lèi)型
- and : 條件分詞后都要匹配
- or : 條件分詞后有一個(gè)匹配即可(默認(rèn)or)
- minmum_should_match : 最低匹配度,即條件在倒排索引中最低的匹配度
#match 分詞后or的效果
GET /es_db/_search
{
"query": {
"match": {
"address": "廣州白云山公園"
}
}
}
# 分詞后 and的效果
GET /es_db/_search
{
"query": {
"match": {
"address": {
"query": "廣州白云山公園",
"operator": "and"
}
}
}
}
minnum_should_match
在match
中的應(yīng)用: 當(dāng)operator
參數(shù)設(shè)置為or
時(shí),minnum_should_match
參數(shù)用來(lái)控制匹配的分詞的最少數(shù)量。
# 最少匹配廣州,公園兩個(gè)詞
GET /es_db/_search
{
"query": {
"match": {
"address": {
"query": "廣州公園",
"minimum_should_match": 2
}
}
}
}
1.4.2 multi_match query 多字段查詢(xún)
可以根據(jù)字段類(lèi)型,決定是否使用分詞查詢(xún),得分最高的在前面
GET /es_db/_search
{
"query": {
"multi_match": {
"query": "長(zhǎng)沙張龍",
"fields": [
"address",
"name"
]
}
}
}
注意:若字段類(lèi)型分詞,將查詢(xún)條件分詞之后進(jìn)行查詢(xún),如果該字段不分詞就會(huì)將查詢(xún)條件作為整體進(jìn)行查詢(xún)。
1.4.3 match_phrase query短語(yǔ)查詢(xún)
短語(yǔ)搜索(match phrase)會(huì)對(duì)搜索文本進(jìn)行文本分析,然后到索引中尋找搜索的每個(gè)分詞并要求分詞相鄰,你可以通過(guò)調(diào)整slop
參數(shù)設(shè)置分詞出現(xiàn)的【最大間隔距離】。match_phrase
會(huì)將檢索關(guān)鍵詞分詞。
下面兩個(gè)查詢(xún)將表現(xiàn)出不一樣的結(jié)果,這是i因?yàn)椤鞠噜彙績(jī)蓚€(gè)字在作怪
# 下面分詞之后得到:廣州、白云山、白云、云山
GET /es_db/_search
{
"query": {
"match_phrase": {
"address": "廣州白云山"
}
}
}
# 下面分詞之后得到:廣州、白云、云山
GET /es_db/_search
{
"query": {
"match_phrase": {
"address": "廣州白云"
}
}
}
思考:為什么查詢(xún)廣州白云山有數(shù)據(jù),廣州白云沒(méi)有數(shù)據(jù)?
分析原因:
【廣州白云山】分詞之后得到:廣州、白云山、白云、云山;
【廣州白云】分詞之后得到:廣州、白云、云山
而match_phrase
匹配的是相鄰的詞條,所以查詢(xún)廣州白云山有結(jié)果,但查詢(xún)廣州白云沒(méi)有結(jié)果。
如何解決詞條間隔的問(wèn)題?可以借助slop
參數(shù),slop
參數(shù)告訴match_phrase
查詢(xún)?cè)~條能夠相隔多遠(yuǎn)時(shí)仍然將文檔視為匹配。
#廣州云山分詞后相隔為2,可以匹配到結(jié)果
GET /es_db/_search
{
"query": {
"match_phrase": {
"address": {
"query": "廣州云山",
"slop": 2
}
}
}
}
1.4.4 query_string query
允許我們?cè)趩蝹€(gè)查詢(xún)字符串中指定AND | OR | NOT
條件,同時(shí)也和 multi_match query 一樣,支持多字段搜索。和match類(lèi)似,但是match需要指定字段名,query_string是在所有字段中搜索,范圍更廣泛。
注意: 查詢(xún)字段分詞就將查詢(xún)條件分詞查詢(xún),查詢(xún)字段不分詞將查詢(xún)條件不分詞查詢(xún)
- 未指定字段查詢(xún)
# AND 要求大寫(xiě)
GET /es_db/_search
{
"query": {
"query_string": {
"query": "趙六 AND 橘子洲"
}
}
}
- 指定單個(gè)字段查詢(xún)
#Query String
GET /es_db/_search
{
"query": {
"query_string": {
"default_field": "address",
"query": "白云山 OR 橘子洲"
}
}
}
- 指定多個(gè)字段查詢(xún)
GET /es_db/_search
{
"query": {
"query_string": {
"fields": ["name","address"],
"query": "張三 OR (廣州 AND 王五)"
}
}
}
1.4.6 simple_query_string
類(lèi)似Query String,但是會(huì)忽略錯(cuò)誤的語(yǔ)法,同時(shí)只支持部分查詢(xún)語(yǔ)法,不支持AND OR NOT
,會(huì)當(dāng)作字符串處理。支持部分邏輯:
-
+
替代AND
-
|
替代OR
-
-
替代NOT
#simple_query_string 默認(rèn)的operator是OR
GET /es_db/_search
{
"query": {
"simple_query_string": {
"fields": ["name","address"],
"query": "廣州公園",
"default_operator": "AND"
}
}
}
GET /es_db/_search
{
"query": {
"simple_query_string": {
"fields": ["name","address"],
"query": "廣州 + 公園"
}
}
}
1.5 復(fù)雜查詢(xún)之——bool query(布爾查詢(xún))
ES的復(fù)雜查詢(xún)其實(shí)有很多種,但這里只介紹這個(gè)了。感興趣的同學(xué)自己看文檔吧(嗚嗚嗚,那個(gè)文檔全英文的太難看懂了)
布爾查詢(xún)可以按照布爾邏輯條件組織多條查詢(xún)語(yǔ)句,只有符合整個(gè)布爾條件的文檔才會(huì)被搜索出來(lái)。在布爾條件中,可以包含兩種不同的上下文。
-
搜索上下文(query context)
:使用搜索上下文時(shí),Elasticsearch需要計(jì)算每個(gè)文檔與搜索條件的相關(guān)度得分,這個(gè)得分的計(jì)算需使用一套復(fù)雜的計(jì)算公式,有一定的性能開(kāi)銷(xiāo),帶文本分析的全文檢索的查詢(xún)語(yǔ)句很適合放在搜索上下文中 -
過(guò)濾上下文(filter context)
:使用過(guò)濾上下文時(shí),Elasticsearch只需要判斷搜索條件跟文檔數(shù)據(jù)是否匹配,例如使用Term query判斷一個(gè)值是否跟搜索內(nèi)容一致,使用Range query判斷某數(shù)據(jù)是否位于某個(gè)區(qū)間等。過(guò)濾上下文的查詢(xún)不需要進(jìn)行相關(guān)度得分計(jì)算,還可以使用緩存加快響應(yīng)速度,很多術(shù)語(yǔ)級(jí)查詢(xún)語(yǔ)句都適合放在過(guò)濾上下文中
布爾查詢(xún)一共支持4種組合類(lèi)型:
PUT /books
{
"settings": {
"number_of_replicas": 1,
"number_of_shards": 1
},
"mappings": {
"properties": {
"id": {
"type": "long"
},
"title": {
"type": "text",
"analyzer": "ik_max_word"
},
"language": {
"type": "keyword"
},
"author": {
"type": "keyword"
},
"price": {
"type": "double"
},
"publish_time": {
"type": "date",
"format": "yyy-MM-dd"
},
"description": {
"type": "text",
"analyzer": "ik_max_word"
}
}
}
}
POST /_bulk
{"index":{"_index":"books","_id":"1"}}
{"id":"1", "title":"Java編程思想", "language":"java", "author":"Bruce Eckel", "price":70.20, "publish_time":"2007-10-01", "description":"Java學(xué)習(xí)必讀經(jīng)典,殿堂級(jí)著作!贏得了全球程序員的廣泛贊譽(yù)。"}
{"index":{"_index":"books","_id":"2"}}
{"id":"2","title":"Java程序性能優(yōu)化","language":"java","author":"葛一鳴","price":46.5,"publish_time":"2012-08-01","description":"讓你的Java程序更快、更穩(wěn)定。深入剖析軟件設(shè)計(jì)層面、代碼層面、JVM虛擬機(jī)層面的優(yōu)化方法"}
{"index":{"_index":"books","_id":"3"}}
{"id":"3","title":"Python科學(xué)計(jì)算","language":"python","author":"張若愚","price":81.4,"publish_time":"2016-05-01","description":"零基礎(chǔ)學(xué)python,光盤(pán)中作者獨(dú)家整合開(kāi)發(fā)winPython運(yùn)行環(huán)境,涵蓋了Python各個(gè)擴(kuò)展庫(kù)"}
{"index":{"_index":"books","_id":"4"}}
{"id":"4", "title":"Python基礎(chǔ)教程", "language":"python", "author":"Helant", "price":54.50, "publish_time":"2014-03-01", "description":"經(jīng)典的Python入門(mén)教程,層次鮮明,結(jié)構(gòu)嚴(yán)謹(jǐn),內(nèi)容翔實(shí)"}
{"index":{"_index":"books","_id":"5"}}
{"id":"5","title":"JavaScript高級(jí)程序設(shè)計(jì)","language":"javascript","author":"Nicholas C. Zakas","price":66.4,"publish_time":"2012-10-01","description":"JavaScript技術(shù)經(jīng)典名著"}
GET /books/_search
{
"query": {
"bool": {
"must": [
{
"match": {
"title": "java編程"
}
},{
"match": {
"description": "性能優(yōu)化"
}
}
]
}
}
}
GET /books/_search
{
"query": {
"bool": {
"should": [
{
"match": {
"title": "java編程"
}
},{
"match": {
"description": "性能優(yōu)化"
}
}
],
"minimum_should_match": 1
}
}
}
GET /books/_search
{
"query": {
"bool": {
"filter": [
{
"term": {
"language": "java"
}
},
{
"range": {
"publish_time": {
"gte": "2010-08-01"
}
}
}
]
}
}
}
1.6 highlight高亮
highlight
關(guān)鍵字: 可以讓符合條件的文檔中的關(guān)鍵詞高亮。
highlight相關(guān)屬性:
- pre_tags 前綴標(biāo)簽
- post_tags 后綴標(biāo)簽
- tags_schema 設(shè)置為styled可以使用內(nèi)置高亮樣式
- require_field_match 多字段高亮需要設(shè)置為false
示例數(shù)據(jù):
#指定ik分詞器
PUT /products
{
"settings" : {
"index" : {
"analysis.analyzer.default.type": "ik_max_word"
}
}
}
PUT /products/_doc/1
{
"proId" : "2",
"name" : "牛仔男外套",
"desc" : "牛仔外套男裝春季衣服男春裝夾克修身休閑男生潮牌工裝潮流頭號(hào)青年春秋棒球服男 7705淺藍(lán)常規(guī) XL",
"timestamp" : 1576313264451,
"createTime" : "2019-12-13 12:56:56"
}
PUT /products/_doc/2
{
"proId" : "6",
"name" : "HLA海瀾之家牛仔褲男",
"desc" : "HLA海瀾之家牛仔褲男2019時(shí)尚有型舒適HKNAD3E109A 牛仔藍(lán)(A9)175/82A(32)",
"timestamp" : 1576314265571,
"createTime" : "2019-12-18 15:56:56"
}
搜索測(cè)試:
GET /products/_search
{
"query": {
"term": {
"name": {
"value": "牛仔"
}
}
},
"highlight": {
"fields": {
"*":{}
}
}
}
1.6.1 自定義高亮html標(biāo)簽
可以在highlight中使用pre_tags
和post_tags
來(lái)自定義高亮html標(biāo)簽
GET /products/_search
{
"query": {
"multi_match": {
"fields": ["name","desc"],
"query": "牛仔"
}
},
"highlight": {
"post_tags": ["</span>"],
"pre_tags": ["<span style='color:red'>"],
"fields": {
"*":{}
}
}
}
1.6.2 多字段高亮
GET /products/_search
{
"query": {
"term": {
"name": {
"value": "牛仔"
}
}
},
"highlight": {
"pre_tags": ["<font color='red'>"],
"post_tags": ["<font/>"],
"require_field_match": "false",
"fields": {
"name": {},
"desc": {}
}
}
}
二、ES 深度分頁(yè)問(wèn)題及針對(duì)不同需求下的解決方案
說(shuō)到分頁(yè)問(wèn)題,這里有一個(gè)很有意思的東西想跟大家分享一下。
你們應(yīng)該記得分頁(yè)是怎么實(shí)現(xiàn)的吧?無(wú)非就這樣嘛:
select * from table_a where col=‘xxx’ limit 0, 100;
select * from table_a where col=‘xxx’ limit 101, 100;
但是不知道大家有沒(méi)有仔細(xì)研究過(guò),這條sql的性能問(wèn)題…
我直接說(shuō)吧:性能很差!因?yàn)?code>limit需要從表頭開(kāi)始遍歷數(shù)據(jù)。也就是對(duì)于第2條sql的limit 101,200
來(lái)說(shuō),他仍然需要遍歷完前面的100
條才開(kāi)始檢索第101-200
條。也正是因?yàn)檫@個(gè)原因,其實(shí)非常推薦主鍵id不要用UUID
的,而是使用自增的bigint
。這樣就方便優(yōu)化,怎么優(yōu)化呢?【假設(shè)id是從0開(kāi)始自增】的情況下,上面的sql可以這么優(yōu)化:
select top 100 * from table_a where col=‘xxx’ and id > 0;
select top 100 * from table_a where col=‘xxx’ and id > 100;
因?yàn)镋S的from
跟size
一樣是會(huì)去遍歷的,所以會(huì)有同樣的問(wèn)題。
2.1 什么是深度分頁(yè)
分頁(yè)問(wèn)題是Elasticsearch中最常見(jiàn)的查詢(xún)場(chǎng)景之一,正常情況下分頁(yè)代碼如實(shí)下面這樣的:
# 查詢(xún)第一頁(yè)5條數(shù)據(jù)
GET /es_db/_search
{
"query": {
"match_all": {}
},
"from": 0,
"size": 5
}
輸出結(jié)果如下圖:
但是如果我們查詢(xún)的數(shù)據(jù)頁(yè)數(shù)特別大,當(dāng)from + size大于10000的時(shí)候,就會(huì)出現(xiàn)問(wèn)題,如下圖報(bào)錯(cuò)信息所示:
ES通過(guò)參數(shù)index.max_result_window
用來(lái)限制單次查詢(xún)滿足查詢(xún)條件的結(jié)果窗口的大小,其默認(rèn)值為10000
2.2 深度分頁(yè)會(huì)帶來(lái)什么問(wèn)題
ES分頁(yè)查詢(xún)流程大致如下:
- 數(shù)據(jù)存儲(chǔ)在各個(gè)分片中,協(xié)調(diào)節(jié)點(diǎn)將查詢(xún)請(qǐng)求轉(zhuǎn)發(fā)給各個(gè)節(jié)點(diǎn),當(dāng)各個(gè)節(jié)點(diǎn)執(zhí)行搜索后,將排序后的前N條數(shù)據(jù)返回給協(xié)調(diào)節(jié)點(diǎn)
- 協(xié)調(diào)節(jié)點(diǎn)匯總各個(gè)分片返回的數(shù)據(jù),再次排序,最終返回前N條數(shù)據(jù)給客戶端
- 這個(gè)流程會(huì)導(dǎo)致一個(gè)深度分頁(yè)的問(wèn)題,也就是翻頁(yè)越多,性能越差,甚至導(dǎo)致ES出現(xiàn)OOM
在分布式系統(tǒng)中,對(duì)結(jié)果排序的成本隨分頁(yè)的深度成指數(shù)上升。
舉個(gè)例子:從10萬(wàn)名高考生中查詢(xún)成績(jī)?yōu)榈?0001-10100位的100名考生的信息,效果圖如下:
從上面案例中不難看出,每次有序的查詢(xún)都會(huì)在每個(gè)分片中執(zhí)行單獨(dú)的查詢(xún),然后進(jìn)行數(shù)據(jù)的二次排序,而這個(gè)二次排序的過(guò)程是發(fā)生在heap中的,也就是說(shuō)當(dāng)你單次查詢(xún)的數(shù)量越大,那么堆內(nèi)存中匯總的數(shù)據(jù)也就越多,對(duì)內(nèi)存的壓力也就越大。這里的單次查詢(xún)的數(shù)據(jù)量取決于你查詢(xún)的是第幾條數(shù)據(jù)而不是查詢(xún)了幾條數(shù)據(jù),比如你希望查詢(xún)的是第10001-10100這一百條數(shù)據(jù),但是ES必須將前10100全部取出進(jìn)行二次查詢(xún)。因此,如果查詢(xún)的數(shù)據(jù)排序越靠后,就越容易導(dǎo)致OOM(Out Of Memory)情況的發(fā)生,頻繁的深分頁(yè)查詢(xún)會(huì)導(dǎo)致頻繁的FGC
。
ES為了避免用戶在不了解其內(nèi)部原理的情況下而做出錯(cuò)誤的操作,設(shè)置了一個(gè)閾值,即max_result_window,其默認(rèn)值為10000,其作用是為了保護(hù)堆內(nèi)存不被錯(cuò)誤操作導(dǎo)致溢出。
2.3 深度分頁(yè)問(wèn)題的常見(jiàn)解決方案
2.3.1 嘗試避免使用深度分頁(yè)
很簡(jiǎn)單的道理,既然解決不了問(wèn)題,那就解決提出問(wèn)題的人。直接從業(yè)務(wù)上【嘗試避免使用深度分頁(yè)】。
解決深度分頁(yè)問(wèn)題最好的辦法就是避免使用深度分頁(yè)。谷歌、百度目前作為全球和國(guó)內(nèi)做大的搜索引擎不約而同的在分頁(yè)條中刪除了“跳頁(yè)”功能,其目的就是為了避免用戶使用深度分頁(yè)檢索。
看看上面的截圖,有沒(méi)有發(fā)現(xiàn),他只有下一頁(yè),或者只能選擇最近10頁(yè),而不能直接跳到指定頁(yè)數(shù)。
這種做法,本質(zhì)上和ES中的max_result_window
作用是一樣的
2.3.2 滾動(dòng)查詢(xún):Scroll Search(當(dāng)前已不推薦)
scroll滾動(dòng)搜索是先搜索一批數(shù)據(jù),然后下次再搜索下一批數(shù)據(jù),以此類(lèi)推,直到搜索出全部的數(shù)據(jù)來(lái)。
scroll搜索會(huì)在第一次搜索的時(shí)候,保存一個(gè)當(dāng)時(shí)的視圖快照,之后只會(huì)基于該視圖快照搜索數(shù)據(jù),如果在搜索期間數(shù)據(jù)發(fā)生了變更,用戶是看不到變更的數(shù)據(jù)的。因此,滾動(dòng)查詢(xún)不適合實(shí)時(shí)性要求高的搜索場(chǎng)景(官方已不推薦使用滾動(dòng)查詢(xún)進(jìn)行深度分頁(yè)查詢(xún),因?yàn)闊o(wú)法保存索引狀態(tài))
目前適合場(chǎng)景:?jiǎn)蝹€(gè)滾動(dòng)搜索請(qǐng)求中檢索大量結(jié)果,即非“C端業(yè)務(wù)”場(chǎng)景
使用示例:
1)第一次進(jìn)行scroll查詢(xún):
#查詢(xún)命令中新增scroll=1m,說(shuō)明采用游標(biāo)查詢(xún),保持游標(biāo)查詢(xún)窗口1分鐘,也就是本次快照的結(jié)果緩存起來(lái)的有效時(shí)間是1分鐘。
GET /es_db/_search?scroll=1m
{
"query": { "match_all": {}},
"size": 2
}
查詢(xún)結(jié)果:除了返回前2條記錄,還返回了一個(gè)游標(biāo)ID值_scroll_id
2)從第二次查詢(xún)開(kāi)始,每次查詢(xún)都要指定_scroll_id參數(shù):
# scroll_id 的值就是上一個(gè)請(qǐng)求中返回的 _scroll_id 的值
GET /_search/scroll
{
"scroll": "1m",
"scroll_id" : "FGluY2x1ZGVfY29udGV4dF91dWlkDXF1ZXJ5QW5kRmV0Y2gBFmNwcVdjblRxUzVhZXlicG9HeU02bWcAAAAAAABmzRY2YlV3Z0o5VVNTdWJobkE5Z3MtXzJB"
}
查詢(xún)結(jié)果:
多次根據(jù)scroll_id游標(biāo)查詢(xún),直到?jīng)]有數(shù)據(jù)返回則結(jié)束查詢(xún)。采用游標(biāo)查詢(xún)索引全量數(shù)據(jù),更安全高效,限制了單次對(duì)內(nèi)存的消耗。
正常來(lái)說(shuō)scroll超過(guò)超時(shí)后,搜索上下文會(huì)自動(dòng)刪除。然而,保持scroll打開(kāi)是有代價(jià)的,因此一旦不再使用,就應(yīng)明確清除scroll上下文
DELETE /_search/scroll
{
"scroll_id" : "FGluY2x1ZGVfY29udGV4dF91dWlkDXF1ZXJ5QW5kRmV0Y2gBFmNwcVdjblRxUzVhZXlicG9HeU02bWcAAAAAAABmzRY2YlV3Z0o5VVNTdWJobkE5Z3MtXzJB"
}
注意事項(xiàng)
- scroll滾動(dòng)查詢(xún)不適合實(shí)時(shí)性要求高的查詢(xún)場(chǎng)景,比較適合數(shù)據(jù)遷移的場(chǎng)景。
- scroll查詢(xún)完畢后,要手動(dòng)清理掉 scroll_id 。雖然ES有自動(dòng)清理機(jī)制,但是 srcoll_id 的存在會(huì)耗費(fèi)大量的資源來(lái)保存一份當(dāng)前查詢(xún)結(jié)果集映像,并且會(huì)占用文件描述符。
官方建議:ES7之后,不再建議使用scroll API進(jìn)行深度分頁(yè)。如果要分頁(yè)檢索超過(guò) Top 10,000+ 結(jié)果時(shí),推薦使用:PIT + search_after
2.3.3 PIT + search_after
scroll API適用于高效的深度滾動(dòng),但滾動(dòng)上下文成本高昂,不建議將其用于實(shí)時(shí)用戶請(qǐng)求。而search_after參數(shù)通過(guò)提供一個(gè)活動(dòng)光標(biāo)來(lái)規(guī)避這個(gè)問(wèn)題。這樣可以使用上一頁(yè)的結(jié)果來(lái)幫助檢索下一頁(yè)。
search_after 分頁(yè)查詢(xún)可以簡(jiǎn)單概括為如下幾個(gè)步驟:
1)獲取索引的pit
使用 search_after 需要具有相同查詢(xún)和排序值的多個(gè)搜索請(qǐng)求。 如果在這些請(qǐng)求之間發(fā)生刷新,結(jié)果的順序可能會(huì)發(fā)生變化,從而導(dǎo)致跨頁(yè)面的結(jié)果不一致。 為防止出現(xiàn)這種情況,可以創(chuàng)建一個(gè)時(shí)間點(diǎn) (PIT) 以保留搜索中的當(dāng)前索引狀態(tài)。Point In Time(PIT)是 Elasticsearch 7.10 版本之后才有的新特性。
# 創(chuàng)建一個(gè)時(shí)間點(diǎn)(PIT)來(lái)保存搜索期間的當(dāng)前索引狀態(tài)
POST /es_db/_pit?keep_alive=1m
#返回結(jié)果,會(huì)返回一個(gè)PID的值
{
"id" : "39K1AwEFZXNfZGIWZTN2N2Nrdk5RRjY3QjBma1h5aFRodwAWdkhjbE9YNVRTMUNDcWNQQVR2ZXYzdwAAAAAAAAA9jhZvaGpLSDlzVVMxbW5idG5DZ0xEUHFRAAEWZTN2N2Nrdk5RRjY3QjBma1h5aFRodwAA"
}
2) 根據(jù)pit首次查詢(xún)
根據(jù)pit查詢(xún)的時(shí)候,不用指定索引的名詞(畢竟前面創(chuàng)建PIT的時(shí)候已經(jīng)指定過(guò)了)
GET /_search
{
"query": {
"match_all": {}
},
"pit": {
"id": "39K1AwEFZXNfZGIWZTN2N2Nrdk5RRjY3QjBma1h5aFRodwAWdkhjbE9YNVRTMUNDcWNQQVR2ZXYzdwAAAAAAAAA9jhZvaGpLSDlzVVMxbW5idG5DZ0xEUHFRAAEWZTN2N2Nrdk5RRjY3QjBma1h5aFRodwAA",
"keep_alive": "1m"
},
"size": 2,
"sort": [
{"_id": "asc"}
]
}
返回結(jié)果:
{
"pit_id" : "39K1AwEFZXNfZGIWZTN2N2Nrdk5RRjY3QjBma1h5aFRodwAWdkhjbE9YNVRTMUNDcWNQQVR2ZXYzdwAAAAAAAAA7hRZvaGpLSDlzVVMxbW5idG5DZ0xEUHFRAAEWZTN2N2Nrdk5RRjY3QjBma1h5aFRodwAA",
"took" : 16,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 5,
"relation" : "eq"
},
"max_score" : null,
"hits" : [
{
"_index" : "es_db",
"_type" : "_doc",
"_id" : "2",
"_score" : null,
"_source" : {
"name" : "李四",
"sex" : 1,
"age" : 28,
"address" : "廣州荔灣大廈",
"remark" : "java assistant"
},
"sort" : [
"2",
0
]
},
{
"_index" : "es_db",
"_type" : "_doc",
"_id" : "3",
"_score" : null,
"_source" : {
"name" : "王五",
"sex" : 0,
"age" : 26,
"address" : "廣州白云山公園",
"remark" : "php developer"
},
"sort" : [
"3",
1
]
}
]
}
}
3)根據(jù)search_after和pit進(jìn)行翻頁(yè)查詢(xún)
要獲得下一頁(yè)結(jié)果,請(qǐng)使用最后一次命中的排序值(包括 tiebreaker)作為 search_after 參數(shù)重新運(yùn)行先前的搜索。 如果使用 PIT,請(qǐng)?jiān)?pit.id 參數(shù)中使用最新的 PIT ID。 搜索的查詢(xún)和排序參數(shù)必須保持不變。(這就跟我一開(kāi)始提到的mysql分頁(yè)優(yōu)化一樣的思路)
注意下面的search_after
參數(shù)值:
#search_after指定為上一次查詢(xún)返回的sort值。
GET /_search
{
"query": {
"match_all": {}
},
"pit": {
"id": "39K1AwEFZXNfZGIWZTN2N2Nrdk5RRjY3QjBma1h5aFRodwAWdkhjbE9YNVRTMUNDcWNQQVR2ZXYzdwAAAAAAAAA9jhZvaGpLSDlzVVMxbW5idG5DZ0xEUHFRAAEWZTN2N2Nrdk5RRjY3QjBma1h5aFRodwAA",
"keep_alive": "1m"
},
"size": 2,
"sort": [
{"_id": "asc"}
],
"search_after": [
3
]
}
返回結(jié)果:
{
"pit_id" : "39K1AwEFZXNfZGIWZTN2N2Nrdk5RRjY3QjBma1h5aFRodwAWdkhjbE9YNVRTMUNDcWNQQVR2ZXYzdwAAAAAAAAA8wxZvaGpLSDlzVVMxbW5idG5DZ0xEUHFRAAEWZTN2N2Nrdk5RRjY3QjBma1h5aFRodwAA",
"took" : 1,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 5,
"relation" : "eq"
},
"max_score" : null,
"hits" : [
{
"_index" : "es_db",
"_type" : "_doc",
"_id" : "4",
"_score" : null,
"_source" : {
"name" : "趙六",
"sex" : 0,
"age" : 22,
"address" : "長(zhǎng)沙橘子洲",
"remark" : "python assistant"
},
"sort" : [
"4"
]
},
{
"_index" : "es_db",
"_type" : "_doc",
"_id" : "5",
"_score" : null,
"_source" : {
"name" : "張龍",
"sex" : 0,
"age" : 19,
"address" : "長(zhǎng)沙麓谷企業(yè)廣場(chǎng)",
"remark" : "java architect assistant"
},
"sort" : [
"5"
]
}
]
}
}
2.4 總結(jié)
文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-735868.html
學(xué)習(xí)總結(jié)
- 學(xué)習(xí)了一些ES的簡(jiǎn)單查詢(xún)和復(fù)雜查詢(xún)
感謝
感謝【jc2182】網(wǎng)站出品的《ElasticSearch 教程》文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-735868.html
到了這里,關(guān)于【ES專(zhuān)題】ElasticSearch 高級(jí)查詢(xún)語(yǔ)法Query DSL實(shí)戰(zhàn)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!