ES中的數(shù)據(jù)關(guān)聯(lián)

1羹令、前言

對于solr來說是無法做兩個collection之間的關(guān)聯(lián)的闷尿,es是否可以做到類似于表的join關(guān)聯(lián)那线椰,這就是本篇需要研究的內(nèi)容,

主要參考內(nèi)容是官方文檔纽窟。

先說下結(jié)論肖油,如果不做特殊處理,es是無法完成類似與表Join的關(guān)聯(lián)查詢的臂港。

2森枪、ES如何做關(guān)聯(lián)

官網(wǎng)里面有幾種支持關(guān)聯(lián)查詢的辦法:

2.1 應(yīng)用程序做關(guān)聯(lián)

  這個沒有什么好說的,其實(shí)不算真正的關(guān)聯(lián)审孽,需要先查詢一個索引县袱,得到值構(gòu)造出條件再去查詢另外一個索引。

  缺點(diǎn)也很明顯佑力,就是需要查詢多次式散。

2.2 冗余數(shù)據(jù)

   簡單的來說就是將需要查詢的數(shù)據(jù)保存在一起,舉個例子如下:

    假設(shè)有用戶索引和用戶發(fā)布博客的索引打颤,需要將用戶和博客信息關(guān)聯(lián)起來杂数,對于用戶來說,我們只需要取得用戶的姓名信息即可瘸洛,則可以這樣做:
image.png

可以看下map信息如下:

實(shí)際在es內(nèi),已經(jīng)將user下面的id和name進(jìn)行了扁平化處理次和,可以通過如下的方式查詢:


image.png
image.png

優(yōu)點(diǎn):查詢速度非撤蠢撸快,缺點(diǎn)是存在數(shù)據(jù)的冗余踏施。

2.3 嵌套對象

在ES中石蔗,對單個文檔的增刪改都是原子操作罕邀,有時候?yàn)榱朔奖阄覀儗?shí)體和它相關(guān)的明細(xì)是放在一個文檔中存儲的。比如論壇發(fā)的帖子和它的回復(fù)信息养距。

其實(shí)和冗余對象有點(diǎn)類似诉探,但是如果只是做查詢會發(fā)現(xiàn)有問題,因?yàn)閑s扁平處理之后:

{
  "title":            [ eggs, nest ],
  "body":             [ making, money, work, your ],
  "tags":             [ cash, shares ],
  "comments.name":    [ alice, john, smith, white ],
  "comments.comment": [ article, great, like, more, please, this ],
  "comments.age":     [ 28, 31 ],
  "comments.stars":   [ 4, 5 ],
  "comments.date":    [ 2014-09-01, 2014-10-22 ]
}

tilte棍厌、body肾胯、tags被稱為父文檔或根文檔。

這樣數(shù)組內(nèi)之間是沒有順序關(guān)系的耘纱,這就導(dǎo)致了后面的查詢?nèi)匀豢梢圆榈綌?shù)據(jù)敬肚,嵌套對象是為了解決這個問題的,先看下普通的對象:


image.png
{
  "query": {
    "bool": {
      "must": [
        { "match": { "comments.name": "Alice" }},
        { "match": { "comments.age":  28      }} ,
        { "match": { "comments.comment.keyword":  "Great article"     }}
      ]
    }
  }
}
image.png

嵌套對象,上面的例子是沒有定義map的情況直接發(fā)送數(shù)據(jù)束析,comments被定義為object艳馒,失去了數(shù)組內(nèi)的順序關(guān)系,如果先定義了nested對象员寇,則如下:

image.png
image.png
PUT my_index2
{
  "mappings": {
    "blogpost2": {
      "properties": {
        "comments": {
          "type": "nested",
          "properties": {
            "name":    { "type": "text"  },
            "comment": { "type": "text"  },
            "age":     { "type": "short"   },
            "stars":   { "type": "short"   },
            "date":    { "type": "date"    }
          }
        }
      }
    }
  }
}

再次發(fā)送相同的數(shù)據(jù):

PUT /my_index2/blogpost2/10
{
  "title": "Nest eggs",
  "body":  "Making your money work...",
  "tags":  [ "cash", "shares" ],
  "comments": [
    {
      "name":    "John Smith",
      "comment": "Great article",
      "age":     28,
      "stars":   4,
      "date":    "2014-09-01"
    },
    {
      "name":    "Alice White",
      "comment": "More like this please",
      "age":     31,
      "stars":   5,
      "date":    "2014-10-22"
    }
  ]
}

再次發(fā)起查詢:

image.png

為什么查不到弄慰,是因?yàn)閚ested對象有自己特定的語法如下:

