【SpringCloud微服务技术栈(下)-分布式搜索】

分布式搜索

DSL查询语法

DSL查询分类和基本语法

[DSL Query的分类]:
Elasticsearch提供了基于JSON的DSL(Domin Specific Language)来定义查询.常见的查询类型包括:

  • 查询所有:查询所有数据,一般用于测试.例如:match_all
  • 全文检索查询:利用分词器对用户输入内容分词,然后去倒排索引库中匹配.例如:match_query、multi_match_query
  • 精确查询:根据精确词条值查找数据,一般查找keyword、数值、日期、Boolean等类型字段.例如:ids、range、term
  • 地理查询:根据经纬度查询.例如:geo_distance、geo_bouding_box
  • 复合查询:复合查询可以将上述各种查询条件组合起来,合并查询条件.例如:bool、function_score

[查询的基本语法如下]:
在这里插入图片描述

全文检索查询

全文检索查询,会对用户输入内容分词,常用于搜索框搜索:
在这里插入图片描述

  • match查询:全文检索查询的一种,会对用户输入内容分词,然后去倒排索引库检索,语法:
    在这里插入图片描述
  • multi_match:与match查询类似,只不过允许同时查询多个字段,语法:
    在这里插入图片描述

[注意]:下面两种情况查询结果是一样的效果
在这里插入图片描述

精确查询

精确查询一般是查找keyword、
数值、日期、boolean等类型字段.所以不会对搜索条件分词.常见的有:

在这里插入图片描述
在这里插入图片描述

地理查询

在这里插入图片描述

  • geo_bouding_box:查询geo_point值落在某个矩形范围的所有文档
    在这里插入图片描述
  • geo_distance:查询到指定中心点小于某个距离值得所有文档
    在这里插入图片描述

相关性算分

复合查询:复合查询可以将其他简单查询组合起来,实现更加复杂的搜寻逻辑,例如:

  • fuction score:算分函数查询,可以控制文档相关性算分(控制查询后结果的排序;比如你根据某个字段值分词查询后,你查出的结果中对应字段的词条与查询词条重合个数较高[相关性,其中相关性有三种算法],你的分数就越高,排名越靠前),控制文档排名.例如百度竞价(你给了钱,我就能提高你的打分将你的查询排名放在前面)
    在这里插入图片描述
    在这里插入图片描述

FunctionScoreQuery

使用function score query,可以修改文档的相关性算分,根据新得到的算分排序.
在这里插入图片描述
举例说明:
在这里插入图片描述

BooleanQuery

[BooleanQuery查询]:
在这里插入图片描述
[案例]:
需求:搜索名字包含"如家",价格不高于400,在坐标31.21,121.5周围10km范围内的酒店
在这里插入图片描述

搜索结果处理

排序

elasticsearch支持对搜索结果排序,默认是根据相关度算分(_score)来排序.我们可以指定字段排序,这样就会取消掉算分可以排序字段类型有:keyword类型、数值类型、地理坐标类型、日期类型等.
在这里插入图片描述
[案例1]:对酒店数据按照用户评价降序排序,评价相同的按照价格升序排序(评价是score字段,价格是price字段,按照顺序添加两个排序规则即可)在这里插入图片描述
[案例2]:实现对酒店数据按照到你的位置坐标的距离升序排序
在这里插入图片描述

分页

elasticsearch默认情况下只返回top10的数据.而且如果要查询更多的数据就需要修改分页参数了.elasticsearch中通过修改from、size参数来控制要返回的分页结果:比如下面找的就是第990个数据到第1000条数据,由于ES的数据结构决定的只能先获取前1000条数据然后再截取第990-1000条数据
在这里插入图片描述
上面属于的是单点查询,由于企业是ES集群查询(集群中的每个单位属于分片),所以真正的查询方式如下:
在这里插入图片描述
深度分页的解决方案:
在这里插入图片描述

高亮

在这里插入图片描述

RestClient查询文档

快速入门

