(四)Elasticsearch RESTful API之搜索

前言

? ? ? ?上一節(jié)我們已經(jīng)介紹過了使用RESTful API來操作Elasticsearch了,但是上一節(jié)我們只是學到了如何新增文檔、刪除文檔和通過文檔id獲取文檔,那接下來我們將來學習一下使用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": "我是一個作家",
                    "interests": [
                        "看書",
                        "寫作"
                    ]
                }
            },
            {
                "_index": "store",
                "_type": "employee",
                "_id": "1",
                "_score": 1,
                "_source": {
                    "name": "張三",
                    "age": 25,
                    "about": "我是一個中國人,張姓在中國是大姓,你有神馬意見嗎?",
                    "interests": [
                        "sports",
                        "music"
                    ]
                }
            },
           省略下面的數(shù)據(jù).....
        ]
    }
}

通過上面的這個RESTful API我們可以發(fā)現(xiàn),我們查詢的依然是store索引庫和employee文檔類型,但是該API跟我們上一節(jié)查詢的又有不一樣的地方,上一節(jié)內(nèi)容我們給了一個文檔id,獲取指定的文檔內(nèi)容,而現(xiàn)在我們沒有給指定的文檔id,取而代之的是用了一個_search這個URL后綴。我們來看看這個返回結(jié)果中各個字段分別代表什么意思:
took:是查詢花費的時間,毫秒單位
time_out:標識查詢是否超時
_shards:描述了查詢分片的信息,查詢了多少個分片、成功的分片數(shù)量、失敗的分片數(shù)量等
hits:搜索的結(jié)果,total是全部的滿足的文檔數(shù)目,hits是返回的實際數(shù)目(默認是10)
_score是文檔的分數(shù)信息,與排名相關度有關,參考各大搜索引擎的搜索結(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": "我是一個中國人,張姓在中國是大姓,你有神馬意見嗎?",
                    "interests": [
                        "sports",
                        "music"
                    ]
                }
            }
        ]
    }
}

通過以上的RESTful API我們可以發(fā)現(xiàn):我們這次使用的RESTful API還是上面那個URL,但是我們給這個URL路徑傳入了參數(shù)了,這個參數(shù)名叫q,參數(shù)的值為name:張三,這就表示我們這次的搜索是需要指定特定內(nèi)容的文檔的,而這個特定內(nèi)容就是name這個字段,值為張三的文檔。

使用DSL語句搜索

我們除了可以使用簡單的傳參方式搜索外,還可以使用Elasticsearch提供豐富且靈活的查詢語言:DSL(Domain Specific Language特定領域語言)查詢,它允許你構(gòu)建更加復雜、強大的查詢。DSL以JSON數(shù)據(jù)格式為載體,用HTTP請求體傳輸數(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": "我是一個中國人,張姓在中國是大姓,你有神馬意見嗎?",
                    "interests": [
                        "sports",
                        "music"
                    ]
                }
            }
        ]
    }
}

以上的這種搜索方式跟我們之前使用簡單搜索效果是一樣的,{ "query" : { "match" : { "name" : "張" } } }這個JSON數(shù)據(jù)就是Elasticsearch的DSL查詢語言,它需要放到HTTP請求體中,query代表執(zhí)行搜索操作,在該屬性下,可以靈活的使用各種查詢類型進行組合,match代表DSL語句中的其中一種查詢類型,在該屬性中就可以匹配我們需要查詢文檔的什么字段和字段值了,并且可以匹配多個字段。
同時我們根據(jù)返回內(nèi)容上看發(fā)現(xiàn),搜索出的文檔score(得分)為0.28..,這是因為我們這次的搜索沒有精準的匹配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的話我們只能匹配到一個單詞,但是如果我們想要同時匹配多個單詞的話就不能使用match了,而是使用match_phrase,該屬性意思是短語搜索,例如上面這條DSL語句就是搜索包含rock climbing這個短語的文檔,這個短語包含兩個單詞,這個兩個單詞是需要相鄰的。

bool查詢:
elasticsearch還提供了bool語法查詢,該語法可以把多個查詢條件組合在一起,看以下的例子:
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": "我是一個中國人,張姓在中國是大姓,你有神馬意見嗎?",
                    "interests": [
                        "sports",
                        "music"
                    ]
                }
            }
        ]
    }
}

