看完這篇還不會(huì) Elasticsearch 搜索,那我就哭了挽放!

本文主要介紹 ElasticSearch 搜索相關(guān)的知識(shí),首先會(huì)介紹下 URI Search 和 Request Body Search蔓纠,同時(shí)也會(huì)學(xué)習(xí)什么是搜索的相關(guān)性辑畦,如何衡量相關(guān)性。

Search API

我們可以把 ES 的 Search API 分為兩大類腿倚,第一類是 URI Search纯出,用 HTTP GET 的方式在 URL 中使用查詢參數(shù)已達(dá)到查詢的目的;另一類為 Request Body Search敷燎,可以使用 ES 提供的基于 JSON 格式的格式更加完備的查詢語言 Query DSL(Domain Specific Language)

語法 范圍
/_search 集群上所有的索引
/jvm/_search jvm
/jvm,sql/_search jvm 和 sql
/jvm*/_search 以 jvm 開頭的索引

在查詢的時(shí)候需要通過 _search 來標(biāo)明這個(gè)請(qǐng)求為搜索請(qǐng)求暂筝,同時(shí)可以指定 index,也可以指定多個(gè) index硬贯,也可以使用通配符的方式對(duì) index 進(jìn)行搜索焕襟。

下面來看下 URI Search:

URI Search

GET /users/_search?q=username:wupx

URI Search 使用的是 GET 方式,其中 q 指定查詢語句饭豹,語法為 Query String Syntax鸵赖,是 KV 鍵值對(duì)的形式;上面的請(qǐng)求表示對(duì) username 字段進(jìn)行查詢拄衰,查詢包含 wupx 的所有文檔它褪。

URI Search 有很多參數(shù)可以指定,除了 q 還有如下參數(shù):

  • df:默認(rèn)字段翘悉,不指定時(shí)會(huì)對(duì)所有字段進(jìn)行查詢
  • sort:根據(jù)字段名排序
  • from:返回的索引匹配結(jié)果的開始值茫打,默認(rèn)為 0
  • size:搜索結(jié)果返回的條數(shù),默認(rèn)為 10
  • timeout:超時(shí)的時(shí)間設(shè)置
  • fields:只返回索引中指定的列妖混,多個(gè)列中間用逗號(hào)分開
  • analyzer:當(dāng)分析查詢字符串的時(shí)候使用的分詞器
  • analyze_wildcard:通配符或者前綴查詢是否被分析老赤,默認(rèn)為 false
  • explain:在每個(gè)返回結(jié)果中,將包含評(píng)分機(jī)制的解釋
  • _source:是否包含元數(shù)據(jù)源葫,同時(shí)支持 _source_includes_source_excludes
  • lenient:若設(shè)置為 true诗越,字段類型轉(zhuǎn)換失敗的時(shí)候?qū)⒈缓雎裕J(rèn)為 false
  • default_operator:默認(rèn)多個(gè)條件的關(guān)系息堂,AND 或者 OR嚷狞,默認(rèn)為 OR
  • search_type:搜索的類型块促,可以為 dfs_query_then_fetchquery_then_fetch,默認(rèn)為 query_then_fetch

在了解了基本的查詢參數(shù)后床未,讓我們先來看下什么是指定字段查詢和什么是泛查詢竭翠?

比如 GET /movies/_search?q=2012&df=title 這個(gè)例子就是指定字段查詢,同樣 GET /movies/_search?q=title:2012 也可以達(dá)到指定字段查詢的目的薇搁。

再舉一個(gè)泛查詢的例子 GET /movies/_search?q=2012斋扰,會(huì)對(duì)所有字段進(jìn)行查詢。

接下來啃洋,看下什么是 Term QueryPhrase Query

比如:Beautiful Mind 等效于 Beautiful OR Mind传货;"Beautiful Mind"等效于 Beautiful AND Mind,另外還要求前后順序保存一致宏娄。

