声明
内容来源尚硅谷知识星球谷粒随享项目,部分概念性的内容,就使用对应文档填写了,若有侵权联系作者删除。
检索模块
技术栈:ElasticSearch
ElasticSearch介绍
1.1 elasticsearch 简介
官网: https://www.elastic.co/
ElasticSearch是一个基于 Lucene 的搜索服务器。它提供了一个分布式多用户能力的全文搜索引擎,基于RESTful web接口。Elasticsearch是用Java开发的,并作为Apache许可条款下的开放源码发布,是当前流行的企业级搜索引擎。
Elastic官方宣布Elasticsearch进入Version 8,在速度、扩展、高相关性和简单性方面开启了一个全新的时代。
说明:Elasticsearch 8最低jdk版本要求jdk17,当前我们选择Elasticsearch版本:Elasticsearch8.5.3
DB-Engines Ranking - popularity ranking of database management systems
1.2 Elasticsearch的特性
实时
理论上数据从写入Elasticsearch到数据可以被搜索只需要1秒左右的时间,实现准实时的数据索引和查询。
分布式、可扩展
天生的分布式的设计,数据分片对于应用层透明,扩展性良好,可以轻易的进行节点扩容,支持上百甚至上千的服务器节点,支持PB级别的数据存储和搜索。
稳定可靠
Elasticsearch的分布式、数据冗余特性提供更加可靠的运行机制,且经过大型互联网公司众多项目使用,可靠性得到验证。
高可用
数据多副本、多节点存储,单节点的故障不影响集群的使用。
Rest API
Elasticsearch提供标准的Rest API,这使得所有支持Rest API的语言都能够轻易的使用Elasticsearch,具备多语言通用的支持特性,易于使用。Elasticsearch Version 8以后,去除了以前Transport API、High-Level API、Low-Level API,统一标准的Rest API,这将使得Elasticsearch更加容易使用,原来被诟病的API混乱问题终于得到完美解决。
高性能
Elasticsearch底层构建基于Lucene,具备强大的搜索能力,即便是PB级别的数据依然能够实现秒级的搜索。
多客户端支持
支持Java、Python、Go、PHP、Ruby等多语言客户端,还支持JDBC、ODBC等客户端。
安全支持
提供单点登录SSO、加密通信、集群角色、属性的访问控制,支持审计等功能,在安全层面上还支持集成第三方的安全组件,在Version 8以后,默认开启了HTTPS,大大简化了安全上的配置。
1.3 Elasticsearch应用场景
搭建日志系统
日志系统应该是Elasticsearch使用最广泛的场景之一了,Elasticsearch支持海量数据的存储和查询,特别适合日志搜索场景。广泛使用的ELK套件(Elasticsearch、Logstash、Kibana)是日志系统最经典的案例,使用Logstash和Beats组件进行日志收集,Elasticsearch存储和查询应用日志,Kibana提供日志的可视化搜索界面。
搭建数据分析系统
Elasitcsearch支持数据分析,例如强大的数据聚合功能,通过搭配Kibana,提供诸如直方图、统计分组、范围聚合等方便使用的功能,能够快速实现一些数据报表等功能。
在数字化转型的大行其道的当下,需要从海量数据中发现数据的规律,从而做出一定的决策,Elasticsearch一定是最适合的解决方案之一。
搭建搜索系统
Elasticsearch为搜索而生,用于搭建全文搜索系统是自然而然的事情,它能够提供快速的索引和搜索功能,还有相关的评分功能、分词插件等,支持丰富的搜索特性,可以用于搭建大型的搜索引擎,更加常用语实现站内搜索,例如银行App、购物App等站内商品、服务搜索。
构建海量数据业务系统即席查询服务
目前大量的需要支持事务的系统使用MySQL作为数据库,但随着业务的开展,数据量会越来越大,而MySQL的性能会越来越差,虽然可以通过分库分表的方案进行解决,但是操作比较复杂,而且往往每隔一段时间就需要进行扩展,且代码需要配合修改。
这种情况下可以将数据从MySQL同步到Elasticsearch,针对实时性要求不太高或者主要查询历史数据且数据量比较大的场景使用Elasticsearch提供查询,而对需要事务实时控制的即时数据还是通过MySQL存储和查询。
作为独立数据库系统
Elasticsearch本身提供了数据持久化存储的能力,并且提供了增删改查的功能,在某些应用场景下可以直接当做数据库系统来使用,既提供了存储能力,又能够同时具备搜索能力,整体技术架构会比较简单,例如博客系统、评论系统。需要注意的是,Elasticsearch不支持事务,且写入的性能相对关系型数据库稍弱,所有需要使用事务的场景都不能将Elasticsearch当做唯一的数据库系统,这使得这种使用场景很少见。
1.4 全文搜索引擎
Google,百度类的网站搜索,它们都是根据网页中的关键字生成索引,我们在搜索的时候输入关键字,它们会将该关键字即索引匹配到的所有网页返回;还有常见的项目中应用日志的搜索等等。对于这些非结构化的数据文本,关系型数据库搜索不是能很好的支持。
一般传统数据库,全文检索都实现的很鸡肋,因为一般也没人用数据库存文本字段。进行全文检索需要扫描整个表,如果数据量大的话即使对SQL的语法优化,也收效甚微。建立了索引,但是维护起来也很麻烦,对于 insert 和 update 操作都会重新构建索引。
这里说到的全文搜索引擎指的是目前广泛应用的主流搜索引擎。它的工作原理是计算机索引程序通过扫描文章中的每一个词,对每一个词建立一个索引,指明该词在文章中出现的次数和位置,当用户查询时,检索程序就根据事先建立的索引进行查找,并将查找的结果反馈给用户的检索方式。这个过程类似于通过字典中的检索字表查字的过程。
” 华为手机 “ 华为-手机
1.5 倒排索引
倒排索引步骤:
- 数据根据词条进行分词,同时记录文档索引位置
- 将词条相同的数据化进行合并
- 对词条进行排序
搜索过程:
先将搜索词语进行分词,分词后再倒排索引列表查询文档位置(docId)。根据docId查询文档数据。
ElasticSearch概念
es对照数据库
索引(Index)
一个索引就是一个拥有几分相似特征的文档的集合。比如说,你可以有一个客户数据的索引,另一个产品目录的索引,还有一个订单数据的索引。一个索引由一个名字来标识(必须全部是小写字母),并且当我们要对这个索引中的文档进行索引、搜索、更新和删除的时候,都要使用到这个名字。在一个集群中,可以定义任意多的索引。
能搜索的数据必须索引,这样的好处是可以提高查询速度,比如:新华字典前面的目录就是索引的意思,目录可以提高查询速度。
Elasticsearch索引的精髓:一切设计都是为了提高搜索的性能。
类型(Type)
在一个索引中,你可以定义一种或多种类型。
一个类型是你的索引的一个逻辑上的分类/分区,其语义完全由你来定。通常,会为具有一组共同字段的文档定义一个类型。不同的版本,类型发生了不同的变化
版本 | Type |
---|---|
5.x | 支持多种type |
6.x | 只能有一种type |
7.x | 默认不再支持自定义索引类型(默认类型为:_doc) |
8.x | 默认类型为:_doc |
文档(Document)
一个文档是一个可被索引的基础信息单元,也就是一条数据
比如:你可以拥有某一个客户的文档,某一个产品的一个文档,当然,也可以拥有某个订单的一个文档。文档以JSON(Javascript Object Notation)格式来表示,而JSON是一个到处存在的互联网数据交互格式。
在一个index/type里面,你可以存储任意多的文档。
字段(Field)
相当于是数据表的字段,对文档数据根据不同属性进行的分类标识。
映射(Mapping)
mapping是处理数据的方式和规则方面做一些限制,如:某个字段的数据类型、默认值、分析器、是否被索引等等。这些都是映射里面可以设置的,其它就是处理ES里面数据的一些使用规则设置也叫做映射,按着最优规则处理数据对性能提高很大,因此才需要建立映射,并且需要思考如何建立映射才能对性能更好。
ElasticSearch使用
分词器
添加分词器,分词器可以帮助我们构建高效的分词索引,提高检索性能。
中文分词器推荐使用Ik分词器,直接搜索对应elastic版本的分词器,安装进入Plugin目录即可
IK分词器效果:
POST _analyze
{"analyzer": "ik_smart","text": "我是中国人"
}
结果:
{"tokens": [{"token": "我","start_offset": 0,"end_offset": 1,"type": "CN_CHAR","position": 0},{"token": "是","start_offset": 1,"end_offset": 2,"type": "CN_CHAR","position": 1},{"token": "中国人","start_offset": 2,"end_offset": 5,"type": "CN_WORD","position": 2}]
}POST _analyze
{"analyzer": "ik_max_word","text": "我是中国人"
}
结果:
{"tokens": [{"token": "我","start_offset": 0,"end_offset": 1,"type": "CN_CHAR","position": 0},{"token": "是","start_offset": 1,"end_offset": 2,"type": "CN_CHAR","position": 1},{"token": "中国人","start_offset": 2,"end_offset": 5,"type": "CN_WORD","position": 2},{"token": "中国","start_offset": 2,"end_offset": 4,"type": "CN_WORD","position": 3},{"token": "国人","start_offset": 3,"end_offset": 5,"type": "CN_WORD","position": 4}]
}
可视化面板操作
- kbana
- 浏览器插件es-client
两者均可
索引操作
创建索引
put /text_index
结果
{"acknowledged": true,"shards_acknowledged": true,"index": "text_index"
}
删除索引
查看索引
查看所有索引
GET /_cat/indices?v
查询索引映射
GET / my_index / _mapping
数据操作
查询文档数据
GET / my_index / _doc / 1
增加文档数据
添加数据:PUT / my_index / _doc / 1{"title": "小米手机","category": "小米","images": "http://www.gulixueyuan.com/xm.jpg","price": 3999
}
查询文档全部数据
GET / my_index / _search
修改数据
PUT / my_index / _doc / 1{"title": "小米手机","category": "小米","images": "http://www.gulixueyuan.com/xm.jpg","price": 4500
}
删除文档数据:
DELETE / my_index / _doc / 1
动态映射:
DELETE / my_index
PUT / my_index{"mappings": {"properties": {"title": {"type": "text","index": true,"store": true,"analyzer": "ik_max_word","search_analyzer": "ik_smart"},"category": {"type": "keyword","index": true,"store": true}}}
}
字段匹配
单个字段匹配
GET /my_index/_search
{"query": {"match": {"title": "华为"}}
}
多个字段匹配
GET /my_index/_search
{"query": {"multi_match": {"query": "华为","fields": ["title","category"]}}
}
精确匹配
GET /my_index/_search
{"query": {"term": {"category": {"value": "华为"}}}
}
多字段精确匹配
GET /my_index/_search
{"query": {"terms": {"category": ["华为","vivo"]}}
}
范围查询
- gte: 大于等于
- lte: 小于等于
- gt: 大于
- lt: 小于
GET /my_index/_search
{"query": {"range": {"price": {"gte": 1000,"lte": 2000}}}
}
指定返回字段
GET /my_index/_search
{"query": {"range": {"price": {"gte": 1000,"lte": 2000}}},"_source": ["category"]
}
组合查询
bool 各条件之间有and,or或not的关系
- must: 各个条件都必须满足,所有条件是and的关系
- should: 各个条件有一个满足即可,即各条件是or的关系
- must_not: 不满足所有条件,即各条件是not的关系
- filter: 与must效果等同,但是它不计算得分,效率更高点。
must
GET /my_index/_search
{"query": {"bool": {"must": [{"match": {"category": "华为"}},{"range": {"price": {"gte": 5500}}}]}}
}
should
GET /my_index/_search
{"query": {"bool": {"should": [{"match": {"category": "华为"}},{"range": {"price": {"gte": 5500}}}]}}
}
must_not
不满足所有条件,即各条件是not的关系
POST /my_index/_search
{"query": {"bool": {"must_not": [{"match": {"title": "华为"}},{"range": {"price": {"gte": 3000,"lte": 5000}}}]}}
}
filter
与must效果等同,但是它不计算得分,效率更高点。
_score的分值为0 在Elasticsearch中,_score
字段代表每个文档的相关性分数(relevance score)。这个分数用于衡量一个文档与特定查询的匹配程度,它是基于搜索查询的条件和文档的内容来计算的。相关性分数越高,表示文档与查询的匹配度越高,排名也越靠前。
POST /my_index/_search
{"query": {"bool": {"filter": [{"match": {"title": "华为"}}]}}
}
聚合查询
聚合允许使用者对es文档进行统计分析,类似与关系型数据库中的group by,当然还有很多其他的聚合,例如取最大值、平均值等等。
POST /my_index/_search
{"query": {"match_all": {}{}},"size": 0, "aggs": {"max_price": {"max": {"field": "price"}}}
}
terms
桶聚合相当于sql中的group by语句
POST /my_index/_search
{"query": {"match_all": {}},"size": 0, "aggs": {"groupby_category": {"terms": {"field": "category","size": 10}}}
}
排序
POST /my_index/_search
{"query": {"bool": {"must": [{"match": {"title": "华为"}}]}},"sort": [{"price": {"order": "asc"}},{"_score": {"order": "desc"}}]
}
分页
POST /my_index/_search
{"query": {"match_all": {}},"from": 0,"size": 2
}
高亮显示
# 检索数据
GET /my_index/_search
{"query": {"match": {"title": "华为手机"}},"highlight": {"fields": {"title": {}},"pre_tags": ["<font color:#e4393c>"],"post_tags": ["</font>"]}
}