以上的查詢涉及到DSL新的語法:bool查詢,這是一個可以讓我們把多個搜索條件組合在一起的語法,結(jié)合屬性must意思為所有組合條件都必須滿足。同時這里還涉及到兩個新的屬性:range意思為范圍查詢和gte屬性,意思為大于等于(gt為大于)。
那么整個查詢語句意思為查詢名字帶有“張”,并且年齡大于等于25歲的員工文檔。
此外,bool查詢語法除了must之外,還有must_notshould。
如果我們把上面那條查詢語句中的must改成should,那么意思就變成了:查詢名字帶有“張”,或者年齡大于等于25歲的員工文檔。
在一條bool查詢語句中還可以把must,must_notshould組合成更復雜的查詢語句,比如以下的這條語句:
{ "query": { "bool": { "must": [ { "match": { "name": "張" } }, { "range": { "age": { "gte":25 } } } ], "must_not":{ "match":{ "age":29 } } } } }
該語句意思是查詢名字包含“張”并且年齡大于等于25歲的,但是不包含年齡為29歲的員工文檔。
由此可以看出,bool查詢可以很靈活的組合各種查詢條件,類似于我們SQL語句中的where多個條件組合。

過濾查詢
之前我們說過score字段指定了文檔的分數(shù),使用query搜索會計算文檔的分數(shù),最后通過分數(shù)確定哪些文檔更相關,返回哪些文檔,并且文檔的排序默認是按分數(shù)倒序的。但是有的時候我們可能對分數(shù)不感興趣,就可以使用filter進行過濾,它不會去計算分值,因此效率也就更高一些。我們來看看以下這條查詢語句:
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": "我是一個中國人,張姓在中國是大姓,你有神馬意見嗎?",
                    "interests": [
                        "sports",
                        "music"
                    ]
                }
            }
        ]
    }
}

filter過濾可以嵌套在bool查詢內(nèi)部使用,比如這條語句意思就是過濾查詢年齡大于20,小于25之間的員工文檔。

高亮結(jié)果
所有帶有全文檢索的應用在搜索出來的文檔結(jié)果上都會把搜索詞高亮標記,這樣用戶就可以直觀的知道為什么這些文檔和查詢條件相匹配了。在Elasticsearch中高亮片段是非常容易的,我們可以來看看以下這個例子:
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": "我是一個中國人,張姓在中國是大姓,你有神馬意見嗎?",
                    "interests": [
                        "sports",
                        "music"
                    ]
                },
                "highlight": {
                    "name": [
                        "<em>張</em>三"
                    ]
                }
            }
        ]
    }
}

這樣,我們就可以把搜索名字帶有“張”的員工文檔搜索出來,并且搜索的結(jié)果多出了一個highlight的屬性,在該屬性中有name這個文檔字段,其中字段值中的“張”是被<em>標簽包裹的,代表高亮的意思,因為我們的搜索詞就是“張”,所以elasticsearch把結(jié)果中的“張”高亮了。

以上就是常用的搜索語句用法,當然,DSL功能非常強大,語法也不僅僅只有這些,但是目前為止,我們先學會了這些已經(jīng)足夠我們使用了,后續(xù)章節(jié)如何會涉及到其他的DSL語句我們再逐一的詳細介紹其用法。

?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

  • 作者:羅海鵬,叩丁狼教育高級講師。原創(chuàng)文章,轉(zhuǎn)載請注明出處。 前言 上一節(jié)我們已經(jīng)介紹過了使用RESTful...
    叩丁狼教育閱讀 3,277評論 1 2
  • 博客原文一博客原文二 翻譯作品,水平有限,如有錯誤,煩請留言指正。原文請見 官網(wǎng)英文文檔 起步 Elasticse...
    rabbitGYK閱讀 3,404評論 0 68
  • 王子披荊斬棘來到了睡美人的宮殿,撥開小睡美人床前的帷幔,輕輕吻了下去。一秒,兩秒,三秒…… 仍然沒有任何動靜,魔法...
    xiaaaajiao閱讀 507評論 0 0
  • 曾幾何時傲班群笙歌鼎沸、鼓吹喧闐,熱火朝天、盛況空前。 如今時過境遷、物是人非。不見帥哥美女激情澎湃、網(wǎng)上同行,只...
    庭上望月閱讀 657評論 5 30
  • 這個細雨不斷的季節(jié),陰冷而又潮濕,循環(huán)播放著手機里幾首已聽爛了的歌,心情有些復雜,煩躁生的根不斷蔓延種植在我身體...
    宋初薇閱讀 181評論 0 0

友情鏈接更多精彩內(nèi)容