通过查询请求获取数据
在这里插入图片描述
结果以json的形式返回给我们了在这里插入图片描述

对查询到的数据(响应)进行解析
在这里插入图片描述
查询请求和解析响应整合:

match、term、range、boot查询

[全问检索擦查询]:
在这里插入图片描述

match与multi查询:
在这里插入图片描述
[精确查询]:term与range查询
在这里插入图片描述
[复合查询]:boolean query
在这里插入图片描述

排序和分页

在这里插入图片描述

高亮显示

在这里插入图片描述
在这里插入图片描述

旅游案例

搜索、分页

[案例]:实现黑马旅游的酒店搜索功能,完成关键字搜索和分页,我们的hotel-demo项目中,自带了前端页面,启动项目以及服务器后我们可以看到:
在这里插入图片描述
具体的分析:
点击"搜索"按钮后,浏览器会发送一个请求,而请求的信息(请求的url地址、请求类型、请求状态和请求的端口号可以借助可视化工具看到)
在这里插入图片描述
除了请求的信息,请求携带的参数 (key[搜索框查询的内容]、page[当前页码数]、size[每页数据的展示量]、sortBy[按照什么排序]) 也可以通过可视化工具看到:
在这里插入图片描述
在这里插入图片描述
发送请求后,后端会有相应的返回值由响应(Long total[数据的总条数]、List<HotelDoc> hotels[酒店数据])携带回来
在这里插入图片描述

[实现步骤]:

  • 步骤一:定义实体类,接收前端请求携带的json参数(key、page、size和sortBy)
    在这里插入图片描述

  • 步骤二:定义controller接口,接收页面请求,调用IHotelService的search方法
    说明:
    在这里插入图片描述在这里插入图片描述
    (1)、定义一个实体类PageResult接收返回值在这里插入图片描述
    在这里插入图片描述
    (2)、HotelController类
    在这里插入图片描述

  • 步骤三:定义IHotelService接口中的search方法,利用match查询实现根据关键字搜索酒店信息
    service层中IHotelService接口与HotelService实现类处理查询逻辑的实现方法
    IHotelService接口:
    在这里插入图片描述
    HotelService实现类:由于我们要实现DSL语句在java环境的操作,所以我们要使用RestClient,为了方便以后全局的使用,我们将其注入到启动类中
    在这里插入图片描述
    在这里插入图片描述
    结果解析:
    在这里插入图片描述

条件过滤

[案例]: 添加品牌、城市、星级、价格等过滤功能:
在这里插入图片描述
说明:点击标签后,请求则会携带标签内容作为参数传递给后台,后台根据标签内容筛选查询结果返回给浏览器

[步骤]:

  • 修改RequestParams类、添加brand、city、starName、minPrice、maxPrice等参数
    在这里插入图片描述
  • 修修改search方法的实现,在关键字搜索时,如果brand等参数存在,对其做过滤
    在这里插入图片描述在这里插入图片描述

我附近的酒店

[案例]:我附近的酒店
说明:除了显示出酒店数据还得将该酒店离我的距离展示出来

[步骤]:

  • 修改ReuestRarams参数,接收location字段
    在这里插入图片描述

  • 修改search方法业务,如果location有值,添加根据geo_distance排序功能.
    在这里插入图片描述在这里插入图片描述

  • 显示每个酒店离我们当前位置的距离
    在这里插入图片描述
    根据我们以前在elasticsearch发送查询请求的结果来看,其实结果中的sort已经包含了距离值这个内容[==由于我们按照距离来排序,所以sort里面是距离的值,要是以后我们按照多个字段来排序,那么sort里面就包含多个字段数组 ==]:
    在这里插入图片描述
    因此我们要修改结果解析:
    在这里插入图片描述

广告置顶

[案例]:让指定的酒店在搜索结果中排名置顶
说明:在这里插入图片描述
[步骤]:

  • 给HotelDoc类添加isAD字段,Boolean类型
    在这里插入图片描述
  • 挑选几个你喜欢的酒店,给它的文档数据添加isAD字段,值为true
    在这里插入图片描述
  • 修改search方法,添加function score功能,给isAD值为true的酒店增加权重
    在这里插入图片描述在这里插入图片描述

