代辦公司注冊靠譜嗎優(yōu)化大師 win10下載
0、前言
在Elasticsearch實(shí)際應(yīng)用中經(jīng)常會(huì)遇到嵌套文檔的情況,而且會(huì)有“對象數(shù)組彼此獨(dú)立地進(jìn)行索引和查詢的訴求”。在ES中這種嵌套文檔稱為父子文檔,父子文檔“彼此獨(dú)立地進(jìn)行查詢”至少有以下兩種方式:
1)父子文檔。在ES的5.x版本中通過parent-child父子type實(shí)現(xiàn),即一個(gè)索引對應(yīng)多個(gè)type;
對于6.X+版本由于不再支持一個(gè)索引多個(gè)type,所以父子索引的實(shí)現(xiàn)改成了Join。
2)Nested嵌套類型。
1、ES數(shù)據(jù)類型概覽
1.常見類型
?? ?binary:接受二進(jìn)制值作為 Base64 編碼的字符串。默認(rèn)情況下,該字段不存儲(chǔ),也不可搜索,不能包含換行符 \n
?? ?boolean:布爾類型,可以接受 true 或 false ,可以使用字符串和直接到布爾類型,空字符串為 false,包含:true,false,"true","false",""
?? ?keyword:關(guān)鍵字類型,不進(jìn)行分詞,直接索引,支持模糊、支持精確匹配,支持聚合、排序操作,用于篩選數(shù)據(jù)。最大支持的長度為——32766 個(gè) UTF-8 類型的字符。
?? ?number:數(shù)字類型,文檔鏈接
?? ??? ?long
?? ??? ?integer
?? ??? ?short
?? ??? ?byte
?? ??? ?double
?? ??? ?float
?? ??? ?half_float
?? ??? ?scaled_float
?? ??? ?unsigned_long?? ?Dates:日期類型
?? ??? ?date:可以是格式化后的日期字符串,也可以是時(shí)間戳,例如 2015-01-01, 2015-01-01T12:10:30Z,1420070400001
?? ??? ?date_nanos:支持納秒的日期格式,在 es 內(nèi)部是存的長整型
?? ?alias :別名類型2.對象和關(guān)系類型
?? ?object:對象類型,是一個(gè) json 對象
?? ?flattened:將對象作為單個(gè)字段值存儲(chǔ)
?? ?nested:嵌套數(shù)據(jù)類型,可以看成是一個(gè)特殊的對象類型,可以讓對象數(shù)組獨(dú)立檢索
?? ?join:同一個(gè)文檔,但具有父子關(guān)系的,類似于樹
3.結(jié)構(gòu)化數(shù)據(jù)類型
?? ?range:范圍類型,可以用來表示數(shù)據(jù)的區(qū)間
?? ??? ?integer_range
?? ??? ?float_range
?? ??? ?long_range
?? ??? ?double_range
?? ??? ?date_range
?? ??? ?ip_range
2、一個(gè)例子說明nested類型的作用
(1)Nested:嵌套對象是object數(shù)據(jù)類型的專用版本,能夠?qū)?對象數(shù)組進(jìn)行彼此獨(dú)立地索引和查詢。
(2)對象數(shù)組默認(rèn)組織形式
內(nèi)部對象字段數(shù)組的實(shí)際存儲(chǔ)機(jī)制與我們想的不一樣。Lucene沒有內(nèi)部對象的概念,因?yàn)镋lasticSearch將對象層次結(jié)構(gòu)扁平化為一個(gè)字段名和字段值的列表。例如下面文檔。
PUT user/user_info/1
{"group" : "man","userName" : [ {"first" : "張","last" : "三"},{"first" : "李","last" : "四"}]
}
這里想要查詢first為“張”,last為“四”的數(shù)據(jù),按照我們的理解應(yīng)該沒有這種數(shù)據(jù)。按如下語句查詢。
PUT user/user_info/1
{"group" : "human","sex": "man","userName" : [ {"first" : "張","last" : "三"},{"first" : "李","last" : "四"}]
}
查詢結(jié)果如下:居然查詢到了。這顯然不符合我們的預(yù)期。
這個(gè)原因就是前面所說的lucene沒有內(nèi)部對象的概念,所謂的內(nèi)部對象實(shí)際是被扁平化為一個(gè)簡單的字段名稱和值列表。文檔內(nèi)部存儲(chǔ)是這個(gè)樣子的:
{"group" : "human","sex" : "man","userName.first" : [ "張", "李" ],"userName.last" : [ "三", "四" ]
}
顯然 userName.first 和 userName.last 字段平面化為多值字段,之前的關(guān)聯(lián)性丟失,查詢就不會(huì)得到預(yù)期的結(jié)果。
那么要如何實(shí)現(xiàn)自己想要的語義呢? —— 顯然就是本文想要說的nested了。
3、nested類型的使用
3.1、首先插入如下一條記錄
其含義為博客文章信息數(shù)據(jù),其中每篇文章的評(píng)論以comments字段數(shù)組存儲(chǔ)。
PUT /financeblogs/blog/docidart1
{"title": "Invest Money","body": "Please start investing money as soon...","tags": ["money", "invest"],"published_on": "18 Oct 2017","comments": [{"name": "William","age": 34,"rating": 8,"comment": "Nice article..","commented_on": "30 Nov 2017"},{"name": "John","age": 38,"rating": 9,"comment": "I started investing after reading this.","commented_on": "25 Nov 2017"},{"name": "Smith","age": 33,"rating": 7,"comment": "Very good post","commented_on": "20 Nov 2017"}]
}
現(xiàn)在對于這條數(shù)據(jù)評(píng)論人姓名、年齡如下。
name | age |
---|---|
William | 34 |
John | 38 |
Smith | 33 |
3.2、非nested時(shí)內(nèi)部對象無法按預(yù)期查詢
我們嘗試查詢{name:John, age:34}評(píng)論過的博客,按照我們的理解應(yīng)該沒有符合條件的記錄。但是由于前面說過的平鋪的原因?qū)嶋H上如下查詢語句是檢索到這條數(shù)據(jù)了的。
GET /financeblogs/blog/_search
{"query":{"bool":{"must":[{"match":{"comments.name":"John"}},{"match":{"comments.age":"34"}}]}}
}
3.3、接下來換成nested的玩法
0.把這個(gè)索引刪除再來一遍
DELETE financeblogs
1.創(chuàng)建如下索引。主要是mapping中的comments字段指定了類型為 nested。
PUT /financeblogs
{"mappings": {"blog": {"properties": {"title": {"type": "text"},"body": {"type": "text"},"tags": {"type": "keyword"},"published_on": {"type": "keyword"},"comments": {"type": "nested","properties": {"name": {"type": "text"},"comment": {"type": "text"},"age": {"type": "short"},"rating": {"type": "short"},"commented_on": {"type": "text"}}}}}}
}
2.插入同樣的目標(biāo)數(shù)據(jù)
PUT /financeblogs/blog/docidart1
{"title": "Invest Money","body": "Please start investing money as soon...","tags": ["money", "invest"],"published_on": "18 Oct 2017","comments": [{"name": "William","age": 34,"rating": 8,"comment": "Nice article..","commented_on": "30 Nov 2017"},{"name": "John","age": 38,"rating": 9,"comment": "I started investing after reading this.","commented_on": "25 Nov 2017"},{"name": "Smith","age": 33,"rating": 7,"comment": "Very good post","commented_on": "20 Nov 2017"}]
}
3.使用nested查詢方法
#查詢name為John,age為34的記錄發(fā)現(xiàn)是沒有數(shù)據(jù)的。GET /financeblogs/blog/_search?pretty
{"query": {"bool": {"must": [{"nested": {"path": "comments","query": {"bool": {"must": [{"match": {"comments.name": "John"}},{"match": {"comments.age": 34}}]}}}}]}}
}
4.查詢name為John,age為38的數(shù)據(jù)就是有的
4、父子和嵌套兩種方式比對
項(xiàng) | 嵌套(nested) | 父子文檔 |
優(yōu)點(diǎn) | 讀取性能高 (據(jù)官方:比父子快5~10倍) | 父子文檔可以獨(dú)立更新 |
缺點(diǎn) | 更新子文檔時(shí)需要更新整個(gè)文檔 | 讀取性能差,CPU占用率高 (需額外的內(nèi)存去維護(hù)關(guān)系) |
適應(yīng)場景 | 查詢?yōu)橹?#xff0c;子文檔偶爾更新的場景 | 子文檔頻繁更新; 子文檔經(jīng)常查詢。 |
嵌套文檔看似只是文檔內(nèi)有一個(gè)集合字段,但內(nèi)部存儲(chǔ)完全不是。以下圖嵌套文檔為例;留言1,留言2,留言3在內(nèi)部實(shí)際存儲(chǔ)為4個(gè)獨(dú)立文檔。
同時(shí),嵌套文檔的字段類型需要設(shè)置為nested。設(shè)置成nested后就不能被直接查詢了,需要使用nested查詢。
總結(jié)來說:
1.普通子對象默認(rèn)實(shí)現(xiàn)了一對多的關(guān)系,會(huì)損失子對象的邊界,子對象屬性的關(guān)聯(lián)性也會(huì)喪失。
2.嵌套(nested)對象可以解決普通子對象存在的問題,但是它有兩個(gè)缺點(diǎn):一是更新文檔的時(shí)候要全部更新,另外就是不支持子文檔從屬多個(gè)主文檔的場景。
3.父子文檔能解決前面兩個(gè)存在的問題,但是它適用于寫多讀少的場景(查詢效率較慢)。
關(guān)于nested更多其他語法,參見:
干貨 | Elasticsearch Nested類型深入詳解_es nest類型-CSDN博客