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":    "xiaoyuer@sina.com",
   "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种锁粒度
全局锁,直接锁掉整个fs index

PUT /fs/lock/global/_create
{}
DELETE /fs/lock/global


优点:操作非常简单,非常容易使用,成本低
缺点:你直接就把整个index给上锁了,这个时候对index中所有的doc的操作,都会被block住,导致整个系统的并发能力很低
文档锁 document level锁
共享锁:这份数据是共享的,然后多个线程过来,都可以获取同一个数据的共享锁,然后对这个数据执行读操作(读)
  排他锁:是排他的操作,只能一个线程获取排他锁,然后执行增删改操作(写)
  总结:如果只是要读取数据,任意个线程都可以同时进来然后读取数据,每个线程都可以上一个共享锁。
   如果有线程要过来修改数据,会尝试上排他锁,排他锁跟共享锁互斥,即,如果有人已经上了共享锁了,那么排他锁就不能上。
如果有人在读数据,就不允许别人来修改数据。反之,也是一样的。