简介
分布式,高性能,高可用,支持 restful
风格 api
的搜索和数据分析引擎,它是经过考验的,很多大型项目都在用,很适合做全文搜索、日志分析、监控分析等。
docker 环境搭建
docker network create elastic
docker run --name es01 --net elastic -p 9200:9200 -p 9300:9300 -it docker.elastic.co/elasticsearch/elasticsearch:8.3.3
# kibana
docker run --name kib-01 --net elastic -p 5601:5601 -e ELASTICSEARCH_HOSTS=http://elasticsearch:9200 docker.elastic.co/kibana/kibana:8.3.3
docker es 启动报错:
| ERROR: [2] bootstrap checks failed. You must address the points described in the following [2] lin
vim /etc/security/limits.conf
末尾追加
* soft nofile 65536
* hard nofile 65536
vim /etc/sysctl.conf
末尾追加
vm.max_map_count=655360
然后执行
sysctl -p
参考:https://blog.youkuaiyun.com/ximaiyao1984/article/details/124732596
docker es 的数据存储
usr/share
可以直接映射出来
es
既然能够存储,为什么还要用关系型数据库进行数据存储(例:mysql)
简而言之:es
不支持事务,一般场景下都是 mysql
+ es
同时使用,mysql
保证原始数据的安全性,es
来做搜索。
mysql
做海量数据查询不合适
- 模糊查询的支持不是很好,使用
LIKE
搜索,不会走索引,全表扫描消耗性能。(例:想要搜索 “扫黑风暴”,手误输入成了 “扫风暴”,sql
语句LIKE %扫风暴%
,就搜索不出数据)。 - 索引建多了,可能会导致磁盘占用变大(本来
10G
大小的数据,建立了索引之后磁盘占用飙升到30G
)。
索引
mapping
- 支持新增字段
- 不支持直接删除/修改字段
- 不支持直接修改字段类型 如果非要做灵活设计,ES 有其他方案可以替换,借助reindex。但是数据量大会有性能问题,建议设计阶段综合权衡考虑。
- 不建议使用动态
mapping
(即直接添加文档,让es
自行创建mapping
)
PUT /my-index-000001
{
"mappings": {
"properties": {
"age": { "type": "integer" },
"email": { "type": "keyword" },
"name": { "type": "text" }
}
}
}
设置字段考虑
- 避免使用动态创建
dynamic
:- true: 默认值,允许动态添加新的字段
- false: 忽略新字段
- strict: 当有新字段时会报错
- enabled: 不需要索引的字段,设置 enabled: false
- keyword: 精确匹配,不用 text ,要用 keyword
如何构建 es
的索引
- 只把需要搜索的数据导入ES,避免索引过大
- 精确值的类型指定为keyword(mapping配置),并且使用term查询
- 避免无路由查询:无路由查询会并发在多个索引上查询、归并排序结果,会使得集群cpu飙升,影响稳定性
- 避免深度分页查询:如有大量数据查询,推荐用scroll滚动查询
- 设置合理的文件系统缓存(filesytem cache)大小,提高性能:因为ES查询的热数据在文件系统缓存中
- 自己预定义
es
索引的mapping
配置,不依赖es
自动生成的mapping
- 数据扁平化处理:如果数据库中有
json
字段列,需要从中提取业务字段,避免嵌套类型的字段,提高性能,宽表。 - ES分片数在创建后不能随意改动,但是副本数可以随时增加,来提高最大QPS。如果单个分片压力过大,需要扩容。
可以设置索引的生命周期
PUT _ilm/policy/log_save_policy
{
"policy": {
"phases": {
"delete": { // 定义删除阶段
"min_age": "365d", // 删除阶段在 365 天后开始
"actions": { // 定义删除动作
"delete": {}
}
}
}
}
}
更新数据
条件更新
POST http://47.105.66.210:9200/article_v1/doc/_update_by_query
{
"script": {
"source":"ctx._source['status']=0;"
},
"query": {
"term": {
"userId": 1
}
}
}
为什么要在中间层中做数据转储?
线上的 DB
数据量大的时候,直接去访问线上 DB
可能会对服务性能产生影响。
没有什么是加一个中间层不能解决的,如果有,那就再加一层。
Hive 用于做数据转储(mysql
-> es
)
相似度评分
TF-IDF
TF-IDF(term frequency–inverse document frequency),取决于:词在该文档中出现的频率(TF,term frequency),越高代表越相关;以及词在所有文档中出现的频率(IDF,inverse document frequency),越高代表越不相关,相当于是一个通用的词,对相关性影响较小。局部常见,全局罕见。
Okapi BM25
7.x 后为 es 的默认相似度算法
es 介绍相似度算法的文章
和 TF-IDF 类似,但是有相应的惩罚措施(长文档分值降低等)。
es 更改相似度评分函数
curl --request PUT \
--url https://localhost:9200/similarity-score \
--header 'content-type: application/json' \
--data '{
"settings": {
"index": {
"number_of_shards": 1,
"similarity": {
"default": {
"type": "BM25", // 这里也可以选择其他的相似度函数,例:LMDirichlet
"b": 0,
"k1": 10
}
}
}
},
"mappings": {
"properties": {
"text": {
"type": "text"
}
}
}
}'
不同的字段可以设置不同的相似度匹配函数
curl -X PUT "localhost:9200/my-index-000001?pretty" -H 'Content-Type: application/json' -d'
{
"mappings": {
"properties": {
"default_field": {
"type": "text"
},
"boolean_sim_field": {
"type": "text",
"similarity": "boolean"
}
}
}
}
'
es
支持的相似度函数
- boolean 不需要相似度匹配,只考虑全匹配时使用
- DFR相似度
- DFI相似度
- IB相似度
- LM Dirichlet相似度
- LM Jelinek Mercer相似度
- 脚本相似度(自定义)
官网介绍
字段长度归一值(norm)
字段长度的归一值对全文搜索非常重要,许多其他字段不需要有归一值。无论文档是否包括这个字段,索引中每个文档的每个 string 字段都大约占用 1 个 byte 的空间。
对于有些应用场景如日志,归一值不是很有用,要关心的只是字段是否包含特殊的错误码或者特定的浏览器唯一标识符。字段的长度对结果没有影响,禁用归一值可以节省大量内存空间。
官网介绍
bulk
批量做文档的操作,先看例子:
POST _bulk
{"create":{"_index":"es_index_one","_type":"_doc","_id":1}}
{"name":"张三one-1","age":13,"birthday":"2021-10-13","address":"中国上海长宁one-1"}
{"create":{"_index":"es_index_one","_type":"_doc","_id":2}}
{"name":"张三one-2","age":23,"birthday":"2021-10-23","address":"中国上海长宁one-2"}
{"create":{"_index":"es_index_one","_type":"_doc","_id":3}}
{"name":"张三one-3","age":33,"birthday":"2021-10-30","address":"中国上海长宁one-3"}
两行为一个行为,第一行为操作的类型和对象,第二行为操作的数据。
操作的动词主要有:
- index 创建或更新
- create 创建
- update 更新
- delete 删除
_bulk 一次最大处理多少数据量?
bulk会把将要处理的数据载入内存中,所以数据量是有限制的,最佳的数据量不是一个确定的数值,它取决于你的硬件,你的文档大小以及复杂性,你的索引以及搜索的负载。
一般建议是1000-5000个文档,如果你的文档很大,可以适当减少队列,大小建议是5-15MB,默认不能超过100M,可以在es的配置文件(即$ES_HOME下的config下的elasticsearch.yml)中。
搜索
match_pharse
短语搜索
match
全文搜索
multi_match
用于一个关键字匹配多个字段,并可以设置字段的算分比重。其实相当于一个语法的简写
GET kibana_sample_data_ecommerce/_search
{
"query": {
"multi_match": {
"query": "Eddie",
"fields": ["customer_full_name^3","customer_first_name"] # 这里通过^3来指定他的算分比重,这个数字越大,他占的比重就越大,其他字段占得比重就越小
}
},
"_source":["customer_full_name","currency","customer_first_name"]
}
partial matching
类似 sql
的 like
_source
指定查询哪些列
搜索优化建议
- 最初始的,索引的构建和文档质量
DSL
优化,需要大量的查询测试,然后做组和调整权重,尽量不要调整similarity
。- 初期最好不要用太多插件,例如拼音,近义词等
关联搜索
es 是不支持类似关系型数据库那样的搜索的,就是要做多次搜索 官方
参考
- 有 es 为什么还要用 mysql 存储数据
- MySQL不香吗,为啥还要Elasticsearch?
- MySQL用得好好的,为什么要转ES?
- 可否完全使用ElasticSearch代替数据库存储?
- ES 既是搜索引擎又是数据库?真的有那么全能吗?
- 架构师必备:多维度查询的最佳实践
- Elasticsearch中的相似度评分介绍
- 干货 | Elasticsearch 索引设计实战指南
- 感觉一般,介绍索引的创建
- 总是搜不到想要的内容?Elasticsearch搜索排名优化了解一下
其他
-
elastic 中文社区:https://elasticsearch.cn/
-
es
可自定义打分,排序,分词。 -
倒排索引,根据文档内容进行分词,小写化等,建立分词与包含该分词的文档之间的映射关系。
-
分布式架构设计,自动迁移分片至新节点,可以在多个节点上查询相应的结果再进行整合,避免了单节点的硬件压力大的问题,轻松支持
PB
级别的数据查询。 -
mysql
的binlog
(binary log),阿里的canal
模拟自己是mysql slave
,从而进行数据dump
。 -
otter
阿里的数据库增量日志解析器,一个分布式数据库同步系统。 -
同时做全量更新和增量更新的时候,有一种情况需要注意:当全量索引正在执行的时候,这时
mysql
中又加入了一条新的数据,触发了增量更新,增量更新结束了,全量更新还未完成,当全量更新完成时会覆盖增量更新的数据。处理方式:当在做全量更新时,可以让增量更新先暂停一下,等全量更新完成后再做。 -
当数据入
es
出错时,添加补救措施,将出错的数据进行记录,创建worker
任务去轮询修复。 -
有了
es
后也可以做db
查询,有业务需求的时候,自行斟酌 -
尽量避免深分页查询(from + size),例:
from 10000
,size 10
,每个分片也会查出10010
个结果,可能OOM
,就算不发生OOM
,也会影响到CPU
和带宽等,从而影响到整个集群的性能。 -
ELK
是三个开源项目的首字母缩写,这三个项目分别是:Elasticsearch
、Logstash
和Kibana
。Elasticsearch 是一个搜索和分析引擎。Logstash 是服务器端数据处理管道,能够同时从多个来源采集数据,转换数据,然后将数据发送到诸如 Elasticsearch 等“存储库”中。Kibana 则可以让用户在 Elasticsearch 中使用图形和图表对数据进行可视化。 ELKB elastic stack。 -
OpenSearch 由于一些开源协议,AWS 宣布推出 OpenSearch 项目,这是 fork 自 Elasticsearch 和 Kibana 的开源分支。
-
关系型数据库索引的左侧原则
-
ES
最厉害的查询是DSL
-
读写不一致时间在秒级:因为有2个耗时阶段,一是同步阶段将数据从MySQL数据库写入ES,二是ES索引refresh阶段,数据从buffer写入索引后才可查到。
-
初始全量导入,后续增量导入:
Canal+MQ
数据管道同步,不需要或仅需少量代码工作 -
不同的索引可以使用别名来同时查找?(待验证)