思考:一個用戶有多篇博客,如何查詢博客作者姓名中帶“旺”字、博客標題中帶“運”的10篇博客列表
elasticsearch關聯模型;
一: 應用層做聯接
2個索引
博客作者、博客發布
先從博客作者中查詢出符合姓名中帶“旺”字的作者ID,
然后根據這些ID、博客標題中帶“運”字這兩個條件查詢出來博客列表
優點: 數據很規范清晰,作者一個索引,博客一個索引
缺點: 如果查詢出來的作者ID很多的情況造成效率很低(如果有10萬作者的話,每一次分頁都需要先查作者,再拿作者ID為條件)
二:非規范化的數據
同一個索引中,博客作者和博客發布表整合成一個文檔
冗余、冗余、冗余
優點:不需要做聯接
缺點:由於作者博客為一對多關系,每次修改了作者姓名,都需要更新所有的索引文檔數據,每次都需要批量改
三:嵌套對象
博客作者和博客發布存在於一個文檔(nested)
索引映射中,所有的博客作為數組嵌套的類型存在
優點:不需聯接
缺點:只能返回符合條件的整個文檔,不能部分返回嵌套文檔中的數據(nested查詢職能返回最頂層的文檔)
四:父-子關系文檔
博客作者和博客發布存在於一個文檔(join)
映射時將其中一個字段作為連接字段,供作關聯關系
優點:能返回想要的數據
缺點:性能差一點
有了這樣的粗略認知之后,實現開始提到的使用場景,選擇第四種方案{父-子關系文檔}, 並在做了一個簡單類似的實驗
// 1、創建索引及映射關系
put bnb_home { "mappings": { "home_search": { "properties": { "shop_room": { "type": "join", "relations": { "shop": "room" } } } } } }
// 2、添加父文檔(酒店信息)
PUT bnb_home/home_search/1?refresh { "data": {"shopId":1, "shopName": "我是客棧鍋手", "description": "我是一條測試數據"}, "shop_room": { "name": "shop" } }
// 3、添加子文檔(酒店房間信息)***划重點:URL中的routing必須是parent ID 的值
***
PUT bnb_home/home_search/2?routing=1&refresh { "data": {"shopId":1, "roomId":1, "roomName": "我是一條小蟲子", "description": "可愛清新風格"}, "shop_room": { "name": "room", "parent": "1" } }
// 4、再添加子文檔(酒店房間信息)
PUT bnb_home/home_search/3?routing=1&refresh { "data": {"shopId":1, "roomId":2, "roomName": "我是第二間房子", "description": "第二件仿佛回到開始"}, "shop_room": { "name": "room", "parent": "1" } }
// 5、查詢酒店(查詢店鋪名稱中帶”你好“,房間名稱帶有“小蟲”的{店鋪})
POST bnb_home/_search { "query": { "bool":{ "must":[ {"match":{"data.shopName":"客棧"}}, { "has_child" : { "type" : "room", "query" : { "bool":{ "must":[ {"match":{"data.roomName":"小蟲子"}} ] } } } } ] } } }
// 6、查詢酒店房間(查詢店鋪名稱中帶”你好“,房間名稱帶有“小蟲”的{房間})
POST bnb_home/_search { "query": { "bool":{ "must":[ {"match":{"data.roomName":"小蟲"}}, { "has_parent" : { "parent_type" : "shop", "query" : { "bool":{ "must":[ {"match":{"data.shopName":"客棧"}} ] } } } } ] } } }