ElasticSearch系列八:掌握ES数据建模

1.将所有有关联关系的数据,放在一个doc json类型数据中。冗余数据,将可能会进行搜索的条件和要搜索的数据,放在一个doc中。一般来说,对于es这种NoSQL类型的数据存储来讲,都是冗余模式
{
"deptId": "1",
"name": "研发部门",
"desc": "负责公司的所有研发项目",
"employees": [
{
"empId": "1",
"name": "张三",
"age": 28,
"gender": "男"
},
{
"empId": "2",
"name": "王兰",
"age": 25,
"gender": "女"
}
]
}
优点:性能高,不需要执行两次搜索
缺点:数据冗余,维护成本高 
2.在构造数据模型的时候,将有关联关系的数据,然后分割为不同的实体
PUT /website/users/1 
{
 "name":     "小鱼儿",
 "email":    "[email protected]",
 "birthday":      "1980-01-01"
}
PUT /website/blogs/1
{
 "title":    "我的第一篇博客",
 "content":     "这是我的第一篇博客,开通啦!!!"
 "userId":     1 
}
优点:数据不冗余,维护方便
缺点:应用层join,如果关联数据过多,导致查询过大,性能很差
3.基于nested object实现博客与评论嵌套关系
修改mapping,将comments的类型从object设置为nested
PUT /website
{
 "mappings": {
"blogs": {
 "properties": {
"comments": {
 "type": "nested", 
 "properties": {
"name":    { "type": "string"  },
"comment": { "type": "string"  },
"age":     { "type": "short"   },
"stars":   { "type": "short"   },
"date":    { "type": "date"    }
 }
}
 }
}
 }
}
  基于nested object中的数据进行聚合分析:
  GET /website/blogs/_search 
{
 "size": 0,
 "aggs": {
"comments_path": {
 "nested": {
"path": "comments"
 },
 "aggs": {
"group_by_comments_age": {
 "histogram": {
"field": "comments.age",
"interval": 10
 },
 "aggs": {
"reverse_path": {
 "reverse_nested": {}, 
 "aggs": {
"group_by_tags": {
 "terms": {
"field": "tags.keyword"
 }
}
 }
}
 }
}
 }
}
 }
}
4.父子关系数据模型
相对于nested数据模型来说,优点是父doc和子doc互相之间不会影响
要点:父子关系元数据映射,用于确保查询时候的高性能,但是有一个限制,就是父子数据必须存在于一个shard中
例:PUT /company
{
 "mappings": {
"rd_center": {},
"employee": {
 "_parent": {
"type": "rd_center" 
 }
}
 }
}
PUT /company/employee/1?parent=1 
{
 "name":  "张三",
 "birthday":   "1970-10-24",
 "hobby": "爬山"
}
例:搜索有1980年以后出生的员工的研发中心:
GET /company/rd_center/_search
{
 "query": {
"has_child": {
 "type": "employee",
 "query": {
"range": {
 "birthday": {
"gte": "1980-01-01"
 }
}
 }
}
 }
}
例:搜索有至少2个以上员工的研发中心
GET /company/rd_center/_search
{
 "query": {
"has_child": {
 "type":         "employee",
 "min_children": 2, 
 "query": {
"match_all": {}
 }
}
 }
}
例:搜索在中国的研发中心的员工:
GET /company/employee/_search 
{
 "query": {
"has_parent": {
 "parent_type": "rd_center",
 "query": {
"term": {
 "country.keyword": "中国"
}
 }
}
 }
}
例:统计每个国家的喜欢每种爱好的员工有多少个
GET /company/rd_center/_search 
{
 "size": 0,
 "aggs": {
"group_by_country": {
 "terms": {
"field": "country.keyword"
 },
 "aggs": {
"group_by_child_employee": {
 "children": {
"type": "employee"
 },
 "aggs": {
"group_by_hobby": {
 "terms": {
"field": "hobby.keyword"
 }
}
 }
}
 }
}
 }
}
5.祖孙三层数据模型
country -> rd_center -> employee
PUT /company
{
 "mappings": {
"country": {},
"rd_center": {
 "_parent": {
"type": "country" 
 }
},
"employee": {
 "_parent": {
"type": "rd_center" 
 }
}
 }
}
PUT /company/employee/1?parent=1&routing=1
routing参数必须跟grandparent相同
6.数据建模之悲观锁的并发控制,3种锁粒度
官方文档参考地址:
https://www.elastic.co/guide/cn/elasticsearch/guide/current/concurrency-solutions.html
全局锁,直接锁掉整个fs index
PUT /fs/lock/global/_create
{}
DELETE /fs/lock/global
优点:操作非常简单,非常容易使用,成本低
缺点:你直接就把整个index给上锁了,这个时候对index中所有的doc的操作,都会被block住,导致整个系统的并发能力很低
文档锁 document level锁
共享锁:这份数据是共享的,然后多个线程过来,都可以获取同一个数据的共享锁,然后对这个数据执行读操作(读)
  排他锁:是排他的操作,只能一个线程获取排他锁,然后执行增删改操作(写)
  总结:如果只是要读取数据,任意个线程都可以同时进来然后读取数据,每个线程都可以上一个共享锁。
   如果有线程要过来修改数据,会尝试上排他锁,排他锁跟共享锁互斥,即,如果有人已经上了共享锁了,那么排他锁就不能上。
如果有人在读数据,就不允许别人来修改数据。反之,也是一样的。

猜你喜欢

转载自blog.csdn.net/zhou870498/article/details/80514950