image.png
{
  "query": {
    "nested": {
      "path": "comments",
       "score_mode": "max",
 
      "query": {
        "bool": {
          "must": [
            {
              "term": {
                "comments.age": 31
              }
            },
            {
              "term": {
                "comments.name": "alice"
             }
            }
          ]
        }
      }
    }
  }
}

score_mode:表示嵌套文檔的最高得分納入到根文檔的計(jì)算之中。
嵌套模型的缺點(diǎn)如下:

當(dāng)對嵌套文檔做增加蝶锋、修改或者刪除時陆爽,整個文檔都要重新被索引。嵌套文檔越多牲览,這帶來的成本就越大墓陈。
查詢結(jié)果返回的是整個文檔,而不僅僅是匹配的嵌套文檔第献。盡管目前有計(jì)劃支持只返回根文檔中最佳匹配的嵌套文檔贡必,但目前還不支持。

2.4 父子對象

父子對象是最類似與表join的對象庸毫,父子關(guān)系的對象分別位于不同的文檔中仔拟,做到了很好的隔離。
有以下優(yōu)點(diǎn):
1)更新父文檔或子文檔時候飒赃,另一方不受影響利花。
2)創(chuàng)建和刪除子文檔,父文檔不受到影響载佳。
3)子文檔可以作為獨(dú)立的結(jié)果單獨(dú)返回炒事。

缺點(diǎn)是:
1)父文檔和子文檔必須存在同一個shard中。
2)貌似只能是同一個index的兩個type(對于es6.x版本只能支持一個type蔫慧,如何處理挠乳,目前還未看到)

原理:
Elasticsearch 維護(hù)了一個父文檔和子文檔的映射關(guān)系,得益于這個映射,父-子文檔關(guān)聯(lián)查詢操作非乘铮快盟蚣。
但是這個映射也對父-子文檔關(guān)系有個限制條件:父文檔和其所有子文檔,都必須要存儲在同一個分片中卖怜。
父-子文檔ID映射存儲在 Doc Values 中屎开。當(dāng)映射完全在內(nèi)存中時, Doc Values 提供對映射的快速處理能力马靠,
另一方面當(dāng)映射非常大時奄抽,可以通過溢出到磁盤提供足夠的擴(kuò)展能力
如何建立父子映射:
建立父-子文檔映射關(guān)系時只需要指定某一個文檔 type 是另一個文檔 type 的父親。 該關(guān)系可以在如下兩個時間點(diǎn)設(shè)置:
1)創(chuàng)建索引時虑粥;
2)在子文檔 type 創(chuàng)建之前更新父文檔的 mapping如孝。
舉例來說,對于公司和員工之間存在著類似的關(guān)系娩贷,即可以將公司信息看成員工信息的父文檔第晰。

如下:

PUT /company
{
  "mappings": {
    "branch": {}, //公司type
    "employee": {
      "_parent": {
        "type": "branch" //employee 文檔 是 branch 文檔的子文檔。
      }
    }
  }
}

父子文檔的創(chuàng)建
1)對于父對象來說彬祖,它是不知道有多少個子對象的茁瘦,所以按照一般的對象創(chuàng)建方法即可。
2)子對象創(chuàng)建方法:

PUT /company/employee/1?parent=london
{
  "name":  "Alice Smith",
  "dob":   "1970-10-24",
  "hobby": "hiking"
}

父文檔 ID 有兩個作用:創(chuàng)建了父文檔和子文檔之間的關(guān)系储笑,并且保證了父文檔和子文檔都在同一個分片上甜熔。

這里面的父ID london 會作為路由的依據(jù),這樣子對象就會路由到父文檔同一個shard上突倍。
在執(zhí)行單文檔的請求時需要指定父文檔的 ID腔稀,單文檔請求包括:通過 GET 請求獲取一個子文檔;創(chuàng)建羽历、更新或刪除一個子文檔焊虏。
而執(zhí)行搜索請求時是不需要指定父文檔的ID,這是因?yàn)樗阉髡埱笫窍蛞粋€索引中的所有分片發(fā)起請求秕磷,而單文檔的操作是只會向存儲該文檔的分片發(fā)送請求诵闭。
因此,如果操作單個子文檔時不指定父文檔的 ID澎嚣,那么很有可能會把請求發(fā)送到錯誤的分片上疏尿。

父文檔的 ID 應(yīng)該在 bulk API 中指定

POST /company/employee/_bulk
{ "index": { "_id": 2, "parent": "london" }}
{ "name": "Mark Thomas", "dob": "1982-05-16", "hobby": "diving" }
{ "index": { "_id": 3, "parent": "liverpool" }}
{ "name": "Barry Smith", "dob": "1979-04-01", "hobby": "hiking" }
{ "index": { "_id": 4, "parent": "paris" }}
{ "name": "Adrien Grand", "dob": "1987-05-11", "hobby": "horses" }

