2023年6月30日发(作者:)
Elasticsearch顶尖⾼⼿系列:核⼼知识篇(⼀)⽬录1.第1-4节第01节:课程介绍略过第02节:什么是Elasticsearch课程⼤纲⼤⽩话、什么是ElasticsearchElasticsearch,分布式,⾼性能,⾼可⽤,可伸缩的搜索和分析系统1、什么是搜索?2、如果⽤数据库做搜索会怎么样?3、什么是全⽂检索、倒排索引和Lucene?4、什么是Elasticsearch?1、什么是搜索?百度:我们⽐如说想找寻任何的信息的时候,就会上百度去搜索⼀下,⽐如说找⼀部⾃⼰喜欢的电影,或者说找⼀本喜欢的书,或者找⼀条感兴趣的新闻(提到搜索的第⼀印象)百度 != 搜索,这是不对的垂直搜索(站内搜索)互联⽹的搜索:电商⽹站,招聘⽹站,新闻⽹站,各种appIT系统的搜索:OA软件,办公⾃动化软件,会议管理,⽇程管理,项⽬管理,员⼯管理,搜索“张三”,“张三⼉”,“张⼩三”;有个电商⽹站,卖家,后台管理系统,搜索“⽛膏”,订单,“⽛膏相关的订单”搜索,就是在任何场景下,找寻你想要的信息,这个时候,会输⼊⼀段你要搜索的关键字,然后就期望找到这个关键字相关的有些信息2、如果⽤数据库做搜索会怎么样?做软件开发的话,或者对IT、计算机有⼀定的了解的话,都知道,数据都是存储在数据库⾥⾯的,⽐如说电商⽹站的商品信息,招聘⽹站的职位信息,新闻⽹站的新闻信息,等等吧。所以说,很⾃然的⼀点,如果说从技术的⾓度去考虑,如何实现如说,电商⽹站内部的搜索功能的话,就可以考虑,去使⽤数据库去进⾏搜索。1、⽐⽅说,每条记录的指定字段的⽂本,可能会很长,⽐如说“商品描述”字段的长度,有长达数千个,甚⾄数万个字符,这个时候,每次都要对每条记录的所有⽂本进⾏扫描,懒判断说,你包不包含我指定的这个关键词(⽐如说“⽛膏”)2、还不能将搜索词拆分开来,尽可能去搜索更多的符合你的期望的结果,⽐如输⼊“⽣化机”,就搜索不出来“⽣化危机”⽤数据库来实现搜索,是不太靠谱的。通常来说,性能会很差的。3、什么是全⽂检索和Lucene?(1)全⽂检索,倒排索引(2)lucene,就是⼀个jar包,⾥⾯包含了封装好的各种建⽴倒排索引,以及进⾏搜索的代码,包括各种算法。我们就⽤java开发的时候,引⼊lucene jar,然后基于lucene的api进⾏去进⾏开发就可以了。⽤lucene,我们就可以去将已有的数据建⽴索引,lucene会在本地磁盘上⾯,给我们组织索引的数据结构。另外的话,我们也可以⽤lucene提供的⼀些功能和api来针对磁盘上额4、什么是Elasticsearch?(1)图解分析第03节:Elasticsearch的功能、适⽤场景以及特点介绍课程⼤纲1、Elasticsearch的功能,⼲什么的2、Elasticsearch的适⽤场景,能在什么地⽅发挥作⽤3、Elasticsearch的特点,跟其他类似的东西不同的地⽅在哪⾥1、Elasticsearch的功能(1)分布式的搜索引擎和数据分析引擎搜索:百度,⽹站的站内搜索,IT系统的检索数据分析:电商⽹站,最近7天⽛膏这种商品销量排名前10的商家有哪些;新闻⽹站,最近1个⽉访问量排名前3的新闻版块是哪些分布式,搜索,数据分析(2)全⽂检索,结构化检索,数据分析全⽂检索:我想搜索商品名称包含⽛膏的商品,select * from products where product_name like “%⽛膏%”结构化检索:我想搜索商品分类为⽇化⽤品的商品都有哪些,select * from products where category_id=‘⽇化⽤品’部分匹配、⾃动完成、搜索纠错、搜索推荐数据分析:我们分析每⼀个商品分类下有多少个商品,select category_id,count(*) from products group by category_id(3)对海量数据进⾏近实时的处理分布式:ES⾃动可以将海量数据分散到多台服务器上去存储和检索海联数据的处理:分布式以后,就可以采⽤⼤量的服务器去存储和检索数据,⾃然⽽然就可以实现海量数据的处理了近实时:检索个数据要花费1⼩时(这就不要近实时,离线批处理,batch-processing);在秒级别对数据进⾏搜索和分析跟分布式/海量数据相反的:lucene,单机应⽤,只能在单台服务器上使⽤,最多只能处理单台服务器可以处理的数据量2、Elasticsearch的适⽤场景国外(1)维基百科,类似百度百科,⽛膏,⽛膏的维基百科,全⽂检索,⾼亮,搜索推荐(2)The Guardian(国外新闻⽹站),类似搜狐新闻,⽤户⾏为⽇志(点击,浏览,收藏,评论)+社交⽹络数据(对某某新闻的相关看法),数据分析,给到每篇新闻⽂章的作者,让他知道他的⽂章的公众反馈(好,坏,热门,垃圾,鄙视,崇拜)(3)Stack Overflow(国外的程序异常讨论论坛),IT问题,程序的报错,提交上去,有⼈会跟你讨论和回答,全⽂检索,搜索相关问题和答案,程序报错了,就会将报错信息粘贴到⾥⾯去,搜索有没有对应的答案(4)GitHub(开源代码管理),搜索上千亿⾏代码(5)电商⽹站,检索商品(6)⽇志数据分析,logstash采集⽇志,ES进⾏复杂的数据分析(ELK技术,elasticsearch+logstash+kibana)(7)商品价格监控⽹站,⽤户设定某商品的价格阈值,当低于该阈值的时候,发送通知消息给⽤户,⽐如说订阅⽛膏的监控,如果⾼露洁⽛膏的家庭套装低于50块钱,就通知我,我就去买(8)BI系统,商业智能,Business Intelligence。⽐如说有个⼤型商场集团,BI,分析⼀下某某区域最近3年的⽤户消费⾦额的趋势以及⽤户群体的组成构成,产出相关的数张报表,**区,最近3年,每年消费⾦额呈现100%的增长,⽽且⽤户群体85%是⾼级⽩领,开⼀个新商场。ES执⾏数据分析和挖掘,Kibana进⾏数据可视化国内(9)国内:站内搜索(电商,招聘,门户,等等),IT系统搜索(OA,CRM,ERP,等等),数据分析(ES热门的⼀个使⽤场景)3、Elasticsearch的特点(1)可以作为⼀个⼤型分布式集群(数百台服务器)技术,处理PB级数据,服务⼤公司;也可以运⾏在单机上,服务⼩公司(2)Elasticsearch不是什么新技术,主要是将全⽂检索、数据分析以及分布式技术,合并在了⼀起,才形成了独⼀⽆⼆的ES;lucene(全⽂检索),商⽤的数据分析软件(也是有的),分布式数据库(mycat)(3)对⽤户⽽⾔,是开箱即⽤的,⾮常简单,作为中⼩型的应⽤,直接3分钟部署⼀下ES,就可以作为⽣产环境的系统来使⽤了,数据量不⼤,操作不是太复杂(4)数据库的功能⾯对很多领域是不够⽤的(事务,还有各种联机事务型的操作);特殊的功能,⽐如全⽂检索,同义词处理,相关度排名,复杂数据分析,海量数据的近实时处理;Elasticsearch作为传统数据库的⼀个补充,提供了数据库所不不能提供的很多功能第04节:Elasticsearch核⼼概念:NRT、索引、分⽚、副本等elasticsearch概念1 lucene和elasticsearch的前世今⽣lucene,最先进、功能最强⼤的搜索库,直接基于lucene开发,⾮常复杂,api复杂(实现⼀些简单的功能,写⼤量的java代码),需要深⼊理解原理(各种索引结构)elasticsearch,基于lucene,隐藏复杂性,提供简单易⽤的restful api接⼝、java api接⼝(还有其他语⾔的api接⼝)(1)分布式的⽂档存储引擎(2)分布式的搜索引擎和分析引擎(3)分布式,⽀持PB级数据开箱即⽤,优秀的默认参数,不需要任何额外设置,完全开源关于elasticsearch的⼀个传说,有⼀个程序员失业了,陪着⾃⼰⽼婆去英国伦敦学习厨师课程。程序员在失业期间想给⽼婆写⼀个菜谱搜索引擎,觉得lucene实在太复杂了,就开发了⼀个封装了lucene的开源项⽬,compass。后来程序员找到了⼯作,是做分布式的⾼性能项⽬的,觉得compass不够,就写了elasticsearch,让lucene变成分布式的系统。2 elasticsearch的核⼼概念(1)Near Realtime(NRT):近实时,两个意思,从写⼊数据到数据可以被搜索到有⼀个⼩延迟(⼤概1秒);基于es执⾏搜索和分析可以达到秒级(2)Cluster:集群,包含多个节点,每个节点属于哪个集群是通过⼀个配置(集群名称,默认是elasticsearch)来决定的,对于中⼩型应⽤来说,刚开始⼀个集群就⼀个节点很正常(3)Node:节点,集群中的⼀个节点,节点也有⼀个名称(默认是随机分配的),节点名称很重要(在执⾏运维管理操作的时候),默认节点会去加⼊⼀个名称为“elasticsearch”的集群,如果直接启动⼀堆节点,那么它们会⾃动组成⼀个elasticsearch集群,当然⼀个节点也可以组成⼀个elasticsearch集群(4)Document&field:⽂档,es中的最⼩数据单元,⼀个document可以是⼀条客户数据,⼀条商品分类数据,⼀条订单数据,通常⽤JSON数据结构表⽰,每个index下的type中,都可以去存储多个document。⼀个document⾥⾯有多个field,每个field就是⼀个数据字段。product document{“product_id”: “1”,“product_name”: “⾼露洁⽛膏”,“product_desc”: “⾼效美⽩”,“category_id”: “2”,“category_name”: “⽇化⽤品”}(5)Index:索引,包含⼀堆有相似结构的⽂档数据,⽐如可以有⼀个客户索引,商品分类索引,订单索引,索引有⼀个名称。⼀个index包含很多document,⼀个index就代表了⼀类类似的或者相同的document。⽐如说建⽴⼀个product index,商品索引,⾥⾯可能就存放了所有的商品数据,所有的商品document。(6)Type:类型,每个索引⾥都可以有⼀个或多个type,type是index中的⼀个逻辑数据分类,⼀个type下的document,都有相同的field,⽐如博客系统,有⼀个索引,可以定义⽤户数据type,博客数据type,评论数据type。商品index,⾥⾯存放了所有的商品数据,商品document但是商品分很多种类,每个种类的document的field可能不太⼀样,⽐如说电器商品,可能还包含⼀些诸如售后时间范围这样的特殊field;⽣鲜商品,还包含⼀些诸如⽣鲜保质期之类的特殊fieldtype,⽇化商品type,电器商品type,⽣鲜商品type⽇化商品type:product_id,product_name,product_desc,category_id,category_name电器商品type:product_id,product_name,product_desc,category_id,category_name,service_period⽣鲜商品type:product_id,product_name,product_desc,category_id,category_name,eat_period每⼀个type⾥⾯,都会包含⼀堆document{“product_id”: “2”,“product_name”: “长虹电视机”,“product_desc”: “4k⾼清”,“category_id”: “3”,“category_name”: “电器”,“service_period”: “1年”}{“product_id”: “3”,“product_name”: “基围虾”,“product_desc”: “纯天然,冰岛产”,“category_id”: “4”,“category_name”: “⽣鲜”,“eat_period”: “7天”}(7)shard:单台机器⽆法存储⼤量数据,es可以将⼀个索引中的数据切分为多个shard,分布在多台服务器上存储。有了shard就可以横向扩展,存储更多数据,让搜索和分析等操作分布到多台服务器上去执⾏,提升吞吐量和性能。每个shard都是⼀个lucene index。(8)replica:任何⼀个服务器随时可能故障或宕机,此时shard可能就会丢失,因此可以为每个shard创建多个replica副本。replica可以在shard故障时提供备⽤服务,保证数据不丢失,多个replica还可以提升搜索操作的吞吐量和性能。primary shard(建⽴索引时⼀次设置,不能修改,默认5个),replica shard(随时修改数量,默认1个),默认每个索引10个shard,5个primary shard,5个replicashard,最⼩的⾼可⽤配置,是2台服务器。3 elasticsearch核⼼概念 vs. 数据库核⼼概念Elasticsearch 数据库Document ⾏Type 表Index 库2.第5-23节第05节:在windows上安装和启动Elasticseach{“name” : “4onsTYV”,“cluster_name” : “elasticsearch”,“cluster_uuid” : “nKZ9VK_vQdSQ1J0Dx9gx1Q”,“version” : {“number” : “5.2.0”,“build_hash” : “24e05b9”,“build_date” : “2017-01-24T19:52:35.800Z”,“build_snapshot” : false,“lucene_version” : “6.4.0”},“tagline” : “You Know, for Search”}5、修改集群名称:6、下载和解压缩Kibana安装包,使⽤⾥⾯的开发界⾯,去操作elasticsearch,作为我们学习es知识点的⼀个主要的界⾯⼊⼝,修改配置⽂件vim config/
# 放开注释,将默认配置改成如下:
: : "0.0.0.0": "192.168.202.128:9200": ".kibana"在浏览器上输⼊当前服务器的IP地址+端⼝号(5601):7、启动Kibana:8、进⼊Dev Tools界⾯9、GET _cluster/health第06节:集群健康检查,⽂档CRUD课程⼤纲1、document数据格式2、电商⽹站商品管理案例:背景介绍3、简单的集群管理4、商品的CRUD操作(document CRUD操作)2.1⾯向⽂档的搜索分析引擎(1)应⽤系统的数据结构都是⾯向对象的,复杂的(2)对象数据存储到数据库中,只能拆解开来,变为扁平的多张表,每次查询的时候还得还原回对象格式,相当⿇烦(3)ES是⾯向⽂档的,⽂档中存储的数据结构,与⾯向对象的数据结构是⼀样的,基于这种⽂档数据结构,es可以提供复杂的索引,全⽂检索,分析聚合等功能(4)es的document⽤json数据格式来表达public class Employee {private String email;private String firstName;private String lastName;private EmployeeInfo info;private Date joinDate;}private class EmployeeInfo {private String bio; // 性格private Integer age;private String[] interests; // 兴趣爱好}EmployeeInfo info = new EmployeeInfo();(“curious and modest”);(30);erests(new String[]{“bike”, “climb”});Employee employee = new Employee();il(“zhangsan@”);stName(“san”);tName(“zhang”);o(info);nDate(new Date());employee对象:⾥⾯包含了Employee类⾃⼰的属性,还有⼀个EmployeeInfo对象两张表:employee表,employee_info表,将employee对象的数据重新拆开来,变成Employee数据和EmployeeInfo数据employee表:email,first_name,last_name,join_date,4个字段employee_info表:bio,age,interests,3个字段;此外还有⼀个外键字段,⽐如employee_id,关联着employee表{“email”: “zhangsan@”,“first_name”: “san”,“last_name”: “zhang”,“info”: {“bio”: “curious and modest”,“age”: 30,“interests”: [ “bike”, “climb” ]},“join_date”: “2017/01/01”}我们就明⽩了es的document数据格式和数据库的关系型数据格式的区别2.2电商⽹站商品管理案例背景介绍有⼀个电商⽹站,需要为其基于ES构建⼀个后台系统,提供以下功能:(1)对商品信息进⾏CRUD(增删改查)操作(2)执⾏简单的结构化查询(3)可以执⾏简单的全⽂检索,以及复杂的phrase(短语)检索(4)对于全⽂检索的结果,可以进⾏⾼亮显⽰(5)对数据进⾏简单的聚合分析2.3简单的集群管理(1)快速检查集群的健康状况es提供了⼀套api,叫做cat api,可以查看es中各种各样的数据GET /_cat/health?vepoch timestamp cluster status shards pri relo init unassign pending_tasks max_task_wait_time active_shards_percent1488006741 15:12:21 elasticsearch yellow 1 1 1 1 0 0 1 0 - 50.0%如何快速了解集群的健康状况?green、yellow、red?green:每个索引的primary shard和replica shard都是active状态的yellow:每个索引的primary shard都是active状态的,但是部分replica shard不是active状态,处于不可⽤的状态red:不是所有索引的primary shard都是active状态的,部分索引有数据丢失了为什么现在会处于⼀个yellow状态?我们现在就⼀个笔记本电脑,就启动了⼀个es进程,相当于就只有⼀个node。现在es中有⼀个index,就是kibana⾃⼰内置建⽴的index。由于默认的配置是给每个index分配5个primary shard和5个replica shard,⽽且primary shard和replica shard不能在同⼀台机器上(为了容错)。现在kibana⾃⼰建⽴的index是1个primary shard和1个replica shard。当前就⼀个node,所以只有1个primary shard被分配了和启动了,但是⼀个replica shard没有第⼆台机器去启动。做⼀个⼩实验:此时只要启动第⼆个es进程,就会在es集群中有2个node,然后那1个replica shard就会⾃动分配过去,然后clusterstatus就会变成green状态。epoch timestamp cluster status shards pri relo init unassign pending_tasks max_task_wait_time active_shards_percent1488007113 15:18:33 elasticsearch green 2 2 2 1 0 0 0 0 - 100.0%----------------------------------------------------------------------------------------------------------------------------2.4快速查看集群中有哪些索引GET /_cat/indices?vhealth status index uuid pri rep d llow open .kibana rUm9n9wMRQCCrRDEhqneBg 1 1 1 0 3.1kb 3.1kb----------------------------------------------------------------------------------------------------------------------------2.5简单的索引操作创建索引:PUT /test_index?prettyhealth status index uuid pri rep d llow open test_index XmS9DTAtSkSZSwWhhGEKkQ 5 1 0 0 650b 650byellow open .kibana rUm9n9wMRQCCrRDEhqneBg 1 1 1 0 3.1kb 3.1kb删除索引:DELETE /test_index?prettyhealth status index uuid pri rep d llow open .kibana rUm9n9wMRQCCrRDEhqneBg 1 1 1 0 3.1kb 3.1kb----------------------------------------------------------------------------------------------------------------------------2.6商品的CRUD操作2.6.1新增商品:新增⽂档,建⽴索引PUT /index/type/id{ "json数据"}PUT /ecommerce/product/1{ "name" : "gaolujie yagao", "desc" : "gaoxiao meibai", "price" : 30, "producer" : "gaolujie producer", "tags": [ "meibai", "fangzhu" ]}PUT /ecommerce/product/2{ "name" : "jiajieshi yagao", "desc" : "youxiao fangzhu", "price" : 25, "producer" : "jiajieshi producer", "tags": [ "fangzhu" ]}PUT /ecommerce/product/3{ "name" : "zhonghua yagao", "desc" : "caoben zhiwu", "price" : 40, "producer" : "zhonghua producer", "tags": [ "qingxin" ]}{ "_index": "ecommerce", "_type": "product", "_id": "1", "_version": 1, "result": "created", "_shards": { "total": 2, "successful": 1, "failed": 0 }, "created": true}GET /_cat/indices/ecommerce?vhealth status index uuid pri rep d een open ecommerce bpxEkrDFS0iCuNwYaemWOQ 5 1 4 1 46.4kb 23.2kbes会⾃动建⽴index和type,不需要提前创建,⽽且es默认会对document每个field都建⽴倒排索引,让其可以被搜索----------------------------------------------------------------------------------------------------------------------------2.6.2查询商品:检索⽂档GET /index/type/idGET /ecommerce/product/1{ "_index": "ecommerce", "_type": "product", "_id": "1", "_version": 1, "found": true, "_source": { "name": "gaolujie yagao", "desc": "gaoxiao meibai", "price": 30, "producer": "gaolujie producer", "tags": [ "meibai", "fangzhu" ] }}----------------------------------------------------------------------------------------------------------------------------2.6.3修改商品:替换⽂档PUT /ecommerce/product/1{ "name" : "jiaqiangban gaolujie yagao", "desc" : "gaoxiao meibai", "price" : 30, "producer" : "gaolujie producer", "tags": [ "meibai", "fangzhu" ]}{ "_index": "ecommerce", "_type": "product", "_id": "1", "_version": 1, "result": "created", "_shards": { "total": 2, "successful": 1, "failed": 0 }, "created": true}PUT /ecommerce/product/1{ "name" : "jiaqiangban gaolujie yagao"}{ "_index": "ecommerce", "_type": "product", "_id": "1", "_version": 2, "result": "updated", "_shards": { "total": 2, "successful": 1, "failed": 0 }, "created": false}替换⽅式有⼀个不好,即使必须带上所有的field,才能去进⾏信息的修改----------------------------------------------------------------------------------------------------------------------------2.6.4修改商品:更新⽂档POST /ecommerce/product/1/_update{ "doc": { "name": "jiaqiangban gaolujie yagao" }}{ "_index": "ecommerce", "_type": "product", "_id": "1", "_version": 8, "result": "updated", "_shards": { "total": 2, "successful": 1, "failed": 0 }}----------------------------------------------------------------------------------------------------------------------------2.6.5删除商品:删除⽂档DELETE /ecommerce/product/1{ "found": true, "_index": "ecommerce", "_type": "product", "_id": "1", "_version": 9, "result": "deleted", "_shards": { "total": 2, "successful": 1, "failed": 0 }}GET /ecommerce/product/1{ "_index": "ecommerce", "_type": "product", "_id": "1", "found": false}第07节:多种搜索⽅式3.1query string search搜索全部商品:took:耗费了⼏毫秒timed_out:是否超时,这⾥是没有_shards:数据拆成了5个分⽚,所以对于搜索请求,会打到所有的primary shard(或者是它的某个replica shard也可以):查询结果的数量,3个_score:score的含义,就是document对于⼀个search的相关度的匹配分数,越相关,就越匹配,分数也⾼:包含了匹配搜索的document的详细数据GET /ecommerce/product/_search{ "took": 0, "timed_out": false, "_shards": { "total": 5, "successful": 5, "skipped": 0, "failed": 0 }, "hits": { "total": 3, "max_score": 1, "hits": [ { "_index": "ecommerce", "_type": "product", "_id": "2", "_score": 1, "_source": { "name": "jiajieshi yagao", "desc": "youxiao fangzhu", "price": 25, "producer": "jiajieshi producer", "tags": [ "fangzhu" ] } }, { "_index": "ecommerce", "_type": "product", "_id": "1", "_score": 1, "_source": { "name": "jiaqiangban gaolujie yagao", "desc": "gaoxiao meibai", "price": 30, "producer": "gaolujie producer", "tags": [ "meibai", "fangzhu" ] } }, { "_index": "ecommerce", "_type": "product", "_id": "3", "_score": 1, "_source": { "name": "zhonghua yagao", "desc": "caoben zhiwu", "price": 40, "producer": "zhonghua producer", "tags": [ "qingxin" ] } } ] }}query string search的由来,因为search参数都是以http请求的query string来附带的搜索商品名称中包含yagao的商品,⽽且按照售价降序排序:GET /ecommerce/product/_search?q=name:yagao&sort=price:desc适⽤于临时的在命令⾏使⽤⼀些⼯具,⽐如curl,快速的发出请求,来检索想要的信息;但是如果查询请求很复杂,是很难去构建的在⽣产环境中,⼏乎很少使⽤query string search----------------------------------------------------------------------------------------------------------------------------3.2query DSLDSL:Domain Specified Language,特定领域的语⾔http request body:请求体,可以⽤json的格式来构建查询语法,⽐较⽅便,可以构建各种复杂的语法,⽐query string search肯定强⼤多了1. 查询所有的商品GET /ecommerce/product/_search{ "query": { "match_all": {} }}2. 查询名称包含yagao的商品,同时按照价格降序排序GET /ecommerce/product/_search{ "query": { "match": { "name": "yagao" } }, "sort": [ { "price": { "order": "desc" } } ]}3. 分页查询商品,总共3条商品,假设每页就显⽰1条商品,现在显⽰第2页,所以就查出来第2个商品GET /ecommerce/product/_search{ "query": { "match_all": {} }, "from": 0,
"size": 1}4. 指定要查询出来商品的名称和价格就可以GET /ecommerce/product/_search{ "query": {"match_all": {}} , "_source": ["name","price"]}更加适合⽣产环境的使⽤,可以构建复杂的查询----------------------------------------------------------------------------------------------------------------------------3.3query filter搜索商品名称包含yagao,⽽且售价⼤于25元的商品GET /ecommerce/product/_search{ "query": { "bool": { "must": [ {"match": { "name": "yagao" }} ], "filter": { "range": { "price": { "gte": 25, "lte": 50 } } } } }}----------------------------------------------------------------------------------------------------------------------------3.4full-text search(全⽂检索)GET /ecommerce/product/_search{ "query" : { "match" : { "producer" : "yagao producer" } }}producer这个字段,会先被拆解,建⽴倒排索引,max_score匹配度分数special 4yagao 4producer 1,2,3,4gaolujie 1zhognhua 3jiajieshi 2yagao producer —> yagao和producer{ "took": 4, "timed_out": false, "_shards": { "total": 5, "successful": 5, "failed": 0 }, "hits": { "total": 4, "max_score": 0.70293105, "max_score": 0.70293105, "hits": [ { "_index": "ecommerce", "_type": "product", "_id": "4", "_score": 0.70293105, "_source": { "name": "special yagao", "desc": "special meibai", "price": 50, "producer": "special yagao producer", "tags": [ "meibai" ] } }, { "_index": "ecommerce", "_type": "product", "_id": "1", "_score": 0.25811607, "_source": { "name": "gaolujie yagao", "desc": "gaoxiao meibai", "price": 30, "producer": "gaolujie producer", "tags": [ "meibai", "fangzhu" ] } }, { "_index": "ecommerce", "_type": "product", "_id": "3", "_score": 0.25811607, "_source": { "name": "zhonghua yagao", "desc": "caoben zhiwu", "price": 40, "producer": "zhonghua producer", "tags": [ "qingxin" ] } }, { "_index": "ecommerce", "_type": "product", "_id": "2", "_score": 0.1805489, "_source": { "name": "jiajieshi yagao", "desc": "youxiao fangzhu", "price": 25, "producer": "jiajieshi producer", "tags": [ "fangzhu" ] } } ] }}}----------------------------------------------------------------------------------------------------------------------------3.5phrase search(短语搜索)跟全⽂检索相对应,相反,全⽂检索会将输⼊的搜索串拆解开来,去倒排索引⾥⾯去⼀⼀匹配,只要能匹配上任意⼀个拆解后的单词,就可以作为结果返回phrase search,要求输⼊的搜索串,必须在指定的字段⽂本中,完全包含⼀模⼀样的,才可以算匹配,才能作为结果返回GET /ecommerce/product/_search{ "query" : { "match_phrase" : { "producer" : "yagao producer" } }}{ "took": 11, "timed_out": false, "_shards": { "total": 5, "successful": 5, "failed": 0 }, "hits": { "total": 1, "max_score": 0.70293105, "hits": [ { "_index": "ecommerce", "_type": "product", "_id": "4", "_score": 0.70293105, "_source": { "name": "special yagao", "desc": "special meibai", "price": 50, "producer": "special yagao producer", "tags": [ "meibai" ] } } ] }}----------------------------------------------------------------------------------------------------------------------------3.6highlight search(⾼亮搜索结果)GET /ecommerce/product/_search{ "query" : { "match" : { "producer" : "producer" } }, "highlight": { "fields" : { "producer" : {} } }}{ "took": 321, "timed_out": false, "_shards": { "total": 5, "successful": 5, "skipped": 0, "failed": 0 }, "hits": { "total": 1, "max_score": 0.8092568, "hits": [ { "_index": "ecommerce", "_type": "product", "_id": "4", "_score": 0.8092568, "_source": { "name": "special yagao", "desc": "special meibai", "price": 50, "producer": "special yagao producer", "tags": [ "meibai" ] }, "highlight": { "producer": [ "special yagao producer" ] } } ] }}第08节:嵌套聚合,下钻分析,聚合分析将⽂本field的fielddata属性设置为truePUT /ecommerce/_mapping/product{ "properties": { "tags": { "type": "text", "fielddata": true } }}4.1第⼀个分析需求:计算每个tag下的商品数量GET /ecommerce/product/_search{ "aggs": { "group_by_tags": { "terms": { "field": "tags" } } }}{ "took": 814, "timed_out": false, "_shards": { "total": 5, "successful": 5, "skipped": 0, "failed": 0 }, "hits": { "total": 4, "max_score": 1, "hits": [ { "_index": "ecommerce", "_type": "product", "_id": "2", "_score": 1, "_source": { "name": "jiajieshi yagao", "desc": "youxiao fangzhu", "price": 25, "producer": "jiajieshi producer", "tags": [ "fangzhu" ] } }, { "_index": "ecommerce", "_type": "product", "_id": "4", "_score": 1, "_source": { "name": "special yagao", "desc": "special meibai", "price": 50, "producer": "special yagao producer", "tags": [ "meibai" ] } }, { { "_index": "ecommerce", "_type": "product", "_id": "1", "_score": 1, "_source": { "name": "jiaqiangban gaolujie yagao", "desc": "gaoxiao meibai", "price": 30, "producer": "gaolujie producer", "tags": [ "meibai", "fangzhu" ] } }, { "_index": "ecommerce", "_type": "product", "_id": "3", "_score": 1, "_source": { "name": "zhonghua yagao", "desc": "caoben zhiwu", "price": 40, "producer": "zhonghua producer", "tags": [ "qingxin" ] } } ] }, "aggregations": { "group_by_tags": { "doc_count_error_upper_bound": 0, "sum_other_doc_count": 0, "buckets": [ { "key": "fangzhu", "doc_count": 2 }, { "key": "meibai", "doc_count": 2 }, { "key": "qingxin", "doc_count": 1 } ] } }}去掉原始数据GET /ecommerce/product/_search{ "size": 0, "aggs": { "all_tags": { "terms": { "field": "tags" } } }}{ "took": 20, "timed_out": false, "_shards": { "total": 5, "successful": 5, "failed": 0 }, "hits": { "total": 4, "max_score": 0, "hits": [] }, "aggregations": { "group_by_tags": { "doc_count_error_upper_bound": 0, "sum_other_doc_count": 0, "buckets": [ { "key": "fangzhu", "doc_count": 2 }, { "key": "meibai", "doc_count": 2 }, { "key": "qingxin", "doc_count": 1 } ] } }}----------------------------------------------------------------------------------------------------------------------------4.2第⼆个聚合分析的需求:对名称中包含yagao的商品,计算每个tag下的商品数量GET /ecommerce/product/_search{ "size": 0, "query": { "match": { "name": "yagao" } }, "aggs": { "all_tags": { "terms": { "field": "tags" } } }}{ "took": 2, "timed_out": false, "_shards": { "total": 5, "successful": 5, "skipped": 0, "failed": 0 }, "hits": { "total": 4, "max_score": 0, "hits": [] }, "aggregations": { "group_by_tags": { "doc_count_error_upper_bound": 0, "sum_other_doc_count": 0, "buckets": [ { "key": "fangzhu", "doc_count": 2 }, { "key": "meibai", "doc_count": 2 }, { "key": "qingxin", "doc_count": 1 } ] } }}----------------------------------------------------------------------------------------------------------------------------4.3第三个聚合分析的需求:先分组,再算每组的平均值,计算每个tag下的商品的平均价格GET /ecommerce/product/_search{ "size": 0, "aggs" : { "group_by_tags" : { "terms" : { "field" : "tags" }, "aggs" : { "avg_price" : { "avg" : { "field" : "price" } } } } }}{ "took": 8, "timed_out": false, "_shards": { "total": 5, "successful": 5, "failed": 0 }, "hits": { "total": 4, "max_score": 0, "hits": [] }, "aggregations": { "group_by_tags": { "doc_count_error_upper_bound": 0, "sum_other_doc_count": 0, "buckets": [ { "key": "fangzhu", "doc_count": 2, "avg_price": { "value": 27.5 } }, { "key": "meibai", "doc_count": 2, "avg_price": { "value": 40 } }, { "key": "qingxin", "doc_count": 1, "avg_price": { "value": 40 } } ] } }}----------------------------------------------------------------------------------------------------------------------------4.4第四个数据分析需求:计算每个tag下的商品的平均价格,并且按照平均价格降序排序GET /ecommerce/product/_search{ "size": 0, "aggs": { "group_by_tags": { "terms": { "field": "tags", "order": { "avg_price": "asc" } }, "aggs": { "avg_price": { "avg": { "field": "price" } } } } }}{ "took": 2, "timed_out": false, "_shards": { "total": 5, "successful": 5, "skipped": 0, "failed": 0 }, "hits": { "total": 4, "max_score": 0, "hits": [] }, "aggregations": { "group_by_tags": { "doc_count_error_upper_bound": 0, "sum_other_doc_count": 0, "buckets": [ { "key": "meibai", "doc_count": 2, "avg_price": { "value": 40 } }, { "key": "qingxin", "doc_count": 1, "avg_price": { "value": 40 } }, { "key": "fangzhu", "doc_count": 2, "avg_price": { "value": 27.5 } } ] } }}我们现在全部都是⽤es的restful api在学习和讲解es的所欲知识点和功能点,但是没有使⽤⼀些编程语⾔去讲解(⽐如java),原因有以下:1、es最重要的api,让我们进⾏各种尝试、学习甚⾄在某些环境下进⾏使⽤的api,就是restful api。如果你学习不⽤es restful api,⽐如我上来就⽤java api来讲es,也是可以的,但是你根本就漏掉了es知识的⼀⼤块,你都不知道它最重要的restful api是怎么⽤的2、讲知识点,⽤es restful api,更加⽅便,快捷,不⽤每次都写⼤量的java代码,能加快讲课的效率和速度,更加易于同学们关注es本⾝的知识和功能的学习3、我们通常会讲完es知识点后,开始详细讲解java api,如何⽤java api执⾏各种操作4、我们每个篇章都会搭配⼀个项⽬实战,项⽬实战是完全基于java去开发的真实项⽬和系统----------------------------------------------------------------------------------------------------------------------------4.5第五个数据分析需求:按照指定的价格范围区间进⾏分组,然后在每组内再按照tag进⾏分组,最后再计算每组的平均价格GET /ecommerce/product/_search{ "size": 0, "aggs": { "group_by_price": { "range": { "field": "price", "ranges": [ { "from": 0, "to": 20 }, { "from": 20, "to": 40 }, { "from": 40, "to": 50 } ] }, "aggs": { "group_by_tags": { "terms": { "field": "tags" }, "aggs": { "average_price": { "avg": { "field": "price" } } } } } } }}{ "took": 54, "timed_out": false, "_shards": { "total": 5, "successful": 5, "skipped": 0, "failed": 0 }, "hits": { "total": 4, "max_score": 0, "hits": [] }, "aggregations": { "group_by_price": { "buckets": [ { "key": "0.0-20.0", "from": 0, "to": 20, "doc_count": 0, "group_by_tags": { "doc_count_error_upper_bound": 0, "sum_other_doc_count": 0, "buckets": [] } }, { "key": "20.0-40.0", "from": 20, "to": 40, "doc_count": 2, "group_by_tags": { "doc_count_error_upper_bound": 0, "sum_other_doc_count": 0, "buckets": [ { "key": "fangzhu", "doc_count": 2, "average_price": { "value": 27.5 } }, { "key": "meibai", "doc_count": 1, "average_price": { "value": 30 } } ] } }, { "key": "40.0-50.0", "from": 40, "to": 50, "doc_count": 1, "group_by_tags": { "doc_count_error_upper_bound": 0, "sum_other_doc_count": 0, "buckets": [ { "key": "qingxin", "doc_count": 1, "average_price": { "value": 40 } } ] } } ] } }}第09节:⼿⼯画图剖析Elasticsearch的基础分布式架构1、Elasticsearch是⼀套分布式的系统,分布式是为了应对⼤数据量隐藏了复杂的分布式机制分⽚机制(我们之前随随便便就将⼀些document插⼊到es集群中去了,我们有没有care过数据怎么进⾏分⽚的,数据到哪个shard中去)cluster discovery(集群发现机制,我们之前在做那个集群status从yellow转green的实验⾥,直接启动了第⼆个es进程,那个进程作为⼀个node⾃动就发现了集群,并且加⼊了进去,还接受了部分数据,replica shard)shard负载均衡(举例,假设现在有3个节点,总共有25个shard要分配到3个节点上去,es会⾃动进⾏均匀分配,以保持每个节点的均衡的读写负载请求)shard副本,请求路由,集群扩容,shard重分配2、Elasticsearch的垂直扩容与⽔平扩容垂直扩容:采购更强⼤的服务器,成本⾮常⾼昂,⽽且会有瓶颈,假设世界上最强⼤的服务器容量就是10T,但是当你的总数据量达到5000T的时候,你要采购多少台最强⼤的服务器啊⽔平扩容:业界经常采⽤的⽅案,采购越来越多的普通服务器,性能⽐较⼀般,但是很多普通服务器组织在⼀起,就能构成强⼤的计算和存储能⼒普通服务器:1T,1万,100万强⼤服务器:10T,50万,500万扩容对应⽤程序的透明性3、增减或减少节点时的数据rebalance保持负载均衡4、master节点(1)创建或删除索引(2)增加或删除节点master不承载所有请求,所有不存在单节点瓶颈5、节点平等的分布式架构(1)节点对等,每个节点都能接收所有的请求(2)⾃动请求路由,将请求路由到存在该数据的节点上(3)响应收集,接收数据节点返回结果,返回给⽤户第10节:shard&replica机制再次梳理以及单node环境中创建index图解1、shard&replica机制再次梳理(1)index包含多个shard(2)每个shard都是⼀个最⼩⼯作单元,承载部分数据,lucene实例,完整的建⽴索引和处理请求的能⼒(3)增减节点时,shard会⾃动在nodes中负载均衡(4)primary shard和replica shard,每个document肯定只存在于某⼀个primary shard以及其对应的replica shard中,不可能存在于多个primary shard(5)replica shard是primary shard的副本,负责容错,以及承担读请求负载(6)primary shard的数量在创建索引的时候就固定了,replica shard的数量可以随时修改(7)primary shard的默认数量是5,replica默认是1,默认有10个shard,5个primary shard,5个replica shard(8)primary shard不能和⾃⼰的replica shard放在同⼀个节点上(否则节点宕机,primary shard和副本都丢失,起不到容错的作⽤),但是可以和其他primary shard的replica shard放在同⼀个节点上2、图解单node环境下创建index是什么样⼦的(1)单node环境下,创建⼀个index,有3个primary shard,3个replica shard(2)集群status是yellow(3)这个时候,只会将3个primary shard分配到仅有的⼀个node上去,另外3个replica shard是⽆法分配的(4)集群可以正常⼯作,但是⼀旦出现节点宕机,数据全部丢失,⽽且集群不可⽤,⽆法承接任何请求PUT /test_index{ "settings" : { "number_of_shards" : 3, "number_of_replicas" : 1 }}第11节:2个node环境下replica shard是如何分配的3、2个node环境下replica shard是如何分配的(1)replica shard分配:3个primary shard,3个replica shard,1 node(2)primary —> replica同步(3)读请求:primary/replica第12节:横向扩容过程1、图解横向扩容过程,如何超出扩容极限,以及如何提升容错性(1)primary&replica⾃动负载均衡,6个shard,3 primary,3 replica(2)每个node有更少的shard,IO/CPU/Memory资源给每个shard分配更多,每个shard性能更好(3)扩容的极限,6个shard(3 primary,3 replica),最多扩容到6台机器,每个shard可以占⽤单台服务器的所有资源,性能最好(4)超出扩容极限,动态修改replica数量,9个shard(3primary,6 replica),扩容到9台机器,⽐3台机器时,拥有3倍的读吞吐量(5)3台机器下,9个shard(3 primary,6 replica),资源更少,但是容错性更好,最多容纳2台机器宕机,6个shard只能容纳1台机器宕机(6)这⾥的这些知识点,你综合起来看,就是说,⼀⽅⾯告诉你扩容的原理,怎么扩容,怎么提升系统整体吞吐量;另⼀⽅⾯要考虑到系统的容错性,怎么保证提⾼容错性,让尽可能多的服务器宕机,保证数据不丢失第13节:容错机制:master选举,replica容错,数据恢复1、图解Elasticsearch容错机制:master选举,replica容错,数据恢复(1)9 shard,3 node(2)master node宕机,⾃动master选举,red(3)replica容错:新master将replica提升为primary shard,yellow(4)重启宕机node,master copy replica到该node,使⽤原有的shard并同步宕机后的修改,green第14节:初步解析document的核⼼元数据以及图解剖析index创建反例1、_index元数据(1)代表⼀个document存放在哪个index中(2)类似的数据放在⼀个索引,⾮类似的数据放不同索引:product index(包含了所有的商品),sales index(包含了所有的商品销售数据),inventory index(包含了所有库存相关的数据)。如果你把⽐如product,sales,human resource(employee),全都放在⼀个⼤的index⾥⾯,⽐如说company index,不合适的。(3)index中包含了很多类似的document:类似是什么意思,其实指的就是说,这些document的fields很⼤⼀部分是相同的,你说你放了3个document,每个document的fields都完全不⼀样,这就不是类似了,就不太适合放到⼀个index⾥⾯去了。(4)索引名称必须是⼩写的,不能⽤下划线开头,不能包含逗号:product,website,blog2、_type元数据(1)代表document属于index中的哪个类别(type)(2)⼀个索引通常会划分为多个type,逻辑上对index中有些许不同的⼏类数据进⾏分类:因为⼀批相同的数据,可能有很多相同的fields,但是还是可能会有⼀些轻微的不同,可能会有少数fields是不⼀样的,举个例⼦,就⽐如说,商品,可能划分为电⼦商品,⽣鲜商品,⽇化商品,等等。(3)type名称可以是⼤写或者⼩写,但是同时不能⽤下划线开头,不能包含逗号3、_id元数据(1)代表document的唯⼀标识,与index和type⼀起,可以唯⼀标识和定位⼀个document(2)我们可以⼿动指定document的id(put /index/type/id),也可以不指定,由es⾃动为我们创建⼀个id第14节:初步解析document的核⼼元数据以及图解剖析index创建反例课程⼤纲1、_index元数据2、_type元数据3、_id元数据{“_index”: “test_index”,“_type”: “test_type”,“_id”: “1”,“_version”: 1,“found”: true,“_source”: {“test_content”: “test test”}}1、_index元数据(1)代表⼀个document存放在哪个index中(2)类似的数据放在⼀个索引,⾮类似的数据放不同索引:product index(包含了所有的商品),sales index(包含了所有的商品销售数据),inventory index(包含了所有库存相关的数据)。如果你把⽐如product,sales,human resource(employee),全都放在⼀个⼤的index⾥⾯,⽐如说company index,不合适的。(3)index中包含了很多类似的document:类似是什么意思,其实指的就是说,这些document的fields很⼤⼀部分是相同的,你说你放了3个document,每个document的fields都完全不⼀样,这就不是类似了,就不太适合放到⼀个index⾥⾯去了。(4)索引名称必须是⼩写的,不能⽤下划线开头,不能包含逗号:product,website,blog2、_type元数据(1)代表document属于index中的哪个类别(type)(2)⼀个索引通常会划分为多个type,逻辑上对index中有些许不同的⼏类数据进⾏分类:因为⼀批相同的数据,可能有很多相同的fields,但是还是可能会有⼀些轻微的不同,可能会有少数fields是不⼀样的,举个例⼦,就⽐如说,商品,可能划分为电⼦商品,⽣鲜商品,⽇化商品,等等。(3)type名称可以是⼤写或者⼩写,但是同时不能⽤下划线开头,不能包含逗号3、_id元数据(1)代表document的唯⼀标识,与index和type⼀起,可以唯⼀标识和定位⼀个document(2)我们可以⼿动指定document的id(put /index/type/id),也可以不指定,由es⾃动为我们创建⼀个id第15节:document id的⼿动指定与⾃动⽣成课程⼤纲1、⼿动指定document id2、⾃动⽣成document id1、⼿动指定document id(1)根据应⽤情况来说,是否满⾜⼿动指定document id的前提:⼀般来说,是从某些其他的系统中,导⼊⼀些数据到es时,会采取这种⽅式,就是使⽤系统中已有数据的唯⼀标识,作为es中document的id。举个例⼦,⽐如说,我们现在在开发⼀个电商⽹站,做搜索功能,或者是OA系统,做员⼯检索功能。这个时候,数据⾸先会在⽹站系统或者IT系统内部的数据库中,会先有⼀份,此时就肯定会有⼀个数据库的primary key(⾃增长,UUID,或者是业务编号)。如果将数据导⼊到es中,此时就⽐较适合采⽤数据在数据库中已有的primary key。如果说,我们是在做⼀个系统,这个系统主要的数据存储就是es⼀种,也就是说,数据产⽣出来以后,可能就没有id,直接就放es⼀个存储,那么这个时候,可能就不太适合说⼿动指定document id的形式了,因为你也不知道id应该是什么,此时可以采取下⾯要讲解的让es⾃动⽣成id的⽅式。(2)put /index/type/idPUT /test_index/test_type/2{ "test_content": "my test"}2、⾃动⽣成document id(1)post /index/typePOST /test_index/test_type{ "test_content": "my test"}{ "_index": "test_index", "_type": "test_type", "_id": "AVp4RN0bhjxldOOnBxaE", "_version": 1, "result": "created", "_shards": { "total": 2, "successful": 1, "failed": 0 }, "created": true}(2)⾃动⽣成的id,长度为20个字符,URL安全,base64编码,GUID,分布式系统并⾏⽣成时不可能会发⽣冲突第16节:document的_source元数据以及定制返回结果解析1. _source元数据put /test_index/test_type/1{“test_field1”: “test field1”,“test_field2”: “test field2”}get /test_index/test_type/1{“_index”: “test_index”,“_type”: “test_type”,“_id”: “1”,“_version”: 2,“found”: true,“_source”: {“test_field1”: “test field1”,“test_field2”: “test field2”}}_source元数据:就是说,我们在创建⼀个document的时候,使⽤的那个放在request body中的json串,默认情况下,在get的时候,会原封不动的给我们返回回来。2. 定制返回结果定制返回的结果,指定_source中,返回哪些fieldGET /test_index/test_type/1?_source=test_field1,test_field2{“_index”: “test_index”,“_type”: “test_type”,“_id”: “1”,“_version”: 2,“found”: true,“_source”: {“test_field2”: “test field2”}}第17节:document的全量替换、强制创建以及图解lazy delete机制1. document的全量替换(1)语法与创建⽂档是⼀样的,如果document id不存在,那么就是创建;如果document id已经存在,那么就是全量替换操作,替换document的json串内容(2)document是不可变的,如果要修改document的内容,第⼀种⽅式就是全量替换,直接对document重新建⽴索引,替换⾥⾯所有的内容(3)es会将⽼的document标记为deleted,然后新增我们给定的⼀个document,当我们创建越来越多的document的时候,es会在适当的时机在后台⾃动删除标记为deleted的document2. document的强制创建(1)创建⽂档与全量替换的语法是⼀样的,有时我们只是想新建⽂档,不想替换⽂档,如果强制进⾏创建呢?(2)PUT /index/type/id?op_type=create,PUT /index/type/id/_create3. document的删除(1)DELETE /index/type/id(2)不会理解物理删除,只会将其标记为deleted,当数据越来越多的时候,在后台⾃动删除第18节:Elasticsearch并发冲突问题18. 深度图解剖析Elasticsearch并发冲突问题第19节:悲观锁与乐观锁两种并发控制⽅案1.
第20节:version乐观锁并发控制(1)_version元数据PUT /test_index/test_type/6{ "test_field": "test test"}{ "_index": "test_index", "_type": "test_type", "_id": "6", "_version": 1, "result": "created", "_shards": { "total": 2, "successful": 1, "failed": 0 }, "created": true}第⼀次创建⼀个document的时候,它的_version内部版本号就是1;以后,每次对这个document执⾏修改或者删除操作,都会对这个_version版本号⾃动加1;哪怕是删除,也会对这条数据的版本号加1{ "found": true, "_index": "test_index", "_type": "test_type", "_id": "6", "_version": 4, "result": "deleted", "_shards": { "total": 2, "successful": 1, "failed": 0 }}我们会发现,在删除⼀个document之后,可以从⼀个侧⾯证明,它不是⽴即物理删除掉的,因为它的⼀些版本号等信息还是保留着的。先删除⼀条document,再重新创建这条document,其实会在delete version基础之上,再把version号加1第21节:version乐观锁并发控制(1)先构造⼀条数据出来PUT /test_index/test_type/7{ "test_field": "test test"}(2)模拟两个客户端,都获取到了同⼀条数据GET test_index/test_type/7{ "_index": "test_index", "_type": "test_type", "_id": "7", "_version": 1, "found": true, "_source": { "test_field": "test test" }}(3)其中⼀个客户端,先更新了⼀下这个数据同时带上数据的版本号,确保说,es中的数据的版本号,跟客户端中的数据的版本号是相同的,才能修改PUT /test_index/test_type/7?version=1
{ "test_field": "test client 1"}{ "_index": "test_index", "_type": "test_type", "_id": "7", "_version": 2, "result": "updated", "_shards": { "total": 2, "successful": 1, "failed": 0 }, "created": false}(4)另外⼀个客户端,尝试基于version=1的数据去进⾏修改,同样带上version版本号,进⾏乐观锁的并发控制PUT /test_index/test_type/7?version=1
{ "test_field": "test client 2"}{ "error": { "root_cause": [ { "type": "version_conflict_engine_exception", "reason": "[test_type][7]: version conflict, current version [2] is different than the one provided [1]", "index_uuid": "6m0G7yx7R1KECWWGnfH1sw", "shard": "3", "index": "test_index" } ], "type": "version_conflict_engine_exception", "reason": "[test_type][7]: version conflict, current version [2] is different than the one provided [1]", "index_uuid": "6m0G7yx7R1KECWWGnfH1sw", "shard": "3", "index": "test_index" }, "status": 409}(5)在乐观锁成功阻⽌并发问题之后,尝试正确的完成更新GET /test_index/test_type/7{ "_index": "test_index", "_type": "test_type", "_id": "7", "_version": 2, "found": true, "_source": { "test_field": "test client 1" }}基于最新的数据和版本号,去进⾏修改,修改后,带上最新的版本号,可能这个步骤会需要反复执⾏好⼏次,才能成功,特别是在多线程并发更新同⼀条数据很频繁的情况下PUT /test_index/test_type/7?version=2
{ "test_field": "test client 2"}{ "_index": "test_index", "_type": "test_type", "_id": "7", "_version": 3, "result": "updated", "_shards": { "total": 2, "successful": 1, "failed": 0 }, "created": false}第22节:external version乐观锁并发控制external versiones提供了⼀个feature,就是说,你可以不⽤它提供的内部_version版本号来进⾏并发控制,可以基于你⾃⼰维护的⼀个版本号来进⾏并发控制。举个列⼦,加⼊你的数据在mysql⾥也有⼀份,然后你的应⽤系统本⾝就维护了⼀个版本号,⽆论是什么⾃⼰⽣成的,程序控制的。这个时候,你进⾏乐观锁并发控制的时候,可能并不是想要⽤es内部的_version来进⾏控制,⽽是⽤你⾃⼰维护的那个version来进⾏控制。version=1version=1&version_type=externalversion_type=external,唯⼀的区别在于,_version,只有当你提供的version与es中的_version⼀模⼀样的时候,才可以进⾏修改,只要不⼀样,就报错;当version_type=external的时候,只有当你提供的version⽐es中的_version⼤的时候,才能完成修改es,_version=1,?version=1,才能更新成功es,_version=1,?version>1&version_type=external,才能成功,⽐如说?version=2&version_type=external(1)先构造⼀条数据PUT /test_index/test_type/8{ "test_field": "test"}{ "_index": "test_index", "_type": "test_type", "_id": "8", "_version": 1, "result": "created", "_shards": { "total": 2, "successful": 1, "failed": 0 }, "created": true}(2)模拟两个客户端同时查询到这条数据GET /test_index/test_type/8{ "_index": "test_index", "_type": "test_type", "_id": "8", "_version": 1, "found": true, "_source": { "test_field": "test" }}(3)第⼀个客户端先进⾏修改,此时客户端程序是在⾃⼰的数据库中获取到了这条数据的最新版本号,⽐如说是2PUT /test_index/test_type/8?version=2&version_type=external{ "test_field": "test client 1"}{ "_index": "test_index", "_type": "test_type", "_id": "8", "_version": 2, "result": "updated", "_shards": { "total": 2, "successful": 1, "failed": 0 }, "created": false}(4)模拟第⼆个客户端,同时拿到了⾃⼰数据库中维护的那个版本号,也是2,同时基于version=2发起了修改PUT /test_index/test_type/8?version=2&version_type=external{ "test_field": "test client 2"}{ "error": { "root_cause": [ { "type": "version_conflict_engine_exception", "reason": "[test_type][8]: version conflict, current version [2] is higher or equal to the one provided [2]", "index_uuid": "6m0G7yx7R1KECWWGnfH1sw", "shard": "1", "index": "test_index" } ], "type": "version_conflict_engine_exception", "reason": "[test_type][8]: version conflict, current version [2] is higher or equal to the one provided [2]", "index_uuid": "6m0G7yx7R1KECWWGnfH1sw", "shard": "1", "index": "test_index" }, "status": 409}(5)在并发控制成功后,重新基于最新的版本号发起更新GET /test_index/test_type/8{ "_index": "test_index", "_type": "test_type", "_id": "8", "_version": 2, "found": true, "_source": { "test_field": "test client 1" }}PUT /test_index/test_type/8?version=3&version_type=external{ "test_field": "test client 2"}{ "_index": "test_index", "_type": "test_type", "_id": "8", "_version": 3, "result": "updated", "_shards": { "total": 2, "successful": 1, "failed": 0 }, "created": false}第23节:partial update1、什么是partial update?PUT /index/type/id,创建⽂档&替换⽂档,就是⼀样的语法⼀般对应到应⽤程序中,每次的执⾏流程基本是这样的:(1)应⽤程序先发起⼀个get请求,获取到document,展⽰到前台界⾯,供⽤户查看和修改(2)⽤户在前台界⾯修改数据,发送到后台(3)后台代码,会将⽤户修改的数据在内存中进⾏执⾏,然后封装好修改后的全量数据(4)然后发送PUT请求,到es中,进⾏全量替换(5)es将⽼的document标记为deleted,然后重新创建⼀个新的documentpartial updatepost /index/type/id/_update
{ "doc": { "要修改的少数⼏个field即可,不需要全量的数据" }}看起来,好像就⽐较⽅便了,每次就传递少数⼏个发⽣修改的field即可,不需要将全量的document数据发送过去2、图解partial update实现原理以及其优点partial update,看起来很⽅便的操作,实际内部的原理是什么样⼦的,然后它的优点是什么3、上机动⼿实战演练partial updatePUT /test_index/test_type/10{ "test_field1": "test1", "test_field2": "test2"}POST /test_index/test_type/10/_update{ "doc": { "test_field2": "updated test2" }}第24-33节第24节:上机动⼿实战演练基于groovy脚本进⾏partial update基于groovy脚本,如何执⾏partial updatees scripting module,我们会在⾼⼿进阶篇去讲解,这⾥就只是初步讲解⼀下PUT /ceshi-01/type/1{ "num": 0, "tags": []}1. 内置脚本POST /ceshi-01/type/1/_update{ "script": "ctx._+=1"}{ "_index": "ceshi-01", "_type": "type", "_id": "11", "_version": 2, "found": true, "_source": { "num": 1, "tags": [] }}2. 外部脚本ctx._+=new_tagPOST /ceshi-01/type/1/_update{ "script": { "lang": "groovy",
"file": "test-add-tags", "params": { "new_tag": "tag1" } }}3. ⽤脚本删除⽂档 = ctx._ == count ? 'delete' : 'none'POST /ceshi-01/type/1/_update{ "script": { "lang": "groovy", "file": "test-delete-document", "params": { "count": 1 } }}4. upsert操作POST /ceshi-01/type/1/_update{ "doc": { "num": 1 }}{ "error": { "root_cause": [ { "type": "document_missing_exception", "reason": "[test_type][11]: document missing", "index_uuid": "6m0G7yx7R1KECWWGnfH1sw", "shard": "4", "index": "test_index" } ], "type": "document_missing_exception", "reason": "[test_type][11]: document missing", "index_uuid": "6m0G7yx7R1KECWWGnfH1sw", "shard": "4", "index": "test_index" }, "status": 404}5. 如果指定的document不存在,就执⾏upsert中的初始化操作;如果指定的document存在,就执⾏doc或者script指定的partialupdate操作POST /test_index/test_type/11/_update{ "script" : "ctx._+=1", "upsert": { "num": 0, "tags": [] }}第25节:图解partial update乐观锁并发控制原理以及相关操作讲解课程⼤纲(1)partial update内置乐观锁并发控制(2)retry_on_conflict(3)_versionpost /index/type/id/_update?retry_on_conflict=5&version=6第26节:上机动⼿实战演练mget批量查询api课程⼤纲1、批量查询的好处就是⼀条⼀条的查询,⽐如说要查询100条数据,那么就要发送100次⽹络请求,这个开销还是很⼤的如果进⾏批量查询的话,查询100条数据,就只要发送1次⽹络请求,⽹络请求的性能开销缩减100倍2、mget的语法(1)⼀条⼀条的查询GET /test_index/test_type/1GET /test_index/test_type/2(2)mget批量查询GET /_mget{ "docs" : [ { "_index" : "test_index", "_type" : "test_type", "_id" : 1 }, { "_index" : "test_index", "_type" : "test_type", "_id" : 2 } ]}{ "docs": [ { "_index": "test_index", "_type": "test_type", "_id": "1", "_version": 2, "found": true, "_source": { "test_field1": "test field1", "test_field2": "test field2" } }, { "_index": "test_index", "_type": "test_type", "_id": "2", "_version": 1, "found": true, "_source": { "test_content": "my test" } } ]}(3)如果查询的document是⼀个index下的不同type种的话GET /test_index/_mget{ "docs" : [ { "_type" : "test_type", "_id" : 1 }, { "_type" : "test_type", "_id" : 2 } ]}(4)如果查询的数据都在同⼀个index下的同⼀个type下,最简单了GET /test_index/test_type/_mget{ "ids": [1, 2]}3、mget的重要性可以说mget是很重要的,⼀般来说,在进⾏查询的时候,如果⼀次性要查询多条数据的话,那么⼀定要⽤batch批量操作的api尽可能减少⽹络开销次数,可能可以将性能提升数倍,甚⾄数⼗倍,⾮常⾮常之重要第27节:分布式⽂档系统_上机动⼿实战演练bulk批量增删改课程⼤纲1、bulk语法POST /_bulk{ "delete": { "_index": "test_index", "_type": "test_type", "_id": "3" }}
{ "create": { "_index": "test_index", "_type": "test_type", "_id": "12" }}{ "test_field": "test12" }{ "index": { "_index": "test_index", "_type": "test_type", "_id": "2" }}{ "test_field": "replaced test2" }{ "update": { "_index": "test_index", "_type": "test_type", "_id": "1", "_retry_on_conflict" : 3} }{ "doc" : {"test_field2" : "bulk test1"} }每⼀个操作要两个json串,语法如下:{"action": {"metadata"}}{"data"}举例,⽐如你现在要创建⼀个⽂档,放bulk⾥⾯,看起来会是这样⼦的:{"index": {"_index": "test_index", "_type", "test_type", "_id": "1"}}{"test_field1": "test1", "test_field2": "test2"}有哪些类型的操作可以执⾏呢?(1)delete:删除⼀个⽂档,只要1个json串就可以了(2)create:PUT /index/type/id/_create,强制创建(3)index:普通的put操作,可以是创建⽂档,也可以是全量替换⽂档(4)update:执⾏的partial update操作bulk api对json的语法,有严格的要求,每个json串不能换⾏,只能放⼀⾏,同时⼀个json串和⼀个json串之间,必须有⼀个换⾏{ "error": { "root_cause": [ { "type": "json_e_o_f_exception", "reason": "Unexpected end-of-input: expected close marker for Object (start marker at [Source: fStreamInput@5a5932cd; line: 1, column: 1])n at [Source: fStreamInput@5a5932cd; line: 1, column: 3]" } ], "type": "json_e_o_f_exception", "reason": "Unexpected end-of-input: expected close marker for Object (start marker at [Source: fStreamInput@5a5932cd; line: 1, column: 1])n at [Source: fStreamInput@5a5932cd; line: 1, column: 3]" }, "status": 500}{ "took": 41, "errors": true, "items": [ { "delete": { "found": true, "_index": "test_index", "_type": "test_type", "_id": "10", "_version": 3, "result": "deleted", "_shards": { "total": 2, "successful": 1, "failed": 0 }, "status": 200 } }, { "create": { "_index": "test_index", "_type": "test_type", "_id": "3", "_version": 1, "result": "created", "_shards": { "total": 2, "successful": 1, "failed": 0 }, "created": true, "status": 201 } }, { "create": { "_index": "test_index", "_type": "test_type", "_id": "2", "status": 409, "error": { "type": "version_conflict_engine_exception", "reason": "[test_type][2]: version conflict, document already exists (current version [1])", "index_uuid": "6m0G7yx7R1KECWWGnfH1sw", "shard": "2", "index": "test_index" } } }, { "index": { "_index": "test_index", "_type": "test_type", "_id": "4", "_version": 1, "result": "created", "_shards": { "total": 2, "successful": 1, "failed": 0 }, "created": true, "status": 201 } }, { "index": { "_index": "test_index", "_type": "test_type", "_id": "2", "_version": 2, "result": "updated", "_shards": { "total": 2, "successful": 1, "failed": 0 }, "created": false, "status": 200 } }, { "update": { "_index": "test_index", "_type": "test_type", "_id": "1", "_version": 3, "result": "updated", "_shards": { "total": 2, "successful": 1, "failed": 0 }, "status": 200 } } ]}bulk操作中,任意⼀个操作失败,是不会影响其他的操作的,但是在返回结果⾥,会告诉你异常⽇志POST /test_index/_bulk{ "delete": { "_type": "test_type", "_id": "3" }}
{ "create": { "_type": "test_type", "_id": "12" }}{ "test_field": "test12" }{ "index": { "_type": "test_type" }}{ "test_field": "auto-generate id test" }{ "index": { "_type": "test_type", "_id": "2" }}{ "test_field": "replaced test2" }{ "update": { "_type": "test_type", "_id": "1", "_retry_on_conflict" : 3} }{ "doc" : {"test_field2" : "bulk test1"} }POST /test_index/test_type/_bulk{ "delete": { "_id": "3" }}
{ "create": { "_id": "12" }}{ "test_field": "test12" }{ "index": { }}{ "test_field": "auto-generate id test" }{ "index": { "_id": "2" }}{ "test_field": "replaced test2" }{ "update": { "_id": "1", "_retry_on_conflict" : 3} }{ "doc" : {"test_field2" : "bulk test1"} }2、bulk size最佳⼤⼩bulk request会加载到内存⾥,如果太⼤的话,性能反⽽会下降,因此需要反复尝试⼀个最佳的bulk size。⼀般从10005000条数据开始,尝试逐渐增加。另外,如果看⼤⼩的话,最好是在515MB之间。第28节:分布式⽂档系统_阶段性总结以及什么是distributed document store1、阶段性总结1~8讲:快速⼊门了⼀下,最基本的原理,最基本的操作9~13讲:在⼊门之后,对ES的分布式的基本原理,进⾏了相对深⼊⼀些的剖析14~27讲:围绕着document这个东西,进⾏操作,进⾏讲解和分析2、什么是distributed document store到⽬前为⽌,你觉得你在学什么东西,给⼤家⼀个直观的感觉,好像已经知道了es是分布式的,包括⼀些基本的原理,然后花了不少时间在学习document本⾝相关的操作,增删改查。⼀句话点出来,给⼤家归纳总结⼀下,其实我们应该思考⼀下,es的⼀个最最核⼼的功能,已经被我们相对完整的讲完了。Elasticsearch在跑起来以后,其实起到的第⼀个最核⼼的功能,就是⼀个分布式的⽂档数据存储系统。ES是分布式的。⽂档数据存储系统。⽂档数据,存储系统。⽂档数据:es可以存储和操作json⽂档类型的数据,⽽且这也是es的核⼼数据结构。存储系统:es可以对json⽂档类型的数据进⾏存储,查询,创建,更新,删除,等等操作。其实已经起到了⼀个什么样的效果呢?其实ES满⾜了这些功能,就可以说已经是⼀个NoSQL的存储系统了。围绕着document在操作,其实就是把es当成了⼀个NoSQL存储引擎,⼀个可以存储⽂档类型数据的存储系统,在操作⾥⾯的document。es可以作为⼀个分布式的⽂档存储系统,所以说,我们的应⽤系统,是不是就可以基于这个概念,去进⾏相关的应⽤程序的开发了。什么类型的应⽤程序呢?(1)数据量较⼤,es的分布式本质,可以帮助你快速进⾏扩容,承载⼤量数据(2)数据结构灵活多变,随时可能会变化,⽽且数据结构之间的关系,⾮常复杂,如果我们⽤传统数据库,那是不是很坑,因为要⾯临⼤量的表(3)对数据的相关操作,较为简单,⽐如就是⼀些简单的增删改查,⽤我们之前讲解的那些document操作就可以搞定(4)NoSQL数据库,适⽤的也是类似于上⾯的这种场景举个例⼦,⽐如说像⼀些⽹站系统,或者是普通的电商系统,博客系统,⾯向对象概念⽐较复杂,但是作为终端⽹站来说,没什么太复杂的功能,就是⼀些简单的CRUD操作,⽽且数据量可能还⽐较⼤。这个时候选⽤ES这种NoSQL型的数据存储,⽐传统的复杂的功能务必强⼤的⽀持SQL的关系型数据库,更加合适⼀些。⽆论是性能,还是吞吐量,可能都会更好。15.第29-33节:29 分布式⽂档系统_深度图解剖析document数据路由原理(1)document路由到shard上是什么意思?(2)路由算法:shard = hash(routing) % number_of_primary_shards举个例⼦,⼀个index有3个primary shard,P0,P1,P2每次增删改查⼀个document的时候,都会带过来⼀个routing number,默认就是这个document的_id(可能是⼿动指定,也可能是⾃动⽣成)routing = _id,假设_id=1会将这个routing值,传⼊⼀个hash函数中,产出⼀个routing值的hash值,hash(routing) = 21然后将hash函数产出的值对这个index的primary shard的数量求余数,21 % 3 = 0就决定了,这个document就放在P0上。决定⼀个document在哪个shard上,最重要的⼀个值就是routing值,默认是_id,也可以⼿动指定,相同的routing值,每次过来,从hash函数中,产出的hash值⼀定是相同的⽆论hash值是⼏,⽆论是什么数字,对number_of_primary_shards求余数,结果⼀定是在0~number_of_primary_shards-1之间这个范围内的。0,1,2。(3)_id or custom routing value
发布者:admin,转转请注明出处:http://www.yc00.com/web/1688109192a82856.html
评论列表(0条)