数据聚合

聚合的分类

聚合(aggregations)可以实现对文档数据的统计、分析、运算.聚合常见的有三类:

桶(Bucket)聚合:用来对文档做分组

  • TermAggregation:按照文档字段值分组
  • Date Histogram:按照日期阶梯分组,例如一周为一组,或者一月为一组

度量(Metric)聚合:用以计算一些值,比如:最大值、最小值、平均值等

  • Avg:求平均值
  • Max:求最大值
  • Min:求最小值
  • State:同时求max、min、avg、sum等

管道(pipeline)聚合:其它聚合的结果为基础做聚合

DSL实现Bucket聚合

[案例]:现在,我们要统计所有数据中的酒店品牌有几种,此时可以根据品牌的名称做聚合.类型为term类型,DSL示例:
在这里插入图片描述
演示效果:
在这里插入图片描述
[说明]:默认情况下,Bucket聚合会统计Bucket内的文档数量,记为_count,并且按照_count降序排序,我们可以修改结果排序的方式:
在这里插入图片描述
默认情况下,Bucket聚合是对索引库的所有文档做聚合,我们可以限定要聚合的文档范围,只要添加query条件即可:

DSL实现Metrics聚合

[案例]:我们要求获取每个品牌的用户评分的min、max、avg等值,我们可以利用stats聚合:
在这里插入图片描述
[演示示例]:
在这里插入图片描述

RestClient实现聚合

聚合查询品牌:
在这里插入图片描述
结果解析:
在这里插入图片描述
具体代码展示:
在这里插入图片描述在这里插入图片描述

多条件聚合

[案例]:在IUserService中定义方法,实现对品牌、城市、星级的聚合
需求:搜索页面的品牌、城市等信息不应该是在页面有我们写死的,毕竟品牌和城市有成千上万种,我们应该通过聚合索引库中的酒店数据得来的:
在这里插入图片描述在这里插入图片描述
[步骤]:首先在service中的业务实现接口类IHotelService中定义聚合方法
在这里插入图片描述
在HotelService类中实现接口的方法
在这里插入图片描述在这里插入图片描述在这里插入图片描述

带过滤体条件的聚合

[现象]:
当我们在搜索框中点击搜索时,浏览器会发送两个携带参数(参数如下)的请求(请求信息如下):
搜索请求:
在这里插入图片描述
聚合请求:
在这里插入图片描述
[案例需求]:
我们发现聚合请求携带的参数与搜索请求的参数一摸一样,可是为什么聚合要携带与搜索一样的参数呢?
聚合携带的参数是为了给聚合提供条件,和搜索请求携带的参数一样是为了点击搜索后聚合出来的结果是与搜索内容相关的,以便达到动态聚合的效果,示例如下图
点击价格范围,并且搜索虹桥后
在这里插入图片描述在这里插入图片描述
聚合内容范围就会缩小:
在这里插入图片描述
[分析]:
在这里插入图片描述

[实现步骤]:

  • 编写controller接口,接收聚合请求
    在这里插入图片描述
  • 修改IUserService#getFilter()方法,添加RequestParam参数
    在这里插入图片描述
  • 修改getFilter方法的业务,聚合添加query条件
    在这里插入图片描述

自动补全

安装拼音分词器

[自动补全]:当用户在搜索框输入字符时,我们应该提示出与该字符有关的搜索项,如图:在这里插入图片描述

要实现根据字母做补全,就必须对文档按照拼音分词.在GitHub上恰好有elasticsearch的拼音分词插件.地址:https://github.com/medcl/elasticsearch-analysis-pinyin

[安装步骤]:

  • 解压
    在这里插入图片描述

  • 上传到虚拟机中,elasticsearch的plugin目录
    在这里插入图片描述

  • 重启elasticsearch
    在这里插入图片描述

  • 测试在这里插入图片描述

