学习路径
入门阶段:
-
理解 Elasticsearch 的基本概念:
- 学习 Elasticsearch 的基本概念,包括文档、索引、分片、节点、集群等。
- 熟悉 Elasticsearch 的基本架构和工作原理。
-
安装和配置 Elasticsearch:
- 在本地或者虚拟环境中安装 Elasticsearch,并进行基本的配置。
- 了解如何启动和停止 Elasticsearch 服务。
-
使用 Elasticsearch 的基本功能:
- 学习如何索引文档、执行基本的搜索和查询操作。
- 尝试使用 REST API 或 Elasticsearch 的客户端库与 Elasticsearch 进行交互。
-
学习查询语法和 DSL:
- 熟悉 Elasticsearch 的查询语法和 DSL,包括全文搜索、字段匹配、范围查询等操作。
进阶阶段:
-
数据建模和索引设计:
- 学习如何设计合适的索引结构,包括映射设置、字段类型选择等。
- 理解索引设计对查询性能和存储效率的影响。
-
性能调优和优化:
- 学习如何优化 Elasticsearch 集群的性能,包括硬件选择、分片设置、缓存调优等方面。
- 掌握监控工具和技术,及时发现和解决性能问题。
-
高级查询和聚合操作:
- 深入学习 Elasticsearch 的高级查询功能,包括布尔查询、模糊查询、聚合分析等。
- 掌握复杂查询语句的编写和调试技巧。
深入阶段:
-
集群管理和扩展:
- 学习如何管理 Elasticsearch 集群,包括节点添加、副本管理、集群监控等。
- 掌握集群扩展和容错机制,以支持大规模数据存储和高并发查询。
-
安全和权限控制:
- 了解如何配置安全功能,包括用户认证、访问控制等。
- 学习如何保护敏感数据和防止安全漏洞。
-
实践项目和案例分析:
- 参与实际的项目开发或者开源项目,应用所学知识解决实际问题。
- 分析和学习一些开源项目的 Elasticsearch 使用案例,了解实际应用场景。
-
持续学习和更新:
- 关注 Elasticsearch 官方文档、博客和社区活动,了解最新的特性和最佳实践。
- 持续学习新的技术和工具,不断提升自己的 Elasticsearch 技能水平。
基本概念
基于Lucene二次开发的分布式搜索引擎,支持分布式,可水平扩展、提供Restful接口不局限与Java语言。
ELK生态
Lucene是Java语言的搜索引擎类库,易扩展、高性能(基于倒排索引)。擅长海量数据的搜索、分析、计算。但没有事务的概念,无法确保数据的安全和一致性。
Apache Lucene - 官网地址https://lucene.apache.org/
ES结构 (mysql对照)
Mapping
字段数据类型
类型 | 含义 | 常用参数 | 含义 |
---|---|---|---|
text | 支持全文检索的文本类型【常用】 | index | 是否创建索引,默认为true。是否添加倒排索引如果是false则在搜索时无法使用倒排索引 |
analyzer | 使用哪种分词器。只和text进行搭配使用 | ||
keyword | 不分词的数据类型 | ||
long integer short byte double float | 存储数值 | ||
date | 时间,会存储成1970年1月1日 00:00:00开始的毫秒值,查询时在格式换化为2015-01-01" 或"2015/01/01 12:10:30"时间 | format | 指定时间格式默认为 strict_date_optional_time||epoch_millis |
boolean | 布尔值 | ||
object | 存储对象结构 | properties | 用于指定对象内的字段数据类型 |
更多数据类型https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-types.html
分词器
es在创建倒排索引时需要对文档进行分词,在搜索时需要对用户输入的内容分词,中文分词器使用IK分词器。
扩展词库
因为最新的网络用词没有 或者 ”的“ 这种语气词没有意义、还有违禁词都需要处理
停用词库
测试分词效果
text 为需要分析的文本
analyzer 用于指定分词器
分词器类型:
english [默认携带]
chinese [默认携带,一般不用]
ik_smart [IK分词器,最少切分]
ik_max_word [IK分词器,最细切分,资源消费更多]
ps: IK分词器是插件需要提前安装到es中才能使用
POST /_analyze
{
"text": "测试分词器",
"analyzer": "standard"
}
自定义分词器
自定义分词器(analyzer)的组成包括三部分:
character filters: 在tokenizer 之前对文本进行处理。例如删除字符、替换字符等
tokenizer: 将文本按照一定规则切割成词条(term)。例如keyword,不分词;还有ik_smart
tokenizer filter: 将tokenizer输出的词条做进一步处理,例如大小写转换、同音词处理、拼音处理等
使用自定义分词器
拼音分词器
使用拼音分词器时需要注意:
1. 拼音分词器的分词效果不佳,默认根据单个汉字进行拼音转换后分词,这样的数据应用场景太低,所以使用拼音分词器建立倒排索引时需要先由ik分词器对内容进行分词之后在由拼音分词器进行分词转换。
2. 搜索时不适用拼音分词器。同音字会导致结果毫不相干。
自动补全
需要配合自定义分词器
倒排索引
将数据进行拆分成词条后,在基于词条建立索引。更擅长对内容进行搜索时。
文档: 每一条数据就是一个文档
词条: 每文档中的内容进行分词,得到的词就是词条
正向索引: 基于文档id创建索引,查找词条时必须先找到文档,然后判断是否包含词条
倒排索引: 对文档内容分词,对词条创建索引,并记录词条所在的文档信息,查询时现根据词条查找到文档id,然后获取文档
关系型数据库 与 Elasticsearch 相辅相成
分片(Shard)
- 分片是索引的基本组成单元,它是存储在集群中的一个单独的 Lucene 实例。
- 索引可以被分成多个分片,每个分片可以存储部分数据,从而实现数据的水平分布和扩展。
副本(Replica)
- 副本是每个分片的一份复制,用于提高数据的可用性和容错能力。
- 副本也可以用来增加查询的并发性能,允许请求在多个副本之间负载均衡。
节点(Node)
- 节点是 Elasticsearch 集群中的一个服务器,它存储数据、参与索引和搜索操作。
- 一个节点可以拥有一个或多个分片,并且可以加入到集群中以扩展集群的容量和性能。
集群(Cluster)
- 集群是由一个或多个节点组成的 Elasticsearch 环境,它们共同存储数据和提供搜索和分析功能。
- 所有节点共享一个集群名称,并且通过集群名称来进行通信和协调工作。
部署
DSL
Query DSL 官网地址https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl.html
ps: 以下DSL使用的时Kibana的 DevTools。curl方式请在路径前加 ip:port
大括号中的内容为需要替换的内容
查看es服务信息
GET /
#结果集
{
"name" : "node-1",
"cluster_name" : "my-es",
"cluster_uuid" : "2nO2C2EwRQyQcWLIqal_cQ",
"version" : {
"number" : "7.6.1",
"build_flavor" : "default",
"build_type" : "docker",
"build_hash" : "aa751e09be0a5072e8570670309b1f12348f023b",
"build_date" : "2020-02-29T00:15:25.529771Z",
"build_snapshot" : false,
"lucene_version" : "8.4.0",
"minimum_wire_compatibility_version" : "6.8.0",
"minimum_index_compatibility_version" : "6.0.0-beta1"
},
"tagline" : "You Know, for Search"
}
索引
创建索引库
索引名称要求小写
PUT /hj_test_index
{
"mappings": {
"properties": {
"familyName":{
"type": "text",
"analyzer": "ik_smart"
},
"familyTitle":{
"type": "keyword",
"index": false
},
"member":{
"properties": {
"memberNname":{
"type":"text"
},
"memberSex":{
"type":"keyword",
"index":false
},
"memberAge":{
"type":"integer"
}
}
}
}
}
}
#结果集
{
"acknowledged" : true,
"shards_acknowledged" : true,
"index" : "hj_test_index"
}
查询索引库
GET /hj_test_index
#结果集
{
"hj_test_index" : {
"aliases" : { },
"mappings" : {
"properties" : {
"familyName" : {
"type" : "text",
"analyzer" : "ik_smart"
},
"familyTitle" : {
"type" : "keyword",
"index" : false
},
"member" : {
"properties" : {
"memberAge" : {
"type" : "integer"
},
"memberNname" : {
"type" : "text"
},
"memberSex" : {
"type" : "keyword",
"index" : false
}
}
}
}
},
"settings" : {
"index" : {
"creation_date" : "1711965364861",
"number_of_shards" : "1",
"number_of_replicas" : "1",
"uuid" : "Vo29qu4aT5eWMXwKUDL1vQ",
"version" : {
"created" : "7060199"
},
"provided_name" : "hj_test_index"
}
}
}
}
查询索引库mapping信息
GET /hj_test_index/_mapping
{
"hj_test_index" : {
"mappings" : {
"properties" : {
"familyName" : {
"type" : "text",
"analyzer" : "ik_smart"
},
"familyTitle" : {
"type" : "keyword",
"index" : false
},
"member" : {
"properties" : {
"memberAge" : {
"type" : "integer"
},
"memberNname" : {
"type" : "text"
},
"memberSex" : {
"type" : "keyword",
"index" : false
}
}
}
}
}
}
}
删除索引库
DELETE /hj_test_index
#结果集
{
"acknowledged" : true
}
更新索引库
禁止修改索引库,因为会破坏原本的倒排索引,但是允许新增字段。
PUT /hj_test_index/_mapping
{
"properties":{
"fieldName":{
"type":"integer"
}
}
}
#结果集
{
"acknowledged" : true
}
文档
新增文档
删除文档
DELETE /index_name/_doc/文档id
修改文档
既能修改也能新增,如果文档id不存在则会新增
查询文档
SQL contrast DSL
SQL | DSL | |
精确匹配 | SELECT * FROM table WHERE field = 'value'; | GET /[index]/_search { "query": { "term": { "field": { "value": "value" } } } } |
模糊匹配查询 | SELECT * FROM table WHERE field LIKE '%value%'; | GET /[index]/_search { "query": { "wildcard": { "field": "*value*" } } } |
范围查询 | SELECT * FROM table WHERE field >= 10 AND field <= 20; | GET /[index]/_search { "query": { "range": { "field": { "gte": 10, "lte": 20 } } } } |
布尔查询(AND) | SELECT * FROM table WHERE field1 = 'value1' AND field2 = 'value2'; | GET /[index]/_search { "query": { "bool": { "must": [ { "term": { "field1": "value1" } }, { "term": { "field2": "value2" } } ] } } } |
布尔查询(OR) | SELECT * FROM table WHERE field1 = 'value1' OR field2 = 'value2'; | GET /[index]/_search { "query": { "bool": { "should": [ { "term": { "field1": "value1" } }, { "term": { "field2": "value2" } } ] } } } |
插入 | INSERT INTO table_name (column1, column2, ...) VALUES (value1, value2, ...); | POST /[index]/_doc { "column1": "value1", "column2": "value2", ... } |
删除 | DELETE FROM table_name WHERE condition; | DELETE /[index]/_doc/[document_id] |
更新 | UPDATE table_name SET column1 = value1, column2 = value2 WHERE condition; | POST /[index]/_update/[document_id] { "doc": { "column1": "value1", "column2": "value2" } } |
批量 | 批量插入、更新或删除在 SQL 中通常需要使用事务进行处理 | POST /_bulk { "index": { "_index": "index_name", "_id": "document_id" } } { "column1": "value1", "column2": "value2" } { "delete": { "_index": "index_name", "_id": "document_id" } } |
新增索引 | PUT /[index] | |
删除索引 | DELETE /[index] | |
刷新索引,最近的索引操作对搜索可见 | POST /[index]/_refresh | |
优化指定索引的存储结构,以减少磁盘空间的使用和提高查询性能 | POST /[index]/_optimize |
GET /index_name/_doc/文档id
match_all
查询所有数据,有分页限制
GET /{indexName}/_search
{
"query": {
"match_all": {}
}
}
curl -X GET "http://172.172.100.1:9200/{indexName}/_search" -H 'Content-Type: application/json' -d'
{
"query": {
"match_all": {}
}
}
'
#结果
{
"took" : 1,
"timed_out" : false,
"_shards" : {
"total" : 3,
"successful" : 3,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 10000,
"relation" : "gte"
},
"max_score" : 1.0,
"hits" : [
内容对象
]
}
}
全文检索 - match
利用分词器对用户输入的内容分词,然后根据倒排索引在库中匹配
GET /{indexName}/_search
{
"query": {
"match": {
"{FIELD}": "{TEXT}"
}
}
}
全文检索 - multi_match 支持搜索多个字段,因为参与搜索字段越多速度越慢
GET /{indexName}/_search
{
"query": {
"multi_match": {
"query": "{TEXT}",
"fields": ["{FIELD1}","{FIELD2}"]
}
}
}
精确查询
一般查找keyword、数值、日期、boolean。适合不分词的类型
range - 根据范围查询
gte 大于等于 ge 大于 lt 小于 lte 小于等于
GET /{indexName}/_search
{
"query": {
"range": {
"{FIELD}": {
"gte": {value},
"lte": {value}
}
}
}
}
term - 根据词条精确匹配
GET /{indexName}/_search
{
"query": {
"term": {
"{FIELD}": {
"value": "{VALUE}"
}
}
}
}
地理geo
根据经纬度查询
geo_distance
geo_bounding_box
复合查询compound
符合查询可以将上述各种查询条件组合起来,合并查询
function_score
bool
排序
分页
es因为倒排索引的缘故只能采用逻辑分页
高亮
将搜索结果中把搜索关键字突出显示。将搜索关键字前后增加html标签。例如<em>context</em>
默认情况下ES搜索字段必须和高亮字段一致。否则不会高亮
require_field_match : false 设置ES搜索字段可以不和高亮字段一致
基本匹配查询 | 使用 match 查询查找包含特定词语的文档 |
精确匹配查询 | 使用 term 查询查找与特定字段值完全匹配的文档 |
范围查询 | 使用 range 查询查找符合特定范围条件的文档 |
布尔查询 | 创建一个包含多个条件的布尔查询,使用 must , should , must_not 子句组合条件。 |
模糊查询 | 使用 fuzzy 查询查找与给定词语相似的文档 |
通配符查询 | 使用 wildcard 或 prefix 查询查找符合通配符模式或前缀的文档 |
组合查询 | 创建一个复杂的查询,包含多个查询条件,使用布尔查询组合它们 |
聚合查询 | 使用聚合查询分析数据,如计算字段的平均值、最大值、最小值等统计信息 |
嵌套查询 | 创建一个嵌套查询,用于在嵌套字段中搜索 |
分页和排序 | 使用 from , size 和 sort 控制分页和排序结果 |
Aggregations | Elasticsearch Guide [8.13] | Elastic
聚合
根据聚合的结果进行排序
Api Client
Elasticsearch Clients | Elastichttps://www.elastic.co/guide/en/elasticsearch/client/index.html
进阶
数据同步
单独项目,可以直接更新数据库时将es中的数据也进行更新。
方案一 同步调用
依次调用,业务耦合,影响性能
方案二 异步通知
依赖mq可靠性,引入了中间件复杂度上升,解除耦合。
业务中发送主键信息,避免微服务之间传输的数据过多
方案三 监听binlog
对mysql的压力增加,引入了canal中间件
集群
集群监控
cerebro 集群监控
节点角色
脑裂
当主节点遇到网络或其他问题导致无法提供服务,剩余副节点选主后,之前因为问题导致无法提供服务的主节点恢复了,导致就会出现两个主节点。
查询和更新的工作流程
explain 可以知道文档在哪个节点中
新增和根据id进行查询时
6. 返回结果到coordinating node
非id进行查询
故障转移
主挂选主, data节点挂则拷贝数据
ES优化
分片数量: 考虑数据量和查询负载、一般来说分片大小不超过50G、以免太大影响管理和备份。
分片大小: 避免过小或者过大的分片,太小会增加分片管理开销,分片太大会增加单个分片的搜索和写入压力
主分片和副本:设置合理的主分片和副本提供数据的可用性和容错能力,主分片通常和集群可用的节点数相同。副本则根据数据重要程度进行衡量
路由策略:确保索引的路由策略均匀分布在各个节点上,以充分利用集群资源。避免热点分片,即某些分片负载过重,可以通过重新分配分片或者自定义路由来解决。
映射设置: 使用映射类型和设置合适的字段数据类型,避免不必要的数据转换和分析开销
分析器[分词器]:选择合适的分析器和分析器设置以满足不同类型的搜索需求,例如中文等语言使用IK分词器以提高搜索的准确性
索引设置:索引的刷新间隔、索引存储、压缩方式等。根据数据更新频率和查询需求调整刷新间隔以平衡写入性能和索引性能
优化索引操作:避免频繁的索引创建、删除、更新操作,以减少集群负载和索引碎片化。定期执行索引优化、刷新、合并操作,以提高索引的性能和可用性
数据预热:对于常用的查询,将数据预加载到内存中,以提高查询性能和相应性能。使用preference参数指定查询优先选择的分片,以提高查询效率
日志管理:日志的级别和大小,减少磁盘空间的占用
硬件: CPU、内存、磁盘。SSD硬盘对ES性能提升非常明显
负载均衡:配置合理的网络带宽和负载均衡。合理的分担请求压力
JVM设置: 调整JVM堆内存大小,设置垃圾回收参数
备份和恢复:定期数据备份和灾备方案,防止数据丢失
监控告警:对集群实时监控,设置告警及时发现和解决问题,资源监控。
定期维护:执行索引优化、索引刷新、索引合并等维护操作。保证索引的健康状态