阅读本文需要一定的Elasticsearch基础哦,本文深度有,但是不深

概述

Elasticsearch中Join数据类型的字段相信大家也都用过,也就是口中常谈的父子文档。在Elasticsearch中Join不能跨索引和分片,所以保存文档信息时要保证父子文档使用相同的路由参数来保证父文档与子文档保存在同一个索引的同一个分片,那么都有哪些限制呢?

父子关系的限制

  • 每个索引中只能有一个关系字段
  • 父文档与子文档必须在同一个索引分片中,所以我们在对父子文档增加、删除、修改时要设置路由值,保证数据都在同一分片
  • 一个父文档可以包含多个子文档,但是一个子文档只能有一个父文档
  • 只能在Join类型的字段上建立关系
  • 在保证当前文档是父文档的前提下可以增加子文档

Global ordinals

翻译过来就是全局序数。什么是全局序数呢,官方文档中说明了,这就是一个加速查询的一个东西,使用了全局序数之后可以让数据更紧凑;详细的就不展开了,后面有机会再详细说明一下全局序数,具体的目前可以查看一下官方文档

对于我们本章节内容来说,我们知道父子文档Join类型是使用全局序数来加速查询的就可以了。默认情况下,全局序数基本是实时构建的,当索引发生变化,全局序数会重新构建。这个过程会增加refresh的时间,当然这个配置也是可以关闭的,但是关闭之后会在我们接下来遇到的第一个父连接或者聚合的查询时重新构建全局序数,这样这一部分的时间就反馈给了用户,官方也是不建议我们这样做的,感觉对用户来说不是那么的友好,主要还是在一个权衡。最坏的情况就是同时有多个写入,也就是同时有多个全局序数需要重新构建,也就会造成在单个refresh的时间间隔内要重新构建多个全局序数

当然如果关联字段使用的不是很频繁并且写入事件很多,禁用掉是值得推荐的,禁用方式如下

PUT my-index-000001
{
  "mappings": {
    "properties": {
      "join_field": {
        "type": "join",
        "relations": {
           "goods": ["details","evaluate"],
           "evaluate":"vote"
        },
        "eager_global_ordinals": false
      }
    }
  }
}

当然,对于全局序数占用的堆大小情况可以使用如下语句查看

# Per-index
GET my-index-000001/_stats/fielddata?human&fields=join_field#goods
# Per-node per-index
GET _nodes/stats/indices/fielddata?human&fields=join_field#goods

父子文档

首先我们还是创建一个正常的父子关系索引,商品作为父文档,详情作为子文档

DELETE my-index-000001
PUT my-index-000001
{
  "mappings": {
    "properties": {
      "id": {
        "type": "keyword"
      },
      "join_field": { 
        "type": "join",
        "relations": {
          "goods": "details" 
        }
      }
    }
  }
}
  • my-index-000001:索引名称
  • id:文档主键
  • join_field:父子关系字段,type标记为Join为父子文档
  • relations: 定义父子关系,goods为父文档类型名称,details为子文档类型名称,后面插入数据,查询都会使用

插入几条测试数据,商品有iphonmac,详情为颜色外观与内存配置等

PUT my-index-000001/_doc/1?refresh
{
  "id": "1",
  "text": "iphone 14 pro max",
  "join_field": {
    "name": "goods" 
  }
}
PUT my-index-000001/_doc/2?refresh
{
  "id": "2",
  "text": "macbook pro ",
  "join_field": {
    "name": "goods"
  }
}
PUT my-index-000001/_doc/3?routing=1&refresh 
{
  "id": "3",
  "text": "512G 16核",
  "join_field": {
    "name": "details", 
    "parent": "1" 
  }
}
PUT my-index-000001/_doc/4?routing=1&refresh
{
  "id": "4",
  "text": "粉/银/黑/抹茶绿",
  "join_field": {
    "name": "details",
    "parent": "1"
  }
}
PUT my-index-000001/_doc/5?routing=1&refresh 
{
  "id": "5",
  "text": "1T 32G",
  "join_field": {
    "name": "details", 
    "parent": "2" 
  }
}
PUT my-index-000001/_doc/6?routing=1&refresh
{
  "id": "6",
  "text": "银/黑",
  "join_field": {
    "name": "details",
    "parent": "2"
  }
}

使用parent_id查询父子文档,以上面插入的测试数据查询,查找mac的详情信息语句如下,前提是知道父文档的id

GET my-index-000001/_search
{
  "query": {
    "parent_id": {
      "type": "details",
      "id":"2"
    }
  },
  "sort":["id"]
}
  • 大部分情况上面是不能满足我们的查询请求的,所以我们还可以使用has_parent或者has_child查询

使用has_parent查询:父文档goods中所有包含macbook的子文档(后文的孙子文档也可以查询)

GET my-index-000001/_search
{
  "query": {
    "has_parent": {
      "parent_type": "goods",
      "query": {
        "match": {
          "text": "macbook"
        }
      }
    }
  }
}

使用hash_child查看details子文档中有1T关键字的所有父文档