當(dāng)為 Term Query 的時(shí)候问裕,就需要把這兩個(gè)詞用括號(hào)括起來,請(qǐng)求為 GET /movies/_search?q=title:(Beautiful Mind)孵坚,意思就是查詢 title 中包括 Beautiful 或者 Mind粮宛。

當(dāng)為 Phrase Query 的時(shí)候就需要用引號(hào)包起來,請(qǐng)求為 GET /movies/_search?q=title:"Beautiful Mind"卖宠。

另外還支持布爾操作巍杈,比如 AND(&&)、OR(||)扛伍、NOT(?昶琛),需要注意大寫蜒秤,不能小寫汁咏。

在這里舉一個(gè) NOT 的例子:GET /movies/_search?q=title:(Beautiful NOT Mind),這個(gè)請(qǐng)求表示查詢 title 中必須包括 Beautiful 不能包括 Mind 的文檔作媚。

URI Search 還包括一些范圍查詢數(shù)學(xué)運(yùn)算符號(hào)攘滩,比如指定電影的年份大于 1994:GET /movies/_search?q=year:>=1994

URI Search 還支持通配符查詢(查詢效率低纸泡,占用內(nèi)存大漂问,不建議使用,特別是放在最前面)女揭,還支持正則表達(dá)式蚤假,以及模糊匹配近似查詢

URI Search 好處就是操作簡單吧兔,只要寫個(gè) URI 就可以了磷仰,方便測試,但是 URI Search 只包含一部分查詢語法境蔼,不能覆蓋所有 ES 支持的查詢語法灶平。

因此讓我們來看下 Request Body Search:

Request Body Search

在 ES 中一些高階用法只能在 Request Body 里做伺通,所以我們盡量使用 Request Body Search,它支持 GET 和 POST 方式對(duì)索引進(jìn)行查詢逢享,需要指定操作的索引名稱罐监,同樣也要通過 _search 來標(biāo)明這個(gè)請(qǐng)求為搜索請(qǐng)求,我們可以在請(qǐng)求體中使用 ES 提供的 DSL瞒爬,下面這個(gè)例子就是簡單的 Query DSL:

POST /users/_search
{
    "query": {
        "match_all": {}
    }
}

上面的請(qǐng)求的意思就是把所以的結(jié)果都返回弓柱。

也可以在 Request Body 中加入 fromsize 參數(shù)以達(dá)到分頁的效果:

POST /movies/_search
{
  "from":10,
  "size":20,
  "query":{
    "match_all": {}
  }
}

默認(rèn) from 從 0 開始,返回 10 個(gè)結(jié)果侧但,獲取靠后的翻頁成本較高矢空。

如果想對(duì)搜索的結(jié)果排序也可以在請(qǐng)求體中加上 sort 參數(shù):

POST /movies/_search
{
  "sort":[{"year":"desc"}],
  "query":{
    "match_all": {}
  }
}

最好在“數(shù)字型”與“日期型”字段上排序,因?yàn)閷?duì)于多值類型或者分析過的字段排序俊犯,系統(tǒng)會(huì)選一個(gè)值妇多,無法得知該值伤哺。

如果 _source 的數(shù)據(jù)量比較大燕侠,有些字段也不需要拿到這個(gè)信息,那么就可以對(duì)它的 _source 進(jìn)行過濾立莉,把需要的信息加到 _source 中绢彤,比如以下請(qǐng)求就是 _source 中只返回 title

POST /movies/_search
{
  "_source":["title"],
  "query":{
    "match_all": {}
  }
}

如果 _source 沒有存儲(chǔ),那就只返回匹配的文檔的元數(shù)據(jù)蜓耻,同時(shí) _source 也支持使用通配符茫舶。

接下來介紹下腳本字段,腳本字段可以使用 ES 中的 painless 的腳本去算出一個(gè)新的字段結(jié)果刹淌。

