ES基本概念
端口
9300:ElasticSearch集群间组件通信端口
9200:浏览器访问的http协议RESTful接口。http://localhost:9200
Windows单机启动之前可能需要修改的部分地方
-
config/elasticsearch.yml
xpack.security.enabled: false
:改为false,禁用安全访问。 -
bin/elasticsearch-env.bat
配置
ES_JAVA_HOME=%JAVA_HOME%
:使得使用系统的JDK,而不是使用ES自带的。对于8.10.0版本来说,JDK8跑不了,使用JDK17可以跑。
ES数据格式与MySQL的对照
ES | MySQL |
---|---|
Index(索引) | Database |
Type(类型,7.x版本后该概念被删除) | Table |
Documents(文档) | Row |
Fields(字段) | Column |
ES基本操作
索引操作
创建索引(PUT请求):http://localhost:9200/shopping
查看索引(GET请求):
删除索引(DELETE请求):http://localhost:9200/shopping
文档操作
添加文档(POST/PUT请求):http://localhost:9200/shopping/_doc/1001。这里的1001表示让ES使用指定的ID,而不是让它自己生成。
{
"title": "小米手机",
"category": "小米",
"price": 3999.00
}
查询文档(GET请求):
修改文档(POST请求):
-
全量修改:跟添加文档一样即可
-
局部修改:http://localhost:9200/shopping/_update/1001
{ "doc": { "title": "mix2" } }
删除文档(DELETE请求):http://localhost:9200/shopping/_doc/1001
查询操作
ES默认是全文检索匹配,因此match的方式会被切词去匹配文档。
-
条件查询:http://localhost:9200/shopping/_search
{ "query": { "match": { "category": "小米" } } }
-
分页查询:http://localhost:9200/shopping/_search
{ "query": { "match_all": { } }, "from": 0, "size": 2 }
match_all:全查询。from+size实现分页
-
筛选字段+排序:http://localhost:9200/shopping/_search
{ "query": { "match_all": { } }, "from": 0, "size": 2, "_source": ["title"], "sort": { "price": { "order": "asc" } } }
_source:筛选字段
-
多条件查询
{ "query": { "bool": { "must": [ { "match": { "category": "小米" } }, { "match": { "price": 3999.00 } } ], "filter": { "range": { "price": { "gt": 5000 } } } } } }
must:相当于多个条件and
should:相当于多个条件or
-
完全匹配查询(不允许切词匹配)
{ "query": { "match_phrase": { "category": "小米" } } }
-
聚合查询
// 分组 { "aggs": { // 聚合操作 "price_group": { // 起个组名 "terms": { "field": "price" // 分组字段 } } }, "size": 0 // 可以不展现文档结果,只展现聚合结果 } // 平均值 { "aggs": { // 聚合操作 "price_avg": { // 起个名 "avg": { "field": "price" // 分组字段 } } } } // topN { "aggs": { "top3": { "top_hits": { "size": 3 } } }, "size": 0 }
-
建立映射关系:http://localhost:9200/user/_mapping
{ "properties": { "name": { "type": "text", // 全文索引,会分词 "index": true, // 建立索引 }, "sex": { "type": "keyword", // 不分词 "index": true }, "tel": { "type": "keyword", "index": false // 不建立索引,即无法通过该字段检索 } } }
ES进阶
补充概念
分片(Shards)
将索引划分为多份,放到不同的节点上,每一份索引称之为分片。
优点:
- 允许水平分割,从而提高索引容量。
- 在分片上进行分布式、并行的操作,提高性能/吞吐量。
副本(Replicas)
分片的一份或多份拷贝。
优点:
- 提高可用性。
- 提高吞吐量,因为可以在所有副本上并行进行。
分配(Allocation)
将分片分配给某个节点的过程,包括分配主分片或副本。如果是副本,还包含从主分片复制数据的过程,这个过程由主master节点完成。
集群
水平扩容
主分片的数目在创建时就确定下来了(具体指的是几份索引),无法修改;但副本分片的数量可以修改,默认是1(其实指的是副本的个数,当主分片数为3,当副本数从1变为2,则增加了3个分片)。
故障应对
某个节点宕机后,如果还有其他节点在,则主分片仍然存在,健康度为黄色(有未分配的分片)。
路由计算和分片控制
路由计算:hash(id) % 主分片数量
。
分片控制:查询时,要让查询打到有对应数据分片的节点上。默认是轮询。
数据写流程
- 客户端请求集群中的任意节点
- 如果当前节点不能处理(即路由计算结果不由当前节点处理),则将请求转发到指定节点
- 主分片保存数据
- 主分片将数据发送到副本节点
- 副本保存数据,返回ack
- 主分片(一致性默认是quorum,可以为one或者all)返回ack给客户端
数据读流程
- 客户端请求集群中的任意节点
- 该节点计算数据所在的分片以及全部的副本信息,选择节点进行查询
- 转发请求到指定节点
- 节点返回结果给客户端
分片原理
倒排索引
- 分词器:keyword(关键词,不再分词)、text(文本,可以分词)、ik_max_word(最细粒度分词)、ik_smart(最粗粒度分词)。默认的IK分词器只能分出单个汉字,需要利用IK插件以使用前述的两种分词器。
- 词条:索引中最小存储和查询单元
- 词典:词条的集合(实现结构,B+树 或 Hash)
- 倒排表:每个关键词出现的位置、频率等,每一项被称为倒排项。
文档搜索
早期的全文检索为整个文档建立很大的倒排索引并写入磁盘。一旦要更新,则等新的索引就绪后,替换旧的索引。倒排索引写入磁盘后不可修改,优点是:1)不需要锁;2)索引被读入内存后,大部分请求直接命中内存;3)写入倒排索引允许启用数据压缩。缺点是更新索引需要重建整个倒排索引。
动态更新索引:增加新的补充索引来反映最新的修改,而不是直接重写整个倒排索引,每个倒排索引都会被轮流查询到,从最早的开始查询完后再对结果进行合并。
文档
-
通过在plugins目录下添加插件,可以增加分词器。
-
分词器可以配置扩展词典,以解决某些被视为整体的词被分词问题。
-
自定义分析器。通过设置字符过滤器、分词器、词汇单元过滤器来创建自定义分析器,按顺序执行。
创建自定义分析器(PUT):http://localhost:9200/my_index
{ "settings": { "analysis": { "char_filter": { "&_to_and": { "type": "mapping", "mappings": ["& => and"] } }, "filter": { "my_stopwords": { "type": "stop", "stopwords": ["the", "a"] } }, "analyzer": { "myanalyzer": { "type": "custom", "char_filter": ["html_strip", "&_to_and"], "tokenizer": "standard", "filter": ["lowercase", "my_stopwords"] } } } } }
测试该分析器(GET):http://localhost:9200/my_index/_analyze
{ "text": "The quick & brown fox", "analyzer": "myanalyzer" }
-
并发更新:使用版本号乐观更新(seq_no、primary_term)
ES优化
磁盘
- 使用SSD。
- 使用RAID0。因为ES有副本机制,所以使用RAID0没问题。
- 如果不用RAID0,还可以用多块磁盘,并允许ES通过多个
path.data
目录配置把数据条带化分配到它们上面。 - 不要使用远程挂载的存储。
分片策略
硬件优化,可以参考的一些原则:
- 控制每个分片占用的磁盘容量不超过ES的最大JVM堆空间设置(一般不超过32G,因为大部分用作服务器的物理机内存为32G,且内存中的数据需要刷到磁盘上,参考下文的JVM设置原则)。因此,如果索引的总量在500G左右,那分片大小在16个左右即可,最好同时考虑原则2。
- 考虑node数量,一般一个节点有时候就是一台物理机,如果分片数量太多,大大超过节点数,可能导致一个节点上存在多个分片,一旦该节点故障,即使保持了1个以上的副本,同样有可能导致数据丢失,集群无法恢复。一般设置分片数不大于节点数的3倍。
- 主分片、副本和节点最大数之间数量,可参考公式
节点数<=主分片数*(副本数+1)
。
推迟分片分配:对于节点瞬时中断的问题,默认情况集群会等待一分钟看节点是否重新加入,如果该节点在此期间重新加入,重新加入的节点会保持其现有的分片数据,不会触发新的分片重新分配,可以减少ES在自动再平衡可用分片时所带来的极大开销。可以修改参数delayed_timeout
,可以延长再均衡时间,可以全局设置也可以在索引级别修改(PUT):
/_all/_settings
{
"settings": {
"index.unassigned.node_left.delayed_timeout": "5m"
}
}
路由选择
shard = hash(routing) % number_of_primary_shards
,其中routing默认是文档的id,也可以采用自定义值如用户id。通过带routing查询,可以直接根据routing信息定位到某个分片查询,不需要查询所有的分片,经过协调节点排序。而不带routing查询,首先将请求达到协调节点上,由协调节点将请求分发到每个分片上,然后,协调节点收集每个分片的查询结果,将查询结果进行排序,返回给用户。
写入速度优化
针对搜索性能要求不高,但对写入要求比较高的场景,可以选择适当的写优化策略:
- 加大Translog Flush,目的是降低Iops、Writeblock。Flush的目的是把文件缓存系统中的段持久化到硬盘,当Translog的数据量达到512M或30分钟时,会触发一次Flush。增大该参数意味着需要为操作系统的文件缓存系统留下足够的空间。
- 增加Index Refresh间隔,目的是减少Segment Merge次数。默认1s写,如果对数据实时性要求不高,可以将Refresh周期延长,从而减少段刷新次数,但意味着需要消耗更多的堆内存。
- 调整Bulk线程池和队列(批量处理的大小)。ES提供Bulk API支持批量操作。
- 优化节点间的任务分布。
- 优化Lucene层的索引建立,目的是降低CPU和IO。
内存设置
ES堆内存分配需要满足以下两个原则:
- 不要超过物理内存的50%;Lucene的设计目的是把底层OS里的数据缓存到内存中。Lucene的段是分别存储到单个文件中的,这些文件不会变化,所以利于缓存,同时操作系统会把这些段文件缓存起来,以便更快地访问。如果堆内存设置过大,Lucene可用内存会减少,将严重影响降低Lucene的全文本查询性能。
- 单个节点的堆内存大小最好不要超过32G(对于64G的机器来说)。
重要配置
参数名 | 参数值 | 说明 |
---|---|---|
cluster.name | elasticsearch | 配置ES的集群名称,默认是ES |
node.name | node-1 | 集群中节点名称,同一集群中要唯一 |
node.master | true | 指定该节点是否有资格被选举为master,默认true |
node.data | true | 指定该节点是否存储索引数据,默认true,增删改查都是在数据节点完成的 |
index.number_of_shards | 1 | 主分片数量,默认1 |
index.number_of_replicas | 1 | 索引副本个数,默认1 |
transport.tcp.compress | true | 节点间传输数据时是否压缩,默认false |
discovery.zen.minimum_master_nodes | 1 | 设置在选举master时需要参与的最少候选节点数,默认为1。如果使用默认值,在网络不稳定时可能出现脑裂,合理的数值是 候选主节点数 / 2 + 1 |
discovery.zen.ping.timeout | 3s | 在集群中自动发现其他节点ping连接的超时时间,默认3s。如果网络环境较差,需要设置大一些,防止因误判节点存活状态而导致分片转移 |
面试题
为什么用ES
利于全文索引进行加快模糊查询速度。
master选举流程
- ES的master选举由ZenDiscovery模块负责,包含Ping(节点间通过该RPC发现彼此)和Unicast(单播模块包含一个主机列表以及控制哪些节点需要Ping通)这两部分。
- 对所有可以成为master的节点根据nodeId字典排序,每次选举每个节点都把自己知道的所有节点排一次序,选出第一个节点,暂时认为它是master节点。
- 如果对某个节点的投票数超过集群中节点数的一半,且该节点也选择了自己,则该节点成为master,否则重复上述过程。
master节点的职责主要包括集群、节点和索引的管理,不负责文档级别的管理。
脑裂问题
脑裂成因:
- 网络问题。
- 节点负载。master节点如果还是data节点,访问量较大时会导致ES停止响应造成大面积延迟,使得其他节点得不到响应而认为master挂了,重新进行选举。
- 内存回收。data节点上的ES进程占用内存较大,触发GC,使ES失去响应。
脑裂解决方案:
- 减少网络延迟的误判。
- minimum_master_nodes配置。
- 角色分离。master和data分离,即主节点配置为
node.master:true, node.data:false
,data节点配置为node.master:false, node.data:true
。
ES 8.x
基础功能
索引模板
-
创建模板
PUT _template/mytemplate { "index_patterns": [ // 模板的应用规则 "my*" ], "settings": { "index": { "number_of_shards": "1" } }, "mappings": { "properties": { "now": { "type": "date", "format": "yyyy/MM/dd" } } } }
-
查看模板
GET _template/mytemplate
-
使用模板
PUT my_test_template
-
删除模板
DELETE _template/mytemplate
文档评分机制
TF(Term Frequency,词频):搜索文本的各个词条(term)在查询文本中出现了多少次,出现次数越多,就越相关。
IDF(Inverse Document Frequency,逆文本频率):搜索文本中的各个词条(term)在整个索引的所有文档中出现了多少次,出现的次数越多,说明越不重要。
评分公式:boost * tf * idf
。
查看评分计算公式:GET shopping/_search?explain=true
。
查询提权:
{
"query": {
"bool": {
"should": [
{
"match": {
"title": {
"query": "Spark",
"boost": 2, // 提权
}
}
},
{
"match": {
"title": {
"query": "Hadoop",
"boost": 1,
}
}
}
]
}
}
}
EQL
EQL(Event Query Language,事件查询语言),是一种基于事件的时间序列数据(如日志、指标等)查询语言。
优点:
- 表达事件之间的关系。使可以匹配不同事件类别和时间跨度的一系列事件。
- EQL类似于其他查询语言如SQL。
- 可用于设计安全用例。
要运用EQL搜索,搜索到的数据流或索引必须包含时间戳和事件类别字段。默认情况下,EQL使用ES通用模式(ECS)中的@timestamp
(时间戳)和event.category
字段(事件分类)。
SQL
从ES6.3开始支持SQL查询,SQL会转换为Query DSL。SQL还可以和DSL混合使用。
1、SQL翻译为DSL
POST _sql/translate
{
"query": """
show tables
"""
}
2、查询所有索引
GET _sql?format=txt
{
"query": """
show tables
"""
}
3、查询指定索引
GET _sql?format=txt
{
"query": """
show tables like 'myindex'
"""
}
4、模糊查询索引
GET _sql?format=txt
{
"query": """
show tables like 'my%'
"""
}
5、查看索引结构
GET _sql?format=txt
{
"query": """
describe "myindex"
"""
}
6、类型转换
GET _sql?format=txt
{
"query": """
SELECT '123'::long as num
"""
}
标签:9200,基础,查询,索引,ElasticSearch,分片,节点,ES
From: https://www.cnblogs.com/sjmuvx/p/17793769.html