自定义分词器

[问题]:
从上面分词的测试中我们可以看出以下问题:在这里插入图片描述
分词器实现的内部结构:
在这里插入图片描述
具体实现:自定义的词库只能对当前索引库适用"/test是当前索引库",要想使用必须按照图二和图三的写法啊
在这里插入图片描述
图二:
在这里插入图片描述
图三:
在这里插入图片描述在这里插入图片描述
[注意]:
在这里插入图片描述
[解决方案]:
在这里插入图片描述

DSL实现自动补全查询

completion suggester查询:
字段约束:
在这里插入图片描述
查询语法:
在这里插入图片描述
演示示例:
在这里插入图片描述

修改酒店索引库数据结构

[案例]:实现hotel索引库的自动补全、拼音搜索功能
[步骤]:

  • (1)、修改hotel索引库结构,设置自定义拼音分词器,其中completion_analyzer中的tokenizer"keyword"表示不分词将其转换成英文,具体内容看分词器的的结构
    在这里插入图片描述

  • (2)、修改索引库的name、all字段,使用自定义分词器
    在这里插入图片描述在这里插入图片描述

  • (3)、索引库添加一个新字段suggestion,类型为completion类型,使用自定义的分词器
    在这里插入图片描述

  • (4)、给HotelDoc类添加suggestion字段,内容包含brand、business
    在这里插入图片描述在这里插入图片描述

  • (5)、重新导入数据到hotel库
    在这里插入图片描述

RestAPI实现自动补全查询

请求参数构造的API:
在这里插入图片描述
结果解析:
在这里插入图片描述

实现搜索框自动补全

[案例]:实现酒店搜索页面输入框的自动补全
说明:查看前端页面,可以发现当我们在输入框键入时,前端会发起ajax请求:
在这里插入图片描述
在服务端编写接口,接收该请求,返回补全结果的集合,类型为List<String>

[步骤]:
在controller类里实现getSuggestion方法,接收请求携带的参数并且处理
在这里插入图片描述
在IHotelService接口中定义getSuggeions方法
在这里插入图片描述
在IHotelService接口的实现类HotelService实现getSuggestions方法
在这里插入图片描述在这里插入图片描述

数据同步

同步方案分析

[数据同步问题分析]:elasticsearch中的酒店数据来自于mysql数据库,因此mysql数据发生改变时,elasticsearch也必须跟着改变,这个就是elasticsearch与mysql之间的数据同步.
在这里插入图片描述
[解决方案]:

  • 方案一:同步调用
    优点:实现简单,粗暴
    缺点:业务耦合度高
    在这里插入图片描述
  • 方案二:异步通知
    优点:低耦合,实现难度一般
    缺点:依赖mq的可靠性
    在这里插入图片描述
    方案三:监听binlog
    优点:完全解除服务间耦合
    开启binlog增加数据库负担,实现复杂度高
    在这里插入图片描述

导入酒店管理项目

案例:实现hotel-admin项目作为酒店管理的微服务.当酒店数据发生增、删、改时,要求对elasticsearch中数据也要完成相同操作.
步骤:

  • 导入课前资料提供的hotel-admin项目,启动并测试酒店数据的CRUD
  • 声明exchange、queue、RoutingKey
  • 在hotel-admin中的增、删、改业务中完成消息发送
  • 在hotel-demo中完成消息监听,并更新elasticsearch中数据
  • 启动并测试数据同步功能

[hotel-admin项目导入说明]:
Controller层:在这里插入图片描述
application.yml配置文件:在这里插入图片描述
页面展示:
在这里插入图片描述

声明队列和交换机