GET my-index-000001/_search
{
  "query": {
    "has_child": {
      "type": "details",
      "query": {
        "match": {
          "text": "1T"
        }
      }
    }
  }
}

使用parent-join 查询或者聚合

Elasticsearch在使用Join类型数据类型时,会自动创建一个附加的字段,结构为Join的字段名加#号加父类型,以上文为例,创建一个附加字段(join_field#goods),如下是使用parent-join字段查询聚合的一个例子,参考自官网,应用了8.1版本的新特性运行时字段

GET my-index-000001/_search
{
  "query": {
    "parent_id": { 
      "type": "details",
      "id": "1"
    }
  },
  "aggs": {
    "parents": {
      "terms": {
        "field": "join_field#goods", 
        "size": 10
      }
    }
  },
  "runtime_mappings": {
    "my_parent_field": {
      "type": "long",
      "script": """
        emit(Integer.parseInt(doc['join_field#goods'].value)) 
      """
    }
  },
  "fields": [
    { "field": "my_parent_field" }
  ]
}

Join类型的父子文档,上面我们演示了一个父文档对应一种子文档类型的例子,Join类型也支持一个父类型有多个子类型,以上文为基础,加入下面语句测试

DELETE my-index-000001
PUT my-index-000001
{
  "mappings": {
    "properties": {
      "id": {
        "type": "keyword"
      },
      "join_field": { 
        "type": "join",
        "relations": {
          "goods": ["details","evaluate"] 
        }
      }
    }
  }
}
PUT my-index-000001/_doc/7?routing=1&refresh
{
  "id": "7",
  "text": "运行流程,无卡顿,待机时间长",
  "join_field": {
    "name": "evaluate",
    "parent": "1"
  }
}
PUT my-index-000001/_doc/8?routing=1&refresh
{
  "id": "8",
  "text": "体重轻,携带方便,编码利器",
  "join_field": {
    "name": "evaluate",
    "parent": "2"
  }
}
  • 同样的,细心的同学已经看到了,上文已经标记了孙子文档,对的,你没看错就是孙子文档,三级的层级,级别可以更深,但是Elasticsearch不建议很深的层次,毕竟Join很消耗性能的,层级再深点没法用了,下面就是多级别的语句测试,此时他们三者的关系就如下所示

DELETE my-index-000001
PUT my-index-000001
{
  "mappings": {
    "properties": {
      "id": {
        "type": "keyword"
      },
      "join_field": { 
        "type": "join",
        "relations": {
          "goods": ["details","evaluate"],
          "evaluate":"vote"
        }
      }
    }
  }
}
PUT my-index-000001/_doc/9?routing=1&refresh
{
  "id": "9",
  "text": "这是投票信息:我买iphone是因为性价比高,保值",
  "join_field": {
    "name": "vote",
    "parent": "1"
  }
}
PUT my-index-000001/_doc/10?routing=1&refresh
{
  "id": "10",
  "text": "这是投票信息:我买mac是因为轻,携带方便,没有流氓软件",
  "join_field": {
    "name": "vote",
    "parent": "2"
  }
}

总结

相信大家也看出来了,官方都不建议使用父子文档的,毕竟性能是一大问题,相信大家用Elasticsearch肯定大部分都是图速度快,用了Join字段变慢了,这谁能同意呢是吧,有利有弊吧,看大家选择,下一篇带给大家的算是Elasticsearch推荐Join字段替代类型Nested,更多关于Elasticsearch Join字段类型的资料请关注Devmax其它相关文章!

