目录
初识elasticsearch
了解ES
什么是elasticsearch
elasticsearch的发展
搜索引擎技术排名:
倒排索引
正向索引和倒排索引
正向索引
倒排索引
es的一些概念
文档
索引
概念对比
架构
安装es,kibana
安装es
安装kibana
安装分词器
分词器
安装IK分词器
查看数据卷
上传ik安装包编辑
重启docker容器
测试
IK分词器扩展和停用词典编辑
索引库操作
mapping映射属性
mapping属性编辑
索引库CRUD
创建索引库
查看,删除索引库编辑
示例:查询
示例:删除
修改索引库
示例:修改
文档操作
新增文档
新增文档的DSL语法如下:编辑
查询文档
删除文档
修改文档
方式一:全量修改,会删除旧文档,添加新文编辑
方式二:增加修改,修改指定字段值编辑
总结
RestAPI
RestClient操作索引库
初始化JavaRestClient
创建索引库编辑
删除索引库
判断索引库是否存在
RestClient操作文档
基本步骤
新增文档
运行结果编辑编辑
查询文档
运行结果编辑
修改文档
修改前编辑
修改后编辑
删除文档
删除前
删除后编辑
批量导入文档
利用JavaRestClient批量导入索引库中
DSL查询文档
DSL查询分类
DSL Query基本语法编辑
全文检索查询编辑
match查询:
multi_match查询:
精准查询
term查询:
range查询:
地理坐标查询
geo_bounding_box:
geo_distance:
复合查询
function score
Bloolean Query
案例:
搜索结果处理
排序
示例:对酒店数据按照用户评价降序排序,评价相同的按照价格升序排序
示例:实现对酒店数据按照你的位置坐标的距离升序排序
分页
针对深度分页,ES提供了两种解决方案:
高亮编辑
总结编辑
RestClient查询文档
快速入门
我们通过match_all来演示下基本api,先看DSL的组织:编辑
我们通过match_all来演示下基本的API,再看结果的解析:编辑
match查询
精确查询编辑
复合查询
排序和分页
高亮
高亮结果处理编辑
黑马旅游案例
案例1:实现黑马旅游的酒店搜索功能,完成关键字搜索和分页
案例2:添加品牌,城市,星际,价格等过滤功能
案例3:我附近的酒店
案例4:让指定的酒店再搜索中排名位置置顶
数据聚合
聚合的种类
聚合分类
什么是聚合?
聚合的常见种类有哪些?
参与聚合的字段类型必须是:
DSL实现聚合
DSL实现Bucket聚合
DSL实现Metrics聚合
RestAPI实现聚合
案例:在IUserService中定义方法,实现对品牌,城市,星级的聚合
自动补全
拼音分词器
测试编辑
自定义分词器
自动补全查询
实现酒店搜索框自动补全
RestAPI实现自动补全
自动补全编辑
数据同步
数据同步思路分析
方案一:同步调用编辑
方案二:异步调用编辑
方案三:监听binlog编辑
实现elasticsearch与数据库同步
利用MQ实现mysql于elasticsearch中数据也要完成操作。
elasticsearch集群
搭建ES集群
ES集群结构
集群脑裂问题
ES集群的脑裂
集权故障转移
集群分布式存储
集群分布式查询编辑
elasticsearch的查询分成两个阶段:
ES集群故障转移
什么是elasticsearch
elasticsearch是一款非常强大的开源搜索引擎,可以帮助我们从海量数据中快速找到需要的内容。
elasticsearch结合kibana,Logstash,Beats,也就是elastic stack(ELK)。被广泛应用在日志数据分析,实时监控等领域。
elasticsearch是elastic stack的核心,负责存储,搜索,分析数据。
Lucene是一个Java语言的搜索引擎类库,是Apache公司的顶级项目,由DougCutting于1999年研发。官网地址:Apache Lucene - Welcome to Apache Lucene 。
Lucene的优势:
-
易扩展
-
高性能(基于倒排索引)
Lucene的缺点:
-
只限于Java语言开发
-
学习曲线陡峭
-
不支持水平扩展
elasticsearch的发展
2004年Shay Banon基于Lucene开发Compass
2010年Shay Banon重写了Compass,取名为Elasticsearch
官网地址:Elasticsearch 平台 — 大规模查找实时答案 | Elastic
相比与lucene,elasticsearch具备下列优势:
-
支持分布式,可水平扩展
-
提供Restful接口,可被任何语言调用
搜索引擎技术排名:
-
Elasticsearch:开源的分布式搜索引擎
-
Splunk:商业项目
-
Solr:Apache的开源搜索引擎
总结
什么是elaticsearch?
一个开源的分布式搜索引擎,可以用来实现搜索,日志统计,分析,系统监控等功能
什么是elastic stack(ELK)?
是以elaticsearch为核心的技术栈,包括bears,Logstash,kibana,elaticsearch
什么是Lucene?
是Apache的开源搜索引擎类库,提供了搜索引擎的核心API
正向索引和倒排索引
正向索引
传统数据库(如MySQL)采用正向索引,例如给下表(tb_goods)中的id创建索引:
倒排索引
elasticsarch采用倒排索引:
-
文档(document):每条数据就是一个文档
-
词条(term):文档按照语义分成的词语
什么是文档和词条?
-
每一条数据就是一个文档
-
对文档中的内容分词,得到的词语就是词条
什么是正向索引?
-
基于文档id创建索引,查询词条时必须先找到文档,而后判断是否包含词条
什么是倒排索引?
-
对文档内容分词,对词条创建索引,并记录词条所在文档的信息。查询时先更具词条查询到文档id,而后获取到文档
文档
elasticsearch是面向文档存储的,可以是数据库中的一条商品数据,一个订单信息。
文档数据会被序列化为json格式后存储在elasticsearch中。
索引
索引(index):相同类型的文档的集合
映射(mapping):索引中文档的字段约束信息,类似表的结构约束
概念对比
架构
MySQL:擅长事物类型操作,可以确保数据的安全和一致性
Elaticsearch:擅长海量数据的搜索,分析,计算
文档:一条数据就是一个文档,es中是Json格式
字段:Json文档中的字段
索引:同类型文档的集合
映射:索引中文档的约束,比如字段名称,类型
elasticaserch与数据库的关系:
-
数据库负责事物类型操作
-
elasticsearch负责海量数据的搜索,分析,计算
安装es
-
创建网络
因为我们还需要部署kibana容器,因此需要让es和kibana容器互联。这里先创建一个网络:
-
加载镜像
-
运行es
命令解释:
-
:设置集群名称
-
:监听的地址,可以外网访问
-
:内存大小
-
:非集群模式
-
:挂载逻辑卷,绑定es的数据目录
-
:挂载逻辑卷,绑定es的日志目录
-
:挂载逻辑卷,绑定es的插件目录
-
:授予逻辑卷访问权
-
:加入一个名为es-net的网络中
-
:端口映射配置
-
-
开放9200端口,访问端口
8.137.59.245:9200
安装kibana
kibana可以给我们提供一个elasticsearch的可视化界面,便于我们学习。
-
部署kibana
-
:加入一个名为es-net的网络中,与elasticsearch在同一个网络中
-
:设置elasticsearch的地址,因为kibana已经与elasticsearch在一个网络,因此可以用容器名直接访问elasticsearch
-
:端口映射配置
kibana启动一般比较慢,需要多等待一会,可以通过命令:
查看运行日志,当查看到下面的日志,说明成功:
此时,在浏览器输入地址访问:http://192.168.150.101:5601,即可看到结果
-
分词器
es在创建倒排索引时需要对文档分词;在搜索时,需要对用户输入内容分词。但默认的分词规则对中文处理并不友好。
我们在kibana中DevTools中测试:
安装IK分词器
查看数据卷
上传ik安装包
重启docker容器
测试
IK分词器包含两种模式:
-
ik_smart:最少切分
-
ik_max_word:最细切分
分词器的作用是什么?
-
创建倒排索引时对文档分词
-
用户搜索时,对输入的内容分词
IK分词器又几种模式?
-
ik_smart:智能切分,粗粒度
-
ik_max_word:最细切分,细粒度
IK分词器如何扩展词条?如何停用词条?
-
利用config目录的IKAnalyzer.cfg.xml文件添加扩展词条和停用词典
-
在词典中添加扩展词条或者停用词条
mapping属性
mapping是对索引库中文档的约束,常见的mapping属性包括:
-
type:字段数据类型,常见的简单类型有:
-
字符串:text(可分词的文本),keyword(精确值,例如:品牌,国家,ip地址)
-
数值:long,integer,short,byte,double,float
-
布尔:boolean
-
日期:date
-
对象:object
-
-
index:是否创建索引,默认为true
-
analyzer:使用哪种分词器
-
properties:该字段的子字段
mapping常见属性有哪些?
-
type:数据类型
-
index:是否索引
-
analyzer:分词器
-
prperties:子字段
type常见的有哪些?
-
字符串:text,keyword
-
数字:long,integer,short,byte,double,float
-
布尔:boolean
-
日期:date
-
对象:object
创建索引库
ES通过Restful请求操作索引库,文档。请求内容用DSL语句来表示。创建索引库和mapping的DSL语法如下:
成功运行
查看,删除索引库
示例:查询
示例:删除
修改索引库
示例:修改
索引库操作有哪些?
-
创建索引库:PUT/索引库名
-
查询索引库:GET/索引库名
-
删除索引库:DELETe/索引库名
-
添加字段:PUT/索引库名/_mapping (可以添加字段但不能修改以前的字段)
新增文档的DSL语法如下:
示例
DSL语法
DSL语法
方式一:全量修改,会删除旧文档,添加新文
运行结果(版本增加1)
方式二:增加修改,修改指定字段值
文档操作有哪些?
-
创建文档:POST /索引库名/_doc/文档id {json文档}
-
查询文档:GET /索引库名/_doc/文档id
-
修改文档:DELETE /索引库名/_doc/文档id
-
修改文档:
-
全量修改: PUT /索引库名/_doc/文档id {json文档}
-
增量修改: POST/索引库名/_update/文档id {"doc":{字段}}
-
什么是RestClient:
ES官方提供了各种不同语言的客户端,用来操作ES。这些客户端的本质就是组装DSL语句,通过http请求发送给ES。官方文档地址:Elasticsearch Clients | Elastic
mapping要考虑的问题:
字段名,数据类型,是否参与搜索,是否分词,如果分词,分词器是什么?
ES中支持两种地理
-
geo_point:由纬度(latitude)和经度(longitude)确定的一个点。例如:"32.83232,120.233231"
-
geo_shape:有多个geo_point组成的复杂几何图形。例如一条直线,"LINESTRING(-77.2344232 36.421231,-77.009099 38.8821384)"
字段拷贝可以使用copy_to属性将当前字段拷贝到指定字段。示例:
"business" : { "type": "keyword", "copy_to": "all" }, "all" : { "type": "text", "analyzer": "ik_max_word" }
初始化JavaRestClient
-
引入es的RestHighLeveClient依赖:
-
因为SpringBoot默认的ES版本是7.6.2,所以我们需要覆盖默认的ES版本:
-
初始化RestHighLevelClient:
新建一个测试类
创建索引库
编写DSL语句
编写测试类
查看运行结果
删除索引库
运行结果
判断索引库是否存在
运行结果
索引库操作的基本步骤:
-
初始化RestHighLevelClient
-
创建XxxIndexRequest。xxx是CREATE,Get,Delete
-
准备DSL(CREATE时需要)
-
发送请求。调用RestHighLevelClient#indices().xx()方法,xxx时create, exists, delete
基本步骤
利用JavaRestClient实现文档的CRUD
去数据库查询酒店数据,导入到hotel索引库,实现酒店数据的CRUD。
基本步骤如下:
-
初始化JavaRestClient
-
利用JavaRestClient新增酒店数据
-
利用JavaRestClient根据id查询酒店数据
-
利用javaRestClient删除酒店数据
-
利用JavaRestClient修改酒店数据
新增文档
先查询酒店数据,然后给这条数据创建倒排索引,即可完成添加:
运行结果
查询文档
根据id查询到文档数据是json,需要反序列化为java对象:
运行结果
修改文档
修改文档数据有两种方式:
方式一:全局更新。再次写入id一样的文档,就会删除旧文档,添加新文档
方式二:局部更新。只跟新局部字段,我们演示方式二
运行结果
修改前
修改后
删除文档
运行结果
删除前
删除后
文档操作的基本步骤
-
初始化RestHighLevelClient
-
创建XxxRequest。XXX是Index,Get,Update,Delete
批量导入文档
利用JavaRestClient批量导入索引库中
思路:
-
利用mybatis-plus查询酒店数据
-
将查询到的酒店数据(Hotel)转换为文档类型数据(HotelDoc)
-
利用JavaRestClient总的Bulk批量处理,实现批量新增文档
运行结果
DSL查询分类
Elasticashearch提供了基于JSON的DSL来定义查询。常见查询类型包括:
-
查询所有:查询出所有数据,一般测试用。例如:mathc_all
-
全文检索(full text)查询:利用分词器对用户输入内容分词,然后倒排索引库中匹配。例如:
-
match_query
-
multi_match_query
-
-
精准查询:根据精准词条查找数据,一般是查找keyword,数值,日期,boolean等类型字段。例如
-
ids
-
range
-
term
-
-
地理(geo)查询:根据经纬度查询。例如
-
geo_distance
-
geo_bounding_box
-
-
复合(compound)查询:复合查询可以将上述各种条件组合起来,合并查询条件。例如:
-
bool
-
funcation_score
-
DSL Query基本语法
运行结果
查询DSL的基本语法是什么?
-
GET /索引库名/_search
-
{ "query" : { "查询类型" : { "FIELD" : "TEXT" } } }
全文检索查询
match查询:
全文检索查询的一种,会对用户输入内容分词,然后去倒排索引检索,语法:
multi_match查询:
与match查询类似,只不过允许同时查询多个字段,语法:
match和multi_match的区别是什么?
-
match:更具一个字段查询
-
muti_match:根据多个字段查询,参与查询字段越多,查阅性能越差
精准查询
准确查询一般是查找keyword,数值,日期,boolean等类型字段。所以不会对搜索条件分词。常见的有:
term查询:
range查询:
精确查询常见的有哪些?
-
term查询:根据词条精确匹配,一般搜索keywored类型,数值类型,布尔类型,日期类型字段
-
range查询:根据数值查询范围,可以是数值,日期的范围
地理坐标查询
根据经纬度查询。常见的使用场景包括:
-
携程:搜索我的附近的酒店
-
滴滴:搜索我附近的出租车
-
微信:搜索我附近的人
根据经纬度查询。例如:
geo_bounding_box:
查询geo_point值落在某个矩形范围所有文档
geo_distance:
查询到指定中心点小于某个距离值的所有文档
# distance查询 GET /hotel/_search { "query": { "geo_distance": { "distance": "5km", "location": "31.21, 121.5" }
复合查询
复合(compound)查询:复合查询可以将其他简单查询组合起来,实现更复杂的搜索逻辑,例如:
function score
算分函数查询,可以控制文档相关性算分,控制文档排名。例如百度竞价
当我们利用match查询时,文档结果会根据与搜索词条的关联度打分(_score),返回结果时安装分值降序排列。
例如,我们搜索”虹桥如家“,结果如下:
使用function score query,可以修改文档的相关性算分(query score),根据新得到得算分排序。
function score query定义得三要素是什么?
-
过滤条件:哪些文档要加分
-
算分函数:如何计算function score
-
加权方式:function score 与 query score如何运算
Bloolean Query
参与算分越多,越影响性能。
布尔查询是一个或多个子句得组合。子查询得组合方式有:
-
must:必须匹配每个子查询,类似 ”与“
-
should:选择性匹配子查询,类似 ”或“
-
must_not:必须不匹配,不参与算法,类似”非“
-
filter:必须匹配,不参与算分
案例:
利用bool查询名字包含 ”如家“,价格不高于400,在坐标31.21,121.5周围10km范围内的酒店。
elasticsearch中的相关性打分算法时什么?
-
TF-IDF:在elasticserch5.0之前,会随着词频增加反而越来越大
-
BM25:在elasticsearch5.0之后,会随着词频增大而增大,但增长曲线会趋于水平
排序
elaticsearch支持对搜索结果排序,默认是根据相关度算分(_score)来排序。可以排序字段类型有:keyword类型,数值类型,地理坐标类型,日期类型等。
示例:对酒店数据按照用户评价降序排序,评价相同的按照价格升序排序
示例:实现对酒店数据按照你的位置坐标的距离升序排序
获取经纬度的方式:获取鼠标点击经纬度-地图属性-示例中心-JS API 2.0 示例 | 高德地图API
分页
elatcsearch默认情况下只返回top10的数据,而如果要查询更多数据就需要修改分页参数了。
elatcsearch中通过修改from,size参数来控制返回的分页结果:
深度ES是分布式的,所以会面临深度分页问题。例如按price排序后,后去from = 990,size = 10的数据:
-
首先在每个数据分片上都排序并查询前1000条文档。
-
然后将所有结点的结果聚合,在内存中重新排序选出前1000条文档
-
最后从这1000条中,选取从990开始的10条文档
如果搜索页数过深,或者结果集(from+size)越大,对内存和CPU的消耗越高。硬扯ES设定结果查询上限时10000
针对深度分页,ES提供了两种解决方案:
-
search after:分页时需要排序,原理上是从上一次的排序值开始,查询下一页数据。官方推荐使用的方式。
-
scroll:原理将排序数据形成快照,保存在内存。官方已经不推荐使用。
from + size:
-
优点:支持随机翻页
-
缺点:深度分页问题,默认查询上限(from+size)是10000
-
场景:百度,京东,谷歌,淘宝这样的随机翻页搜索
after search:
-
优点:没有查询上线(单次查询的size不超过10000)
-
缺点:智能下岗后逐页查询,不支持随机翻页
-
场景:没有随机分页需求的搜索,例如手机向下滚动翻页
scroll:
-
优点:没有查询上限(单次查询的size不超过10000)
-
缺点:会有额外内存损耗,并且搜索结果是非实时的
-
场景:海量数据的获取和迁移。重ES7.1开始不推荐使用,建议用after search 方案
高亮
高亮:就是在搜索结果中把收索关键字突出显示。
原理是这样的:
-
将搜索结果中的关键字用标签标记出来
-
在页面中给标签添加css样式
语法:
总结
RestClient查询文档
快速入门
我们通过match_all来演示下基本api,先看DSL的组织:
代码
运行结果
我们通过match_all来演示下基本的API,再看结果的解析:
运行结果
RestAPI其中构建DSL是通过HighLevelRestClient中的resource()来实现的,其中包含了查询,排序,分页,高亮等所有功能
RestAPI中其中构建查询条件的核心是由一个名为QueryBuilders的工具类提供的,其中包含了各种查询方法:
-
创建SearchRequest对象
-
准备Request.source(),也就是DSL.
-
QueryBuilders来构建查询条件
-
传入Request.source()的query()方法
-
-
发送请求,得到结果
-
解析结果(参考JSON结果,从外到内,逐层解析)
match查询
运行结果
精确查询
复合查询
精确查询常见的有term查询和range查询,同样利用QueryBuilders实现:
要构建查询条件,只要记住一个类:QueryBuilders
排序和分页
运行结果
高亮
高亮API包括请求DSL构建和结果解析两部分,我们先看请求的DSL构建:
高亮结果处理
运行结果
-
所有的搜索DSL的构建,记住一个API:SearchRequest的source()方法
-
高亮结果解析是参考JSON结果,逐层解析
案例1:实现黑马旅游的酒店搜索功能,完成关键字搜索和分页
步骤:
-
定义实体类,接收前端请求
-
定义controller接口,接收页面请求,调用IHotelService的search方法
-
定义IHotelService中的search方法,利用match查询实现根据关键字搜索酒店信息
案例2:添加品牌,城市,星际,价格等过滤功能
步骤:
-
修改RequestParams类,添加brand,city,starName,minPrice,maxPrice等参数
-
修改search方法的实现类,再关键字搜索时,如果brand等参数存在,对其做过滤
-
city精确匹配
-
brand精确匹配
-
starNmae精确匹配
-
price范围过滤
-
注意事项
-
多个条件之间时AND关系,组合多条件用BooleanQuery
-
参数存在才需要过滤,做好非空判断
-
-
案例3:我附近的酒店
步骤
-
前端页面定位后,会将你所有的位置发送到后台:
-
我们根据这个坐标,将酒店结果按照这个点的距离升序排序。
-
思路如下:
-
修改RequestParams参数,接收location字段
-
修改search方法业务逻辑,如果location有值,添加根据geo_distance排序的功能
-
案例4:让指定的酒店再搜索中排名位置置顶
步骤
我们给需要置顶的酒店文档添加一个标记。然后利用function score给带有标记的文档增加权重。
实现步骤分析:
-
给HotelDoc类添加isAD字段,Boolean类型
-
挑选几个你喜欢的酒店,给它的文档数据添加isAD字段,值为true
-
修改search方法,添加function score功能,给isAD值为true的酒店增加权重
聚合分类
聚合(aggregatons)可以实现对文档数据的统计,分析,运算。聚合常见的有三类:
-
桶(Bucket)聚合:用来对文档做分组
-
TermaAggregation:按照文档字段值分组
-
Date Histogram:按照日期阶梯分组,例如一周为一组,或者一月为一组
-
-
度量(Metric)聚合:用以计算一些值,比如:最大值,最小值,平均值等
-
Avg:求平均值
-
Max:求最大值
-
Min:求最小值
-
Stats:同时求max,min,avg,sum等
-
-
管道(pipeline)聚合:其它聚合的结果为基础做聚合
什么是聚合?
聚合是对文档数据的统计,分析,计算
聚合的常见种类有哪些?
-
Bucket:对文档数据分组,并统计每组数量
-
Meric:最文档数做计算,例如avg
-
Pipeline:基于其他聚合结果在做聚合
参与聚合的字段类型必须是:
-
keword
-
数值
-
日期
-
布尔
DSL实现Bucket聚合
现在,我们要统计所有数据中的酒店品牌有几种,此时可以根据酒店品牌的名称做聚合。
类型为term类型,DSL示例:
默认情况下,Bucket聚合会统计Bucket内的文档数量,记为_count,并且按照 _count升序排序。
我们可以修改结果排序方式:
默认情况下,Bucket聚合是对索引库的所有文档做聚合,我们可以根据聚合的文档范围,只要添加query条件即可:
aggs代表聚合,与query同级,此时query的作用是?
限定聚合的文档范围
聚合必须的三要素
-
聚合名称
-
聚合类型
-
聚合字段
聚合可配置属性有:
-
size:指定聚合结果数量
-
order:指定聚合结果排序方式
-
field:指定聚合字段
DSL实现Metrics聚合
例如,我们要求获取每个品牌的用户评分的min,max,avg等值。
我们可以利用stats聚合:
我们以品牌聚合为例,演示以下Java的RestClient使用,先看请求组装:
再看下聚合结果解析
案例:在IUserService中定义方法,实现对品牌,城市,星级的聚合
需求:在搜索页面的品牌,城市等信息不应该是在页面写死,而是通过聚合索引库中的酒店数据得来的:
前端页面会向服务端发起请求,查询品牌,城市,星级等字段的聚合结果:
要实现根据字母做补全,就必须对文档按照拼音分词。在GiHub上恰好有elasticsearch的拼音分词插件。地址:
GitHub - infinilabs/analysis-pinyin: 🛵 This Pinyin Analysis plugin is used to do conversion between Chinese characters and Pinyin.
测试
elasticsearch中分词器(analyzer)的组成包含三部分:
-
character fiters:在tokenizer之前对文本进行处理。例如删除字符,替换字符
-
tokenizer:将文本按照按照一定的规则切割词条(term)。例如keyword,就是不分词;还有ik_smart
-
tokenizer filter :将tokenizer输出的词条做进一步处理。例如大小写转换,同义词处理,拼音处理等
拼音分词器适合在创建倒排索引的时候使用,但不能在搜索的时候使用。
如何使用拼音分词器?
-
下载pinyin分词器
-
解压并放到elasticsearch的plugin目录
-
重启即可
如何自定义分词器?
-
创建索引库,在settings中配置,可以包含三部分
-
character filter
-
tokenizer
-
filter
拼音分词器注意思事项?
为了避免搜索到同音字,搜索时不要使用拼音分词器
completion suggester查询
elasticsearch提供了Completion Suggester查询来实现自动补全功能。这个查询会匹配以用户输入内容开头的词条并返回。为了提高补全查询的效率,对于文档中字段的类型有一些约束:
-
参与补全查询的字段必须时completion类型。
-
字段的类容一般是用来补全的多词条形成的数组
自动补全对字段的要求:
-
类型是completion类型
-
字段值是多词条的数组
实现思路如下:
-
修改hotel索引库结构,设置自定义拼音分词器
-
修改索引库的name,all字段,使用自定义分词器
-
索引库添加一个新字段suggestion,类型为completion类型,使用自定义的分词器
-
给HoteDoc类添加suggestio字段,内容包含brand,susiness
-
重新导入数据到hotel库
先看请求参数构造API
自动补全
elasticsearch中的酒店数据来自于mysql数据库,因此mysql数据发生改变时,elasticsearch也必须跟着改变,这个就是elasticserch于mysql之间的数据同步。
方案一:同步调用
方案二:异步调用
方案三:监听binlog
方式一:同步调用
-
优点:实现简单,粗暴
-
缺点:业务耦合度高
方式二:异步通知
-
优点:低耦合,实现难度一般
-
缺点:依赖mq的可靠性
方式三:监听binlog
-
优点:完全解除服务耦合
-
缺点:开启binlog增加数据库负担,实现复杂度高
利用课前资料提供的hotel-admin项目作为酒店管理的微服务。当酒店数据发生增,删,查,改时,要求对elasticsearch中数据也要完成相同操作。
利用MQ实现mysql于elasticsearch中数据也要完成操作。
步骤:
-
导入课前资料提供的hotel-admin项目,启动并测试酒店数据的CRUD
-
声明exchange,queue,RoutingKey
-
在hotel-admin中的增,删,改业务中完成发送消息
-
在hotel-demo中完成消息监听,并更新elasticsearch中数据
-
启动并测试数据同步功能
ES集群结构
单机的elasticsearch做数据存储,必然面临两个问题:海量数据存储问题,单点故障问题。
-
海量数据存储问题:将索引从逻辑上拆分为N个分片(shard),存储到多个结点
-
单点故障问题:将分片数据在不同结点备份(replica)
文件资料里有对应文档。
elasticsearch中集群结点有不同的职责划分:
ES集群的脑裂
默认情况下,每个节点都是master eligible节点,因此一旦master节点宕机,其它候选节点会选举一个成为主节点。当主节点于其它节点网路解耦故障时,可能发生脑裂问题。
为了避免脑裂,需要要求选票超过(eligible节点数量+1)/ 2 才能当选为主节点,因此eligible节点数量组好是奇数。对于配置项discovery.zen.minimum_master_nodes,在es7.0以后,已经成为我们配置,因此一般不会发生脑裂问题
master eligible节点的作用是上面?
-
参与集群选主
-
主节点可以管理集群状态,管理分片信息,处理创建和删除索引库的请求
-
data节点的作用是上面?
data节点的作用是上面?
-
数据的CRUD
coordinator节点的作用是什么?
-
路由请求到其它节点
-
合并查询到的结果,返回给用户
当新增文档时,应该保存不同分片,保证数据均衡,那么coordinating node如何确定数据存储到哪个分片呢?
elasticsearch会通过hash算法来计算文档应该存储到哪个分片:
shard = hash(_routing) % number_of_shards
说明:
-
_routing默认是文旦的id
-
算法与分片数量有关,因此索引库一旦创建,分片数量不能修改!
elasticsearch的查询分成两个阶段:
-
scatter phase:分散阶段,coordinating node会把请求分发到每一个分片
-
gather phase:聚集阶段,coordinating node汇总data node的搜索结果,并处理为最终结果集返回给用户
分布式新增如何确定分片?
-
coordinating node根据id做hash运算,得到结果对shard数量取余,余数就是对应的分片
分布式查询:
-
分散阶段:coordinating node将查询请求分发给不同分片
-
收集阶段:将查询结果汇总到coordinating node,整理并返回给用户
集群的master节点会监控集群中的节点状态,如果发现有节点宕机,会立即将宕机节点的分片数据迁移到其它急待你,确保数据安全,这个叫做故障转移
总结
故障转移
-
master宕机后,EligibleMaster选举为新的主节点。
-
master节点监控分片,阶段状态,将故障节点上的分片转移到正常节点,确保数据安全。