GET /movies/_search
{
  "script_fields": {
    "new_field": {
      "script": {
        "lang": "painless",
        "source": "doc['year'].value+'_hello'"
      }
    }
  },
  "query": {
    "match_all": {}
  }
}

這個(gè)例子中就使用 painless 把電影的年份和 _hello 進(jìn)行拼接形成一個(gè)新的字段 new_field饶氏。

在上面我們剛介紹了在 URI Search 中的 Term QueryPhrase Query,接下來讓我們看下 Request Body 中是怎么做的吧有勾!

在此之前先來插播一條小知識(shí)-字段類查詢疹启,字段類查詢主要包括以下兩類:

  • 全文匹配:針對(duì) text 類型的字段進(jìn)行全文檢索,會(huì)對(duì)查詢語句先進(jìn)行分詞處理蔼卡,如 match喊崖,match_phrase 等 query 類型
  • 單詞匹配:不會(huì)對(duì)查詢語句做分詞處理,直接去匹配字段的倒排索引雇逞,如 term荤懂,terms,range 等 query 類型

好了塘砸,現(xiàn)在我們來接著往下看节仿。

可以在 Request Body 中使用在 query match 的方式把信息填在里面,我們先來看下 Match Query掉蔬,比如下面這個(gè)例子廊宪,填入兩個(gè)單詞查近,默認(rèn)是 wupx or huxy 的查詢條件,如果想查詢兩者同時(shí)出現(xiàn)挤忙,可以通過加 "operator": "and" 來實(shí)現(xiàn)霜威。

POST /users/_search
{
  "query": {
    "match": {
      "title": "wupx huxy"
      "operator": "and"
    }
  }
}

我們通過一張圖來看下 Match Query 的流程:

image

首先對(duì)查詢語句進(jìn)行分詞,分成 wupxhuxy 兩個(gè) Term册烈,然后 ES 會(huì)拿到 username 的倒排索引戈泼,對(duì) wupxhuxy 去進(jìn)行匹配的算分,比如 wupx 對(duì)應(yīng)的文檔是 1 和 2赏僧,huxy 對(duì)應(yīng)的文檔為 1大猛,然后 ES 會(huì)利用算分算法(比如 TF/IDF 和 BM25,BM25 模型 5.x 之后的默認(rèn)模型)列出文檔跟查詢的匹配得分淀零,然后 ES 會(huì)對(duì) wupx huxy 的文檔的得分結(jié)果做一個(gè)匯總挽绩,最終根據(jù)得分排序,返回匹配文檔驾中。

Request Body 中還支持 Match Phrase 查詢唉堪,但在 query 條件中的詞必須順序出現(xiàn)的,可以通過 slop 參數(shù)控制單詞間的間隔肩民,比如加上 "slop" :1唠亚,表示中間可以有一個(gè)其他的字符。

POST /movies/_search
{
  "query": {
    "match_phrase": {
      "title":{
        "query": "one love"
        "slop":1
      }
    }
  }
}

了解完 Match Query持痰,讓我們?cè)賮砜聪?Term Query:

如果不希望 ES 對(duì)輸入語句作分詞處理的話灶搜,可以用 Term Query,將查詢語句作為整個(gè)單詞進(jìn)行查詢工窍,使用方法和 Match 類似割卖,只需要把 match 換為 term 就可以了,如下所示:

POST /users/_search
{
  "query": {
    "term": {
        "username":"wupx"
    }
  }
}

Terms Query 顧名思義就是一次可以傳入多個(gè)單詞進(jìn)行查詢患雏,關(guān)鍵詞是 terms鹏溯,如下所示:

POST /users/_search
{
  "query": {
    "terms": {
      "username": [
        "wupx",
        "huxy"
      ]
    }
  }
}

另外 DSL 還支持特定的 Query String 的查詢抄肖,比如指定默認(rèn)查詢的字段名 default_field 就和前面介紹的 df 是一樣的达箍,在 query 中也可以使用 AND 來實(shí)現(xiàn)一個(gè)與的操作。