[分析]:根据分析案例,elasticsearch对于增和改属于同一类型的请求(DSL语句可以使用一样的),所以elasticsearch只要针对(增、改)和删除两种请求做出操作即可,因此我们只要声明两个队列(分别绑定关键字[bindingKey]hotel_insert和hotel_delete即可),具体模型如下:
在这里插入图片描述
[步骤]:

  • 步骤一:在消费者项目hotel-demo中引入amqp依赖在这里插入图片描述

  • 步骤二:在hotel-demo中配置rabbitmq的地址信息
    在这里插入图片描述

  • 步骤三:新建一个MqConstants类,将交换机、队列、RoutingKey的名字声明为常量:
    在这里插入图片描述

  • 步骤四:在config目录下新建一个MqConfig类,在里面定义交换机、队列和绑定关系的bean,用来声明
    在这里插入图片描述
    在这里插入图片描述在这里插入图片描述

发送MQ消息

  • 步骤一:在消息提供者hotel_admin中同样加入(复制过来即可)交换机、队列和绑定关系常量
    在这里插入图片描述
    步骤二:同样在服务提供者hotel_admin中添加依赖
    在这里插入图片描述
    步骤三:同样在application.yml配置上配置rabbitmq地址:
    在这里插入图片描述
    步骤四:在Controller层实现发送MQ消息的代码
    在这里插入图片描述在这里插入图片描述

监听MQ消息

新增一个监听类HotelListener,编写监听业务
在这里插入图片描述
在IHotelService接口定义相应的方法,并在实体类完成对应的业务逻辑
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

ES集群

集群结构介绍

单机的elasticsearch做数据存储,必然面临两个问题:海量数据存储、单点故障问题.

  • 海量数据存储问题:将索引库从逻辑上拆分为N个分片(shard),存储到多个节点
  • 单点故障问题:将分片数据在不同节点备份(replica)

在这里插入图片描述

搭建集群

【说明】:
在这里插入图片描述
【步骤】:
建立es集群
在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
集群状态监控
在这里插入图片描述在这里插入图片描述
cerebro界面:
在这里插入图片描述在这里插入图片描述

创建索引库

  • 利用kibana的DevTools创建索引库
    在这里插入图片描述
  • 利用cerebro创建索引库
    在这里插入图片描述在这里插入图片描述

查看分片效果
在这里插入图片描述

集群职责及脑裂

elasticsearch中集群节点有不同的职责划分:
在这里插入图片描述
ES集群中的节点默认有这四种属性以及职责,但是实际开发中我们要根据节点类型的不同去为节点分配主机配置
elasticsearch中每个节点角色都有自己不同的职责,因此建议集群部署时,每个节点都有独立的角色:
在这里插入图片描述
默认情况下,每个节点都是master eligible节点,因此一旦master节点宕机,其他候选节点会选举一个成为主节点。当主节点与其他节点网络故障时,可能发生脑裂问题

为了避免脑裂问题,需要要求选票超过(eligible节点数量+1)/2才能当选为主,因此eligible节点数量最好是奇数。对应配置项discovery.zen.minmum_master_nodes,在es7.0以后,已经成为默认配置,因此一般不会发生脑裂问题
在这里插入图片描述

分布式新增和查询流程

当我们向某个节点分片(通过节点的ip和端口找到该节点)新增多条文档时,我们发信啊这些文档并不是存放在当前分片上,而是通过某一规则分别存储在各个分片上,这就体现了es集群分片的好处(而执行这一规则的节点责任是coordinating)
那么当新增文档时候,应该保存到不同分片,保证数据均衡,那么coordinating node如何确定数据该存储到哪一个分片呢?elasticsearch会通过hash算法来计算文档存储到哪个分片:
在这里插入图片描述
【分布式新增工作流程】:
在这里插入图片描述
【分布式查询过程】:
在这里插入图片描述

故障转移

集群的master节点会监控集群中的节点状态,如果发现有节点宕机,会立即将宕机节点的分片数据迁移到其他节点,确保数据安全,这个叫做故障转移。
在这里插入图片描述
【测试】:
停掉主节点es01
在这里插入图片描述
在这里插入图片描述
结果:刷新后
在这里插入图片描述
当我们重启es01后,分片又会恢复,但es01将不再是主节点了

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值