Elasticsearch Join字段类型简单快速上手教程的更多相关文章

  1. iOS – 开始iOS教程 – 变量之前的下划线?

    这是正确的还是我做错了什么?

  2. Swift开发快速上手系列教程目录-陆续完善,由浅入深

    Swift开发教程一.Swift基础Swift教程01-使用switfc终端命令编译运行swift程序Swift教程02-抓住下一个浪潮之巅Swift教程03-playground剖析swift语言Swift教程04-定义声明变量重要原则Swift教程05-基本数据类型(一)整型浮点型Swift教程06-基本数据类型(二)Bool布尔类型对比Java-boolean,Objc-BOOLSwift教

  3. Swift2.0不深入只浅出入门教程-01-The Basic

    本套视频教程是Swift2.0的入门教程,如果你看过其他的教程,可以不看这套教程,录制这套教程的目的,一个是为了自学,一个是为之后自己的另一套教程打基础。本期教程主要介绍Swift语言的一些基础知识。由于CSDN学院的课程审核还没有通过,所以暂时就放到了百度网盘。

  4. Swift教程-视频拍摄教程

    在此教程中,我们将拍摄一段保存到手机相册的视频。教程运行在iOS8.4和Xcode6.4下。打开Xcode并创建一个newSingleViewApplication,项目名称为IOS8SwiftTakeVideoPlayerTutorial,接着填上你的OrganizationName和OrganizationIdentifier,选择Swift语言,在设备一栏只选择iPhone。ImagePickerController的数据可以是Camera或Movie两种类型。视频的maximum长度设置为10秒。

  5. 详解 SiriKit - SiriKit 教程Part 2

    此文章是SiriKit教程系列的第二篇,建议先去阅读第一篇。处理SiriKit请求为了让集成的Siri更有用,可以使用INSendMessageIntentHandling协议的回调方法增加信息内容。协议有以下可选方法:只要实现这些方法,就可以给SiriKit提供更多信息,例如接收者、内容、小组名字、服务名字或者发送者。后面会详细说明区别,现在先介绍如何使用Siri提供的数据。Siri传入的intent对象包含文字版的消息内容。现在当我们尝试发送消息时,SiriKit就明白必须要提供内容值。

  6. swift 学习资源 - Swift 语言指南

    对于精选项目及文章,可直接访问《Swift项目精选》和《Swift文章精选》。对于Swift开源及跨平台开发的同学,可以关注swift.org教程文章开源项目推荐网站苹果官方Swift:Swift概述、博客以及开发资源。swift.org:开源后独立出来的Swift开源社区。ksm/SwiftInFlux:作者将AppleDeveloperForums上有关Swift特性、缺陷及变更讨论分类汇总并更新到GitHub,具有很好的可读性。从中可以一窥Swift缺陷及未来潜在地变化。近期第一时间出了三本Swif

  7. [译] NSCollectionView 入门教程

    Mac中自带的Finder和Photos就是使用了它:通过一个CollectionView来展示所有的文件和图片。NSCollectionView最早在OSX10.5被推出,它可以非常方便地布局一组具有相同大小的item,并把它们展示在一个可以滑动的ScrollView中。在OSX10.11ElCapitan中,参照iOS上的UICollectionView,NSCollectionView被全面进行了升级。在这个NSCollectionView的入门教程中,你将会创造一个叫SlideMagic的app,

  8. 数组 – Swift中数组“Join”函数的用途[closed]

    在数组中使用join()是什么?在其他语言中,它用于将数组的元素连接成字符串。

  9. swift -- 定义空字符串 hasPrefix hasSuffix trim split join range

    //定义空的字符串varstr1=""varstr2=String()str1.isEmpty//判断字符串是否为空//输出字符串中所有的字符varstr3="Asgodname"forcinstr3{println}Int.max//Int类型的最大值Int.min//Int类型的最小值vararr1=["c","oc","ios","swift"]varcount=0fornameinarr1{ifname.hasPrefix("i"){//hasPrefix前缀count++count}}count

  10. 在Swift 2.0中无法使用类型为(String,[String])的参数列表调用`join`

    与Xcode7beta6:使用Xcode7发布版本:

随机推荐

  1. 基于EJB技术的商务预订系统的开发

    用EJB结构开发的应用程序是可伸缩的、事务型的、多用户安全的。总的来说,EJB是一个组件事务监控的标准服务器端的组件模型。基于EJB技术的系统结构模型EJB结构是一个服务端组件结构,是一个层次性结构,其结构模型如图1所示。图2:商务预订系统的构架EntityBean是为了现实世界的对象建造的模型,这些对象通常是数据库的一些持久记录。

  2. Java利用POI实现导入导出Excel表格

    这篇文章主要为大家详细介绍了Java利用POI实现导入导出Excel表格,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  3. Mybatis分页插件PageHelper手写实现示例

    这篇文章主要为大家介绍了Mybatis分页插件PageHelper手写实现示例,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

  4. (jsp/html)网页上嵌入播放器(常用播放器代码整理)

    网页上嵌入播放器,只要在HTML上添加以上代码就OK了,下面整理了一些常用的播放器代码,总有一款适合你,感兴趣的朋友可以参考下哈,希望对你有所帮助

  5. Java 阻塞队列BlockingQueue详解

    本文详细介绍了BlockingQueue家庭中的所有成员,包括他们各自的功能以及常见使用场景,通过实例代码介绍了Java 阻塞队列BlockingQueue的相关知识,需要的朋友可以参考下

  6. Java异常Exception详细讲解

    异常就是不正常,比如当我们身体出现了异常我们会根据身体情况选择喝开水、吃药、看病、等 异常处理方法。 java异常处理机制是我们java语言使用异常处理机制为程序提供了错误处理的能力,程序出现的错误,程序可以安全的退出,以保证程序正常的运行等

  7. Java Bean 作用域及它的几种类型介绍

    这篇文章主要介绍了Java Bean作用域及它的几种类型介绍,Spring框架作为一个管理Bean的IoC容器,那么Bean自然是Spring中的重要资源了,那Bean的作用域又是什么,接下来我们一起进入文章详细学习吧

  8. 面试突击之跨域问题的解决方案详解

    跨域问题本质是浏览器的一种保护机制,它的初衷是为了保证用户的安全,防止恶意网站窃取数据。那怎么解决这个问题呢?接下来我们一起来看

  9. Mybatis-Plus接口BaseMapper与Services使用详解

    这篇文章主要为大家介绍了Mybatis-Plus接口BaseMapper与Services使用详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

  10. mybatis-plus雪花算法增强idworker的实现

    今天聊聊在mybatis-plus中引入分布式ID生成框架idworker,进一步增强实现生成分布式唯一ID,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

返回
顶部