POST users/_search
{
  "query": {
    "query_string": {
      "default_field": "username",
      "query": "wupx AND huxy"
    }
  }
}

下面來看下 Simple Query String Query腻异,它其實(shí)和 Query String 類似攻人,但是會(huì)忽略錯(cuò)誤的查詢語法取试,同時(shí)只支持部分查詢語法,不支持 AND OR NOT怀吻,會(huì)當(dāng)作字符串處理瞬浓,Term 之間默認(rèn)的關(guān)系是 OR,可以指定 default_operator 來實(shí)現(xiàn) AND 或者 OR蓬坡,支持用 + 替代 AND猿棉,用 | 替代 OR磅叛,用 - 替代 NOT。

下面這個(gè)例子就是查詢 username 字段中同時(shí)包含 wupx 的請(qǐng)求:

{
  "query": {
    "simple_query_string": {
      "query": "wu px",
      "fields": ["username"],
      "default_operator": "AND"
    }
  }
}

到此為止萨赁,我們就對(duì) DSL 做了個(gè)簡單介紹弊琴,更高階的 DSL 會(huì)在以后的文章中進(jìn)行介紹。

然后杖爽,我們來看下請(qǐng)求后返回的結(jié)果 Response 長什么樣吧敲董!

Response

{
  "took" : 1,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 1,
      "relation" : "eq"
    },
    "max_score" : 0.9808292,
    "hits" : [
      {
        "_index" : "users",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : 0.9808292,
        "_source" : {
          "username" : "wupx",
          "age" : "18"
        }
      }
    ]
  }
}

其中 took 表示花費(fèi)的時(shí)間;total 表示符合條件的總文檔數(shù)慰安;hits 為結(jié)果集腋寨,默認(rèn)是前 10 個(gè)文檔;_index 為索引名化焕;_id 為文檔 id萄窜;_score 為相關(guān)性評(píng)分;_source 為文檔的原始信息撒桨。

搜索的相關(guān)性(Relevance)

那么我們平時(shí)在搜索的時(shí)候查刻,比如輸入小米手機(jī),會(huì)返回很多結(jié)果元莫,從用戶角度關(guān)心的有:是否找到所有相關(guān)的內(nèi)容赖阻,有多少不相關(guān)的內(nèi)容被返回了,比如輸入的小米手機(jī)的時(shí)候不應(yīng)該返回糧食的小米給用戶踱蠢,同時(shí)文檔應(yīng)該按照打分的方式進(jìn)行排序,也就是搜索結(jié)果中的 _score棋电,另外茎截,搜索引擎需要結(jié)合業(yè)務(wù)需求,平衡結(jié)果排名赶盔。

如何評(píng)估相關(guān)性企锌?

在信息檢索學(xué)中對(duì)相關(guān)性是有指標(biāo)去評(píng)估的,第一個(gè)是查準(zhǔn)率(Precision)于未,具體含義是盡可能返回較少的無關(guān)文檔給用戶撕攒;第二個(gè)為查全率(Recall),也就是盡量返回較多的相關(guān)文檔烘浦;第三個(gè)為是否能夠按照相關(guān)度進(jìn)行排序(Ranking)抖坪。

下面通過一張圖來對(duì)查準(zhǔn)率和查全率有一個(gè)更形象的理解:

image

其中黃色的三角形代表不相關(guān)的內(nèi)容,綠色的圓代表相關(guān)的內(nèi)容闷叉;在搜索結(jié)果中擦俐,黃色的三角形起名為 False Positive(納偽,簡寫 fp)握侧,通常稱作誤報(bào)蚯瞧,綠色的圓起名為 True Positive(納真嘿期,簡寫 tp);在沒有被搜索到的范圍中埋合,綠色的圓的起名為 False Negatives(去真备徐,簡寫 fn),也常稱作漏報(bào)甚颂,黃色的三角形起名為 True Negative(去偽坦喘,簡寫 tn)

