作者:羅海鵬,叩丁狼教育高級(jí)講師另绩。原創(chuàng)文章儒陨,轉(zhuǎn)載請(qǐng)注明出處花嘶。
前言
? ? ? ?上一節(jié)我們已經(jīng)介紹過了使用RESTful API來操作Elasticsearch了,但是上一節(jié)我們只是學(xué)到了如何新增文檔蹦漠、刪除文檔和通過文檔id獲取文檔椭员,那接下來我們將來學(xué)習(xí)一下使用RESTful API來操作Elasticsearch的文檔搜索。
簡單搜索
首先我們來看看不帶任何搜索條件的最簡單的搜索:
GET /store/employee/_search
{
"took": 203,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"skipped": 0,
"failed": 0
},
"hits": {
"total": 3,
"max_score": 1,
"hits": [
{
"_index": "store",
"_type": "employee",
"_id": "2",
"_score": 1,
"_source": {
"name": "李四",
"age": 24,
"about": "我是一個(gè)作家",
"interests": [
"看書",
"寫作"
]
}
},
{
"_index": "store",
"_type": "employee",
"_id": "1",
"_score": 1,
"_source": {
"name": "張三",
"age": 25,
"about": "我是一個(gè)中國人笛园,張姓在中國是大姓隘击,你有神馬意見嗎?",
"interests": [
"sports",
"music"
]
}
},
省略下面的數(shù)據(jù).....
]
}
}
通過上面的這個(gè)RESTful API我們可以發(fā)現(xiàn)研铆,我們查詢的依然是store索引庫和employee文檔類型埋同,但是該API跟我們上一節(jié)查詢的又有不一樣的地方,上一節(jié)內(nèi)容我們給了一個(gè)文檔id棵红,獲取指定的文檔內(nèi)容凶赁,而現(xiàn)在我們沒有給指定的文檔id,取而代之的是用了一個(gè)_search
這個(gè)URL后綴逆甜。我們來看看這個(gè)返回結(jié)果中各個(gè)字段分別代表什么意思:
took:是查詢花費(fèi)的時(shí)間虱肄,毫秒單位
time_out:標(biāo)識(shí)查詢是否超時(shí)
_shards:描述了查詢分片的信息,查詢了多少個(gè)分片忆绰、成功的分片數(shù)量、失敗的分片數(shù)量等
hits:搜索的結(jié)果可岂,total是全部的滿足的文檔數(shù)目错敢,hits是返回的實(shí)際數(shù)目(默認(rèn)是10)
_score是文檔的分?jǐn)?shù)信息,與排名相關(guān)度有關(guān)缕粹,參考各大搜索引擎的搜索結(jié)果稚茅,就容易理解。
帶搜索條件的搜索
GET /store/employee/_search?q=name:張三
{
"took": 292,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"skipped": 0,
"failed": 0
},
"hits": {
"total": 1,
"max_score": 0.5753642,
"hits": [
{
"_index": "store",
"_type": "employee",
"_id": "1",
"_score": 0.5753642,
"_source": {
"name": "張三",
"age": 25,
"about": "我是一個(gè)中國人平斩,張姓在中國是大姓亚享,你有神馬意見嗎?",
"interests": [
"sports",
"music"
]
}
}
]
}
}
通過以上的RESTful API我們可以發(fā)現(xiàn):我們這次使用的RESTful API還是上面那個(gè)URL绘面,但是我們給這個(gè)URL路徑傳入了參數(shù)了欺税,這個(gè)參數(shù)名叫q,參數(shù)的值為name:張三,這就表示我們這次的搜索是需要指定特定內(nèi)容的文檔的揭璃,而這個(gè)特定內(nèi)容就是name這個(gè)字段晚凿,值為張三的文檔。
使用DSL語句搜索
我們除了可以使用簡單的傳參方式搜索外瘦馍,還可以使用Elasticsearch提供豐富且靈活的查詢語言:DSL(Domain Specific Language特定領(lǐng)域語言)查詢,它允許你構(gòu)建更加復(fù)雜歼秽、強(qiáng)大的查詢。DSL以JSON數(shù)據(jù)格式為載體情组,用HTTP請(qǐng)求體傳輸數(shù)據(jù)內(nèi)容燥筷。
match查詢:
POST /store/employee/_search
{ "query" : { "match" : { "name" : "張" } } }
{
"took": 8,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"skipped": 0,
"failed": 0
},
"hits": {
"total": 1,
"max_score": 0.2876821,
"hits": [
{
"_index": "store",
"_type": "employee",
"_id": "1",
"_score": 0.2876821,
"_source": {
"name": "張三",
"age": 25,
"about": "我是一個(gè)中國人箩祥,張姓在中國是大姓,你有神馬意見嗎肆氓?",
"interests": [
"sports",
"music"
]
}
}
]
}
}
以上的這種搜索方式跟我們之前使用簡單搜索效果是一樣的袍祖,{ "query" : { "match" : { "name" : "張" } } }
這個(gè)JSON數(shù)據(jù)就是Elasticsearch的DSL查詢語言,它需要放到HTTP請(qǐng)求體中做院,query代表執(zhí)行搜索操作盲泛,在該屬性下,可以靈活的使用各種查詢類型進(jìn)行組合键耕,match代表DSL語句中的其中一種查詢類型寺滚,在該屬性中就可以匹配我們需要查詢文檔的什么字段和字段值了,并且可以匹配多個(gè)字段屈雄。
同時(shí)我們根據(jù)返回內(nèi)容上看發(fā)現(xiàn)村视,搜索出的文檔score(得分)為0.28..,這是因?yàn)槲覀冞@次的搜索沒有精準(zhǔn)的匹配name字段為“張三”的文檔酒奶,而是只匹配“張”蚁孔,那么搜索出的文檔得分就比較低了。
除此之外惋嚎,我們還可以結(jié)合DSL語句的其他語法來控制搜索結(jié)果杠氢。如:
{ "query" : { "match_all":{} }, "size":2 }
搜索全部員工文檔,并返回前面兩條數(shù)據(jù)另伍,如果不給size字段鼻百,那么就返回前10條。
{ "query" : { "match" : { "name" : "張" } }, "from":2, "size":2 }
搜索name字段帶有“張”的員工文檔摆尝,并且返回搜索結(jié)果從第二條開始温艇,共兩條數(shù)據(jù)。
{ "query" : { "match_all":{} }, "sort":{ "age":{"order":"desc"} } }
搜索全部文檔堕汞,并且返回結(jié)果安照“age”字段做倒序排序勺爱。
{ "query":{ "match_phrase":{ "about":"rock climbing" } } }
使用match的話我們只能匹配到一個(gè)單詞,但是如果我們想要同時(shí)匹配多個(gè)單詞的話就不能使用match了讯检,而是使用match_phrase琐鲁,該屬性意思是短語搜索,例如上面這條DSL語句就是搜索包含rock climbing這個(gè)短語的文檔人灼,這個(gè)短語包含兩個(gè)單詞绣否,這個(gè)兩個(gè)單詞是需要相鄰的。
bool查詢:
elasticsearch還提供了bool語法查詢挡毅,該語法可以把多個(gè)查詢條件組合在一起蒜撮,看以下的例子:
POST /store/employee/_search
{ "query": { "bool": { "must": [ { "match": { "name": "張" } }, { "range": { "age": { "gte":25 } } } ] } } }
查詢結(jié)果如下:
{
"took": 18,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"skipped": 0,
"failed": 0
},
"hits": {
"total": 1,
"max_score": 1.5753641,
"hits": [
{
"_index": "store",
"_type": "employee",
"_id": "1",
"_score": 1.5753641,
"_source": {
"name": "張三",
"age": 25,
"about": "我是一個(gè)中國人,張姓在中國是大姓,你有神馬意見嗎段磨?",
"interests": [
"sports",
"music"
]
}
}
]
}
}
以上的查詢涉及到DSL新的語法:bool查詢取逾,這是一個(gè)可以讓我們把多個(gè)搜索條件組合在一起的語法,結(jié)合屬性must意思為所有組合條件都必須滿足苹支。同時(shí)這里還涉及到兩個(gè)新的屬性:range意思為范圍查詢和gte屬性砾隅,意思為大于等于(gt為大于)。
那么整個(gè)查詢語句意思為查詢名字帶有“張”债蜜,并且年齡大于等于25歲的員工文檔晴埂。
此外,bool查詢語法除了must之外寻定,還有must_not和should儒洛。
如果我們把上面那條查詢語句中的must改成should,那么意思就變成了:查詢名字帶有“張”狼速,或者年齡大于等于25歲的員工文檔琅锻。
在一條bool查詢語句中還可以把must,must_not和should組合成更復(fù)雜的查詢語句向胡,比如以下的這條語句:
{ "query": { "bool": { "must": [ { "match": { "name": "張" } }, { "range": { "age": { "gte":25 } } } ], "must_not":{ "match":{ "age":29 } } } } }
該語句意思是查詢名字包含“張”并且年齡大于等于25歲的恼蓬,但是不包含年齡為29歲的員工文檔。
由此可以看出僵芹,bool查詢可以很靈活的組合各種查詢條件处硬,類似于我們SQL語句中的where多個(gè)條件組合。
過濾查詢
之前我們說過score字段指定了文檔的分?jǐn)?shù)拇派,使用query搜索會(huì)計(jì)算文檔的分?jǐn)?shù)荷辕,最后通過分?jǐn)?shù)確定哪些文檔更相關(guān),返回哪些文檔攀痊,并且文檔的排序默認(rèn)是按分?jǐn)?shù)倒序的桐腌。但是有的時(shí)候我們可能對(duì)分?jǐn)?shù)不感興趣拄显,就可以使用filter進(jìn)行過濾鲫售,它不會(huì)去計(jì)算分值用狱,因此效率也就更高一些。我們來看看以下這條查詢語句:
POST /store/employee/_search
{ "query": { "bool": { "must": { "match_all": {} }, "filter": { "range": { "age": { "gt": 20, "lt": 25 } } } } } }
{
"took": 44,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"skipped": 0,
"failed": 0
},
"hits": {
"total": 2,
"max_score": 1,
"hits": [
{
"_index": "store",
"_type": "employee",
"_id": "2",
"_score": 1,
"_source": {
"name": "李四",
"age": 24,
"about": "I love to go rock climbing",
"interests": [
"sports",
"music",
"coding"
]
}
},
{
"_index": "store",
"_type": "employee",
"_id": "1",
"_score": 1,
"_source": {
"name": "張三",
"age": 25,
"about": "我是一個(gè)中國人,張姓在中國是大姓概漱,你有神馬意見嗎?",
"interests": [
"sports",
"music"
]
}
}
]
}
}
filter過濾可以嵌套在bool查詢內(nèi)部使用掖蛤,比如這條語句意思就是過濾查詢年齡大于20毡鉴,小于25之間的員工文檔。
高亮結(jié)果
所有帶有全文檢索的應(yīng)用在搜索出來的文檔結(jié)果上都會(huì)把搜索詞高亮標(biāo)記博助,這樣用戶就可以直觀的知道為什么這些文檔和查詢條件相匹配了险污。在Elasticsearch中高亮片段是非常容易的,我們可以來看看以下這個(gè)例子:
GET /store/employee/_search
{ "query" : { "match" : { "name" : "張" } }, "highlight": { "fields" : { "name" : {} } } }
{
"took": 8,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"skipped": 0,
"failed": 0
},
"hits": {
"total": 1,
"max_score": 0.2876821,
"hits": [
{
"_index": "store",
"_type": "employee",
"_id": "1",
"_score": 0.2876821,
"_source": {
"name": "張三",
"age": 25,
"about": "我是一個(gè)中國人,張姓在中國是大姓蛔糯,你有神馬意見嗎拯腮?",
"interests": [
"sports",
"music"
]
},
"highlight": {
"name": [
"<em>張</em>三"
]
}
}
]
}
}
這樣,我們就可以把搜索名字帶有“張”的員工文檔搜索出來蚁飒,并且搜索的結(jié)果多出了一個(gè)highlight的屬性动壤,在該屬性中有name這個(gè)文檔字段,其中字段值中的“張”是被<em>標(biāo)簽包裹的淮逻,代表高亮的意思琼懊,因?yàn)槲覀兊乃阉髟~就是“張”,所以elasticsearch把結(jié)果中的“張”高亮了爬早。
以上就是常用的搜索語句用法哼丈,當(dāng)然,DSL功能非常強(qiáng)大凸椿,語法也不僅僅只有這些削祈,但是目前為止,我們先學(xué)會(huì)了這些已經(jīng)足夠我們使用了脑漫,后續(xù)章節(jié)如何會(huì)涉及到其他的DSL語句我們?cè)僦鹨坏脑敿?xì)介紹其用法髓抑。