Elasticsearch Join字段類(lèi)型簡(jiǎn)單快速上手教程
閱讀本文需要一定的Elasticsearch
基礎(chǔ)哦,本文深度有,但是不深
概述
Elasticsearch中Join
數(shù)據(jù)類(lèi)型的字段相信大家也都用過(guò),也就是口中常談的父子文檔。在Elasticsearch中Join
不能跨索引和分片,所以保存文檔信息時(shí)要保證父子文檔使用相同的路由參數(shù)來(lái)保證父文檔與子文檔保存在同一個(gè)索引的同一個(gè)分片,那么都有哪些限制呢?
父子關(guān)系的限制
- 每個(gè)索引中只能有一個(gè)關(guān)系字段
- 父文檔與子文檔必須在同一個(gè)索引分片中,所以我們?cè)趯?duì)父子文檔增加、刪除、修改時(shí)要設(shè)置路由值,保證數(shù)據(jù)都在同一分片
- 一個(gè)父文檔可以包含多個(gè)子文檔,但是一個(gè)子文檔只能有一個(gè)父文檔
- 只能在
Join
類(lèi)型的字段上建立關(guān)系 - 在保證當(dāng)前文檔是父文檔的前提下可以增加子文檔
Global ordinals
翻譯過(guò)來(lái)就是全局序數(shù)。什么是全局序數(shù)呢,官方文檔中說(shuō)明了,這就是一個(gè)加速查詢(xún)的一個(gè)東西,使用了全局序數(shù)之后可以讓數(shù)據(jù)更緊湊;詳細(xì)的就不展開(kāi)了,后面有機(jī)會(huì)再詳細(xì)說(shuō)明一下全局序數(shù),具體的目前可以查看一下官方文檔
對(duì)于我們本章節(jié)內(nèi)容來(lái)說(shuō),我們知道父子文檔Join
類(lèi)型是使用全局序數(shù)來(lái)加速查詢(xún)的就可以了。默認(rèn)情況下,全局序數(shù)基本是實(shí)時(shí)構(gòu)建的,當(dāng)索引發(fā)生變化,全局序數(shù)會(huì)重新構(gòu)建。這個(gè)過(guò)程會(huì)增加refresh
的時(shí)間,當(dāng)然這個(gè)配置也是可以關(guān)閉的,但是關(guān)閉之后會(huì)在我們接下來(lái)遇到的第一個(gè)父連接或者聚合的查詢(xún)時(shí)重新構(gòu)建全局序數(shù),這樣這一部分的時(shí)間就反饋給了用戶(hù),官方也是不建議我們這樣做的,感覺(jué)對(duì)用戶(hù)來(lái)說(shuō)不是那么的友好,主要還是在一個(gè)權(quán)衡。最壞的情況就是同時(shí)有多個(gè)寫(xiě)入,也就是同時(shí)有多個(gè)全局序數(shù)需要重新構(gòu)建,也就會(huì)造成在單個(gè)refresh
的時(shí)間間隔內(nèi)要重新構(gòu)建多個(gè)全局序數(shù)
當(dāng)然如果關(guān)聯(lián)字段使用的不是很頻繁并且寫(xiě)入事件很多,禁用掉是值得推薦的,禁用方式如下
PUT my-index-000001 { "mappings": { "properties": { "join_field": { "type": "join", "relations": { "goods": ["details","evaluate"], "evaluate":"vote" }, "eager_global_ordinals": false } } } }
當(dāng)然,對(duì)于全局序數(shù)占用的堆大小情況可以使用如下語(yǔ)句查看
# Per-index GET my-index-000001/_stats/fielddata?human&fields=join_field#goods # Per-node per-index GET _nodes/stats/indices/fielddata?human&fields=join_field#goods
父子文檔
首先我們還是創(chuàng)建一個(gè)正常的父子關(guān)系索引,商品作為父文檔,詳情作為子文檔
DELETE my-index-000001 PUT my-index-000001 { "mappings": { "properties": { "id": { "type": "keyword" }, "join_field": { "type": "join", "relations": { "goods": "details" } } } } }
- my-index-000001:索引名稱(chēng)
- id:文檔主鍵
- join_field:父子關(guān)系字段,
type
標(biāo)記為Join
為父子文檔 - relations: 定義父子關(guān)系,
goods
為父文檔類(lèi)型名稱(chēng),details
為子文檔類(lèi)型名稱(chēng),后面插入數(shù)據(jù),查詢(xún)都會(huì)使用
插入幾條測(cè)試數(shù)據(jù),商品有iphon和mac,詳情為顏色外觀與內(nèi)存配置等
PUT my-index-000001/_doc/1?refresh { "id": "1", "text": "iphone 14 pro max", "join_field": { "name": "goods" } } PUT my-index-000001/_doc/2?refresh { "id": "2", "text": "macbook pro ", "join_field": { "name": "goods" } } PUT my-index-000001/_doc/3?routing=1&refresh { "id": "3", "text": "512G 16核", "join_field": { "name": "details", "parent": "1" } } PUT my-index-000001/_doc/4?routing=1&refresh { "id": "4", "text": "粉/銀/黑/抹茶綠", "join_field": { "name": "details", "parent": "1" } } PUT my-index-000001/_doc/5?routing=1&refresh { "id": "5", "text": "1T 32G", "join_field": { "name": "details", "parent": "2" } } PUT my-index-000001/_doc/6?routing=1&refresh { "id": "6", "text": "銀/黑", "join_field": { "name": "details", "parent": "2" } }
使用parent_id
查詢(xún)父子文檔,以上面插入的測(cè)試數(shù)據(jù)查詢(xún),查找mac
的詳情信息語(yǔ)句如下,前提是知道父文檔的id
GET my-index-000001/_search { "query": { "parent_id": { "type": "details", "id":"2" } }, "sort":["id"] }
- 大部分情況上面是不能滿(mǎn)足我們的查詢(xún)請(qǐng)求的,所以我們還可以使用
has_parent
或者has_child
查詢(xún)
使用has_parent
查詢(xún):父文檔goods
中所有包含macbook
的子文檔(后文的孫子文檔也可以查詢(xún))
GET my-index-000001/_search { "query": { "has_parent": { "parent_type": "goods", "query": { "match": { "text": "macbook" } } } } }
使用hash_child
查看details
子文檔中有1T
關(guān)鍵字的所有父文檔
GET my-index-000001/_search { "query": { "has_child": { "type": "details", "query": { "match": { "text": "1T" } } } } }
使用parent-join
查詢(xún)或者聚合
Elasticsearch
在使用Join
類(lèi)型數(shù)據(jù)類(lèi)型時(shí),會(huì)自動(dòng)創(chuàng)建一個(gè)附加的字段,結(jié)構(gòu)為Join
的字段名加#號(hào)
加父類(lèi)型,以上文為例,創(chuàng)建一個(gè)附加字段(join_field#goods
),如下是使用parent-join
字段查詢(xún)聚合的一個(gè)例子,參考自官網(wǎng),應(yīng)用了8.1版本
的新特性運(yùn)行時(shí)字段
GET my-index-000001/_search { "query": { "parent_id": { "type": "details", "id": "1" } }, "aggs": { "parents": { "terms": { "field": "join_field#goods", "size": 10 } } }, "runtime_mappings": { "my_parent_field": { "type": "long", "script": """ emit(Integer.parseInt(doc['join_field#goods'].value)) """ } }, "fields": [ { "field": "my_parent_field" } ] }
Join
類(lèi)型的父子文檔,上面我們演示了一個(gè)父文檔對(duì)應(yīng)一種子文檔類(lèi)型的例子,Join
類(lèi)型也支持一個(gè)父類(lèi)型有多個(gè)子類(lèi)型,以上文為基礎(chǔ),加入下面語(yǔ)句測(cè)試
DELETE my-index-000001 PUT my-index-000001 { "mappings": { "properties": { "id": { "type": "keyword" }, "join_field": { "type": "join", "relations": { "goods": ["details","evaluate"] } } } } } PUT my-index-000001/_doc/7?routing=1&refresh { "id": "7", "text": "運(yùn)行流程,無(wú)卡頓,待機(jī)時(shí)間長(zhǎng)", "join_field": { "name": "evaluate", "parent": "1" } } PUT my-index-000001/_doc/8?routing=1&refresh { "id": "8", "text": "體重輕,攜帶方便,編碼利器", "join_field": { "name": "evaluate", "parent": "2" } }
- 同樣的,細(xì)心的同學(xué)已經(jīng)看到了,上文已經(jīng)標(biāo)記了孫子文檔,對(duì)的,你沒(méi)看錯(cuò)就是孫子文檔,三級(jí)的層級(jí),級(jí)別可以更深,但是
Elasticsearch
不建議很深的層次,畢竟Join
很消耗性能的,層級(jí)再深點(diǎn)沒(méi)法用了,下面就是多級(jí)別的語(yǔ)句測(cè)試,此時(shí)他們?nèi)叩年P(guān)系就如下所示
DELETE my-index-000001 PUT my-index-000001 { "mappings": { "properties": { "id": { "type": "keyword" }, "join_field": { "type": "join", "relations": { "goods": ["details","evaluate"], "evaluate":"vote" } } } } } PUT my-index-000001/_doc/9?routing=1&refresh { "id": "9", "text": "這是投票信息:我買(mǎi)iphone是因?yàn)樾詢(xún)r(jià)比高,保值", "join_field": { "name": "vote", "parent": "1" } } PUT my-index-000001/_doc/10?routing=1&refresh { "id": "10", "text": "這是投票信息:我買(mǎi)mac是因?yàn)檩p,攜帶方便,沒(méi)有流氓軟件", "join_field": { "name": "vote", "parent": "2" } }
總結(jié)
相信大家也看出來(lái)了,官方都不建議使用父子文檔的,畢竟性能是一大問(wèn)題,相信大家用Elasticsearch
肯定大部分都是圖速度快,用了Join
字段變慢了,這誰(shuí)能同意呢是吧,有利有弊吧,看大家選擇,下一篇帶給大家的算是Elasticsearch
推薦Join
字段替代類(lèi)型Nested
,更多關(guān)于Elasticsearch Join字段類(lèi)型的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
jpa多條件查詢(xún)重寫(xiě)Specification的toPredicate方法
這篇文章主要介紹了多條件查詢(xún)重寫(xiě)Specification的toPredicate方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-11-11Spring?Boot深入排查?java.lang.ArrayStoreException異常
這篇文章介紹了Spring?Boot深入排查?java.lang.ArrayStoreException異常,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-12-12Java中為什么重寫(xiě)equals()也需要重寫(xiě)hashCode方法
這篇文章主要介紹了Java中為什么重寫(xiě)equals()也需要重寫(xiě)hashCode(),本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-04-04關(guān)于SpringBoot靜態(tài)資源路徑管理問(wèn)題
這篇文章主要介紹了SpringBoot靜態(tài)資源路徑管理,主要包括默認(rèn)靜態(tài)資源路徑,增加靜態(tài)資源路徑前綴的相關(guān)操作,本文給大家介紹的非常詳細(xì),需要的朋友可以參考下2022-05-05Java org.w3c.dom.Document 類(lèi)方法引用報(bào)錯(cuò)
這篇文章主要介紹了Java org.w3c.dom.Document 類(lèi)方法引用報(bào)錯(cuò)的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-08-08如何在Java中獲取當(dāng)前年份(實(shí)例代碼)
在Java語(yǔ)言中獲取當(dāng)前年份有幾種方法:使用java.util包下的Calendar類(lèi),使用java.time包下的LocalDate類(lèi)或者使用java.text包下的SimpleDateFormat類(lèi),本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友參考下吧2023-11-11