那么我們可以得到:

  • 查準(zhǔn)率等于正確的搜索結(jié)果除以全部返回的結(jié)果西设,即 Precision = tp / ( tp + fp )
  • 查全率等于正確的搜索結(jié)果除以所有應(yīng)該返回的結(jié)果瓣铣,即 Recall = tp / ( tp + fn )

在 ES 中提供了許多的查詢相關(guān)參數(shù)來改善搜索的 Precision 和 Recall。

總結(jié)

本文主要簡單介紹了 ES Search API 的兩種形式贷揽,學(xué)習(xí)了 URI Search 的基本方法棠笑,還學(xué)習(xí)了 Term Search 和 Phrase Search 的區(qū)別,同時(shí)介紹了什么叫搜索相關(guān)性禽绪,以及如何評(píng)估相關(guān)性蓖救。

參考文獻(xiàn)

《Elasticsearch技術(shù)解析與實(shí)戰(zhàn)》

Elastic Stack從入門到實(shí)踐

Elasticsearch頂尖高手系列

Elasticsearch核心技術(shù)與實(shí)戰(zhàn)

https://www.elastic.co/guide/en/elasticsearch/reference/7.1/search.html

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市印屁,隨后出現(xiàn)的幾起案子循捺,更是在濱河造成了極大的恐慌,老刑警劉巖雄人,帶你破解...
    沈念sama閱讀 216,372評(píng)論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件从橘,死亡現(xiàn)場離奇詭異,居然都是意外死亡础钠,警方通過查閱死者的電腦和手機(jī)恰力,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來旗吁,“玉大人踩萎,你說我怎么就攤上這事『艿觯” “怎么了香府?”我有些...
    開封第一講書人閱讀 162,415評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長码倦。 經(jīng)常有香客問我企孩,道長,這世上最難降的妖魔是什么叹洲? 我笑而不...
    開封第一講書人閱讀 58,157評(píng)論 1 292
  • 正文 為了忘掉前任柠硕,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘蝗柔。我一直安慰自己闻葵,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,171評(píng)論 6 388
  • 文/花漫 我一把揭開白布癣丧。 她就那樣靜靜地躺著槽畔,像睡著了一般。 火紅的嫁衣襯著肌膚如雪胁编。 梳的紋絲不亂的頭發(fā)上厢钧,一...
    開封第一講書人閱讀 51,125評(píng)論 1 297
  • 那天,我揣著相機(jī)與錄音嬉橙,去河邊找鬼早直。 笑死,一個(gè)胖子當(dāng)著我的面吹牛市框,可吹牛的內(nèi)容都是我干的霞扬。 我是一名探鬼主播,決...
    沈念sama閱讀 40,028評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼枫振,長吁一口氣:“原來是場噩夢啊……” “哼喻圃!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起粪滤,我...
    開封第一講書人閱讀 38,887評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤斧拍,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后杖小,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體肆汹,經(jīng)...
    沈念sama閱讀 45,310評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,533評(píng)論 2 332
  • 正文 我和宋清朗相戀三年窍侧,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了县踢。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,690評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡伟件,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出议经,到底是詐尸還是另有隱情斧账,我是刑警寧澤,帶...
    沈念sama閱讀 35,411評(píng)論 5 343
  • 正文 年R本政府宣布煞肾,位于F島的核電站咧织,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏籍救。R本人自食惡果不足惜习绢,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,004評(píng)論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧闪萄,春花似錦梧却、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至圆裕,卻和暖如春广鳍,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背吓妆。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評(píng)論 1 268
  • 我被黑心中介騙來泰國打工赊时, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人行拢。 一個(gè)月前我還...
    沈念sama閱讀 47,693評(píng)論 2 368
  • 正文 我出身青樓祖秒,卻偏偏與公主長得像,于是被迫代替她去往敵國和親剂陡。 傳聞我的和親對(duì)象是個(gè)殘疾皇子狈涮,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,577評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容