Elasticsearch 基础
Elaticsearch
ES简介:
Elaticsearch,简称为 ES,ES 是一个开源的高扩展的分布式全文搜索引擎,是整个 Elastic Stack 技术栈的核心。它可以近乎实时的存储、检索数据;本身扩展性很好,可以扩展到上百台服务器,处理 PB 级别的数据。
安装:
Elasticsearch 安装
Elasticsearch 的官方地址:https://www.elastic.co/cn/
Elasticsearch 最新的版本是 8.3.1(截止 2022.7.4),我们选择 8.1.1 版本(最新版本半年前的版本)
下载地址:https://www.elastic.co/cn/downloads/past-releases#elasticsearch
Windows 版的 Elasticsearch 压缩包,解压即安装完毕,解压后的 Elasticsearch 的目录结构如下 :
解压后,进入 bin 文件目录,点击 elasticsearch.bat 文件启动 ES 服务 。
注意: 9300 端口为 Elasticsearch 集群间组件的通信端口, 9200 端口为浏览器访问的 http协议 RESTful 端口。
打开浏览器,输入地址: https://localhost:9200,测试返回结果,返回结果如下:
因为,es 8.x 版本以后都是默认打开了 SSL 服务的。但是 证书 不行,所以不能访问。(为什么证书不行? 不知道)
解决:将 这里面的 true 全都改成 false ,然后,
打开浏览器,输入地址: http://localhost:9200(不要用 https),测试返回结果,返回结果如下:
{
"name" : "DESKTOP-FUBSCCM",
"cluster_name" : "elasticsearch",
"cluster_uuid" : "8S1QJAkJSj2Gw8WoDtlWLg",
"version" : {
"number" : "8.1.0",
"build_flavor" : "default",
"build_type" : "zip",
"build_hash" : "3700f7679f7d95e36da0b43762189bab189bc53a",
"build_date" : "2022-03-03T14:20:00.690422633Z",
"build_snapshot" : false,
"lucene_version" : "9.0.0",
"minimum_wire_compatibility_version" : "7.17.0",
"minimum_index_compatibility_version" : "7.0.0"
},
"tagline" : "You Know, for Search"
}
ES 数据格式
Elasticsearch 是面向文档型数据库,一条数据在这里就是一个文档。为了方便大家理解,
我们将 Elasticsearch 里存储文档数据和关系型数据库 MySQL 存储数据的概念进行一个类比
ES 里的 Index 可以看做一个表,Documents 则相当于表的行数据。
这里 Types 的概念已经被逐渐弱化,Elasticsearch 6.X 中,一个 index 下已经只能包含一个type,Elasticsearch 7.X 中, Type 的概念已经被删除了。
ES 的 重点:倒排索引
下面是倒排索引,将原本 根据 id 查找内容, 倒转为 根据内容查找 id。 内容作为索引。
索引操作
创建索引
对比关系型数据库,创建索引 就等同于 创建表 .
在 Postman 中,向 ES 服务器发 PUT 请求 : http://localhost:9200/shopping
如果 索引 已经存在,则会报错:
查询索引信息
使用 GET 请求,查看 单个 索引 : get : http://localhost:9200/shopping
查看 所有 索引 , 访问 _cat/indices?v : http://localhost:9200/_cat/indices?v
表的每个字段的 含义:
删除 索引
使用 delete 请求: http://localhost:92000/shopping
再用 get 请求 查看 索引, 发现 已经不存在了。
映射关系
有了索引库,等于有了数据库中的 表。
接下来就需要建索引库(index)中的映射了,类似于数据库(database)中的表结构(table)。
创建数据库表需要设置字段名称,类型,长度,约束等;索引库也一样,需要知道这个类型
下有哪些字段,每个字段有哪些约束信息,这就叫做 映射(mapping)。
创建映射
先创建一个 索引 :向 ES 服务器发 PUT 请求: http://127.0.0.1:9200/user
在 Postman 中,向 ES 服务器发 PUT 请求: http://127.0.0.1:9200/user/_mapping
_mapping 请求地址、“properties” 标签
{
"properties":{ // 表示 属性,即表中的各个字段
"name":{
"type":"text", //字段类型,"text" 文本字符串,可分词
"index":"true" // 是否使用 索引,默认为 true
},
"sex":{
"type":"keyword",//字段类型,"keyword" 关键字字符串,不可分词
"index":"true"
},
"tel":{
"type":"keyword",
"index":"false"
}
}
}
映射数据说明:
字段名:任意填写,下面指定许多属性,例如:title、subtitle、images、price
type:类型,Elasticsearch 中支持的数据类型非常丰富,说几个关键的
String 类型,又分两种:
text:可分词,match 的时候会被拆分 来匹配
keyword:不可分词,数据会作为完整字段进行匹配
Numerical:数值类型,分两类
基本数据类型:long、integer、short、byte、double、float、half_float
浮点数的高精度类型:scaled_float
Date:日期类型
Array:数组类型
Object:对象
index:是否索引,默认为 true,也就是说你不进行任何配置,所有字段都会被索引。
true:字段会被索引,则可以用来进行搜索
false:字段不会被索引,不能用来搜索
store:是否将数据进行独立存储,默认为 false
原始的文本会存储在 _source 里面,默认情况下其他提取出来的字段都不是独立存储的,是从 _source 里面提取出来的。
当然你也可以独立的存储某个字段,只要设置"store": true 即可,获取独立存储的字段要比从_source 中解析快得多,
但是也会占用更多的空间,所以要根据实际业务需求来设置。
analyzer:分词器,这里的 ik_max_word 即使用 ik 分词器,后面会有专门的章节学习
查看映射
在 Postman 中,向 ES 服务器发 GET 请求 : http://127.0.0.1:9200/user/_mapping
文档操作
创建文档
索引已经创建好了,接下来我们来创建文档,并添加数据。这里的文档可以类比为关系型数
据库中的表数据,添加的数据格式为 JSON 格式
在 Postman 中,向 ES 服务器发 POST 请求,然后带上 _doc : http://127.0.0.1:9200/shopping/_doc
,带请求体。(不能用put, 会报错)
上面的数据创建后,由于没有指定数据唯一性标识(ID),默认情况下,ES 服务器会随机生成一个。
如果想要自定义唯一性标识,需要在创建时指定: http://127.0.0.1:9200/shopping/_doc/1001
查询 文档数据
查询 单个文档数据
使用 get 请求: http://127.0.0.1:9200/shopping/_doc/1001 (要使用 主键 进行 查询)
查询 全部的 文档数据
使用 get 请求, 然后带上 _search : http://127.0.0.1:9200/shopping/_search
修改 文档
全局修改
和新增文档一样,输入相同的 URL 地址请求,如果请求体变化,会将原有的数据内容覆盖
在 Postman 中,向 ES 服务器发 POST 请求 : http://127.0.0.1:9200/shopping/_doc/1001
再用 get 查询,看到已修改。
局部修改 (修改字段)
修改数据时,也可以只修改某一给条数据的局部信息。
在 Postman 中,向 ES 服务器发 POST 请求,然后 带上 _update :http://127.0.0.1:9200/shopping/_update/1
//请求体内容为:
{
//固定要加上 “doc”
"doc": {
//"要修改的字段":新值
"price":1999.0
}
}
get 查看,对应字段的数字 已经 修改了。
删除文档
删除整个文档数据(一行)
删除一个文档不会立即从磁盘上移除,它只是被标记成已删除(逻辑删除)。(但是 查询 是 查不到的)
在 Postman 中,向 ES 服务器发 delete 请求 : http://127.0.0.1:9200/shopping/_doc/1001
复杂查询
条件 查询
使用 get 请求, 带上 _search 。 将条件 写入到 请求体中:
{
// "query" 表示查询,
"query":{
// "match" 表示匹配条件,对于 字符串 就相当于 "like", 对于 数字, 就相当于 "等于"
"match":{
// 要 匹配的 字段
"price":4000.00
}
}
}
分页查询
请求体 中加上 from 字段 和 size 字段:
{
"query":{
"match":{
"comment":"good for us"
}
},
"from":0, //表示 第 n 个数据,本页数据从这个数据开始
"size":2 // 表示 查询 多少数据
// 所以获取的其实就是 从 from 开始 取 size 个数据,相当于是 mysql 中的 limit from:size.
// 要实现分页, 则 from 要计算:from = (页码-1)*size
}
也可以单独查询 页数。
排序 查询
如果你想通过排序查出价格最高的手机,在 Postman 中,向 ES 服务器发 GET请求 : http://127.0.0.1:9200/shopping/_search,附带JSON体如下:
{
// 可以 结合 条件查询
"query":{
//"match_al" 表示 无条件
"match_all":{}
},
//"sort" 表示 排序, 相当于 order by
"sort":{
"price":{
//"order" 表示 排序顺序 "desc"(降序)、"asc"(升序)
"order":"desc"
}
},
// 可以 分页
"from":0,
"size":2
}
{
// 可以 结合 条件查询
"query":{
//"match_al" 表示 无条件
"match_all":{}
},
//"sort" 表示 排序, 相当于 order by
"sort":[{ // 多字段 排序时 ,用 中括号 括起来。
"price":{
//"order" 表示 排序顺序 "desc"(降序)、"asc"(升序)
"order":"desc"
},{
"category":{
"order":"asc"
}
}]
},
// 可以 分页
"from":0,
"size":2
}
多条件查询:
使用 get 请求, 带上 _search : http://127.0.0.1:9200/shopping/_search
请求体内容: (bool、must、match)
must 、must_not 、should 内部可以 有多个 match,must 和 must_not 里面的 match 是 and 的关系。should 内部 match 间 是 or 的关系。
{
"query":{ //表示 查询
"bool":{ // 表示 条件, "where"
"must":[{ // 表示 要满足什么条件,是个 数组,每个元素就是一个条件。"must" 相当于 "and" , "should" 相当于 "or","must_not" 相当于 一定不匹配
"match":{ // 匹配条件,字符串 相当于 "like"
"category":"小米"
// "title":"小米手机" , 不支持多个字段,每个match只能一个字段
}
},{
"match":{ // 匹配条件,数字 相当于 "等于"
"price":3999.00
}
}],
// 可以 三个 进行组合 也行。
"must_not":[{ // 一定不能 匹配,相当于 排除 and xxx != xxx
"match":{
"price":6999.99
}
}],
"should":[{ // 或, 等于下面也可以 or xxx like xxx
"match":{
"title":"华为"
}
}]
}
}
}
匹配 查询
模糊匹配(全文检索)
由上可知, “match” 关键字 可以实现 模糊查询。具有 like 的功能。但在 es 里, 其作用远不止 like 那么简单。match 匹配类型查询,会把查询条件进行分词,然后进行查询,多个词条之间是 or 的关系。
es 里的索引 是 倒排索引, 会将所有字符 拆分成 一个个的 索引**(关键字)。 所以 字符串匹配** 的时候, 字符串会 先被拆分,然后 再按 字符 来索引。
所以 es 能很容易 实现 like 的功能。 而且, 更强大的是, 由于是 拆分成 字符了, 所以 即使匹配的 整个单词是不存在的, 但是单词中的 字符是 有些 数据有的, 也是可以被 检索 出来的。 如下:检索”小华“,但是可以检索出 ”小米“ 和 ”华为“。这就是 es 强大的检索能力。
{
"query":{ //表示 查询
"match":{ // 匹配条件,字符串 相当于 "like"
"category":"小华"
}
}
}
完全匹配查询
要想 完全匹配 字符串 来查询, 则不能使用 “match”, 而是要用 “match_phrase” 即 分词匹配。 将字符串当成 完整的 词 来匹配。
改成 “match_phrase” 就找不到 “小华” 了。
{
"query":{ //表示 查询
"match_phrase":{ // 匹配条件,字符串 相当于 "like"
"category":"小华"
}
}
}
多字段匹配查询
“match” 和 “match_phrase” 都是只能 匹配 一个字段, 要能在 多个字段 检索, 则需要 使用 “multi_match”。
同 “match” 一样, “multi_match” 也是 先分词 再 检索的。
{
"query": {// 表示查询
"multi_match": {//表示 多字段匹配
"query": "小华", // 要查询的 字符串
"fields": ["title","category"] // 要检索的 字段
}
},
"highlight":{
"fields":{ // 高亮 的字段, 和上面一样
"title":{},
"category":{}
}
}
}
高亮显示匹配字段
对查询结果 中的 字段 高亮 显示。应该只有在 网页的 文本上才能 做到吧。(只对字符串有效)
{
"query":{ //表示 查询
"match_phrase":{ // 匹配条件,字符串 相当于 "like"
"category":"小华"
}
},
// 高亮显示
"highlight":{
"fields":{ // 字段, 与上面的保持一致,只对字符串 字段有效,数字无效
"category":{},
}
}
}
结合 多条件 查询 + 高亮显示:get : http://127.0.0.1:9200/shopping/_search
{
"query":{ //表示 查询
"bool":{ // 表示 条件
"should":[{ // 表示 要满足什么条件,是个 数组,每个元素就是一个条件。"must" 相当于 "and" , "should" 相当于 "or"
"match":{ // 条件,
"title":"小米"
}
},{
"match":{
"category":"华为"
}
}]
}
},
// 高亮显示
"highlight":{
"fields":{ // 字段,和上面的 保持一致
"title":{},
"category":{}
}
}
}
结果: 按哪个字段 匹配 到的, 哪个 字段 就会 高亮。如果有 多个字段 都匹配上的, 则 这些字段 都会 高亮。
所以, 也可以拿来 看 是那条 条件 匹配上了, 就像是mysql 的 explain 查看 哪个 索引用上了一样。
多个字段 匹配 到了, 都高亮
可以自定义 怎么高亮(默认是 斜体( ))
{
"query":{ //表示 查询
"bool":{ // 表示 条件
"should":[{ // 表示 要满足什么条件,是个 数组,每个元素就是一个条件。相当于 where ... and ... and ...
"match":{ // 条件,相当于 等于
//"category":"小米"
"title":"小米" // 不支持多个字段,每个match只能一个字段
}
},{
"match":{
"category":"小米"
}
}]
}
},
// 高亮显示
"highlight":{
"pre_tags":"</font color='red'>", //自定义 标签前缀,这里是 改字体颜色为红色
"post_tags":"</font>", //自定义 标签后缀,这里是 改字体颜色为红色
"fields":{ // 字段
"title":{},
"category":{}
}
}
}
聚合查询
聚合允许使用者对 es 文档进行统计分析,类似与关系型数据库中的 group by,当然还有很多其他的聚合,例如取最大值max、平均值avg等等。 (不支持 字符串数据 的字段)
接下来按price字段进行分组:
在 Postman 中,向 ES 服务器发 GET 请求 : http://127.0.0.1:9200/shopping/_search
返回了 分组结果, 展示了 分组中的数据 大小。
{
"aggs":{ // 表示 聚合 查询
"price_group":{ // 名称, 随意起名,表示 返回的结果的名。类似于 计算字段
// 聚合函数: "terms" 分组(group by),"avg" 求平均, "max" 取最大值,"sum" 求和,
// "cardinality" 去重后的总数,
// "stats" 聚合,对某个字段一次性返回 count,max,min,avg 和 sum 五个指标
"terms":{
"field":"price" // 要进行 聚合操作的字段。不支持字符串数据的字段
}
}
},
"size":0 // 表示 展示多少条原始数据, 0-不展示。去掉 该行就会显示所有的 原始数据
}
在 terms 分组下再进行聚合:
stats 聚合,对某个字段一次性返回 count,max,min,avg 和 sum 五个指标