## 基础
> * nested object的建模,有个不好的地方,就是采取的是类似冗余数据的方式,将多个数据都放在一起了,维护成本就比较高
> * parent child建模方式,采取的是类似于关系型数据库的三范式类的建模,多个实体都分割开来,每个实体之间都通过一些关联方式,进行了父子关系的关联,各种数据不需要都放在一起,父doc和子doc分别在进行更新的时候,都不会影响对方
> * 一对多关系的建模,维护起来比较方便,类似关系型数据库的建模方式,应用层join的方式,会导致性能比较差,因为做多次搜索。父子关系的数据模型,不会,性能很好。因为虽然数据实体之间分割开来,但是我们在搜索的时候,由es自动为我们处理底层的关联关系,并且通过一些手段保证搜索性能。
> 1. 父子关系数据模型,相对于nested数据模型来说,优点是父doc和子doc互相之间不会影响
> 要点:
>
> 1. 父子关系元数据映射,用于确保查询时候的高性能,但是有一个限制,就是父子数据必须存在于一个shard中
> 2. 父子关系数据存在一个shard中,而且还有映射其关联关系的元数据,那么搜索父子关系数据的时候,不用跨分片,一个分片本地自己就搞定了,性能当然高了
## 1\. 父子关系建模
> 1. mapping中建立两个索引(父index和子index)
> 2. 子index加入`_parent`属性,指明自己的父index
案例背景:研发中心员工管理案例,一个IT公司有多个研发中心,每个研发中心有多个员工
~~~
PUT /company
{
"mappings": {
"rd_center": {},
"employee": {
"_parent": {
"type": "rd_center" # 指顶父index
}
}
}
}
~~~
父子关系建模的核心,多个type之间有父子关系,用\_parent指定父type
* 插入父index数据
~~~
POST /company/rd_center/_bulk
{ "index": { "_id": "1" }}
{ "name": "北京研发总部", "city": "北京", "country": "中国" }
{ "index": { "_id": "2" }}
{ "name": "上海研发中心", "city": "上海", "country": "中国" }
{ "index": { "_id": "3" }}
{ "name": "硅谷人工智能实验室", "city": "硅谷", "country": "美国" }
~~~
> * shard路由的时候,id=1的rd\_center doc,默认会根据id进行路由,到某一个shard
~~~
PUT /company/employee/1?parent=1 # 指定父doc的id,可以保证父子doc路由到用一个share上
{
"name": "张三",
"birthday": "1970-10-24",
"hobby": "爬山"
}
~~~
> * 维护父子关系的核心,parent=1,指定了这个数据的父doc的id
> 此时,parent-child关系,就确保了说,父doc和子doc都是保存在一个shard上的。内部原理还是doc routing,employee和rd\_center的数据,都会用parent id作为routing,这样就会到一个shard
> 就不会根据id=1的employee doc的id进行路由了,而是根据parent=1进行路由,会根据父doc的id进行路由,那么就可以通过底层的路由机制,保证父子数据存在于一个shard中
~~~
POST /company/employee/_bulk
{ "index": { "_id": 2, "parent": "1" }}
{ "name": "李四", "birthday": "1982-05-16", "hobby": "游泳" }
{ "index": { "_id": 3, "parent": "2" }}
{ "name": "王二", "birthday": "1979-04-01", "hobby": "爬山" }
{ "index": { "_id": 4, "parent": "3" }}
{ "name": "赵五", "birthday": "1987-05-11", "hobby": "骑马" }
~~~
## 2\. 搜索、聚合
1. 搜索有1980年以后出生的员工的研发中心
> 因为要得到研发中心,所以从研发中心index中search,并指明查询类型是has\_child(从父往下查,过滤子信息1980),这里是从rd\_center(父index)search
~~~
GET company/rd_center/_search
{
"query": {
"has_child": { # 指明query类型 ,和nested object类似,
"type": "employee", # 查询分析的是子index,指明从父里边查,还是子index查
"query": {
"range": {
"birthday": {
"gte": 1980
}
}
}
}
}
}
~~~
得到
~~~
"hits": [
{
"_index": "company",
"_type": "rd_center",
"_id": "1",
"_score": 1,
"_source": {
"name": "北京研发总部",
"city": "北京",
"country": "中国"
}
},
{
"_index": "company",
"_type": "rd_center",
"_id": "3",
"_score": 1,
"_source": {
"name": "硅谷人工智能实验室",
"city": "硅谷",
"country": "美国"
}
}
]
~~~
2. 搜索有名叫张三的员工的研发中心
~~~
GET /company/rd_center/_search
{
"query": {
"has_child": {
"type": "employee",
"query": {
"match": {
"name": "张三"
}
}
}
}
}
~~~
3. 搜索有至少2个以上员工的研发中心
~~~
GET /company/rd_center/_search
{
"query": {
"has_child": {
"type": "employee",
"min_children": 2, # 指明父index中至少有两个doc的才符合
"query": {
"match_all": {}
}
}
}
}
~~~
4. 搜索在中国的研发中心的员工
这里是对父index查询过滤出子index
* 错误的
~~~
GET /company/employee/_search
{
"query": {
"has_parent": {
"parent_type": "rd_center",
"query": {
"term": {
"country": {
"value": "中国"
}
}
}
}
}
}
~~~
因为倒排索引中的“中国”已经被分为“中”,“国”,term有事精准查询,所以上边的查询是无效de
正确的使用es默认为我们创建的country.keyword查询
## 3\. 祖孙三代
父子关系,祖孙三层关系的数据建模,搜索
~~~
PUT /company
{
"mappings": {
"country": {},
"rd_center": {
"_parent": {
"type": "country"
}
},
"employee": {
"_parent": {
"type": "rd_center"
}
}
}
}
~~~
country -> rd\_center -> employee,祖孙三层数据模型
~~~
POST /company/country/_bulk
{ "index": { "_id": "1" }}
{ "name": "中国" }
{ "index": { "_id": "2" }}
{ "name": "美国" }
POST /company/rd_center/_bulk
{ "index": { "_id": "1", "parent": "1" }}
{ "name": "北京研发总部" }
{ "index": { "_id": "2", "parent": "1" }}
{ "name": "上海研发中心" }
{ "index": { "_id": "3", "parent": "2" }}
{ "name": "硅谷人工智能实验室" }
~~~
~~~
PUT /company/employee/1?parent=1&routing=1
{
"name": "张三",
"dob": "1970-10-24",
"hobby": "爬山"
}
~~~
routing参数的讲解,必须跟grandparent相同,否则有问题
country,用的是自己的id去路由; rd\_center,parent,用的是country的id去路由; employee,如果也是仅仅指定一个parent,那么用的是rd\_center的id去路由,这就导致祖孙三层数据不会在一个shard上
孙子辈儿,要手动指定routing,指定为爷爷辈儿的数据的id
搜索有爬山爱好的员工所在的国家
~~~
GET /company/country/_search
{
"query": {
"has_child": {
"type": "rd_center",
"query": {
"has_child": {
"type": "employee",
"query": {
"match": {
"hobby": "爬山"
}
}
}
}
}
}
}
~~~
~~~
{
"took": 10,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"failed": 0
},
"hits": {
"total": 1,
"max_score": 1,
"hits": [
{
"_index": "company",
"_type": "country",
"_id": "1",
"_score": 1,
"_source": {
"name": "中国"
}
}
]
}
}
~~~
- springcloud
- springcloud的作用
- springboot服务提供者和消费者
- Eureka
- ribbon
- Feign
- feign在微服务中的使用
- feign充当http请求工具
- Hystrix 熔断器
- Zuul 路由网关
- Spring Cloud Config 分布式配置中心
- config介绍与配置
- Spring Cloud Config 配置实战
- Spring Cloud Bus
- gateway
- 概念讲解
- 实例
- GateWay
- 统一日志追踪
- 分布式锁
- 1.redis
- springcloud Alibaba
- 1. Nacos
- 1.1 安装
- 1.2 特性
- 1.3 实例
- 1. 整合nacos服务发现
- 2. 整合nacos配置功能
- 1.4 生产部署方案
- 环境隔离
- 原理讲解
- 1. 服务发现
- 2. sentinel
- 3. Seata事务
- CAP理论
- 3.1 安装
- 分布式协议
- 4.熔断和降级
- springcloud与alibba
- oauth
- 1. abstract
- 2. oauth2 in micro-service
- 微服务框架付费
- SkyWalking
- 介绍与相关资料
- APM系统简单对比(zipkin,pinpoint和skywalking)
- server安装部署
- agent安装
- 日志清理
- 统一日志中心
- docker安装部署
- 安装部署
- elasticsearch 7.x
- logstash 7.x
- kibana 7.x
- ES索引管理
- 定时清理数据
- index Lifecycle Management
- 没数据排查思路
- ELK自身组件监控
- 多租户方案
- 慢查询sql
- 日志审计
- 开发
- 登录认证
- 链路追踪
- elk
- Filebeat
- Filebeat基础
- Filebeat安装部署
- 多行消息Multiline
- how Filebeat works
- Logstash
- 安装
- rpm安装
- docker安装Logstash
- grok调试
- Grok语法调试
- Grok常用表达式
- 配置中常见判断
- filter提取器
- elasticsearch
- 安装
- rpm安装
- docker安装es
- 使用
- 概念
- 基础
- 中文分词
- 统计
- 排序
- 倒排与正排索引
- 自定义dynamic
- 练习
- nested object
- 父子关系模型
- 高亮
- 搜索提示
- kibana
- 安装
- docker安装
- rpm安装
- 整合
- 收集日志
- 慢sql
- 日志审计s
- 云
- 分布式架构
- 分布式锁
- Redis实现
- redisson
- 熔断和降级