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

