ElasticSearch
The Elastic Stack, 包括 Elasticsearch、Kibana、Beats 和 Logstash,这三个项目组合在一块的技术栈也称为 ELK Stack。能够安全可靠地获取任何来源、任何格式的数据,然后实时地对数据进行搜索、分析和可视化。
- Elasticsearch:用于存储搜索数据的项目
- Beats 和 Logstash:用于采集和传输数据的项目
- Kibana:用于展示数据的项目
Elaticsearch,简称为ES, ES是一个开源的高扩展的分布式全文搜索引擎,是整个Elastic Stack技术栈的核心。它可以近乎实时的存储、检索数据;本身扩展性很好,可以扩展到上百台服务器,处理PB级别的数据。
ElasticSearch入门
在学习ElasticSearch之前我们先要把系统环境搭建起来,这样更有利于我们上手实操,有助于我们对ElasticSearch的深入学习,下面我们进行安装。
- ElasticSearch官网:https://www.elastic.co/cn/
ES安装下载
- ES下载地址:https://www.elastic.co/cn/downloads/elasticsearch
- 可以再地址下载需要安装的版本:https://www.elastic.co/cn/downloads/past-releases#elasticsearch
- 到目前未知(2021.06.26)最新版本是7.13.2,我们就下载最新版本的安装包,这里我们在Windows10上学习,所以先下载Windows版本的安装包。
- Windows 版的 Elasticsearch 的安装
安装很简单,解压即安装完毕,解压后的 Elastic s earch 的目录结构如下
目录 | 含义 |
---|---|
bin | 可执行脚本目录 |
config | 配置目录 |
jdk | 内置JDK 目录 |
lib | 类库,放置一些第三方的Jar包 |
logs | 日志目录 |
modules | 模块目录 |
plugins | 插件目录 |
- 安装完毕后启动项目
解压后,进入bin
文件目录,点击elasticsearch.bat
文件启动ES
服务,双击后可看到如下界面
注意:9300 端口为
Elasticsearch
集群间组件的通信端口, 9200 端口为浏览器访问的 http协议 RESTful 端口。
- 看到上面的日志后,打开浏览器(推荐使用谷歌浏览器),输入地址:http://localhost:9200 ,测试结果,看到如下则证明启动成功
ES安装常见问题
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
Xmx1g
ES的基本操作
在来对ES进行基本操前,我们要对RESTful风格和JSON有一定了解。
RESTful风格
REST指的是一组架构约束条件和原则。满足这些约束条件和原则的应用程序或设计就是RESTful 。 Web应用程序最重要的 REST 原则是,客户端和服务器之间的交互在请求之间是无状态的。从客户端到服务器的每个请求都必须包含理解请求所必需的信息。如果服务器在请求之间的任何时间点重启,客户端不会得到通知。此外,无状态请求可以由任何可用服务器回答,这十分适合云计算之类的环境。客户端可以缓存数据以改进性能。在服务器端,应用程序状态和功能可以分为各种资源。资源是一个有趣的概念实体,它向客户端公开。资源的例子有:应用程序对象、数据库记录、算法等等。每个资源都使用 URI(Universal Resource Identifier) 得到一个唯一的地址。所有资源都共享统一的接口,以便在客户端和服务器之间传输状态。使用的是标准的 HTTP 方法,比如 GET 、 PUT 、 POST 和DELETE 。
在REST 样式的 Web 服务中,每个资源都有一个地址。资源本身都是方法调用的目标,方法列表对所有资源都是一样的。这些方法都是标准方法,包括 HTTP GET 、 POST 、PUT 、 DELETE ,还可能包括 HEAD 和 OPTIONS 。
简单的理解就是,如果想要访问互联网上的资源,就必须向资源所在的服务器发出请求,请求体中必须包含资源的网络路径, 以及对资源进行的操作增删改查 。
JSON
JSON 是 JavaScript Object Notation(JavaScript 对象表示法)
- JSON 指的是 JavaScript 对象表示法(JavaScript Object Notation)
- JSON 是轻量级的文本数据交换格式
- JSON 独立于语言:JSON 使用 Javascript语法来描述数据对象,但是 JSON 仍然独立于语言和平台。JSON 解析器和 JSON 库支持许多不同的编程语言。 目前非常多的动态(PHP,JSP,.NET)编程语言都支持JSON。
- JSON 具有自我描述性,更易理解
总结:JSON字符串是在网络中传递的字符串的格式
Postman
如果直接通过浏览器向 Elasticsearch 服务器发请求,需要在发送的请求中包含HTTP 标准的方法,而 HTTP 的大部分特性且仅支持 GET 和 POST 方法。
所以为了能方便地进行客户端的访问,可以使用 Postman 软件Postman 是一款强大的网页调试工具,提供功能强大的 Web API 和 HTTP 请求调试。
Postman官网: https://www.getpostman.com
Postman下载: https://www.getpostman.com/apps
ES数据格式
Elasticsearch是面向文档型数据库,一条数据在这里就是一个文档。 为了方便大家理解,我们将 Elasticsearch 里存储文档数据和关系型数据库 MySQL 存储数据的概念进行一个类比
ES里的 Index 可以看做一个库,而 Types 相当于表, Documents 则相当于表的行。这里Types 的概念已经被逐渐弱化, Elasticsearch 6.X 中,一个 index 下已经只能包含一个type Elasticsearch 7.X 中 , Type 的概念已经被删除了。
正排索引(正向索引)& 倒排索引(反向索引)
正排表示以文档的ID为关键字,表中记录文档中每个字的位置信息,查找时扫描表中每个文档中字的信息直到找出所有包含查询关键字的文档。
倒排表示以字或词为关键字进行索引,表中关键字所对应的记录表项记录了出现这个字或词的所有文档,一个表项就是一个字表段,它记录该文档的ID和字符在该文档中出现的位置情况。
索引操作
创建索引
对比关系型数据库,创建索引就等同于创建数据库在Postman 中,向ES
服务器发 PUT 请求 http://127.0.0.1:9200/home
请求后,服务器返回响应
{
"acknowledged"【相应结果】: true, # true操作成功
"shards_acknowledged"【分片结果】: true, # 分片操作成功
"index"【索引名称】: "home"
}
# 注意:创建索引库的分片数默认 1 片,在 7.0.0 之前的 Elasticsearch 版本中,默认5片
如果重复添加索引,会返回错误信息
查看索引
- 查看单个索引
Postman中,向ES服务器发 GET 请求 http://127.0.0.1:9200/home
查看索引向ES 服务器发送的请求路径和创建索引是一致的。但是 HTTP 方法不一致。这里可以体会一下 RESTful 的意义,
{
"shopping": {//索引名
"aliases": {},//别名
"mappings": {},//映射
"settings": {//设置
"index": {//设置 - 索引
"creation_date": "1617861426847",//设置 - 索引 - 创建时间
"number_of_shards": "1",//设置 - 索引 - 主分片数量
"number_of_replicas": "1",//设置 - 索引 - 主分片数量
"uuid": "J0WlEhh4R7aDrfIc3AkwWQ",//设置 - 索引 - 主分片数量
"version": {//设置 - 索引 - 主分片数量
"created": "7080099"
},
"provided_name": "shopping"//设置 - 索引 - 主分片数量
}
}
}
}
- 查看当前创建的全部index索引
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服务器发 DELETE 请求 : http://127.0.0.1:9200/home
再次查看所有索引,GET http://127.0.0.1:9200/_cat/indices?v,返回结果如下:
文档操作
创建文档
假设索引已经创建好了
http://127.0.0.1:9200/shopping
接下来我们来创建文档,并添加数据。这里的文档可以类比为关系型数据库中的表数据,添加的数据格式为 JSON 格式
在 Postman 中,向 ES 服务器发 POST 请求 : http://127.0.0.1:9200/shopping/_doc,请求体JSON内容为:
```json
{
"title":"HUAWEI Mate 40 Pro",
"category":"华为",
"images":"https://consumer.huawei.com/cn/phones/",
"price":5699.00
}
{
"_index": "shopping",//索引
"_type": "_doc",//类型-文档
"_id": "ANQqsHgBaKNfVnMbhZYU",//唯一标识,可以类比为 MySQL 中的主键,随机生成
"_version": 1,//版本
"result": "created",//结果,这里的 create 表示创建成功
"_shards": {//
"total": 2,//分片 - 总数
"successful": 1,//分片 - 总数
"failed": 0//分片 - 总数
},
"_seq_no": 0,
"_primary_term": 1
}
上面的数据创建后,由于没有指定数据唯一性标识(ID),默认情况下, ES 服务器会随机生成一个。
如果想要自定义唯一性标识,需要在创建时指定: http://127.0.0.1:9200/shopping/_doc/1,请求体JSON内容为:
{
"title":"HUAWEI Mate 40 Pro",
"category":"华为",
"images":"https://consumer.huawei.com/cn/phones/",
"price":5699.00
}
此处发送请求的方式必须为POST ,不能是 PUT 否则会发生错误。但是如果增加数据时明确数据主键,那么请求方式也可以为 PUT
主键查询&全查询
查看文档时,需要指明文档的唯一性标识,类似于 MySQL 中数据的主键查询
在 Postman 中,向 ES 服务器发 GET 请求 :
http://127.0.0.1:9200/shopping/_doc/1 。
返回结果:
{
"_index": "shopping",
"_type": "_doc",
"_id": "1",
"_version": 1,
"_seq_no": 1,
"_primary_term": 1,
"found": true,
"_source": {
"title": "HUAWEI Mate 40 Pro",
"category": "华为",
"images": "https://consumer.huawei.com/cn/phones/",
"price": 5699.00
}
}
查找不存在的内容,向 ES 服务器发 GET 请求 : http://127.0.0.1:9200/shopping/_doc/1
{
"_index": "shopping",
"_type": "_doc",
"_id": "2",
"found": false
}
查看索引下所有数据,向 ES 服务器发 GET 请求 : http://127.0.0.1:9200/shopping/_search
{
"took": 316,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 4,
"relation": "eq"
},
"max_score": 1.0,
"hits": [
{
"_index": "shopping",
"_type": "_doc",
"_id": "9zvVR3oBq6p-InCrPNWO",
"_score": 1.0,
"_source": {
"title": "HUAWEI Mate 40 Pro",
"category": "华为",
"images": "https://consumer.huawei.com/cn/phones/",
"price": 5699.00
}
},
{
"_index": "shopping",
"_type": "_doc",
"_id": "1",
"_score": 1.0,
"_source": {
"title": "HUAWEI Mate 40 Pro",
"category": "华为",
"images": "https://consumer.huawei.com/cn/phones/",
"price": 5699.00
}
},
{
"_index": "shopping",
"_type": "_doc",
"_id": "-DvaR3oBq6p-InCrJNX_",
"_score": 1.0,
"_source": {
"title": "HUAWEI Mate 40 Pro",
"category": "华为",
"images": "https://consumer.huawei.com/cn/phones/",
"price": 5699.00
}
},
{
"_index": "shopping",
"_type": "_doc",
"_id": "-TvaR3oBq6p-InCrSdUp",
"_score": 1.0,
"_source": {
"title": "HUAWEI Mate 40 Pro",
"category": "华为",
"images": "https://consumer.huawei.com/cn/phones/",
"price": 5699.00
}
}
]
}
}
全量修改&局部修改&删除
1、全量修改
和新增文档一样,输入相同的 URL 地址请求,如果请求体变化,会将原有的数据内容覆盖
在 Postman 中,向 ES 服务器发 POST 请求 : http://127.0.0.1:9200/shopping/_doc/1
{
"title":"HUAWEI Mate 40 Pro",
"category":"华为",
"images":"https://consumer.huawei.com/cn/phones/",
"price":5099.00
}
{
"_index": "shopping",
"_type": "_doc",
"_id": "1",
"_version": 2,
"result": "updated", #表示已修改
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"_seq_no": 4,
"_primary_term": 1
}
2、局部修改
修改数据时,也可以只修改某一给条数据的局部信息
在 Postman 中,向 ES 服务器发 POST 请求 : http://127.0.0.1:9200/shopping/_update/1
请求体JSON内容为:
{
"doc": {
"title":"HUAWEI P40",
"category":"华为手机"
}
}
请求返回:
{
"_index": "shopping",
"_type": "_doc",
"_id": "1",
"_version": 3,
"result": "updated",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"_seq_no": 5,
"_primary_term": 1
}
在 Postman 中,向 ES 服务器发 GET请求 : http://127.0.0.1:9200/shopping/_doc/1,查看修改内容:
{
"_index": "shopping",
"_type": "_doc",
"_id": "1",
"_version": 3,
"_seq_no": 5,
"_primary_term": 1,
"found": true,
"_source": {
"title": "HUAWEI P40",
"category": "华为手机",
"images": "https://consumer.huawei.com/cn/phones/",
"price": 5099.0
}
}
3、删除
删除一个文档不会立即从磁盘上移除,它只是被标记成已删除(逻辑删除)。
在 Postman 中,向 ES 服务器发 DELETE 请求 : http://127.0.0.1:9200/shopping/_doc/1
返回结果:
{
"_index": "shopping",
"_type": "_doc",
"_id": "1",
"_version": 8,
"result": "deleted", # 表示删除
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"_seq_no": 10,
"_primary_term": 1
}
在 Postman 中,向 ES 服务器发 GET请求 : http://127.0.0.1:9200/shopping/_doc/1,查看是否删除成功:
{
"_index": "shopping",
"_type": "_doc",
"_id": "1",
"found": false
}
条件查询&分页查询&查询排序
条件查询
1、URL带参数
查找category为华为的文档,在 Postman 中,向 ES 服务器发 GET请求 :
http://127.0.0.1:9200/shopping/_search?q=category:华为
,返回结果如下:
{
"took": 3,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 3,
"relation": "eq"
},
"max_score": 0.5753642,
"hits": [
{
"_index": "shopping",
"_type": "_doc",
"_id": "9zvVR3oBq6p-InCrPNWO",
"_score": 0.5753642,
"_source": {
"title": "HUAWEI Mate 40 Pro",
"category": "华为",
"images": "https://consumer.huawei.com/cn/phones/",
"price": 5699.00
}
},
{
"_index": "shopping",
"_type": "_doc",
"_id": "-DvaR3oBq6p-InCrJNX_",
"_score": 0.5753642,
"_source": {
"title": "HUAWEI Mate 40 Pro",
"category": "华为",
"images": "https://consumer.huawei.com/cn/phones/",
"price": 5699.00
}
},
{
"_index": "shopping",
"_type": "_doc",
"_id": "-TvaR3oBq6p-InCrSdUp",
"_score": 0.5753642,
"_source": {
"title": "HUAWEI Mate 40 Pro",
"category": "华为",
"images": "https://consumer.huawei.com/cn/phones/",
"price": 5699.00
}
}
]
}
}
上述为URL带参数形式查询,这种方式一是不安全,二是参数值出现中文会出现乱码情况。为了避免这些情况,我们可用使用带JSON请求体请求进行查询。
2、请求体带参查询
还是查找category为小米的文档,在 Postman 中,向 ES 服务器发 GET请求 : http://127.0.0.1:9200/shopping/_search,附带JSON体如下:
{
"query":{
"match":{
"category":"小米"
}
}
}
返回参数:
{
"took": 3,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 3,
"relation": "eq"
},
"max_score": 0.5753642,
"hits": [
{
"_index": "shopping",
"_type": "_doc",
"_id": "9zvVR3oBq6p-InCrPNWO",
"_score": 0.5753642,
"_source": {
"title": "HUAWEI Mate 40 Pro",
"category": "华为",
"images": "https://consumer.huawei.com/cn/phones/",
"price": 5699.00
}
},
{
"_index": "shopping",
"_type": "_doc",
"_id": "-DvaR3oBq6p-InCrJNX_",
"_score": 0.5753642,
"_source": {
"title": "HUAWEI Mate 40 Pro",
"category": "华为",
"images": "https://consumer.huawei.com/cn/phones/",
"price": 5699.00
}
},
{
"_index": "shopping",
"_type": "_doc",
"_id": "-TvaR3oBq6p-InCrSdUp",
"_score": 0.5753642,
"_source": {
"title": "HUAWEI Mate 40 Pro",
"category": "华为",
"images": "https://consumer.huawei.com/cn/phones/",
"price": 5699.00
}
}
]
}
}
3、带请求体方式查找所有与内容
查找所有文档内容,也可以这样,在 Postman 中,向 ES 服务器发 GET请求 : http://127.0.0.1:9200/shopping/_search,附带JSON体如下:
{
"query":{
"match_all":{}
}
}
返回结果:
{
"took": 2,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 4,
"relation": "eq"
},
"max_score": 1.0,
"hits": [
{
"_index": "shopping",
"_type": "_doc",
"_id": "9zvVR3oBq6p-InCrPNWO",
"_score": 1.0,
"_source": {
"title": "HUAWEI Mate 40 Pro",
"category": "华为",
"images": "https://consumer.huawei.com/cn/phones/",
"price": 5699.00
}
},
{
"_index": "shopping",
"_type": "_doc",
"_id": "-DvaR3oBq6p-InCrJNX_",
"_score": 1.0,
"_source": {
"title": "HUAWEI Mate 40 Pro",
"category": "华为",
"images": "https://consumer.huawei.com/cn/phones/",
"price": 5699.00
}
},
{
"_index": "shopping",
"_type": "_doc",
"_id": "-TvaR3oBq6p-InCrSdUp",
"_score": 1.0,
"_source": {
"title": "HUAWEI Mate 40 Pro",
"category": "华为",
"images": "https://consumer.huawei.com/cn/phones/",
"price": 5699.00
}
},
{
"_index": "shopping",
"_type": "_doc",
"_id": "2",
"_score": 1.0,
"_source": {
"title": "三星手机",
"category": "三星",
"images": "https://consumer.huawei.com/cn/phones/",
"price": 5699.00
}
}
]
}
}
4、查找指定字段
如果你想查询指定字段,在 Postman 中,向 ES 服务器发 GET请求 : http://127.0.0.1:9200/shopping/_search,附带JSON体如下:
{
"query":{
"match_all":{}
},
"_source":["title"]
}
返回结果:
{
"took": 6,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 4,
"relation": "eq"
},
"max_score": 1.0,
"hits": [
{
"_index": "shopping",
"_type": "_doc",
"_id": "9zvVR3oBq6p-InCrPNWO",
"_score": 1.0,
"_source": {
"title": "HUAWEI Mate 40 Pro"
}
},
{
"_index": "shopping",
"_type": "_doc",
"_id": "-DvaR3oBq6p-InCrJNX_",
"_score": 1.0,
"_source": {
"title": "HUAWEI Mate 40 Pro"
}
},
{
"_index": "shopping",
"_type": "_doc",
"_id": "-TvaR3oBq6p-InCrSdUp",
"_score": 1.0,
"_source": {
"title": "HUAWEI Mate 40 Pro"
}
},
{
"_index": "shopping",
"_type": "_doc",
"_id": "2",
"_score": 1.0,
"_source": {
"title": "三星手机"
}
}
]
}
}
分页查询
在 Postman 中,向 ES 服务器发 GET请求 : http://127.0.0.1:9200/shopping/_search,附带JSON体如下:
{
"query":{
"match_all":{}
},
"from":0,
"size":2
}
返回结果:
{
"took": 3,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 4,
"relation": "eq"
},
"max_score": 1.0,
"hits": [
{
"_index": "shopping",
"_type": "_doc",
"_id": "9zvVR3oBq6p-InCrPNWO",
"_score": 1.0,
"_source": {
"title": "HUAWEI Mate 40 Pro",
"category": "华为",
"images": "https://consumer.huawei.com/cn/phones/",
"price": 5699.00
}
},
{
"_index": "shopping",
"_type": "_doc",
"_id": "-DvaR3oBq6p-InCrJNX_",
"_score": 1.0,
"_source": {
"title": "HUAWEI Mate 40 Pro",
"category": "华为",
"images": "https://consumer.huawei.com/cn/phones/",
"price": 5699.00
}
}
]
}
}
查询排序
如果你想通过排序查出价格最高的手机,在 Postman 中,向 ES 服务器发 GET请求 : http://127.0.0.1:9200/shopping/_search,附带JSON体如下:
{
"query":{
"match_all":{}
},
"sort":{
"price":{
"order":"desc"
}
}
}
返回结果:
{
"took": 628,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 4,
"relation": "eq"
},
"max_score": null,
"hits": [
{
"_index": "shopping",
"_type": "_doc",
"_id": "9zvVR3oBq6p-InCrPNWO",
"_score": null,
"_source": {
"title": "HUAWEI Mate 40 Pro",
"category": "华为",
"images": "https://consumer.huawei.com/cn/phones/",
"price": 5699.00
},
"sort": [
5699.0
]
},
{
"_index": "shopping",
"_type": "_doc",
"_id": "-TvaR3oBq6p-InCrSdUp",
"_score": null,
"_source": {
"title": "HUAWEI Mate 40 Pro",
"category": "华为",
"images": "https://consumer.huawei.com/cn/phones/",
"price": 5699.00
},
"sort": [
5699.0
]
},
{
"_index": "shopping",
"_type": "_doc",
"_id": "-DvaR3oBq6p-InCrJNX_",
"_score": null,
"_source": {
"title": "HUAWEI Mate 40 Pro",
"category": "华为",
"images": "https://consumer.huawei.com/cn/phones/",
"price": 5091.00
},
"sort": [
5091.0
]
},
{
"_index": "shopping",
"_type": "_doc",
"_id": "2",
"_score": null,
"_source": {
"title": "三星手机",
"category": "三星",
"images": "https://consumer.huawei.com/cn/phones/",
"price": "3999.00"
},
"sort": [
3999.0
]
}
]
}
}
多条件查询&范围查询
多条件查询
1、假设想找出三星牌子,价格为3999.00元的。(must相当于数据库的 &&)
在 Postman 中,向 ES 服务器发 GET请求 : http://127.0.0.1:9200/shopping/_search,附带JSON体如下:
{
"query":{
"bool":{
"must":[{
"match":{
"category":"三星"
}
},{
"match":{
"price":3999.00
}
}]
}
}
}
返回结果:
{
"took": 15,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 1,
"relation": "eq"
},
"max_score": 2.3862944,
"hits": [
{
"_index": "shopping",
"_type": "_doc",
"_id": "2",
"_score": 2.3862944,
"_source": {
"title": "三星手机",
"category": "三星",
"images": "https://consumer.huawei.com/cn/phones/",
"price": "3999.00"
}
}
]
}
}
2、假设想找出三星和华为的牌子。(should相当于数据库的||)
{
"query":{
"bool":{
"should":[{
"match":{
"category":"三星"
}
},{
"match":{
"category":"华为"
}
}]
}
}
}
返回结果:
{
"took": 3,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 4,
"relation": "eq"
},
"max_score": 1.3862942,
"hits": [
{
"_index": "shopping",
"_type": "_doc",
"_id": "9zvVR3oBq6p-InCrPNWO",
"_score": 1.3862942,
"_source": {
"title": "HUAWEI Mate 40 Pro",
"category": "华为",
"images": "https://consumer.huawei.com/cn/phones/",
"price": 5699.00
}
},
{
"_index": "shopping",
"_type": "_doc",
"_id": "-DvaR3oBq6p-InCrJNX_",
"_score": 1.3862942,
"_source": {
"title": "HUAWEI Mate 40 Pro",
"category": "华为",
"images": "https://consumer.huawei.com/cn/phones/",
"price": 5091.00
}
},
{
"_index": "shopping",
"_type": "_doc",
"_id": "-TvaR3oBq6p-InCrSdUp",
"_score": 1.3862942,
"_source": {
"title": "HUAWEI Mate 40 Pro",
"category": "华为",
"images": "https://consumer.huawei.com/cn/phones/",
"price": 5699.00
}
},
{
"_index": "shopping",
"_type": "_doc",
"_id": "2",
"_score": 1.3862942,
"_source": {
"title": "三星手机",
"category": "三星",
"images": "https://consumer.huawei.com/cn/phones/",
"price": "3999.00"
}
}
]
}
}
范围查询
假设想找出小米和华为的牌子,价格大于2000元的手机。
在 Postman 中,向 ES 服务器发 GET请求 : http://127.0.0.1:9200/shopping/_search,附带JSON体如下:
{
"query":{
"bool":{
"should":[{
"match":{
"category":"三星"
}
},{
"match":{
"category":"华为"
}
}],
"filter":{
"range":{
"price":{
"gt":3999.00
}
}
}
}
}
}
返回结果:
{
"took": 4,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 3,
"relation": "eq"
},
"max_score": 1.3862942,
"hits": [
{
"_index": "shopping",
"_type": "_doc",
"_id": "9zvVR3oBq6p-InCrPNWO",
"_score": 1.3862942,
"_source": {
"title": "HUAWEI Mate 40 Pro",
"category": "华为",
"images": "https://consumer.huawei.com/cn/phones/",
"price": 5699.00
}
},
{
"_index": "shopping",
"_type": "_doc",
"_id": "-DvaR3oBq6p-InCrJNX_",
"_score": 1.3862942,
"_source": {
"title": "HUAWEI Mate 40 Pro",
"category": "华为",
"images": "https://consumer.huawei.com/cn/phones/",
"price": 5091.00
}
},
{
"_index": "shopping",
"_type": "_doc",
"_id": "-TvaR3oBq6p-InCrSdUp",
"_score": 1.3862942,
"_source": {
"title": "HUAWEI Mate 40 Pro",
"category": "华为",
"images": "https://consumer.huawei.com/cn/phones/",
"price": 5699.00
}
}
]
}
}
全文检索&完全匹配&高亮查询
全文检索(match)
这功能像搜索引擎那样,如品牌输入“小华”,返回结果带回品牌有“小米”和华为的。
在 Postman 中,向 ES 服务器发 GET请求 : http://127.0.0.1:9200/shopping/_search,附带JSON体如下:
{
"query":{
"match":{
"category" : "星华"
}
}
}
返回结果:
{
"took": 3,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 4,
"relation": "eq"
},
"max_score": 0.6931471,
"hits": [
{
"_index": "shopping",
"_type": "_doc",
"_id": "9zvVR3oBq6p-InCrPNWO",
"_score": 0.6931471,
"_source": {
"title": "HUAWEI Mate 40 Pro",
"category": "华为",
"images": "https://consumer.huawei.com/cn/phones/",
"price": 5699.00
}
},
{
"_index": "shopping",
"_type": "_doc",
"_id": "-DvaR3oBq6p-InCrJNX_",
"_score": 0.6931471,
"_source": {
"title": "HUAWEI Mate 40 Pro",
"category": "华为",
"images": "https://consumer.huawei.com/cn/phones/",
"price": 5091.00
}
},
{
"_index": "shopping",
"_type": "_doc",
"_id": "-TvaR3oBq6p-InCrSdUp",
"_score": 0.6931471,
"_source": {
"title": "HUAWEI Mate 40 Pro",
"category": "华为",
"images": "https://consumer.huawei.com/cn/phones/",
"price": 5699.00
}
},
{
"_index": "shopping",
"_type": "_doc",
"_id": "2",
"_score": 0.6931471,
"_source": {
"title": "三星手机",
"category": "三星",
"images": "https://consumer.huawei.com/cn/phones/",
"price": "3999.00"
}
}
]
}
}
完美匹配(match_phrase)
在 Postman 中,向 ES 服务器发 GET请求 : http://127.0.0.1:9200/shopping/_search,附带JSON体如下:
{
"query":{
"match_phrase":{
"category" : "为"
}
}
}
返回结果:
{
"took": 2,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 3,
"relation": "eq"
},
"max_score": 0.6931471,
"hits": [
{
"_index": "shopping",
"_type": "_doc",
"_id": "9zvVR3oBq6p-InCrPNWO",
"_score": 0.6931471,
"_source": {
"title": "HUAWEI Mate 40 Pro",
"category": "华为",
"images": "https://consumer.huawei.com/cn/phones/",
"price": 5699.00
}
},
{
"_index": "shopping",
"_type": "_doc",
"_id": "-DvaR3oBq6p-InCrJNX_",
"_score": 0.6931471,
"_source": {
"title": "HUAWEI Mate 40 Pro",
"category": "华为",
"images": "https://consumer.huawei.com/cn/phones/",
"price": 5091.00
}
},
{
"_index": "shopping",
"_type": "_doc",
"_id": "-TvaR3oBq6p-InCrSdUp",
"_score": 0.6931471,
"_source": {
"title": "HUAWEI Mate 40 Pro",
"category": "华为",
"images": "https://consumer.huawei.com/cn/phones/",
"price": 5699.00
}
}
]
}
}
高量查询
在 Postman 中,向 ES 服务器发 GET请求 : http://127.0.0.1:9200/shopping/_search,附带JSON体如下:
{
"query":{
"match_phrase":{
"category" : "为"
}
},
"highlight":{
"fields":{
"category":{}//<----高亮这字段
}
}
}
返回结果:
{
"took": 130,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 3,
"relation": "eq"
},
"max_score": 0.6931471,
"hits": [
{
"_index": "shopping",
"_type": "_doc",
"_id": "9zvVR3oBq6p-InCrPNWO",
"_score": 0.6931471,
"_source": {
"title": "HUAWEI Mate 40 Pro",
"category": "华为",
"images": "https://consumer.huawei.com/cn/phones/",
"price": 5699.00
},
"highlight": {
"category": [
"华<em>为</em>" //高亮一个为字
]
}
},
{
"_index": "shopping",
"_type": "_doc",
"_id": "-DvaR3oBq6p-InCrJNX_",
"_score": 0.6931471,
"_source": {
"title": "HUAWEI Mate 40 Pro",
"category": "华为",
"images": "https://consumer.huawei.com/cn/phones/",
"price": 5091.00
},
"highlight": {
"category": [
"华<em>为</em>"
]
}
},
{
"_index": "shopping",
"_type": "_doc",
"_id": "-TvaR3oBq6p-InCrSdUp",
"_score": 0.6931471,
"_source": {
"title": "HUAWEI Mate 40 Pro",
"category": "华为",
"images": "https://consumer.huawei.com/cn/phones/",
"price": 5699.00
},
"highlight": {
"category": [
"华<em>为</em>"
]
}
}
]
}
}
聚合查询
聚合允许使用者对 es 文档进行统计分析,类似与关系型数据库中的 group by,当然还有很多其他的聚合,例如取最大值max、平均值avg等等。
接下来按price字段进行分组:
在 Postman 中,向 ES 服务器发 GET请求 : http://127.0.0.1:9200/shopping/_search,附带JSON体如下:
{
"aggs":{//聚合操作
"price_group":{//名称,随意起名
"terms":{//分组
"field":"price"//分组字段
}
}
}
}
返回结果:
{
"took": 3,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 4,
"relation": "eq"
},
"max_score": 1.0,
"hits": [
{
"_index": "shopping",
"_type": "_doc",
"_id": "9zvVR3oBq6p-InCrPNWO",
"_score": 1.0,
"_source": {
"title": "HUAWEI Mate 40 Pro",
"category": "华为",
"images": "https://consumer.huawei.com/cn/phones/",
"price": 5699.00
}
},
{
"_index": "shopping",
"_type": "_doc",
"_id": "-DvaR3oBq6p-InCrJNX_",
"_score": 1.0,
"_source": {
"title": "HUAWEI Mate 40 Pro",
"category": "华为",
"images": "https://consumer.huawei.com/cn/phones/",
"price": 5091.00
}
},
{
"_index": "shopping",
"_type": "_doc",
"_id": "-TvaR3oBq6p-InCrSdUp",
"_score": 1.0,
"_source": {
"title": "HUAWEI Mate 40 Pro",
"category": "华为",
"images": "https://consumer.huawei.com/cn/phones/",
"price": 5699.00
}
},
{
"_index": "shopping",
"_type": "_doc",
"_id": "2",
"_score": 1.0,
"_source": {
"title": "三星手机",
"category": "三星",
"images": "https://consumer.huawei.com/cn/phones/",
"price": "3999.00"
}
}
]
},
"aggregations": {
"price_group": {
"doc_count_error_upper_bound": 0,
"sum_other_doc_count": 0,
"buckets": [
{
"key": 5699.0,
"doc_count": 2
},
{
"key": 3999.0,
"doc_count": 1
},
{
"key": 5091.0,
"doc_count": 1
}
]
}
}
}
上面返回结果会附带原始数据的。若不想要不附带原始数据的结果,在 Postman 中,向 ES 服务器发 GET请求 : http://127.0.0.1:9200/shopping/_search,附带JSON体如下:
{
"aggs":{
"price_group":{
"terms":{
"field":"price"
}
}
},
"size":0
}
返回结果:
{
"took": 14,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 4,
"relation": "eq"
},
"max_score": null,
"hits": []
},
"aggregations": {
"price_group": {
"doc_count_error_upper_bound": 0,
"sum_other_doc_count": 0,
"buckets": [
{
"key": 5699.0,
"doc_count": 2
},
{
"key": 3999.0,
"doc_count": 1
},
{
"key": 5091.0,
"doc_count": 1
}
]
}
}
}
若想对所有手机价格求平均值。
在 Postman 中,向 ES 服务器发 GET请求 : http://127.0.0.1:9200/shopping/_search,附带JSON体如下:
{
"aggs":{
"price_avg":{//名称,随意起名
"avg":{//求平均
"field":"price"
}
}
},
"size":0
}
返回结果:
{
"took": 6,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 4,
"relation": "eq"
},
"max_score": null,
"hits": []
},
"aggregations": {
"price_avg": {
"value": 5122.0
}
}
}
映射关系
有了索引库,等于有了数据库中的 database。
接下来就需要建索引库(index)中的映射了,类似于数据库(database)中的表结构(table)。
创建数据库表需要设置字段名称,类型,长度,约束等;索引库也一样,需要知道这个类型下有哪些字段,每个字段有哪些约束信息,这就叫做映射(mapping)。
先创建一个索引:
PUT http://127.0.0.1:9200/user
返回结果
{
"acknowledged": true,
"shards_acknowledged": true,
"index": "user"
}
创建映射
# PUT http://127.0.0.1:9200/user/_mapping
{
"properties": {
"name":{
"type": "text",
"index": true
},
"sex":{
"type": "keyword",
"index": true
},
"tel":{
"type": "keyword",
"index": false
}
}
}
返回结果:
{
"acknowledged": true
}
查询映射
GET http://127.0.0.1:9200/user/_mapping
返回结果:
{
"user": {
"mappings": {
"properties": {
"name": {
"type": "text"
},
"sex": {
"type": "keyword"
},
"tel": {
"type": "keyword",
"index": false
}
}
}
}
}
增加数据
//PUT http://127.0.0.1:9200/user/_create/101
{
"name":"小米",
"sex":"男的",
"tel":"1111"
}
返回结果:
{
"_index": "user",
"_type": "_doc",
"_id": "101",
"_version": 1,
"result": "created",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"_seq_no": 0,
"_primary_term": 1
}
查找name含有 “小” 的数据
//GET http://127.0.0.1:9200/user/_search
{
"query":{
"match":{
"name":"小"
}
}
}
返回结果:
{
"took": 763,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 1,
"relation": "eq"
},
"max_score": 1.0,
"hits": [
{
"_index": "user",
"_type": "_doc",
"_id": "101",
"_score": 1.0,
"_source": {
"name": "小米",
"sex": "男的",
"tel": "1111"
}
}
]
}
}
查找sex中含有 “男” 的数据
//GET http://127.0.0.1:9200/user/_search
{
"query":{
"match":{
"sex":"男"
}
}
}
返回结果:
{
"took": 1,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 0,
"relation": "eq"
},
"max_score": null,
"hits": []
}
}
找不到想要的结果,只因创建映射时 “sex” 的类型为”keyword”。”sex”只能完全为”男的“,才能得出原数据。
//GET http://127.0.0.1:9200/user/_search
{
"query":{
"match":{
"sex":"男的"
}
}
}
返回结果:
{
"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": "user",
"_type": "_doc",
"_id": "101",
"_score": 0.2876821,
"_source": {
"name": "小米",
"sex": "男的",
"tel": "1111"
}
}
]
}
}
查询电话
//GET http://127.0.0.1:9200/user/_search
{
"query":{
"match":{
"tel":"11"
}
}
}
返回结果:
{
"error": {
"root_cause": [
{
"type": "query_shard_exception",
"reason": "failed to create query: Cannot search on field [tel] since it is not indexed.",
"index_uuid": "IwgFL46ZSJ2NJHz_AmBfZA",
"index": "user"
}
],
"type": "search_phase_execution_exception",
"reason": "all shards failed",
"phase": "query",
"grouped": true,
"failed_shards": [
{
"shard": 0,
"index": "user",
"node": "9JfkMzZUTJG-AtTy6E0cVg",
"reason": {
"type": "query_shard_exception",
"reason": "failed to create query: Cannot search on field [tel] since it is not indexed.",
"index_uuid": "IwgFL46ZSJ2NJHz_AmBfZA",
"index": "user",
"caused_by": {
"type": "illegal_argument_exception",
"reason": "Cannot search on field [tel] since it is not indexed."
}
}
}
]
},
"status": 400
}
报错只因创建映射时”tel”的”index”为false。
ElasticSearch在Java中操作
Elasticsearch软件是由 Java 语言开发的,所以也可以通过 Java API 的方式对 Elasticsearch服务进行访问。
Java API对ES进行操作步骤
我们在IDEA 开发工具中创建 Maven 项目(模块也可)ES
<dependencies>
<!--单元测试-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<!--elasticsearch-->
<dependency>
<groupId>org.elasticsearch</groupId>
<artifactId>elasticsearch</artifactId>
<version>7.13.2</version>
</dependency>
<!-- elasticsearch 的客户端 -->
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-high-level-client</artifactId>
<version>7.8.0</version>
</dependency>
<!-- elasticsearch 依赖 2.x 的 log4j -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.8.2</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.8.2</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.9</version>
</dependency>
</dependencies>
创建HelloElasticsearch测试类,进行测试 Java API链接ES,如果打印出客户端对象(client)就说明连接成功
package org.example;
import org.apache.http.HttpHost;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import java.io.IOException;
public class HelloElasticsearch {
public static void main(String[] args) throws IOException {
// 创建客户端对象
RestHighLevelClient client = new RestHighLevelClient(RestClient.builder(new HttpHost("localhost", 9200, "http")));
System.out.println(client);
// 关闭客户端连接
client.close();
}
}
Java API - 索引
创建索引
public static void main(String[] args) throws IOException {
// 创建客户端对象
RestHighLevelClient client = new RestHighLevelClient(RestClient.builder(new HttpHost("localhost", 9200, "http")));
// 创建索引 - 请求对象
CreateIndexRequest request = new CreateIndexRequest("user1");
// 发送请求,获取响应
CreateIndexResponse response = client.indices().create(request, RequestOptions.DEFAULT);
boolean acknowledged = response.isAcknowledged();
//打印相应状态
System.out.println(acknowledged); //打印结果 true 为创建成功
}
后台打印结果为:
七月 07, 2021 6:35:11 下午 org.elasticsearch.client.RestClient logResponse
警告: request [PUT http://localhost:9200/user1?master_timeout=30s&include_type_name=true&timeout=30s] returned 2 warnings: [299 Elasticsearch-7.13.2-4d960a0733be83dd2543ca018aa4ddc42e956800 "Elasticsearch built-in security features are not enabled. Without authentication, your cluster could be accessible to anyone. See https://www.elastic.co/guide/en/elasticsearch/reference/7.13/security-minimal-setup.html to enable security."],[299 Elasticsearch-7.13.2-4d960a0733be83dd2543ca018aa4ddc42e956800 "[types removal] Using include_type_name in create index requests is deprecated. The parameter will be removed in the next major version."]
true
查询索引
package org.example.index;
import org.apache.http.HttpHost;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.GetIndexRequest;
import org.elasticsearch.client.indices.GetIndexResponse;
import java.io.IOException;
/**
* @author ChenJia
*/
public class EsQueryIndex {
public static void main(String[] args) throws IOException {
// 创建客户端对象
RestHighLevelClient client = new RestHighLevelClient(RestClient.builder(new HttpHost("localhost", 9200, "http")));
// 查询索引 - 请求对象
GetIndexRequest request = new GetIndexRequest("user1");
// 发送请求,获取响应
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());
client.close();
}
}
输出
七月 07, 2021 7:27:54 下午 org.elasticsearch.client.RestClient logResponse
警告: request [GET http://localhost:9200/user1?master_timeout=30s&ignore_throttled=false&ignore_unavailable=false&expand_wildcards=open%2Cclosed&allow_no_indices=false] returned 1 warnings: [299 Elasticsearch-7.13.2-4d960a0733be83dd2543ca018aa4ddc42e956800 "Elasticsearch built-in security features are not enabled. Without authentication, your cluster could be accessible to anyone. See https://www.elastic.co/guide/en/elasticsearch/reference/7.13/security-minimal-setup.html to enable security."]
aliases:{user1=[]}
mappings:{user1=org.elasticsearch.cluster.metadata.MappingMetadata@ac3fede2}
settings:{user1={"index.creation_date":"1625655285721","index.number_of_replicas":"1","index.number_of_shards":"1","index.provided_name":"user1","index.routing.allocation.include._tier_preference":"data_content","index.uuid":"Q1xmI1lYRL2DeHzsxAgI0Q","index.version.created":"7130299"}}
删除索引
package org.example.index;
import org.apache.http.HttpHost;
import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
import org.elasticsearch.action.admin.indices.create.CreateIndexResponse;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.support.master.AcknowledgedResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import java.io.IOException;
/**
* @author ChenJia
*/
public class EsDeleteIndex {
public static void main(String[] args) throws IOException {
// 创建客户端对象
RestHighLevelClient client = new RestHighLevelClient(RestClient.builder(new HttpHost("localhost", 9200, "http")));
// 创建索引 - 请求对象
DeleteIndexRequest request = new DeleteIndexRequest("user1");
// 发送请求,获取响应
AcknowledgedResponse response = client.indices().delete(request,RequestOptions.DEFAULT);
// 操作结果
System.out.println("操作结果 : " + response.isAcknowledged());
}
}
输出
操作结果 : true
Java API - 文档
创建文档
控制台打印结果:
_index:user
_id:1001
_result:CREATED
查询文档
_index:user
_id:1001
_result:UPDATED
删除文档
_index:user
_type:_doc
_id:1001
source:{"name":"laochen","age":"19","sex":"男"}