Elasticsearch 父子关系

Elasticsearch的父子关系在一定场景下非常有利于我们进行关联查询,合理使用能加快我们的索引速度。

父子关系图
对于Elasticsearch的 Parent and Child:

1.家庭关系:
在这里插入图片描述
2.学校关系:
在这里插入图片描述
3.等等关系我们都可以用父子关系来表示,这非常有利于我们进行父子关系的查询。

Parent and Child 有如下特点:

  1. 父子关系
  2. 每个父母有多个孩子
  3. 多个层次的亲子关系

这里我们使用汽车关系来进行相关展示:
在这里插入图片描述
在这里插入图片描述
创建相关索引

PUT family_tree
{
  "settings": {
    "index":{
      "number_of_shards":1,
      "number_of_replicas":0
    }
  },
  "mappings": {
    "properties": {
      "name":{
        "type": "text"
      },
      "price":{
        "type": "text"
      },
      "isSale":{
        "type": "boolean"
      },
      "relation_type":{
        "type": "join",
        "eager_global_ordinals": true,
        "relations":{
          "parent":"child"
        }
      }
    }
  }
}

注意: 父子关系中使用 “eager_global_ordinals” 能加速join.

由于存储的数据已被非规范化。因此联接不能跨索引,子文档和父文档必须位于相同的索引和相同的分片中。父子关系需要在统一分片中:通过固定值来路由(routing)到同一个分片中。

分片规则: shard = hash(routing_value) % number_of_primary_shards
父节点插入数据

PUT family_tree/_doc/1?routing=Car
{
  "name":"Car",
  "price":"2000000",
  "isSale":true,
  "relation_type":{
    "name":"parent"
  }
}

子节点插入数据

PUT family_tree/_doc/2?routing=Car
{
  "name":"Van",
  "price":"10000",
  "isSale":true,
  "relation_type":{
    "name":"child",
    "parent":1
  }
}
PUT family_tree/_doc/3?routing=Car
{
  "name":"Sedan",
  "price":"10000",
  "isSale":true,
  "relation_type":{
    "name":"child",
    "parent":1
  }
}
PUT family_tree/_doc/4?routing=Car
{
  "name":"SUV",
  "price":"8000",
  "isSale":true,
  "relation_type":{
    "name":"child",
    "parent":1
  }
}

注意:子文档和父文档必须位于同一分片上的限制。

查询数据 — 搜索和过滤指定的父节点
获取Car的所有子级:parent_id查询可用于查找属于特定父级的子级文档。

GET /family_tree/_search?pretty=true
{
  "query": {
    "parent_id":{
      "type":"child",
      "id":"1"
    }
  }
}

结果:以查找出属于parent_id为 1 的所有子级文档。
在这之前我们先为 Car 添加一个不再销售的汽车类型:

PUT family_tree/_doc/5?routing=Car
{
  "name":"Sports car",
  "price":"30000000",
  "isSale":false,
  "relation_type":{
    "name":"child",
    "parent":1
  }
}

1.用bool与must结合获取所有未售 Car 的孩子:

GET /family_tree/_search
{
  "query": {
    "bool": {
      "filter": {
        "term": {
          "isSale": "false"
        }
      },
      "must": [
        {
          "parent_id":{
            "type":"child",
            "id":"1"
          }
        }
      ]
    }
  }
}

结果: 从查询到的结果中可以看到:只有"Sports car"符合我们查询的条件。
2.我们也可以通过has_child查询拥有子节点未销售状态的父节点信息:

GET /family_tree/_search?pretty
{
  "query": {
    "has_child": {
      "type": "child",
      "query": {
        "bool": {
          "must": [
            {"match": {"isSale": "false"}}
          ]
        }
      }
    }
  }
}

3.has_parent关键字可帮助我们获取所有有父母且符合过滤条件的孩子信息。通过has_parent来查询父节点状态为在售的所有子节点信息:

GET /family_tree/_search?pretty
{
  "query": {
    "has_parent": {
      "parent_type": "parent",
      "query": {
        "match": {
          "isSale": "true"
        }
      }
    }
  }
}

每个关系级别都会在查询时增加内存和计算方面的开销,不建议使用多个级别的关系模型。

本次收获:

  1. 父子文档必须索引到同一个分片中。
  2. 每个索引仅允许一个连接字段映射。
  3. 一个元素可以有多个子级,但只能有一个父级。
  4. 可以向已存在的联接字段添加新关系。
  5. 也可以将子元素添加到现有元素中,但前提是该元素已经是父元素。

当索引时间性能比搜索时间性能更重要时,父子join可能是管理关系的一种不错选择,但代价是很高的。必须意识到这种权衡,例如父子文档的物理存储约束和增加的复杂性。另一个预防措施是避免多层父子关系,因为这将消耗更多的内存和计算量。这些都是我们在使用父子关系的时候必须要考虑到的相关内容,避免造成不必要的损失。二哈觉得大家还是要根据实际场景来选择合适自己的,综合考虑自己的需求,没有什么是一套全通的呀!ღゝ◡╹)ノ♡

二哈最近开通了公众号呀,在这里你可以收获最新的资讯呀,千万别错过啦!欢迎兄弟们关注关注。
BKing的订阅号

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值