通過子文檔查詢父文檔
查詢80后所在的公司信息:

GET /company/branch/_search
{
  "query": {
    "has_child": {
      "type": "employee",
      "query": {
        "range": {
          "dob": {
            "gte": "1980-01-01"
          }
        }
      }
    }
  }
}
image.png

查詢至少兩個員工的公司:

GET /company/branch/_search
{
  "query": {
    "has_child": {
      "type":         "employee",
      "min_children": 2,
      "query": {
        "match_all": {}
      }
    }
  }
}

通過父文檔查詢子文檔

GET /company/employee/_search
{
  "query": {
    "has_parent": {
      "type": "branch",
      "query": {
        "match": {
          "country": "UK"
        }
      }
    }
  }
}
 
查詢公司在UK的所有員工。

每個子文檔都保存了父文檔的ID易桃。

image.png

當(dāng)你考慮父子關(guān)系是否適合你現(xiàn)有關(guān)系模型時褥琐,請考慮下面這些建議

  • 盡量少地使用父子關(guān)系,僅在子文檔遠(yuǎn)多于父文檔時使用晤郑。
  • 避免在一個查詢中使用多個父子聯(lián)合語句踩衩。
  • 在 has_child 查詢中使用 filter 上下文嚼鹉,或者設(shè)置 score_mode 為 none 來避免計(jì)算文檔得分。
  • 保證父 IDs 盡量短驱富,以便在 doc values 中更好地壓縮,被臨時載入時占用更少的內(nèi)存匹舞。
  • 父子關(guān)聯(lián)查詢比普通的查詢慢5-10倍褐鸥。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市赐稽,隨后出現(xiàn)的幾起案子叫榕,更是在濱河造成了極大的恐慌,老刑警劉巖姊舵,帶你破解...
    沈念sama閱讀 207,248評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件晰绎,死亡現(xiàn)場離奇詭異,居然都是意外死亡括丁,警方通過查閱死者的電腦和手機(jī)荞下,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,681評論 2 381
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來史飞,“玉大人尖昏,你說我怎么就攤上這事」棺剩” “怎么了抽诉?”我有些...
    開封第一講書人閱讀 153,443評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長吐绵。 經(jīng)常有香客問我迹淌,道長,這世上最難降的妖魔是什么己单? 我笑而不...
    開封第一講書人閱讀 55,475評論 1 279
  • 正文 為了忘掉前任唉窃,我火速辦了婚禮,結(jié)果婚禮上荷鼠,老公的妹妹穿的比我還像新娘句携。我一直安慰自己,他們只是感情好允乐,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,458評論 5 374
  • 文/花漫 我一把揭開白布矮嫉。 她就那樣靜靜地躺著,像睡著了一般牍疏。 火紅的嫁衣襯著肌膚如雪蠢笋。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,185評論 1 284
  • 那天鳞陨,我揣著相機(jī)與錄音昨寞,去河邊找鬼瞻惋。 笑死,一個胖子當(dāng)著我的面吹牛援岩,可吹牛的內(nèi)容都是我干的歼狼。 我是一名探鬼主播,決...
    沈念sama閱讀 38,451評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼享怀,長吁一口氣:“原來是場噩夢啊……” “哼羽峰!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起添瓷,我...
    開封第一講書人閱讀 37,112評論 0 261
  • 序言:老撾萬榮一對情侶失蹤梅屉,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后鳞贷,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體坯汤,經(jīng)...
    沈念sama閱讀 43,609評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,083評論 2 325
  • 正文 我和宋清朗相戀三年搀愧,在試婚紗的時候發(fā)現(xiàn)自己被綠了惰聂。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,163評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡妈橄,死狀恐怖庶近,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情眷蚓,我是刑警寧澤鼻种,帶...
    沈念sama閱讀 33,803評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站沙热,受9級特大地震影響叉钥,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜篙贸,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,357評論 3 307
  • 文/蒙蒙 一投队、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧爵川,春花似錦敷鸦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,357評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至圃泡,卻和暖如春碟案,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背颇蜡。 一陣腳步聲響...
    開封第一講書人閱讀 31,590評論 1 261
  • 我被黑心中介騙來泰國打工价说, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留辆亏,地道東北人。 一個月前我還...
    沈念sama閱讀 45,636評論 2 355
  • 正文 我出身青樓鳖目,卻偏偏與公主長得像扮叨,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子领迈,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,925評論 2 344

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