這篇介紹稍多,篇幅可能有點多,下面會針對一些重要的點作一些小測試html
hits
搜索返回的結果中最重要的一部分其中包含了 索引信息(_index,_type,_index,_source,_score),_source又是其中咱們最須要的東西,裏面包含了查詢的整個文檔的內容,默認返回10個文檔,這塊能夠結合分頁處理mysql
took
顯示查詢花費的時間sql
shards
查詢的數據實際都檢索了幾個分區,這塊跟關係型數據庫中的表分區差很少,mysql 中的 partitions 經過執行計劃查看能夠看到
"_shards" : {
"failed" : 0,
"successful" : 10,
"total" : 10
}
看下上面的問題,這裏能夠會有失敗的檢索分片個數,在時間過程當中若是數據分片丟失了,這裏仍然會返回查詢到的數據數據庫
timeout
查詢是否超時
"timed_out" : false,咱們也能夠這樣來寫
GET _index/_type/?timeout=50 (ms)
給出咱們的預期檢索時間,當數據體量過大的時候或服務器性能自己的瓶頸,可能一次有效的搜索返回的結果很大(不少知足條件的搜索),這可能須要很長的時間,這是用戶不能接受的,給出一個預期的須要查詢的失效時間,知足這個時間就會中止查詢,返回咱們的結果,固然 可能搜索 10ms可能也會有不少數據,這塊就須要分頁顯示了,給數據庫分頁一個概念json
知足以下規則便可
_index1,_index2/_type1,_type2/_search 用逗號分隔開緩存
對應泛指狀況可使用*來處理,這點有點相似 Window系統中經常使用的搜索 如 *.jpg
a*,b*/_type1,_type2/_search
這裏須要說明的是全部的 索引類型都是組合關係服務器
分頁查詢結合前面的查詢經過 size 、from 來處理
GET _index/_type/_search?size=10&from=10
size:須要查詢的數據條數 、from:從那一條開始 默認是0,這塊與EF中的 Take(size).Skip(from) 相似,取多少條,跳過多少開始取app
這裏若是是單個分片查詢還好,若是數據來之多個分片的狀況下,排序就須要處理了,不然查詢出來的數據可能不是最知足咱們條件的數據。curl
若是咱們能在查詢來自3個分片,咱們須要在咱們實際查詢的邏輯是先查詢出來在組合起來排序取到size,這點相似 你高中時期的成績elasticsearch
如:咱們須要取出來 整年級排名前40-50的人員信息,首先咱們不能取每一個班級第40-50的人員 而後按班級組合在一塊兒 在取第40-50,顯然這樣作是錯誤的,由於 班級1-50中的一些徹底有可能在年紀40-50中,可是這裏有一個臨界點,就是班級中50之後的絕對不會在年級的前50,這是能夠確定的,爲了查詢到最後的結果,必須把每一個班級都是取前5-條數據,而後合併後在取第40-50的數據纔是正確的
注:這裏咱們實際要檢索的數據 是 【分片數據*from】的數量,當咱們的分頁縱深很大的時候 取到第500頁,每頁10條,3個分片,最終檢索出來的數據是 3*5000 條數據的排序 ,若是取到數據縱深越大,搜索效率也是越低的
輕量級查詢不須要寫表達式,通常經過get請求,經過參數的方式查詢結果,帶有query match 等表達式的查詢不同,它是經過地址欄組合參數來處理
結合前面數據例子:
http://192.168.0.212:9200/liyouming/_search?pretty&q=+mytext:黎又銘)
結果:
{ "took" : 7, "timed_out" : false, "_shards" : { "total" : 5, "successful" : 5, "skipped" : 0, "failed" : 0 }, "hits" : { "total" : 3, "max_score" : 3.0561461, "hits" : [ { "_index" : "liyouming", "_type" : "liyoumingtext", "_id" : "c7eQAWoB0Mh7sqcTGY-K", "_score" : 3.0561461, "_source" : { "mytext" : "中午黎又銘在操場上打籃球" } }, { "_index" : "liyouming", "_type" : "liyoumingtext", "_id" : "dLeQAWoB0Mh7sqcTdo9b", "_score" : 2.1251993, "_source" : { "mytext" : "深夜還在寫代碼的人只有黎又銘" } }, { "_index" : "liyouming", "_type" : "liyoumingtext", "_id" : "crePAWoB0Mh7sqcTzY-2", "_score" : 0.8630463, "_source" : { "mytext" : "黎又銘早上吃了一碗麪" } } ] } }
固然:咱們要對同一個字段獲得 or 這種操做 經過 條件空格 來分割多個選項,參數只能寫q
如:http://192.168.0.212:9200/liyouming/_search?pretty&q=+mytext:(值1 值2)
這裏還有其餘的一些符號
+ 表示+後面的字段必須知足 值條件 相似 sql中的 in 包含
- 表示 - 後面的字段不能知足 值條件 相似 sql中的 not in 不包含
:表示用來區分字段與字段值
() 表示對於多個值的一種組合
這是對字符串的操做,有時候咱們須要對日期 數字 等進行範圍 大小等查詢操做
下面來加幾條數據
{ "url":"datetest/mytest", "param":{ "name":"張三", "date":"2019-04-18 15:15:16" } }
例子:
日期 http://192.168.0.212:9200/liyouming/_search?pretty&q=+date:>2019-03-01
顯然這樣搜索可能跟咱們預期的結果不同,一條數據有沒有,其實添加的時候這個格式就錯誤了,可能沒有被es認知並轉換爲時間類型,elasticsearch中會轉換它認爲是時間格式的字符串,詳細能夠參考這裏:
https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-date-format.html
咱們先不加入時間段部分,查詢搜索就ok了
如同前面對日期的識別,其實es映射支持類型有,當知足格式es會猜想類型
字符串:string
整數:byte, short, integer, long
浮點數:float, double
布爾型: boolean
日期: date
咱們能夠經過以下地址查看映射
http://192.168.0.212:9200/datetest/_mapping?pretty
來查看下 datetest 對於字段的映射,能夠看到屬性中的字段類型
結果:
{ "datetest" : { "mappings" : { "test" : { "properties" : { "date" : { "type" : "date" }, "name" : { "type" : "text", "fields" : { "keyword" : { "type" : "keyword", "ignore_above" : 256 } } } } } } } }
接下來檢驗下這些類型映射狀況並實現搜索下查看下最終的結果 Put建立下
{ "index":"mappingtest/test", "param":{ "booltest1":false, "booltest2":"true", "inttest":123, "inttest1":"456", "floattest":123.45, "floattest1":"456.45", "datetest1":"2019-02-01", "datetest2":"2019-02-01 15:15:15", "datetest3":"2019-02-01T15:15:15", "datetest4":"10:15:30", "datetest5":"Tue, 3 Jun 2008 11:05:30 GMT", "datetest6":"2018-12-03+01:00", "datetest7":"20190103", } }
咱們看下這些格式的映射狀況 經過結果咱們能夠看到哪些字段被識別成了相應的類型
這是實際類型的識別狀況
{ "mappingtest" : { "mappings" : { "test" : { "properties" : { "booltest1" : { "type" : "boolean" }, "booltest2" : { "type" : "text", "fields" : { "keyword" : { "type" : "keyword", "ignore_above" : 256 } } }, "datetest1" : { "type" : "date" }, "datetest2" : { "type" : "text", "fields" : { "keyword" : { "type" : "keyword", "ignore_above" : 256 } } }, "datetest3" : { "type" : "date" }, "datetest4" : { "type" : "text", "fields" : { "keyword" : { "type" : "keyword", "ignore_above" : 256 } } }, "datetest5" : { "type" : "text", "fields" : { "keyword" : { "type" : "keyword", "ignore_above" : 256 } } }, "datetest6" : { "type" : "text", "fields" : { "keyword" : { "type" : "keyword", "ignore_above" : 256 } } }, "datetest7" : { "type" : "text", "fields" : { "keyword" : { "type" : "keyword", "ignore_above" : 256 } } }, "floattest" : { "type" : "float" }, "floattest1" : { "type" : "text", "fields" : { "keyword" : { "type" : "keyword", "ignore_above" : 256 } } }, "inttest" : { "type" : "long" }, "inttest1" : { "type" : "text", "fields" : { "keyword" : { "type" : "keyword", "ignore_above" : 256 } } } } } } } }
{ "index":"mappingtest/test", "param":{ "booltest1":false, // boolean "booltest2":"true", // text "inttest":123, // long "inttest1":"456", //text "floattest":123.45, //float "floattest1":"456.45", //text "datetest1":"2019-02-01",//date "datetest2":"2019-02-01 15:15:15",//text "datetest3":"2019-02-01T15:15:15", //date "datetest4":"10:15:30", //text "datetest5":"Tue, 3 Jun 2008 11:05:30 GMT", ", //text "datetest6":"2018-12-03+01:00", ", //text "datetest7":"20190103", ", //text } }
固然咱們是能夠對這塊映射預先設置對於的類型(type)以及 分析器(analyzed),可是這塊須要預先設置,若是對以前已經有的進行修改不會成功,下面咱們添加了一個datetest10,咱們在來測試羨慕提娜佳的數據看一下
{ "index":"mappingtest/_mapping/test", "param":{ "properties" : { "datetest10" : { "type" : "date", "analyzed":"ik_smart" } } } }
預先設定好類型後對後續的收錄會出現相關的類型校驗,若是沒有被識別到對於類型的格式就會錯誤
標準分析器:是Elasticsearch默認使用的分析器。它是分析各類語言文本最經常使用的選擇
空格分析器:在空格的地方劃分文本。它會產生
簡單分析器:在任何不是字母的地方分隔文本,將詞條小寫。它會產生
語言分析器:特定語言分析器可用於 {ref}/analysis-lang-analyzer.html[不少語言]。它們能夠考慮指定語言的特色
這裏用中文分詞分析器來舉例,分析器會幫會將文檔內容中一個字段按照分詞的方式拆解開
這塊跟搜索密不可分,這裏就須要分詞插件 分詞庫,這裏測試用的ik
安裝ik在前面的文章中已經介紹過了
若是是在數據中要查找新聞內容的化會出現 like '%搜索詞彙%' 也能夠經過全文查找,下面來介紹下es中的怎麼來處理的
打個比方 分析器就是物流運輸過程當中的 分揀員,他會根據包裹的 地區 位置 等信息 分揀包裹 以便於用戶可以準確的收到本身的包裹,分詞以下同樣,每一個分詞組都記錄了來源的文檔位置方便索引,同時對匹配會有一個評分,匹配度高的詞彙來源文檔次數越多,這樣文檔的評分就越高
咱們來建立一個咱們的IK分析器測試 ik_max_word
{ "index":"_analyze?pretty", "param":{ "analyzer":"ik_max_word", "text":"這是一個很是好的分詞庫測試" } } 分詞結果: { "tokens": [ { "token": "這是", "start_offset": 0, "end_offset": 2, "type": "CN_WORD", "position": 0 }, { "token": "一個", "start_offset": 2, "end_offset": 4, "type": "CN_WORD", "position": 1 }, { "token": "一", "start_offset": 2, "end_offset": 3, "type": "TYPE_CNUM", "position": 2 }, { "token": "個", "start_offset": 3, "end_offset": 4, "type": "COUNT", "position": 3 }, { "token": "很是好", "start_offset": 4, "end_offset": 7, "type": "CN_WORD", "position": 4 }, { "token": "很是", "start_offset": 4, "end_offset": 6, "type": "CN_WORD", "position": 5 }, { "token": "好", "start_offset": 6, "end_offset": 7, "type": "CN_CHAR", "position": 6 }, { "token": "的", "start_offset": 7, "end_offset": 8, "type": "CN_CHAR", "position": 7 }, { "token": "分詞", "start_offset": 8, "end_offset": 10, "type": "CN_WORD", "position": 8 }, { "token": "詞庫", "start_offset": 9, "end_offset": 11, "type": "CN_WORD", "position": 9 }, { "token": "測試", "start_offset": 11, "end_offset": 13, "type": "CN_WORD", "position": 10 } ] }
一樣的句子咱們再來以另外一種規則分詞 ik_smart
{ "index":"_analyze?pretty", "param":{ "analyzer":"ik_smart", "text":"這是一個很是好的分詞庫測試" } } 分詞結果能夠看到 { "tokens": [ { "token": "這是", "start_offset": 0, "end_offset": 2, "type": "CN_WORD", "position": 0 }, { "token": "一個", "start_offset": 2, "end_offset": 4, "type": "CN_WORD", "position": 1 }, { "token": "很是好", "start_offset": 4, "end_offset": 7, "type": "CN_WORD", "position": 2 }, { "token": "的", "start_offset": 7, "end_offset": 8, "type": "CN_CHAR", "position": 3 }, { "token": "分", "start_offset": 8, "end_offset": 9, "type": "CN_CHAR", "position": 4 }, { "token": "詞庫", "start_offset": 9, "end_offset": 11, "type": "CN_WORD", "position": 5 }, { "token": "測試", "start_offset": 11, "end_offset": 13, "type": "CN_WORD", "position": 6 } ] }
說到這塊的查詢,表達式是以請求體的方式發送的並且是Get請求,一開始我也以爲很奇怪,我在.NetCore環境下模擬這些請求,Get請求帶請求體連個人Api路由都沒辦法匹配到
我又嘗試了用POST請求,可是這是能夠查詢到結果的,因而我在Linux上又試了一次
curl -XGET "localhost:9200/test/_search?pretty" -H "Context-Type:application/json" -d "{Query DSL}"
這樣也是沒問題的,這塊是怎麼回事呢?
官方也給出了說明:
某些特定語言(特別是 JavaScript)的 HTTP 庫是不容許 GET 請求帶有請求體的。事實上,一些使用者對於 GET 請求能夠帶請求體感到很是的吃驚,而事實是這個RFC文檔 RFC 7231— 一個專門負責處理 HTTP 語義和內容的文檔 — 並無規定一個帶有請求體的 GET 請求應該如何處理!結果是,一些 HTTP 服務器容許這樣子,而有一些 — 特別是一些用於緩存和代理的服務器 — 則不容許。
對於一個查詢請求,Elasticsearch 的工程師偏向於使用 GET 方式,由於他們以爲它比 POST 能更好的描述信息檢索(retrieving information)的行爲。然而,由於帶請求體的 GET 請求並不被普遍支持,因此 search API同時支持 POST 請求
這也就是我使用POST請求的方式可以成功的緣由,它是都(GET/POST)支持的
合併查詢語句
葉子語句: 被用於將查詢字符串和一個字段(或者多個字段)對比 , 入宮MSSQL中組成的一個一個的條件,在MSSQL中一個一個的條件之間會存在必定的關係,好比 >、 <、 in、 not in 、= 、還有就是組合()括號內的條件 等等,那麼在es中是怎麼來處理這樣的查詢關係呢?須要組合條件
若是是單個的查詢 match 匹配 not_match 等,這裏都是match 匹配 相似(like)而非精確查找,如 = 這種精確查找 要結合 _mapping 中的 not_analyzed 設置 和 terms 來處理
複合語句:在EF中用到過Linq lambda表達的都知道Expression,有時候在查詢結果組合後都會返回一個 boolean值,在es中這塊也是殊途同歸。
查詢表達式須要在query裏面,固然也能夠經過簡單查詢經過url地址處理,這裏的是表達式方式,能夠處理複雜的一些查詢條件
{ "query":{ "match":{"filed1":"value1"}, "match":{"filed2":"value2"} } }
這裏的每個match都是匹配型的相似like,這裏兩個match之間的關係是and而且關係,下面咱們來驗證下
{ "index":"liyouming/_search?pretty", "param":{ "query":{ "match": { "mytext": "黎又銘" } } } }
能夠看到結果 全部包含【黎又銘】的都檢索出來了
{ "took": 6, "timed_out": false, "_shards": { "total": 5, "successful": 5, "skipped": 0, "failed": 0 }, "hits": { "total": 3, "max_score": 3.0561461, "hits": [ { "_index": "liyouming", "_type": "liyoumingtext", "_id": "c7eQAWoB0Mh7sqcTGY-K", "_score": 3.0561461, "_source": { "mytext": "中午黎又銘在操場上打籃球" } }, { "_index": "liyouming", "_type": "liyoumingtext", "_id": "dLeQAWoB0Mh7sqcTdo9b", "_score": 2.1251993, "_source": { "mytext": "深夜還在寫代碼的人只有黎又銘" } }, { "_index": "liyouming", "_type": "liyoumingtext", "_id": "crePAWoB0Mh7sqcTzY-2", "_score": 0.8630463, "_source": { "mytext": "黎又銘早上吃了一碗麪" } } ] } }
接下來使用2個條件
{ "index":"liyouming/_search?pretty", "param":{ "query":{ "match": { "mytext": "黎又銘" }, "match": { "mytext": "中午" } } } } 查詢結果 同時知足條件的就只有1條數據了 { "took": 4, "timed_out": false, "_shards": { "total": 5, "successful": 5, "skipped": 0, "failed": 0 }, "hits": { "total": 1, "max_score": 1.0187154, "hits": [ { "_index": "liyouming", "_type": "liyoumingtext", "_id": "c7eQAWoB0Mh7sqcTGY-K", "_score": 1.0187154, "_source": { "mytext": "中午黎又銘在操場上打籃球" } } ] } }
關於這塊查詢還有太多的東西,將會在後面的章節繼續介紹