一、前言
从本章开始,我将进入elasticSearch(后面简称es)的学习,同样也是通过书籍自学,并且会通过自己归纳和拓展将我觉得比较值得记录的知识点分享出来,如果大家觉得有用的话可以和我一起学习。我打算在总结学习完es后,通过gitee的一个开源项目做一个es的springboot的 java客户端调用封装工具,到时候同样也会对项目进行讲解和分享。那么本次我主要是根据下面这本书籍进行学习,我觉得里面的内容挺不错,难度把握也刚好,并且结合了当下流行的Springboot框架。我个人是比较喜欢实体书学习,看电子书会看的我眼睛累,所以有条件的小伙伴我还是很推荐可以去买一本结合我的博客一块儿学习。
另外,我将会在es的这次学习中抛弃掉对es集群这一部分的学习,更倾向于es单体本身。
那么本章主要是es的概念,很多内容都比较生硬,没有什么拓展点,但是却是了解这个框架的最好渠道。希望大家能和我好好了解。
二、es概述
2.1、es简介
当前,很多应用都有搜索功能。Lucene作为“老牌”的搜索技术库,它提供的很多功能都能用于处理文本类型的数据。但是使用Lucene结构搜索引擎需要使用者熟悉搜索引擎的很多知识,对使用者的要求非常高,并且Lucene仅仅提供了基础的搜索引擎支持,而对搜索的分布式,容错性和实时性并不支持。
ES是建立在Lucene基础之上的分布式准实时搜索引擎,它所提供的诸多功能 中有一大优点,即实时性好。怎样才算实时性好呢?一般的业务需求中,新增加的数据至少要1min才能被搜索到,而在ES中,数秒甚至1s内即可搜索到新增的数据。
除了良好的实时性外,ES还提供了很多优秀的功能。例如,ES是分布式的架构设计,当单台或者少量的计算机不能很好地支持搜索任务时,完全可以扩展到足够多的计算机上进行搜索;并且ES提供了REST风格的API接口,使用户可以借助任何语言使用HTTP对ES执行请求来完成搜索任务;ES本身还提供了聚合功能,用户可以使用该功能对索引中的数据进行统计分析;在数据安全方面,ES提供了X-Pack进行用户验证。
如今,ES不仅是一个搜索引擎框架,而且官方还提供了ELK“全家桶”,为构建搜索引擎提供了很好的解决方案。其中,E代表Elasticsearch,主要提供数据搜索和分析功能,L代表LogStash,借助它可以将数据库和日志等结构化或非结构化数据轻松导入ES中;K代表Kibana,它可以将分析结果进行图形化展示,此外还可以使用它提供的开发工具对ES进行请求的交互。
2.2、Elasticsearch的基本概念
在使用ES进行数据的索引和搜索时,会用到一些基本概念,下面分别进行介绍。
1、索引
在使用传统的关系型数据库时,如果数据有存取和更新操作,需要操作一个数据库。相应地,在ES中则需要建立索引。用户的数据新增、搜索和更新等操作的对象全部对应索引。但是,ES中的索引和Lucene中的索引不是一一对应的。ES中的一个索引对应一个或多个Lucene索引,这是由其分布式的设计方案决定的。
2、文档
在使用传统的关系型数据库时,需要把数据封装成数据库的一条记录,而在ES中对应的则是文档。ES的文档中可以有一个或多个字段,每个字段可以是各种类型。用户对数据操作的最细粒度对象就是文档。ES文档操作使用了版本的概念,即文档的初始版本为1,每次的写操作会把文档的版本加1,每次使用文档时,ES返回给用户的是最新版本的文档。另外,为了减轻集群负载和提升效率,ES提供了文档的批量索引、更新和删除功能。
3、字段
一个文档可以包含一个或多个字段,每个字段都有一个类型与其对应。除了常用的数据类型(如字符串型、文本型和数值型)外,ES还提供了多种数据类型,如数组类型、经纬度类型和IP地址类型等。ES对不同类型的字段可以支持不同的搜索功能。例如,当使用文本类型的数据时,可以按照某种分词方式对数据进行搜索,并且可以设定搜索后的打分因子来影响最终的排序。再如,使用经纬度的数据时,ES可以搜索某个地点附近的文档,也可以查询地理围栏内的文档。在排序函数的使用上,ES也可以基于某个地点按照衰减函数进行排序。
索引、文档和字段的逻辑关系如下图所示:
4、映射
建立索引时需要定义文档的数据结构,这种结构叫作映射。在映射中,文档的字段类型一旦设定后就不能更改。因为字段类型在定义后,ES已经针对定义好的类型建立了特定的索引结构,这种结构不能更改。借助映射可以给文档新增字段。另外还提供了自动映射功能,即在添加数据时,如果该字段没有定义类型,ES会根据用户提供的该字段的真实数据来猜测可能的类型,从而自动进行字段类型的定义。
5、集群和节点
在分布式系统中,为了完成海量数据存储、计算并提升系统的高可用性,需要多台计算机集成在一起协作,这种形式被称为集群,这些集群中的每台计算机叫作节点。ES集群的节点个数不受限制,用户可以根据需求增加计算机对搜索服务进行扩展。
6、分片
在分布式系统中,为了能存储和计算海量的数据,会先对数据进行切分,然后再将它们存储到多台计算机中。这样不仅能分担集群的存储和计算压力,而且在该架构基础上进一步优化,还可以提升系统中的高可用性。在ES中,一个分片对应的就是一个Lucene索引,每个分片可以设置多个副分片,这样当主分片所在的计算机因为发生故障而离线时,副分片会充当主分片继续服务。索引的分片个数只能设置一次,之后不能更改。在默认情况下,ES的每个索引设置为5个分片。
7、副分片
为了提升系统索引数据的高可用性并减轻集群搜索的负载,可以启用的副本,该副本叫作副分片,而原有分片叫做主分片.在一个索引中,主分片的副分片个数是没有限制的,用户可以按需设定。在默认情况下,ES不会为索引的分片开启副分片,用户需要手动设置。副分片的个数设定后,也可以进行更改。一个分片的主分片和副分片分别存储在不同的计算机上,下图为一个3个节点的集群,某个索引设置了3个主分片,每个主分片分配两个副分片。
其中深色方框中的P代表该分片为主分片,R表示该分片为副分片,P和R后面的数字表示其编号。在极端情况下,当只有一个节点时,如果索引的副分片个数设置大于1,则系统只分配主分片,而不会分配副分片。
8、DSL
ES使用DSL(Domain Specific Language,领域特定语言),来定义查询。与编程语言不同,DSL是在特定领域解决特定任务的语言,它可以有多种表达形式,如我们常见的HTML、CSS、SQL等都属于DSL。ES中的DSL采用JSON进行表达,相应地,ES也将响应客户端请求的返回数据封装成了JSON形式。这样不仅可以简单明了地表达请求/响应内容,而且还屏蔽了各种编程语言之间数据通信的差异。
2.3、Elasticsearch和关系型数据库的对比
应用系统一般需要借助数据产品实现数据查询加速的需求。业界主流的数据产品分为两类,一类是传统的关系型数据库,另一类是非关系型数据库。ES属于非关系型数据库。在判断该使用ES还是关系型数据库之前,要先比较一下这两种不同类别的产品。
2.3.1、索引方式
关系型数据库的索引大多是B-Tree结构,而ES使用的是倒排索引,两种不同的数据索引方式决定了这两种产品在某些场景中性能和速度的差异。例如,对一个包含几亿条数据的关系型数据库执行最简单的count查询时,关系型数据库可能需要秒级的响应时间,如果数据表设计不合理,甚至可能会把整个关系型数据库拖垮,影响其他的数据服务;而ES可以在毫秒级别进行返回,该查询对整个集群的影响微乎其微。再例如,一个需求是进行分词匹配,关系型数据库需要依靠其他的组件才能完成这种查询,查询的结果只能是满足匹配,但是不能按照匹配程度进行打分排序;ES建立在Lucene基础之上,与生俱来就能完成分词匹配,并且支持多种打分排序算法,还支持用户自定义排序脚本。
2.3.2、事务支持
事务是关系型数据库的核心组成模块,而ES是不支持事务的。ES更新文档时,先读取文档在进行修改,然后再为文档重新建立索引。如果同一个文档同时有多个并发请求,则极有可能会丢失某个更新操作。为了解决这个问题,ES使用了乐观锁,即假定冲突是不会发生的,不阻塞当前数据的更新操作,每次更新会增加当前版本的版本号,最新的数据由文档的最新版本来决定,这种机制就决定了ES没有事务管理。因此,如果你的需求是类似商品库存的精准查询或者金融系统的核心并发业务的支持,那么关系型数据是不错的选择。
2.3.3、SQL和DSL
SQL和DSL都有自己的语法结构,都是各自和用户之间进行交互的一种语言表达方式。SQL是关系型数据库使用的语言,主要因为SQL查询的逻辑比较简单直接,一般是大小、相等之类的比较运算,以及逻辑与,或,非的关系运算。ES不仅包含上述运算,而且支持文本搜索、地理位置搜索等复杂数据的搜索,因此ES使用DSL查询进行请求通信。虽然ES的高版本也开始支持SQL查询,但若需要完成比较复杂的数据搜索需求,使用DSL查询会更加方便快捷。
2.3.4、扩展方式
假设随着业务的增长,我们的数据也迅速膨胀了几倍甚至几十倍。这时需要考虑数据产品扩展方式的难易程度。关系型数据库的扩展,需要借助第三方组件完成分库分表的支持。分库分表即按照某个ID取模将数据打散后分散到不同的数据节点中,借此来分摊集群的压力。但是分库分表有多种策略,需要使用人员对业务数据特别精通才能进行正确的选择。另外,分库分表会对一些业务造成延迟,如查询结果的合并及多表join操作。ES本身就是支持分片的,只要初期对分片的个数进行了合理的设置,后期是不需要对扩展过分担心的,即使现有集群负载较高,也可以通过后期增加节点和副分片的方式来解决。
2.3.5、数据的查询速度
在少量字段和记录的情况下,传统的关系型数据库的查询速度非常快。如果单表有上百个字段和几十亿条记录,则查询速度是比较慢的。虽然可以通过索引进行缓解,但是随着数据量的增长,查询速度还是会越来越慢。ES是基于Lucene库的搜索引擎,可以支持全字段建立索引,在ES中,单个索引存储上百个字段或几十亿条记录都是没有问题的,并且查询速度也不会变慢。
2.3.6、数据的实时性
关系型数据库存储和查询数据基本上是实时的,即单条数据写入之后可以立即查询。为了提高数据写入之的性能,ES在内存和磁盘之间增加了一层系统缓存。ES响应写入数据的请求后,会先将数据存储在内存中,此时该数据还不能搜索到。内存中的数据每隔一段时间(默认为1s)被刷新到系统缓存内,此时数据才能被搜索到。因此,ES的数据写入不是实时的,而是准实时的
2.4、ElasticSearch的架构原理
2.4.1、节点职责
节点按照职责可以分为master节点、数据节点和协调节点,每个节点类型可以进行单独配置。默认情况下,集群不会对节点角色进行划分,所有节点都是平等的,可以担任所有的职责。但是在生产环境中需要对这些节点的角色进行最优划分,否则在高并发请求的情况下,集群容易出现服务阻塞超时甚至服务崩溃的隐患。
master节点负责维护整个集群的相关工作,管理集群的变更,如创建/删除索引、节点健康状态监测、节点上/下线等。master节点是由集群节点通过选举算法选举出来的,一个集群中只有一个节点可以成为master节点,但是可以有一个或多个节点参与master节点的选举。在默认情况下,任意节点都可以作为master的候选节点,可以通过配置项node.master对当前节点是否作为master的候选节点进行控制。
数据节点主要负责索引数据的保存工作,此外也执行数据的其他操作,如文档的删除、修改和查询操作。数据节点的很多工作是调用Lucene库进行Lucene索引操作,因此这种节点对于内存和I/O的消耗比较大,生产环境中应多注意数据节点的计算机负载情况。
客户端可以向ES集群的节点发出请求,这个节点叫作协调节点。在默认情况下,协调节点可以是集群中的任意节点,此时它的生命周期是和一个单独的请求相关的。也就是说,当客户端向集群中的某个节点发出请求时,此时该节点被称为当前请求的协调节点;当它将响应结果返回给客户端时,该协调节点的生命周期就结束了。如下图左右两边分别表示两次不同的请求,因为请求时客户端指定的请求地址不同,所以图中左边的请求协调节点是node1,图中右边中的请求协调节点是node3.协调节点。协调节点根据具体情况将请求发给其他节点,并将最终的汇总处理返回给客户端。
当然,为了降低集群的负载,可以设置某些节点作为单独的协调节点。在节点的配置文件中设置node.master和node.data配置项为false,此时,这个节点就不会被选中为master节点并且不再担任数据节点,而客户端就可以把这类节点作为协调节点来使用,把所有的请求都分发到这些节点上:
2.4.2、主分片和副分片
ES为了支持分布式搜索,会把数据按照分片进行切分。一个索引由一个或者多个分片构成,并且每个分片有0个甚至多个副分片。多个分片分布在不同的节点中,通过这种分布式结构提升了分片数据的高可用性和服务的高并发支持。
那么ES是如何提升分片数据的高可用性的呢?
集群中的索引主分片和副分片在不同的计算机上,如果某个主分片所在的节点宕机,则原有的某个副分片会提升为主分片继续对外进行服务。
例如下图所示集群中,如果node1发生故障宕机,集群感知到分片0的主分片P0将要丢失,此时集群会立即将其他节点(例如node3)上的分片0对应的副分片R0作为主分片P0进行服务。集群中由node2和node3对外提供服务,所有的分片相关的服务不受影响:
如果node1恢复了服务并加入集群中,因为在node1上还保留有分片0的数据,此时node1上的分片P0会变成副分片R0,在此期间缺失的数据会通过node3上的主分片P0进行补充。并且node1上的分片R1和R2也会分别从node3和node2上对应的P1和P2分片上补充数据,如下图:
那么Es是如何提升服务的高并发性能的呢?
当客户端对某个索引的请求被分发到ES的协调节点时,协调节点会将请求进行转发,转发的对象是包含这个索引的所有分片的部分节点。协调节点中有一份分片-节点路由表,该表主要存放分片和节点的对应关系。协调节点采用轮询算法,选取该索引的主/副分片所在的节点进行请求转发。一个索引的主分片设定后就不能再修改,如果想继续提升索引的并发性能,则可以增加索引的副分片个数,此时协调节点会将这些副分片加入轮询算法中。
2.4.3、路由计算
当客户端向一个ES协调节点发送一条数据的写入请求时,协调节点如何确认当前数据应该存储在哪个节点的哪个分片上呢?
协调节点根据数据获取分片ID的计算公式如下:
shard=hash(routing)%number_of_primary_shards
式中,rounting代表每条文档提交时的参数,该值是可变的,用户可以自定义,在默认情况下使用的是文档的_id值;number_of_primary_shards是索引中主分片的个数,计算rounting的哈希值后,除以索引的主分片数再取余,就是当前文档实际应该存储的分片ID。
获取到分片ID后,根据分片-节点路由表获取该分片的主/副分片节点列表,然后再转发请求进行分片内的数据写入。
通过上面的公式可以观察到,主分片个数作为取余的分母不能进行更改,否则分片ID计算就会发生错误,进而导致找不到存储节点,这也是ES索引的主分片个数不能更改的原因。
2.4.4、文档读写过程
①写入
当ES协调节点接收到来自客户端对某个索引的写入文档请求时,该节点会根据一定的路由算法将该文档映射到某个主分片上,然后将请求转发到该分片所在的节点。完成数据的存储后,该节点会将请求转发给该分片的其他副分片所在的节点,直到所有副分片节点全部完成写入,ES协调节点向客户端报告写入成功。
如下图所示为一个包含三个节点的ES集群,假设索引中只有3个主分片和6个副分片,客户端向节点1发起向索引写入一条文档的请求,在本次请求中,节点1被称为协调节点。节点1判断数据应该映射到哪个分片上。假设将数据映射到分片1上,因为分片1的主分片在节点2上,因此节点1把请求转发到节点2上。节点2接收客户端的数据并进行存储,然后把请求转发到副分片1所在的节点1和节点3上,当所有副分片所在的节点全部完成存储后,协调节点也就是节点1向客户端返回成功标志。
当ES协调节点接收到来自客户端获取某个索引的某文档请求时,协调节点会找到该文档所在的所有分片,然后根据轮询算法在主/副分片中选择一个分片并将请求转发到该分片所在的节点,该节点会将目标数据发送给协调节点,协调节点再将数据返回给客户端。
如下图所示为一个包含三个节点的ES集群,假设索引中只有3个主分片和6个副分片,客户端向节点1发起向索引虎丘文档的请求,在本次请求中,节点1被称为协调节点。节点1判断数据应该映射到哪个分片上。假设将数据映射到分片1上,分片1有主/副两种分片,分别在节点2、节点1和节点3上。假设此时协调节点的轮询算法选择的是节点3,那么它会将请求转发到节点3上,然后节点3会把数据传输给协调节点,也就是节点1,最后由节点1向客户端返回文档数据。
2.5、ElasticSearch的应用场景
2.5.1、搜索引擎
毫无疑问,ES最擅长的是充当搜索引擎,在这类场景中较典型的应用领域是垂直搜索,如电商搜索、地图搜索、新闻搜索等各类站内搜索。
创建索引时,业务系统模块把数据存储到数据库中,第三方数据同步模块(如Canal)负责将数据库中的数据按照业务需求同步到ES中。搜索时,前端应用先向搜索模块发起搜索请求,然后搜索模块组织搜索DSL向ES发起请求,ES响应搜索模块的请求开始搜索,并将搜索到的商品信息进行封装,然后把数据传送给搜索模块,进而数据再由搜索模块传递到前端进行展现,如下图:
2.5.2、推荐系统
ES在高版本(7.0及以上版本)中引入了高维向量的数据类型,可以把推荐模型算法计算的商品和用户向量存储到ES索引中,当实时请求时,加载用户向量并使用ES的Script Score进行查询,使每个文档最终的排序分值等于当前用户向量与当前文档向量的相似度。为同时满足实时向量计算和实时数据过滤的需求,可以在Script Score查询中添加filter(即过滤条件,如库存、上下架状态等)。ES推荐系统架构如下:
2.5.3、二级索引
在有些场景中,部分数据是强事务性的,或者说这些数据需要关联多张表才可以获取到,这种数据不适合在ES中作为最终数据进行呈现,最好将它们存储在RDBMS中。如果还需要使用任意组合字段进行查询,或者按照某些文本字段进行搜索且这些字段是弱事务性的,那么可以考虑使用ES作为二级索引。如下图所示:数据存储在RDBMS中,建立ES索引时其中仅包含查询字段,RDBMS中的主键在ES中仅存储不用建立索引。这些主键存在于RDBMS的索引中,叫作一级索引;ES中的查询字段构成的索引叫作二级索引。查询时客户端可以把查询请求分发到ES中,ES从索引中查询并返回符合条件的记录主键,客户端再根据返回的记录主键请求RDBMS得到实时数据。
2.5.4、日志分析
ES具有很强的查询能力,支持任意字段的各种组合查询,同时它又具有很强大的数据统计和分析能力,因此也可以当做数据分析引擎。ES官方提供的ELK(Elasticsearch+Logstash+kibana)全家桶可以完成日志采集、索引创建再到可视化的数据分析等工作,使用户可以0代码完成搭建工作。ES支持的日志分析类型可以是多种多样的,生产环境中的用户行为日志、Web容器日志、接口调用日志及数据库日志等都可以通过ELK进行分析。如下图所示为ES官网提供的ELK-Stack架构层级,其中的Beats是新加入的成员,定位为轻量型的单一功能数据采集器。
2.6、Elasticsearch的安装
这里呢由于我在学习前已经安装好了,这里就不带着大家重新安装一遍了,我这边是在windows安装的,版本号为7.10.2,并且我把es弄成开机自启,这些在网上有很多的帖子,大家跟着安装就行,难度不大。并且我在文章一开始也说过,本次学习暂不考虑对es的集群的学习,所以这里也不考虑es的集群安装,感兴趣的小伙伴自行了解。
出于安全性考虑,ES不允许用root账户启动,应创建其他账户启动ES。对基本的入门使用而言,ES的默认配置已经是最佳配置,用户不需要更改配置文件即可启动。需要指出的是,在默认情况下,配置文件中ES近程占用的内存为1GB。如果计算机的内存较小,需要更改config/jvm.options配置文件,修改其中的-Xms和-Xmx参数值到合适的值即可。然后启动es的服务即可。
当ES启动后,在其安装目录下会增加一个data目录,该目录主要用于存储索引数据文件。
我们可以直接访问localhost:9200,ES返回的信息如下:
{
"name" : "DESKTOP-UV81PKT",
"cluster_name" : "elasticsearch",
"cluster_uuid" : "P3TEq-pQQYywXvCN2GjwJw",
"version" : {
"number" : "7.10.2",
"build_flavor" : "default",
"build_type" : "zip",
"build_hash" : "747e1cc71def077253878a59143c1f785afa92b9",
"build_date" : "2021-01-13T00:42:12.435326Z",
"build_snapshot" : false,
"lucene_version" : "8.7.0",
"minimum_wire_compatibility_version" : "6.8.0",
"minimum_index_compatibility_version" : "6.0.0-beta1"
},
"tagline" : "You Know, for Search"
}
其中,name为当前ES的实例名称,默认取值是当前服务器的主机名。cluster_name为集群的名称,该项在配置文件的默认值即为elasticsearch.当在同一个网络中部署多个ES集群时,将依靠cluster_name的值作为集群的唯一标识,各节点只有和集群下的其他节点的cluster_name值一致才能加入集群中。在这种情况下,不同的集群节点需要将cluster_name的值定义为不同的名称。version内为当前集群版本及使用的Lucene组件等版本信息。
2.7、Elasticsearch搜索入门
2.7.1、创建索引
完成搜索的第一步是建立搜索数据集的对象,即建立索引。在定义酒店的搜索需求时,应该包括的字段有酒店标题、所属城市和房价等。对于酒店标题来说,需要按照用户输入的关键词进行模糊搜索,因此应该定义成文本型(text);对于所属城市来说,只需进行相等与否的判断,定义成普通的关键词类型(keyword)即可;对于房价来说,只需进行大小比较的判断,因此定义成数值中的双精度浮点类型。
假设使用默认的分片数和副本数,整体的索引创建语句如下,我们可以通过postman模拟:
在postman中输入localhost:9200/hotel,URL最后面的hotel是将要创建的索引名称,然后body使用json形式传输入参,这样它便会在我们的header中给我们自动添加Content-Type:application/json,请求类型为PUT类型:
body内容如下:
{
"mappings":{
"properties":{
"title":{
"type":"text"
},
"city":{
"type":"keyword"
},
"price":{
"type":"double"
}
}
}
}
当然如果我将上面的请求体换为如下方式:
PUT /hotel
{
"mappings":{
"properties":{
"title":{
"type":"text"
},
"city":{
"type":"keyword"
},
"price":{
"type":"double"
}
}
}
}
对Kibana熟悉的读者可能已经已经看出来了,上面的请求形式和Kibana钟Dev Tools界面的请求形式是一样的,因此大家也可以在Kibana中演练示例。在后面的章节中也会对Kibana中的Dev Tools进行介绍。那这一章我们就先通过postman模拟请求。
2.7.2、写入文档
hotel索引创建后,需要在索引中填充一些数据。例如,在目标索引中写入下面的数据:
postman中请求路径为localhost:9200/hotel/_doc/001,其中hotel代表你创建的索引名称,001代表你要创建ID为001的文档,请求方式为POST
请求参数为:
{
"title":"mbw酒店",
"city":"成都",
"price":"1145.14"
}
2.7.3、根据_id搜索文档
下面进入简单搜索环节。有的时候需要根据文档的ID直接定位某个文档,例如,把之前写入的文档检索出来:
postman中请求路径仍然为localhost:9200/hotel/_doc/001,其中hotel代表你创建的索引名称,001代表你要查询ID为001的文档,请求方式为GET
检索结果如下:
{
"_index": "hotel", //索引名称
"_type": "_doc",
"_id": "001", //文档ID
"_version": 1, //文档版本
"_seq_no": 0,
"_primary_term": 1,
"found": true,
"_source": { //文档内容
"title": "mbw酒店",
"city": "成都",
"price": "1145.14"
}
}
从上面显示的结果中可以看出搜索的一些元数据,如是否找到、索引名称、文档ID值、文档版本等,在_source中展示了命中的文档的原始数据,这和之前写入的数据是相同的。
2.7.4、根据一般字段搜索文档
在ES中进行搜索时需要用到query子句,其请求形式如下:
GET /${index_name}/_search
{
"query":{
...
}
}
query子句可以按照需求填充查询项。假设按照城市进行搜索,把酒店文档搜索出来。因为只需要进行文本是否相等的判断,所以需要用到term搜索,之后会详细介绍term搜索,此处只是简单使用:
postman中请求路径为localhost:9200/hotel/_search,请求方式为GET
{
"query":{
"term":{
"city":{
"value":"成都" //根据城市搜索文档
}
}
}
}
搜索结果如下:
{
"took": 0,
"timed_out": false,
"_shards": { //命中的分片信息
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": { //命中的文档总数
"value": 1,
"relation": "eq"
},
"max_score": 0.2876821, //命中的文档中的最高分
"hits": [ //命中文档集合的信息
{
"_index": "hotel", //文档所在索引
"_type": "_doc",
"_id": "001", //文档ID
"_score": 0.2876821, //文档分值
"_source": { //文档内容
"title": "mbw酒店",
"city": "成都",
"price": "1145.14"
}
}
]
}
}
由上面的结果可以看出,ES不仅返回了搜索的文档结果,而且对结果进行了打分计算,因为本例使用的是比较简单的搜索,并没有使用其核心的计算公式,所以得分是1.
2.7.5、根据文本字段搜索文档
前面的搜索功能传统的关系型数据也可以胜任,但是对文本进行模糊匹配并给出匹配分数这一功能是搜索引擎所独有的。此处使用match搜索对某个字段进行模糊匹配,按照标题进行模糊搜索,示例如下:
postman中请求路径为localhost:9200/hotel/_search,请求方式为GET:
{
"query":{
"match":{
"title":"mbw" //根据title字段搜索
}
}
}
搜索结果如下:
{
"took": 2,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 1,
"relation": "eq"
},
"max_score": 0.2876821, //命中的文档中的最高分
"hits": [ //命中文档集合的信息
{
"_index": "hotel",
"_type": "_doc",
"_id": "001",
"_score": 0.2876821,
"_source": {
"title": "mbw酒店",
"city": "成都",
"price": "1145.14"
}
}
]
}
}
```进行了打分计算,此处使用了对文本打分计算的算法,关于算法后面再详细说明
由上面的结果可以看出,ES对结果