ElasticSearch
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ElasticSearch相关的知识,希望对你有一定的参考价值。
参考技术A 名词概念1.天生支持分布式
1.添加索引
2.增加故障转移
3.横向扩展
4.继续扩展
5.应对故障
2.倒排索引
可以看到,倒排索引是per field的,一个字段由一个自己的倒排索引。 18,20这些叫做 term , 而[1,3]就是posting list 。Posting list就是一个int的数组,存储了所有符合某个term的文档id。
假设我们有很多个term,找出某个特定的term一定很慢,因为term没有排序,需要全部过滤一遍才能找出特定的term。排序之后我们可以用 二分查找 的方式,比全遍历更快地找出目标的term。这个就是 term dictionary。有了term dictionary之后,可以用 logN 次磁盘查找得到目标。
但是磁盘的随机读操作仍然是非常昂贵的所以尽量少的读磁盘,有必要把一些数据缓存到内存里。 但是整个term dictionary本身又太大了,无法完整地放到内存里。于是就有了term index 。term index有点像一本字典的大的章节表。比如:A开头的term ……… Xxx页;C开头的term ……… Xxx页;E开头的term ………Xxx页。
例子是一个包含 "A", "to", "tea", "ted", "ten", "i", "in", 和 "inn" 的 trem 树。这棵树不会包含所有的term, 它包含的是term的一些前缀 。通过term index可以快速地 定位到term dictionary的某个offset ,然后从这个位置再往后顺序查找。整体上来说就是这样的效果。所以term index不需要存下所有的term,而仅仅是他们的一些前缀与Term Dictionary的block之间的映射关系,再结合 FST(Finite State Transducers) 的压缩技术,可以使term index缓存到内存中。从term index查到对应的term dictionary的block位置之后,再去磁盘上找term,大大减少了磁盘随机读的次数。
假设我们现在要将mop, moth, pop, star, stop and top(term index里的term前缀)映射到序号:0,1,2,3,4,5(term dictionary的block位置)。最简单的做法就是定义个Map,大家找到自己的位置对应入座就好了,但从内存占用少的角度想想,有没有更优的办法呢?答案就是: FST
关于FST的博文:https://www.cnblogs.com/jiu0821/p/7688669.html
term dictionary压缩
Term dictionary在磁盘上是以分block的方式保存的,一个block内部利用公共前缀压缩, 比如都是Ab开头的单词就可以把Ab省去 。这样term dictionary可以比b-tree更节约磁盘空间。
现在我们可以回答“为什么Elasticsearch/Lucene检索可以比mysql快了。Mysql只有term dictionary这一层,是以b-tree排序的方式存储在磁盘上的。检索一个term需要若干次的random access的磁盘操作。
为了提高查询的效率,减少磁盘寻道次数,将多个值作为一个数组通过连续区间存放,一次寻道读取多个数据
而Lucene在term dictionary的基础上添加了term index来加速检索,term index以树的形式缓存在内存中。从term index查到对应的term dictionary的block位置之后,再去磁盘上找term,大大减少了磁盘的random access次数。
posting list压缩技巧
Elasticsearch里除了上面说到用FST压缩term index外,对posting list也有压缩技巧。”posting list不是已经只存储文档id了吗?还需要压缩?”
嗯,我们再看回最开始的例子,如果Elasticsearch需要对同学的性别进行索引,会怎样?如果有上千万个同学,而世界上只有男/女这样两个性别,每个posting list都会有至少百万个文档id。 Elasticsearch是如何有效的对这些文档id压缩的呢?
Frame Of Reference
增量编码压缩,将大数变小数,按字节存储
首先,Elasticsearch要求posting list是有序的(为了提高搜索的性能,再任性的要求也得满足),这样做的一个好处是方便压缩,看下面这个图例:
上面说了半天都是单field索引,如果多个field索引的联合查询,倒排索引如何满足快速查询的要求呢?
利用 跳表 (Skip list)的数据结构快速做“与”运算,或者
利用上面提到的bitset按位“与”
先看看跳表的数据结构:
将一个有序链表level0,挑出其中几个元素到level1及level2,每个level越往上,选出来的指针元素越少,查找时依次从高level往低查找,比如55,先找到level2的31,再找到level1的47,最后找到55,一共3次查找,查找效率和2叉树的效率相当,但也是用了一定的空间冗余来换取的。
跳表原理:https://www.cnblogs.com/a8457013/p/8251967.html
假设有下面三个posting list需要联合索引:
如果使用跳表,对最短的posting list中的每个id,逐个在另外两个posting list中查找看是否存在,最后得到交集的结果。
ElasticSearch知识概括
ElasticSearch知识概括
- ElasticSearch简介
- Elasticsearch HTTP操作
- Elasticsearch Java API 操作
- Elasticsearch 环境
- Elasticsearch 进阶
- Elasticsearch 集成
- Elasticsearch 优化
- Elasticsearch 面试题
ElasticSearch简介
Elasticsearch 是什么:
- Elasticsearch是一个分布式、RESTful风格的搜索和数据分析引擎,能够解决不断涌现出的各种用例。作为Elastic Stack的核心,它集中存储您的数据,帮助您发现意料之中以及意料之外的情况。
The Elastic Stack, 包括 Elasticsearch、Kibana、Beats 和 Logstash(也称为 ELK Stack)
。 能够安全可靠地获取任何来源、任何格式的数据,然后实时地对数据进行搜索、分析和可视化。
①Elasticsearch:
核心中的核心组件,基于著名的全文检索引擎lucence的一个分布式版本。由于扩展成分布式,容量和性能得到极大的提升,使得Elasticsearch得以成为目前许多大数据产品和大数据架构的核心组件。
②Logstash:
一个灵活的数据传输和处理系统,在beats出来之前,还负责进行数据收集。Logstash的任务,就是将各种各样的数据,经过配置转化规则,统一化存入Elasticsearch。使用Ruby开发的Logstash在灵活性上,确实非常出色。不过性能一直是被诟病的问题。
③Kibana:
展示组件,基于angularjs。从Elasticsearch中读取数据并展示。具有强大而且灵活的界面配置。
④由于Logstash在数据收集上并不出色,而且作为agent,性能并不达标。elastic发布了beats系列轻量级采集组件。
- Elaticsearch,简称为 ES, ES 是一个开源的高扩展的分布式全文搜索引擎,是整个 Elastic Stack
技术栈的核心。它可以近乎实时的存储、检索数据;本身扩展性很好,可以扩展到上 百台服务器,处理 PB 级别的数据。
全文搜索引擎:
- Google,百度类的网站搜索,它们都是根据网页中的关键字生成索引,我们在搜索的时 候输入关键字,它们会将该关键字即索引匹配到的所有网页返回;还有常见的项目中应用日 志的搜索等等。对于这些非结构化的数据文本,关系型数据库搜索不是能很好的支持。
- 一般传统数据库,全文检索都实现的很鸡肋,因为一般也没人用数据库存文本字段。进 行全文检索需要扫描整个表,如果数据量大的话即使对 SQL的语法优化,也收效甚微。建 立了索引,但是维护起来也很麻烦,对于 insert 和 update 操作都会重新构建索引。基于以上原因可以分析得出,在一些生产环境中,使用常规的搜索方式,性能是非常差的:
①搜索的数据对象是大量的非结构化的文本数据。
②文件记录量达到数十万或数百万个甚至更多。
③支持大量基于交互式文本的查询。
④需求非常灵活的全文搜索查询。
⑤对高度相关的搜索结果的有特殊需求,但是没有可用的关系数据库可以满足。
⑥对不同记录类型、非文本数据操作或安全事务处理的需求相对较少的情况。 - 为了解决结构化数据搜索和非结构化数据搜索性能问题,我们就需要专业,健壮,强大的全 文搜索引擎这里说到的全文搜索引擎指的是目前广泛应用的主流搜索引擎。它的工作原理是计算机索引程序通过扫描文章中的每一个词,对每一个词建立一个索引,指明该词在文章中出现的次数和位置,当用户查询时,检索程序就根据事先建立的索引进行查找,并将查找的结果反馈给用户的检索方式。这个过程类似于通过字典中的检索字表查字的过程。
Elasticsearch And Solr:
- Lucene 是 Apache 软件基金会 Jakarta 项目组的一个子项目,提供了一个简单却强大的应用程式接口,能够做全文索引和搜寻。在 Java 开发环境里 Lucene 是一个成熟的免费开源 工具。就其本身而言,Lucene是当前以及最近几年最受欢迎的免费 Java 信息检索程序库。 但 Lucene只是一个提供全文搜索功能类库的核心工具包,而真正使用它还需要一个完善的 服务框架搭建起来进行应用。
- 目前市面上流行的搜索引擎软件,主流的就两款:Elasticsearch 和 Solr,这两款都是基于 Lucene搭建的,可以独立部署启动的搜索引擎服务软件。由于内核相同,所以两者除了服务器安装、部署、管理、集群以外,对于数据的操作修改、添加、保存、查询等等都十分类似。
- 在使用过程中,一般都会将 Elasticsearch 和 Solr 这两个软件对比,然后进行选型。这两个搜索引擎都是流行的,先进的的开源搜索引擎。它们都是围绕核心底层搜索库 - Lucene 构建的,但它们又是不同的。像所有东西一样,每个都有其优点和缺点:
特征 | Solr/SolrCloud | Elasticsearch |
---|---|---|
社区和开发者 | Apache软件基金和社区支持 | 单一商业实体及其员工 |
节点发现 | Apache Zookeeper,在大量项目中成熟且经过实战测试 | zen内置于Elasticsearch本身,需要专用的主节点才能进行分裂脑保护 |
碎片放置 | 本质上是静态,需要手动工作来迁移分片,从Solr 7开始–Autoscaling API允i许—些动态操作 | 动态,可L以根据群集状态按需移动分片 |
高速缓存 | 全局,每个段更改无效 | 每段,更适合动态更改数据 |
分析引擎性能 | 非常适合精确计算的静态数据 | 结果的往确性取决于数据放置 |
全文搜索功能 | 基于Lucene的语言分析,多建议,拼写检查,丰富的高亮显示支持 | 基于Lucene的语言分析,单—建议API实现,高亮显示重新计算 |
DevOps支持 | 尚未完全,但即将到来 | 非常好的API |
非平面数据处 | 嵌套文档和父-子支持 | 嵌套和对象类型的自然支持允许几乎无限的嵌套和父-子支持 |
查询DSL | JSON(有限),XML(有限)或URL参数 | JSON |
索引/收集领导控制 | 领导者安置控制和领导者重新平衡甚至可以节点上的负载 | 不可能 |
机器学习 | 内置–在流聚合之上,专注于逻辑回归和学习排名贡献模块 | 商业功能,专注于异常和异常值以及时间序列数据 |
- Elasticsearch 和 Solr 都是开源搜索引擎,那么我们在使用时该如何选择呢?
① Google 搜索趋势结果表明,与 Solr 相比,Elasticsearch 具有很大的吸引力,但这并不 意味着 Apache Solr 已经死亡。虽然有些人可能不这么认为,但 Solr 仍然是最受欢迎的 搜索引擎之一,拥有强大的社区和开源支持。
②与 Solr 相比,Elasticsearch 易于安装且非常轻巧。此外,你可以在几分钟内安装并运行 Elasticsearch。但是,如果 Elasticsearch 管理不当,这种易于部署和使用可能会成为一个 问题。基于 JSON 的配置很简单,但如果要为文件中的每个配置指定注释,那么它不适 合您。总的来说,如果你的应用使用的是 JSON,那么 Elasticsearch 是一个更好的选择。 否则,请使用 Solr,因为它的 schema.xml 和 solrconfig.xml 都有很好的文档记录。
③Solr 拥有更大,更成熟的用户,开发者和贡献者社区。ES 虽拥有的规模较小但活跃的 用户社区以及不断增长的贡献者社区。Solr 贡献者和提交者来自许多不同的组织,而 Elasticsearch 提交者来自单个公司。
④Solr 更成熟,但 ES 增长迅速,更稳定。
⑤Solr 是一个非常有据可查的产品,具有清晰的示例和 API 用例场景。 Elasticsearch 的 、文档组织良好,但它缺乏好的示例和清晰的配置说明。 - 那么到底是 Solr 还是 Elasticsearch?
①有时很难找到明确的答案。无论您选择 Solr 还是 Elasticsearch,首先需要了解正确的用 例和未来需求。总结他们的每个属性。
<1>由于易于使用,Elasticsearch 在新开发者中更受欢迎。一个下载和一个命令就可以启动 一切。
<2>如果除了搜索文本之外还需要它来处理分析查询,Elasticsearch 是更好的选择
<3>如果需要分布式索引,则需要选择 Elasticsearch。对于需要良好可伸缩性和以及性能分 布式环境,Elasticsearch 是更好的选择。
<4>Elasticsearch 在开源日志管理用例中占据主导地位,许多组织在 Elasticsearch 中索引它 们的日志以使其可搜索。
<5>如果你喜欢监控和指标,那么请使用 Elasticsearch,因为相对于 Solr,Elasticsearch 暴露 了更多的关键指标
DSL语言:
- Query DSL 是一个 Java 开源框架,用于构建 类型安全 的 SQL 查询语句。采用 API 代替传统的拼接字符串来构造查询语句。 目前 Querydsl 支持的平台包括 JPA,JDO,SQL,JavaCollections,RDF,Lucene,Hibernate Search。
- Elasticsearch 提供了一整套基于 JSON 的查询 DSL 语言来定义查询。 Query DSL当作是一系列的抽象的查询表达式树 (AST) 特定查询能够包含其它的查询,(如 bool ), 有些查询能够包含过滤器(如constant_score), 还有的可以同时包含查询和过滤器 (如 filtered). 都能够从 ES支持查询集合里面选择任意一个查询或者是从过滤器集合里面挑选出任意一个过滤器, 这样的话,我们就可以构造出任意复杂(maybe非常有趣)的查询了。
Elasticsearch 应用案例:
- GitHub: 2013 年初,抛弃了 Solr,采取 Elasticsearch 来做 PB 级的搜索。“GitHub 使用 Elasticsearch 搜索 20TB 的数据,包括 13 亿文件和 1300 亿行代码”。
- 维基百科:启动以 Elasticsearch 为基础的核心搜索架构
- SoundCloud:“SoundCloud 使用 Elasticsearch 为 1.8 亿用户提供即时而精准的音乐搜索 服务”。
- 百度:目前广泛使用 Elasticsearch 作为文本数据分析,采集百度所有服务器上的各类指 标数据及用户自定义数据,通过对各种数据进行多维分析展示,辅助定位分析实例异常 或业务层面异常。目前覆盖百度内部 20多个业务线(包括云分析、网盟、预测、文库、 直达号、钱包、风控等),单集群最大 100 台机器,200 个 ES 节点,每天导入30TB+ 数据。
- 新浪:使用 Elasticsearch 分析处理 32 亿条实时日志。
- 阿里:使用 Elasticsearch 构建日志采集和分析体系。
- Stack Overflow:解决 Bug 问题的网站,全英文,编程人员交流的网站。
Elasticsearch 安装:
- 链接:
①Elasticsearch 的官方地址
②下载地址 - Elasticsearch 最新的版本是 7.11.2(截止 2021.3.10),我们选择 7.8.0 版本(最新版本半年前的版本)
- Elasticsearch 分为 Linux 和 Windows 版本,基于我们主要学习的是 Elasticsearch 的 Java 客户端的使用,所以课程中使用的是安装较为简便的 Windows 版本。
- 安装软件:Windows 版的 Elasticsearch 的安装很简单,解压即安装完毕,解压后的 Elasticsearch的目录结构如下:
目录 | 含义 |
---|---|
bin | 可执行脚本目录 |
config | 配置目录 |
jdk | 内置JDK目录 |
lib | 类库 |
logs | 日志目录 |
modules | 模块目录 |
plugins | 插件目录 |
- 解压后,进入 bin 文件目录,点击 elasticsearch.bat 文件启动 ES 服务
①注意:9300 端口为 Elasticsearch 集群间组件的通信端口,9200 端口为浏览器访问的http协议 RESTful 端口。
②打开浏览器(推荐使用谷歌浏览器),输入地址:http://localhost:9200,测试结果
name" : “LAPTOP-J9IRK5BM”",
"cluster_name” : “elasticsearch~,
~cluster_uuid”: “fe4UTupLTCKHshF zDY7Gdg”,
"version:
"number” : ”7.8.0”,
“build_flavor-: "default”,“build_type”: “zip”.
"build_hash”: “757314695644ea9aldc2fecd26d1a43856725e65","build_date”:”2020-06-14T19:35:50.234439Z”,
“build_snapshot”: false,
“lucene_version: “8.5.1~.
"minimum_wire_compatibility_version": "6.8.0",
“minimun_index_compatibility_version”: "6.0.0-beta1"
,
~tagline” : “You Knov,for Search”
- 问题解决:
①Elasticsearch 是使用 java 开发的,且 7.8 版本的 ES 需要 JDK 版本 1.8 以上,默认安装包带有 jdk 环境,如果系统配置 JAVA_HOME,那么使用系统默认的 JDK,如果没有配 置使用自带的 JDK,一般建议使用系统配置的 JDK。
②双击启动窗口闪退,通过路径访问追踪错误,如果是“空间不足”,请修改 config/jvm.options 配置文件
#设置JVM初始内存为1G。此值可以设置与-Xmx相同,以避免每次垃圾回收完成后JVM重新分配内存# Xms represents the initial size of total heap space
#设置JVM最大可用内存为1G
# Xmx represents the maximum size of total heap space
-Xms1g
-xmxlg
Elasticsearch 数据格式:
- Elasticsearch 是面向文档型数据库,一条数据在这里就是一个文档。为了方便大家理解, 我们将 Elasticsearch里存储文档数据和关系型数据库 MySQL 存储数据的概念进行一个类比。
- ES 里的 Index 可以看做一个库,而 Types 相当于表,Documents 则相当于表的行。
- 这里 Types 的概念已经被逐渐弱化,Elasticsearch 6.X 中,一个 index 下已经只能包含一个type,Elasticsearch 7.X 中, Type 的概念已经被删除了。
- 用 JSON 作为文档序列化的格式,比如一条用户信息:
"name" : "John",
"sex" : "Male",
"age" : 25,
"birthDate": "1990/05/01",
"about" : "I love to go rock climbing",
"interests": [ "sports", "music" ]
Elasticsearch HTTP操作
索引操作:
创建索引:
对比关系型数据库,创建索引就等同于创建数据库,在 Postman 中向 ES 服务器发PUT
请求 :http://127.0.0.1:9200/shopping。请求后服务器返回响应:
响应结果:
"acknowledged"【响应结果】: true, # true操作成功
"shards_acknowledged"【分片结果】: true, # 分片操作成功
"index"【索引名称】: "shopping"
# 注意:创建索引库的分片数默认 1片,在 7.0.0之前的 Elasticsearch版本中,默认 5片
如果重复添加索引,会返回错误信息
查看所有索引:
在 Postman 中,向 ES 服务器发GET
请求 :http://127.0.0.1:9200/_cat/indices?v。这里请求路径中的_cat 表示查看的意思,indices 表示索引,所以整体含义就是查看当前 ES
服务器中的所有索引,就好像 MySQL 中的 show tables 的感觉,服务器响应结果如下:
表头 | 含义 |
---|---|
health | 当前服务器健康状态:green(集群完整) yellow(单点正常、集群不完整) red(单点不正常) |
status | 索引打开、关闭状态 |
index | 索引名 |
uuid | 索引统一编号 |
pri | 主分片数量 |
rep | 副本数量 |
docs.count | 可用文档数量 |
docs.deleted | 文档删除状态(逻辑删除) |
store.size | 主分片和副分片整体占空间大小 |
pri.store.size | 主分片占空间大小 |
查看单个索引:
在 Postman 中,向 ES 服务器发GET
请求:http://127.0.0.1:9200/shopping。查看索引向 ES 服务器发送的请求路径和创建索引是一致的。但是 HTTP方法不一致。这里 可以体会一下 RESTful 的意义。
响应结果:
"shopping"【索引名】:
"aliases"【别名】: ,
"mappings"【映射】: ,
"settings"【设置】:
"index"【设置- 索引】:
"creation_date"【设置- 索引- 创建时间】: "1614265373911",
"number_of_shards"【设置- 索引- 主分片数量】: "1",
"number_of_replicas"【设置- 索引- 副分片数量】: "1",
"uuid"【设置- 索引- 唯一标识】: "eI5wemRERTumxGCc1bAk2A",
"version"【设置- 索引- 版本】:
"created": "7080099"
,
"provided_name"【设置- 索引- 名称】: "shopping"
删除索引:
在 Postman 中,向 ES 服务器发DELETE
请求:http://127.0.0.1:9200/shopping。重新访问索引时,服务器返回响应:索引不存在。
文档操作:
创建文档:
索引已经创建好了,接下来我们来创建文档,并添加数据。这里的文档可以类比为关系型数据库中的表数据,添加的数据格式为 JSON 格式,在Postman 中,向 ES 服务器发 POST 请求:http://127.0.0.1:9200/shopping/_doc。此处发送请求的方式必须为 POST,不能是 PUT,否则会发生错误。
①上面的数据创建后,由于没有指定数据唯一性标识(ID),默认情况下,ES 服务器会随机生成一个。如果想要自定义唯一性标识,需要在创建时指定:http://127.0.0.1:9200/shopping/_doc/1
②此处需要注意:如果增加数据时明确数据主键,那么请求方式也可以为 PUT。
③PUT 和 POST 的区别:
<1>POST 新增,如果不指定id,会自动生成 id。指定 id 就会修改这个数据,并新增版本号。
1、 post 方法不带 id 时是新增,带 id 不存在时也是新增,带 id 且数据存在时是更新操作。
<2>PUT 可以新增也可以修改,PUT 必须指定 id,由于 PUT 需要指定 id,我们一般都用来做修改。
响应结果:
"_index"【索引】: "shopping",
"_type"【类型-文档】: "_doc",
"_id"【唯一标识】: "Xhsa2ncBlvF_7lxyCE9G", #可以类比为 MySQL中的主键,随机生成
"_version"【版本】: 1,
"result"【结果】: "created", #这里的 create表示创建成功
"_shards"【分片】:
"total"【分片-总数】: 2,
"successful"【分片- 成功】: 1,
"failed"【分片- 失败】: 0
,
"_seq_no": 0,
"_primary_term": 1
查看文档:
查看文档时,需要指明文档的唯一性标识,类似于 MySQL 中数据的主键查询在Postman 中,向 ES 服务器发 GET 请求:http://127.0.0.1:9200/shopping/_doc/1
响应结果:
"_index"【索引】: "shopping",
"_type"【文档类型】: "_doc",
"_id": "1",
"_version": 2,
"_seq_no": 2,
"_primary_term": 2,
"found"【查询结果】: true, # true表示查找到,false表示未查找到
"_source"【文档源信息】:
"title": "华为手机",
"category": "华为",
"images": "http://www.gulixueyuan.com/hw.jpg",
"price": 4999.00
修改文档(全量修改):
和新增文档一样,输入相同的 URL 地址请求,如果请求体变化,会将原有的数据内容覆盖在Postman 中,向 ES 服务器发 POST 请求 :http://127.0.0.1:9200/shopping/_doc/1
响应结果:
"_index": "shopping",
"_type": "_doc",
"_id": "1",
"_version"【版本】: 2,
"result"【结果】: "updated", # updated表示数据被更新
"_shards":
"total": 2,
"successful": 1,
"failed": 0
,
"_seq_no": 2,
"_primary_term": 2
修改字段(局部修改):
修改数据时,也可以只修改某一给条数据的局部信息,在 Postman 中,向 ES 服务器发 POST 请求 :http://127.0.0.1:9200/shopping/_update/1。
请求体:
"doc":
"title":"小米手机",
"category":"小米"
删除文档:
删除一个文档不会立即从磁盘上移除,它只是被标记成已删除(逻辑删除)。在Postman 中,向 ES 服务器发 DELETE 请求:http://127.0.0.1:9200/shopping/_doc/1。
响应结果:
"_index": "shopping",
"_type": "_doc",
"_id": "1",
"_version"【版本】: 4, #对数据的操作,都会更新版本
"result"【结果】: "deleted", # deleted表示数据被标记为删除
"_shards":
"total": 2,
"successful": 1,
"failed": 0
,
"_seq_no": 4,
"_primary_term": 2
如果删除一个并不存在的文档的响应结果::
"_index": "shopping",
"_type": "_doc",
"_id": "1",
"_version": 1,
"result"【结果】: "not_found", # not_found表示未查找到
"_shards":
"total": 2,
"successful": 1,
"failed": 0
,
"_seq_no": 5,
"_primary_term": 2
条件删除文档:
一般删除数据都是根据文档的唯一性标识进行删除,实际操作时,也可以根据条件对多条数据进行删除:向 ES 服务器发 POST请求:http://127.0.0.1:9200/shopping/_delete_by_query
响应结果:
"took"【耗时】: 175,
"timed_out"【是否超时】: false,
"total"【总数】: 2,
"deleted"【删除数量】: 2,
"batches": 1,
"version_conflicts": 0,
"noops": 0,
"retries":
"bulk": 0,
"search": 0
,
"throttled_millis": 0,
"requests_per_second": -1.0,
"throttled_until_millis": 0,
"failures": []
请求体内容为:
"query":
"match":
"price":4000.00
映射操作:
- 有了索引库,等于有了数据库中的database。接下来就需要建索引库(index)中的映射了,类似于数据库(database)中的表结构(table)。 创建数据库表需要设置字段名称,类型,长度,约束等;索引库也一样,需要知道这个类型下有哪些字段,每个字段有哪些约束信息,这就叫做映射(mapping)。
创建映射:
在Postman 中,向 ES 服务器发 PUT 请求:http://127.0.0.1:9200/student/_mapping。
映射数据说明:
①字段名:任意填写,下面指定许多属性,例如:title、subtitle、images、price
②type:类型,Elasticsearch 中支持的数据类型非常丰富,说几个关键的:
<1>String 类型,又分两种:
1、text:可分词
2、keyword:不可分词,数据会作为完整字段进行匹配
<2>Numerical:数值类型,分两类
1、基本数据类型:long、integer、short、byte、double、float、half_float
2、浮点数的高精度类型:scaled_float
<3>Date:日期类型
<4>Array:数组类型
<5>Object:对象
③index:是否索引,默认为 true,也就是说你不进行任何配置,所有字段都会被索引。
<1>true:字段会被索引,则可以用来进行搜索
<2>false:字段不会被索引,不能用来搜索
④store:是否将数据进行独立存储,默认为false。原始的文本会存储在_source 里面,默认情况下其他提取出来的字段都不是独立存储的,是从_source 里面提取出来的。当然你也可以独立的存储某个字段,只要设置 “store”: true 即可,获取独立存储的字段要比从_source 中解析快得多,但是也会占用 更多的空间,所以要根据实际业务需求来设置。
⑤analyzer:分词器,这里的 ik_max_word 即使用 ik 分词器
请求体:
"properties":
"name":
"type": "text",
"index": true
,
"sex":
"type": "text",
"index": false
,
"age":
"type": "long",
"index": false
查看映射:
在Postman 中,向 ES 服务器发 GET 请求:http://127.0.0.1:9200/student/_mapping索引映射关联:
初始化索引,并创建索引中的字段对应的映射关系。在Postman 中,向 ES 服务器发 PUT请求:http://127.0.0.1:9200/student
请求体:
"settings": ,
"mappings":
"properties":
"name":
"type": "text",
"index": true
,
"sex":
"type": "text",
"index": false
,
"age":
"type": "long",
"index": false
ES数据类型:
- 字符串类型 - string(不再支持):可知string类型的field已经被移除了, 我们需要用text或keyword类型来代替string.
①文本类型 - text:
在Elasticsearch 5.4 版本开始, text取代了需要分词的string,当一个字段需要用于全文搜索(会被分词), 比如产品名称、产品描述信息, 就应该使用text类型。text的内容会被分词,可以设置是否需要存储: “index”: “true|false”。text类型的字段不能用于排序, 也很少用于聚合。
②关键字类型 - keyword:
在Elasticsearch 5.4 版本开始, keyword取代了不需要分词的string,当一个字段需要按照精确值进行过滤、排序、聚合等操作时, 就应该使用keyword类型,keyword的内容不会被分词, 可以设置是否需要存储: “index”: “true|false”。 数字类型 - 8种:
数字类型有如下分类:
类型 | 说明 |
---|---|
byte | 有符号的8位整数, 范围: [-128 ~ 127] |
short | 有符号的16位整数, 范围: [-32768 ~ 32767] |
integer | 有符号的32位整数, 范围: [−231 ~ 231-1] |
long | 有符号的64位整数, 范围: [−263 ~ 263-1] |
float | 32位单精度浮点数 |
double | 64位双精度浮点数 |
half_float | 16位半精度IEEE 754浮点类型 |
scaled_float | 缩放类型的的浮点数, 比如price字段只需精确到分, 57.34缩放因子为100, 存储结果为5734 |
日期类型 - date:
①JSON没有日期数据类型, 所以在ES中, 日期可以是:
<1>包含格式化日期的字符串, “2018-10-01”, 或"2018/10/01 12:10:30".
<2>代表时间毫秒数的长整型数字.
<3>代表时间秒数的整数.
②如果时区未指定, 日期将被转换为UTC格式, 但存储的却是长整型的毫秒值.
③可以自定义日期格式, 若未指定, 则使用默认格式: strict_date_optional_time||epoch_millis布尔类型 - boolean:
①可以接受表示真、假的字符串或数字:
②真值: true, “true”, “on”, “yes”, “1”…
③假值: false, “false”, “off”, “no”, “0”, “”(空字符串), 0.0, 0二进制型 - binary:
①二进制类型是Base64编码字符串的二进制值, 不以默认的方式存储, 且不能被搜索. 有2个设置项:
<1>doc_values: 该字段是否需要存储到磁盘上, 方便以后用来排序、聚合或脚本查询. 接受true和false(默认);
<2>store: 该字段的值是否要和_source分开存储、检索, 意思是除了_source中, 是否要单独再存储一份. 接受true或false(默认).范围类型 - range:
range类型支持以下几种:
类型 | 范围 |
---|---|
integer_range | −231 ~ 231−1 |
long_range | −263 ~ 263−1 |
float_range | 32位单精度浮点型 |
double_range | 64位双精度浮点型 |
date_range | 64位整数, 毫秒计时 |
ip_range | IP值的范围, 支持IPV4和IPV6, 或者这两种同时存在 |
数组类型 - array:
①ES中没有专门的数组类型, 直接使用[]定义即可,数组中所有的值必须是同一种数据类型, 不支持混合数据类型的数组:
<1>字符串数组: [“one”, “two”];
<2>整数数组: [1, 2];
<3>由数组组成的数组: [1, [2, 3]], 等价于[1, 2, 3];
<4>对象数组: [“name”: “Tom”, “age”: 20, “name”: “Jerry”, “age”: 18].
②注意:
<1>动态添加数据时, 数组中第一个值的类型决定整个数组的类型;
<2>不支持混合数组类型, 比如[1, “abc”];
<3>数组可以包含null值, 空数组[]会被当做missing field —— 没有值的字段.
<4>数组字段的定义,不是array哦。数组类型不需要单独设置,建立mapping映射时只需成单个字段一样,在插入的数据时候.插入多个值时,该字段就会自动变成数组类型的。
<5>数组字段搜索时数组字段的每个值默认是OR关系,即搜索其中一个值即可。
对象类型 - object:
JSON文档是分层的: 文档可以包含内部对象, 内部对象也可以包含内部对象。嵌套类型 - nested:
嵌套类型是对象数据类型的一个特例, 可以让array类型的对象被独立索引和搜索。- 地理数据类型:
①地理点类型 - geo point:
地理点类型用于存储地理位置的经纬度对, 可用于。
<1>查找一定范围内的地理点;
<2>通过地理位置或相对某个中心点的距离聚合文档;
<3>将距离整合到文档的相关性评分中;
<4>通过距离对文档进行排序.
②地理形状类型 - geo_shape:
是多边形的复杂形状. 使用较少。 IP类型:
IP类型的字段用于存储IPv4或IPv6的地址, 本质上是一个长整型字段。计数数据类型 - token_count:
①token_count类型用于统计字符串中的单词数量.
②本质上是一个整数型字段, 接受并分析字符串值, 然后索引字符串中单词的个数.- 链接:
① Elasticsearch的数据类型 (text、keyword、date、object、geo等)
高级查询:
- Elasticsearch 提供了基于 JSON 提供完整的查询 DSL 来定义查询。
查询所有文档:
在 Postman 中,向 ES 服务器发 GET 请求 :http://127.0.0.1:9200/student/_search
请求体:
"query":
"match_all":
# "query":这里的 query代表一个查询对象,里面可以有不同的查询属性
# "match_all":查询类型,例如:match_all(代表查询所有),match,term ,range 等等
# 查询条件:查询条件会根据类型的不同,写法也有差异
服务器响应结果如下:
"took【查询花费时间,单位毫秒】" : 1116,
"timed_out【是否超时】" : false,
"_shards【分片信息】" :
"total【总数】" : 1,
"successful【成功】" : 1,
"skipped【忽略】" : 0,
"failed【失败】" : 0
,
"hits【搜索命中结果】" :
"total"【搜索条件匹配的文档总数】:
"value"【总命中计数的值】: 3,
"relation"【计数规则】: "eq" # eq 表示计数准确, gte表示计数不准确
,
"max_score【匹配度分值】" : 1.0,
"hits【命中结果集合】" : [
。。。
]
匹配查询:
match 匹配类型查询,会把查询条件进行分词,然后进行查询,多个词条之间是 or 的关系在Postman 中,向 ES 服务器发 GET 请求:http://127.0.0.1:9200/student/_search
请求体:
"query":
"match":
"name":"zhangsan"
字段匹配查询:
multi_match 与 match 类似,不同的是它可以在多个字段中查询。 在 Postman 中,向 ES 服务器发GET 请求 :http://127.0.0.1:9200/student/_search
请求体:
"query":
"multi_match":
"query": "zhangsan",
"fields": ["name","nickname"]
关键字精确查询:
term 查询,精确的关键词匹配查询,不对查询条件进行分词。 在 Postman 中,向 ES 服务器发 GET 请求:http://127.0.0.1:9200/student/_search
请求体:
"query":
"term":
"name":
"value": "zhangsan"
多关键字精确查询(in查询):
terms 查询和 term 查询一样,但它允许你指定多值进行匹配。 如果这个字段包含了指定值中的任何一个值,那么这个文档满足条件,类似于 mysql 的 in 在 Postman 中,向ES服务器发 GET 请求 :http://127.0.0.1:9200/student/_search
请求体:
"query":
"terms":
"name": ["zhangsan","lisi"]
指定查询字段:
默认情况下,Elasticsearch 在搜索的结果中,会把文档中保存在_source 的所有字段都返回。 如果我们只想获取其中的部分字段,我们可以添加_source 的过滤 在 Postman 中,向 ES 服务器发 GET 请求:http://127.0.0.1:9200/student/_search
请求体:
"_source": ["name","nickname"],
"query":
"terms":
"nickname": ["zhangsan"]
过滤字段:
我们也可以通过一下字段在Postman中,向ES服务器发GET请求:http://127.0.0.1:9200/student/_search
①includes:来指定想要显示的字段
②excludes:来指定不想要显示的字段
请求体:
"_source":
"includes": ["name","nickname"]
,
"query":
"terms":
"nickname": ["zhangsan"]
exists查询:
查找指定字段包含任何非空值【不是null 也不是[ ]】的文档。【ps:等价于mysql 的 is null】
①注意:这些值不属于空值
<1>空字符串,例如"“或”-"
<2>包含null和另一个值的数组,例如[null, “foo”]
<3>自定义null-value,在字段映射中定义
请求体:
"query":
"exists":
"field":"field"
前缀查询(prefix):
prefix 关键字用来检索含有指定前缀的关键词的相关文档。URL:http://127.0.0.1:9200/student/_search
请求体:
"query":
"prefix":
"content":
"value": "redis"
通配符查询(wildcard):
wildcard 关键字,通配符查询: ? 用来匹配一个任意字符, * 用来匹配多个任意字符。URL:http://127.0.0.1:9200/student/_search
请求体:
GET /ems/emp/_search
"query":
"wildcard":
"content":
"value": "re*"
组合查询:
bool把各种其它查询通过must(必须 )、must_not(必须不)、should(应该)的方式进行组合在Postman 中,向 ES 服务器发 GET 请求:http://127.0.0.1:9200/student/_search
请求体:
"query":
"bool":
"must": [
"match":
"name": "zhangsan"
],
"must_not": [
"match":
"age": "40"
,
"exists":
"field": "name"//空值查询
,
"terms":
"name": [
"老万",
"小明"
]//not in 查询
],
"should": [
"match":
"sex": "男"
]
范围查询:
range 查询找出那些落在指定区间内的数字或者时间。range 查询允许以下字符。在 Postman 中,向 ES 服务器发 GET 请求 :http://127.0.0.1:9200/student/_search
操作符 | 说明 |
---|---|
gt> | 大于> |
gte | 大于等于>= |
lt | 小于< |
lte | 小于等于<= |
请求体:
"query":
"range":
"age":
"gte": 30,
"lte": 35
模糊查询:
返回包含与搜索字词相似的字词的文档。
①编辑距离是将一个术语转换为另一个术语所需的一个字符更改的次数。这些更改可以包括:
<1>更改字符(box → fox)
<2>删除字符(black → lack)
<3>插入字符(sic → sick)
<4>转置两个相邻字符(act → cat)
②为了找到相似的术语,fuzzy 查询会在指定的编辑距离内创建一组搜索词的所有可能的变体 或扩展。然后查询返回每个扩展的完全匹配。
③通过 fuzziness 修改编辑距离。一般使用默认值 AUTO,根据术语的长度生成编辑距离。 在 Postman 中,向 ES 服务器发 GET 请求 :http://127.0.0.1:9200/student/_search
请求体:
"query":
"fuzzy":
"title":
"value": "zhangsan"
单字段排序:
sort 可以让我们按照不同的字段进行排序,并且通过 order 指定排序的方式。desc 降序,asc 升序。 在Postman 中,向 ES 服务器发 GET 请求 :http://127.0.0.1:9200/student/_search
请求体:
"query":
"match":
"name":"zhangsan"
,
"sort": [
"age":
"order":"desc"
]
多字段排序:
假定我们想要结合使用age 和_score 进行查询,并且匹配的结果首先按照年龄排序,然后 按照相关性得分排序在Postman中,向 ES 服务器发 GET 请求: http://127.0.0.1:9200/student/_search
请求体:
"query":
"match_all":
,
"sort": [
"age":
"order": "desc"
,
"_score":
"order": "desc"
]
高亮查询:
在进行关键字搜索时,搜索出的内容中的关键字会显示不同的颜色,称之为高亮。 Elasticsearch可以对查询内容中的关键字部分,进行标签和样式(高亮)的设置。
①在使用 match 查询的同时,加上一个highlight 属性:
<1>pre_tags:前置标签
<2>post_tags:后置标签
<3>fields:需要高亮的字段
<4>title:这里声明 title 字段需要高亮,后面可以为这个字段设置特有配置,也可以空
②在Postman 中,向 ES 服务器发 GET 请求 :http://127.0.0.1:9200/student/_search
请求体:
"query":
"match":
"name": "zhangsan"
,
"highlight":
"pre_tags": "<font color='red'>",
"post_tags": "</font>",
"fields":
"name":
分页查询:
from:当前页的起始索引,默认从 0 开始。 from = (pageNum - 1) * size 。size:每页显示多少条。在 Postman 中,向 ES 服务器发 GET 请求:http://127.0.0.1:9200/student/_search
请求体:
"query":
"match_all":
,
"sort": [
"age":
"order": "desc"
],
"from": 0,
"size": 2
聚合查询:
聚合允许使用者对 es 文档进行统计分析,类似与关系型数据库中的 group by,当然还有很 多其他的聚合,例如取最大值、平均值等等。 对某个字段取最大值 max 在 Postman 中,向 ES 服务器发GET 请求:http://127.0.0.1:9200/student/_search
①对某个字段取最小值 min
②对某个字段取最大值 max
③对某个字段求和 sum
④对某个字段取平均值 avg
⑤对某个字段的值进行去重之后再取总数distinct
③stats 聚合,对某个字段一次性返回 count,max,min,avg 和 sum 五个指标
请求体:
"aggs":
"max_age":
"max":"field":"age"
,
"size":0
桶聚合查询:
桶聚和相当于 sql 中的 group by 语句。terms 聚合,分组统计,在 Postman 中,向 ES 服务器发 GET 请求 :http://127.0.0.1:9200/student/_search
Elasticsearch Java API 操作
Elasticsearch Java API 操作准备:
- Elasticsearch 软件是由 Java 语言开发的,所以也可以通过 Java API 的方式对 Elasticsearch服务进行访问
- 修改 pom 文件,增加 Maven 依赖关系
<dependencies>
<dependency>
<groupId>org.elasticsearch</groupId>
<artifactId>elasticsearch</artifactId>
<version>7.8.0</version>
</dependency>
<!-- elasticsearch的客户端 -->
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-high-level-client</artifactId>
<version>7.8.0</version>
</dependency>
</dependencies>
- 客户端对象:创建 com.atguigu.es.test.Elasticsearch01_Client 类,代码中创建 Elasticsearch 客户端对象,因为早期版本的客户端对象已经不再推荐使用,且在未来版本中会被删除,所以这里我们采用高级 REST 客户端对象。
①注意:9200 端口为 Elasticsearch 的 Web 通信端口,localhost 为启动 ES 服务的主机名
// 创建客户端对象
RestHighLevelClient client = new RestHighLevelClient(
RestClient.builder(new HttpHost("localhost", 9200, "http"))
);
...
// 关闭客户端连接
client.close();
- ES 服务器正常启动后,可以通过 Java API 客户端对象对 ES 索引进行操作
索引操作:
- 创建索引:
// 创建索引 - 请求对象
CreateIndexRequest request = new CreateIndexRequest("user");
// 发送请求,获取响应
CreateIndexResponse response = client.indices().create(request,
RequestOptions.DEFAULT);
boolean acknowledged = response.isAcknowledged();
// 响应状态
System.out.println("操作状态 = " + acknowledged);
- 查看索引:
// 查询索引 - 请求对象
GetIndexRequest request = new GetIndexRequest("user");
// 发送请求,获取响应
GetIndexResponse response = client.indices().get(request,
RequestOptions.DEFAULT);
System.out.println("aliases:"+response.getAliases());
System.out.println("mappings:"+response.getMappings());
System.out.println("settings:"+response.getSettings());
- 删除索引:
// 删除索引 - 请求对象
DeleteIndexRequest request = new DeleteIndexRequest("user");
// 发送请求,获取响应
AcknowledgedResponse response = client.indices().delete(request,
RequestOptions.DEFAULT);
// 操作结果
System.out.println("操作结果 : " + response.isAcknowledged());
文档操作:
- 新增文档:
// 新增文档 - 请求对象
IndexRequest request = new IndexRequest();
// 设置索引及唯一性标识
request.index("user").id("1001");
// 创建数据对象
User user = new User();
user.setName("zhangsan");
user.setAge(30);
user.setSex("男");
ObjectMapper objectMapper = new ObjectMapper();
String productJson = objectMapper.writeValueAsString(user);
// 添加文档数据,数据格式为 JSON格式
request.source(productJson,XContentType.JSON);
// 客户端发送请求,获取响应对象
IndexResponse response = client.index(request, RequestOptions.DEFAULT);
3.打印结果信息
System.out.println("_index:" + response.getIndex());
System.out.println("_id:" + response.getId());
2) 修改文档
System.out.println("_result:" + response.getResult());
- 修改文档:
// 修改文档 - 请求对象
UpdateRequest request = new UpdateRequest();
// 配置修改参数
request.index("user").id("1001");
// 设置请求体,对数据进行修改
request.doc(XContentType.JSON, "sex", "女");
// 客户端发送请求,获取响应对象
UpdateResponse response = client.update(request, RequestOptions.DEFAULT);
System.out.println("_index:" + response.getIndex());
System.out.println("_id:" + response.getId());
System.out.println("_result:" + response.getResult());
- 查询文档:
//1.创建请求对象
GetRequest request = new GetRequest().index("user").id("1001");
//2.客户端发送请求,获取响应对象
GetResponse response = client.get(request, RequestOptions.DEFAULT);
3.打印结果信息
System.out.println("_index:" + response.getIndex());
System.out.println("_type:" + response.getType());
System.out.println("_id:" + response.getId());
System.out.println("source:" + response.getSourceAsString());
- 删除文档:
//创建请求对象
DeleteRequest request = new DeleteRequest().index("user").id("1");
//客户端发送请求,获取响应对象
DeleteResponse response = client.delete(request, RequestOptions.DEFAULT);
//打印信息
System.out.println(response.toString());
- 批量操作:
--------批量新增:--------
//创建批量新增请求对象
BulkRequest request = new BulkRequest();
request.add(new
IndexRequest().index("user").id("1001").source(XContentType.JSON, "name",
"zhangsan"));
request.add(new
IndexRequest().index("user").id("1002").source(XContentType.JSON, "name",
"lisi"));
request.add(new
IndexRequest().index("user").id("1003").source(XContentType.JSON, "name",
"wangwu"));
//客户端发送请求,获取响应对象
BulkResponse responses = client.bulk(request, RequestOptions.DEFAULT);
//打印结果信息
System.out.println("took:" + responses.getTook());
System.out.println("items:" + responses.getItems());
--------批量删除:--------
//创建批量删除请求对象
BulkRequest request = new BulkRequest();
request.add(new DeleteRequest().index("user").id("1001"));
request.add(new DeleteRequest().index("user").id("1002"));
request.add(new DeleteRequest().index("user").id("1003"));
//客户端发送请求,获取响应对象
BulkResponse responses = client.bulk(request, RequestOptions.DEFAULT);
//打印结果信息
System.out.println("took:" + responses.getTook());
System.out.println("items:" + responses.getItems());
高级查询:
- 请求体查询:
--------查询所有索引数据:--------
// 创建搜索请求对象
SearchRequest request = new SearchRequest();
request.indices("student");
// 构建查询的请求体
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
// 查询所有数据
sourceBuilder.query(QueryBuilders.matchAllQuery());
request.source(sourceBuilder);
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
// 查询匹配
SearchHits hits = response.getHits();
System.out.println("took:" + response.getTook());
System.out.println("timeout:" + response.isTimedOut());
System.out.println("total:" + hits.getTotalHits());
System.out.println("MaxScore:" + hits.getMaxScore());
System.out.println("hits========>>");
for (SearchHit hit : hits)
//输出每条查询的结果信息
System.out.println(hit.getSourceAsString());
System.out.println("<<========");
--------term 查询,查询条件为关键字:--------
// 创建搜索请求对象
SearchRequest request = new SearchRequest();
request.indices("student");
// 构建查询的请求体
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
sourceBuilder.query(QueryBuilders.termQuery("age", "30"));
request.source(sourceBuilder);
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
// 查询匹配
SearchHits hits = response.getHits();
System.out.println("took:" + response.getTook());
System.out.println("timeout:" + response.isTimedOut());
System.out.println("total:" + hits.getTotalHits());
System.out.println("MaxScore:" + hits.getMaxScore());
System.out.println("hits========>>");
for (SearchHit hit : hits)
//输出每条查询的结果信息
System.out.println(hit.getSourceAsString());
System.out.println("<<========");
--------分页查询:--------
// 创建搜索请求对象
SearchRequest request = new SearchRequest();
request.indices("student");
// 构建查询的请求体
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
sourceBuilder.query(QueryBuilders.matchAllQuery());
// 分页查询
// 当前页其实索引(第一条数据的顺序号),from
sourceBuilder.from(0);
// 每页显示多少条 size
sourceBuilder.size(2);
request.source(sourceBuilder);
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
// 查询匹配
SearchHits hits = response.getHits();
System.out.println("took:" + response.getTook());
System.out.println("timeout:" + response.isTimedOut());
System.out.println("total:" + hits.getTotalHits());
System.out.println("MaxScore:" + hits.getMaxScore());
System.out.println("hits========>>");
for (SearchHit hit : hits)
//输出每条查询的结果信息
System.out.println(hit.getSourceAsString());
System.out.println("<<========");
--------数据排序:--------
// 构建查询的请求体
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
sourceBuilder.query(QueryBuilders.matchAllQuery());
// 排序
sourceBuilder.sort("age", SortOrder.ASC);
request.source(sourceBuilder);
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
// 查询匹配
SearchHits hits = response.getHits();
System.out.println("took:" + response.getTook());
System.out.println("timeout:" + response.isTimedOut());
System.out.println("total:" + hits.getTotalHits());
System.out.println("MaxScore:" + hits.getMaxScore());
System.out.println("hits========>>");
for (SearchHit hit : hits)
//输出每条查询的结果信息
System.out.println(hit.getSourceAsString());
System.out.println("<<========");
--------过滤字段:--------
// 创建搜索请求对象
SearchRequest request = new SearchRequest();
request.indices("student");
// 构建查询的请求体
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
sourceBuilder.query(QueryBuilders.matchAllQuery());
//查询字段过滤
String[] excludes = ;
String[] includes = "name", "age";
sourceBuilder.fetchSource(includes, excludes);
request.source(sourceBuilder);
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
// 查询匹配
SearchHits hits = response.getHits();
System.out.println("took:" + response.getTook());
System.out.println("timeout:" + response.isTimedOut());
System.out.println("total:" + hits.getTotalHits());
System.out.println("MaxScore:" + hits.getMaxScore());
System.out.println("hits========>>");
for (SearchHit hit : hits)
//输出每条查询的结果信息
System.out.println(hit.getSourceAsString());
System.out.println("<<========以上是关于ElasticSearch的主要内容,如果未能解决你的问题,请参考以下文章