ElasticSearch学习文档

@author Gandalf

介绍

ES是什么

Elasticsearch实时的分布式全文搜索分析引擎,内部使用Lucene做索引与搜索,开发语言为Java

全文:对全部的文本内容进行分析,建立索引,使之可以被搜索

实时:新增到 ES 中的数据在1秒后就可以被检索到,这种新增数据对搜索的可见性称为“准实时/近实时搜索”。

分布式:可以动态调整集群规模,弹性扩容

Github:https://github.com/elastic/elasticsearch

可以做什么

  • 搜索:搭建搜索引擎(类似百度、谷歌、知乎等可搜索功能的实现)、日志收集分析系统
  • 聚合分析:进行数据分析、统计,生成指标数据。
  • 适用场景:适合用于中等规模数据的应用场景,据官方描述,集群规模支持“上百”个节点,ES适合中等数据量的业务,不适合海量数据存储

优缺点

  • 迭代快速,目前每2周左右就会发布新版本

  • 社区活跃且生态丰富

  • 语法与关系型数据库迥异,语法学习成本高

基本概念

ES是面向文档的。各种文本内容以文档(document)的形式存储到ES中,文档可以是一封邮件、一条日志,一条关系型数据库的记录,或者一个网页的内容。使用 JSON 作为文档的序列化格式,文档可以有很多字段,创建索引的时候,同关系型数据库创建表约束一样,可指定各字段的数据类型(也可不指定,动态生成文档),可指定不同字段不同的分词器,指定字段是否被搜索到。

索引结构

存储结构上,由_index_type_id标识一个文档

  • _index:为指向一个或多个分片的物理存储命名,存储某一类型文档的集合

  • _type:用于区分一个_index中的不同细分,多个_type的数据结构应是相似的,如建立一个订单类的索引,有不同_type类型的订单:物流订单、采购订单、出库订单...,索引中的多个type,实际上是存放在一起的,一个index下,不能有多个字段重名但type不一致

  • _id:文档唯一标识,可自行指定,ES自动生成的id,长度为20个字符,URL安全,base64编码,GUID,分布式环境也不会发生冲突

分片

分片(Shard): ES利用分片解决单机无法存储规模巨大的问题,将数据分为多个分片,分片就是一个lucene实例,会自动创建索引和处理请求,不同分片可存储在不同的机器上,通过路由策略找到分片所在的位置;分布式存储中还会把分片复制成多个副本,实现水平扩展能力以及高可用(HA),同时副本还可以执行读请求,分担集群压力,ES将数据副本分为主从两部分,即主分片primary hard和副分片replica shard,主数据作为权威数据,写过程中先写主分片,成功后再写副分片,当集群规模扩大或缩小时,ES 会自动在各节点中迁移分片,使数据仍然均匀分布在集群里

primary shard不能和自己replica shad在同一节点,单节点创建primary shard和replica shard在同一台机器上时,是不会分配给replica shard的。

Tip :分片一旦指定久可以修改,所以一开始就尽量规划好主分片数量,先依据硬件情况定好单个分片容量,然后依据业务场景预估数据量和增长量,再除以单个分片容量。

文档结构

_mapping:自动或者手动为ES中index的typet建立的一种数据结构和相关配置

_all:ES会自动将多个field的值用串联的方式链接起来,变成一个长的字符串,作为_all field的值,同时建立索引,在搜索的时候,没有指定field的值时候,就默认搜索_all

倒排索引

建立倒排索引的时候,会执行一个操作,对各个拆分的各个单词进行相应的处理(noralization)归一化,搜索的时候也要进行分词并归一化,提升搜索命中文档的概率 likes-->like Tom-->tom

如不提前指定索引及类型,es会自动建立index和type,不需要提前创建,会默认对每个field建立倒排索引,让其可以被搜索

各节点说明

  • master节点:管理ES的元数据,管理索引的创建和删除,结点增加和移除,默认会选出一台做master,不会处理所有的请求,通过配置 node.master: true(默认),使节点具有被选举为 Master 的资格,主结点也可做数据节点,生产环境尽量分离主节点与数据节点
  • 数据节点(Data node):保存数据、执行数据相关操作:CRUD、搜索、聚合等。数据节点对CPU、内存、I/O要求较高
  • 预处理节点(Ingest node):在索引文档之前,即写入数据之前,通过定义好的一系列的processors(处理器)和pipeline(管道),对数据进行某种转换。processors和pipeline拦截bulk和index请求
  • 协调节点(Coordinateing node):处理客户端请求的节点,并将请求转发给文档所在的位置,在收集各节点的处理请求后,合并数据并转换为客户端,每个节点都可以作为协调节点
集群状态示意图

ES读请求与写请求都是首先通过协调节点,由协调节点进行请求分发到对应的shard以及对应的node,各node处理完后回复协调节点再向客户端做响应

分词

IK 分词器简介:ik有两种分词模式,ik_max_word,和ik_smart模式;

ik_max_word: 会将文本做最细粒度的拆分,比如会将“中华人民共和国国歌”拆分为“中华人民共和国,中华人民,中华,华人,人民共和国,人民,人,民,共和国,共和,和,国国,国歌”,会穷尽各种可能的组合;
ik_smart: 会做最粗粒度的拆分,比如会将“中华人民共和国国歌”拆分为“中华人民共和国,国歌”。

进阶知识

集群健康状态

从数据完整性的角度划分,集群健康状态分为三种:

  • Green:所有的主分片和副分片都正常运行。

  • Yellow:所有的主分片都正常运行,但不是所有的副分片都正常运行。这意味着存在单点故障风险

  • Red:有主分片没能正常运行,不是所有的主分片都是active状态。

集群状态是全局信息,包括内容路由信息、配置信息,描述了“哪个分片位于哪个节点”这种信息,

集群状态发布流程:集群状态由主节点负责维护,主节点更新后广播到其它节点 ,该操作是一个不完全分布事务,分为两阶段,commit与apply阶段, master变更集群信息后,广播变更信息到各个子节点,多数节点确认后,集群状态发布成功

主节点主分片选举过程

当master节点挂掉后,会自动选举一个node成为新的maste,基于Bully算法,每个节点个ID,选出各节点认为ID值最小的作为主节点

新主节点将丢失掉的primary shard的某个replica shard提升为primary shard, 此时cluster status会变为yellow,因为primary全都变成active了,但少了一个replica shard

重启故障的node,主节点会将缺失的副本都cpy到该node上,而且该node会用之前已有的shard数据,只是同步一下挂掉后发生过的修改

之后cluster status状态就变为green,因为primary shard和replica shard都属于可用状态

ES节点内部通信与数据传输都是基于TCP,基于netty,包括REST接口也是基于netty进行封装路由

ES数据可被搜索流程

段合并

默认情况下索引的refresh_interval为1秒,

ES并发控制

通过乐观锁实现并发控制,通过版本号的方式控制,每次更新之前先拿到版本号与ES中的版本号对比,如果不一致,则过去当前版本号中的最新数据,再修改

悲观锁:每次获取数据都会加锁,悲观的认为别人会修改数据,其余线程想获取数据必须等到该锁被释放后才能获取到,悲观适用于多写,乐观适用于多读,乐观锁存在ABA问题

悲观锁可通过版本号与CAS实现,如Java中的原子类;

写数据流程

image-20210121112939821
  1. 客户端向NODE1发送写请求。
  2. NODE1使用文档ID来确定文档属于分片0,通过集群状态中的内容路由表信息获知分片0的主分片位于NODE3,因此请求被转发到NODE3上。
  3. NODE3上的主分片执行写操作。如果写入成功,则它将请求并行转发到 NODE1和NODE2的副分片上,等待返回结果。当所有的副分片都报告成功,NODE3将向协调节点报告成功,协调节点再向客户端报告成功
详细流程
image-20210121113357715

在客户端收到成功响应时,意味着写操作已经在主分片和所有副分片都执行完成

建立索引流程
image

读数据流程

查询分为两阶段:QUERY_THEN_FETCH查询与获取,Query阶段知道了要取哪些数据,但是并没有取具体的数据,Fetch阶段获取具体的数据

Query阶段
query阶段

QUERY_THEN_FETCH搜索类型的查询阶段步骤如下:
(1)客户端发送search请求到NODE 3。
(2)Node 3将查询请求转发到索引的每个主分片或副分片中。
(3)每个分片在本地执行查询,并使用本地的Term/DocumentFrequency信息进行打分,添加结果到大小为from + size的本地有序优先队列中。
(4)每个分片返回各自优先队列中所有文档的ID和排序值给协调节点,协调节点合并这些值到自己的优先队列中,产生一个全局排序后的列表。

Fetch阶段
image-20210121114352581

Fetch阶段由以下步骤构成:
(1)协调节点向相关NODE发送GET请求。
(2)分片所在节点向协调节点返回数据。
(3)协调节点等待所有文档被取得,然后返回给客户端。

分布式系统搜索执行流程
image

删数据流程

删除方式为标记删除,只会对文档进行标记为delete,不会真正物理删除,等es存储达到一定阈值时,才会自动删除标记为delete的文档,查询时会过滤掉被标记为删除的数据,或者lucene段合并时才会清除标记为删除的数据

修改数据流程

ES配置

节点配置

创建独立主节点的配置:

node.master: true
node.data: false

数据节点配置

node.master: false
node.data: true
node.ingest: false

预处理节点配置

node.master: false
node.data: false
node.ingest: true

协调节点配置

node.master: false
node.data: false
node.ingest: false

ES模板配置

{
    "template": "*",
    "order" : 0,
    "settings": 
    {
        "index.merge.policy.max_merged_segment" : "2gb",
        "index.merge.policy.segments_per_tier" : "24",
        "index.number_of_replicas" : "1",
        "index.number_of_shards" : "24",
        "index.optimize_auto_generated_id" : "true",
        "index.refresh_interval" : "120s",
        "index.translog.durability" : "async",
        "index.translog.flush_threshold_size" : "1000mb",
        "index.translog.sync_interval" : "120s",
        "index.unassigned.node_left.delayed_timeout" : "5d"
    }
}

配置修改

重要配置修改

https://www.elastic.co/guide/cn/elasticsearch/guide/current/important-configuration-changes.html

设置es堆内存

https://www.elastic.co/guide/cn/elasticsearch/guide/current/heap-sizing.html

时间类型存储:往 ES 写入时间类型的数据的时候,可以写入不同的时间格式的值,最终在 ES 中都会转化成 long 类型用于查询和排序。

ES使用

安装使用

下载 https://www.elastic.co/cn/downloads/elasticsearch

java环境:确保服务器的jvm和运行程序的jvm的版本是完全一致的

  1. 启动
/usr/java/jdk1.8.0_144/bin/java -Xms24g -Xmx24g -XX:+UseConcMarkSweepGC -XX:CMSInitiatingOccupancyFraction=75 -XX:+UseCMSInitiatingOccupancyOnly -XX:+AlwaysPreTouch -server -Xss1m -Djava.awt.headless=true -Dfile.encoding=UTF-8 -Djna.nosys=true -Djdk.io.permissionsUseCanonicalPath=true -Dio.netty.noUnsafe=true -Dio.netty.noKeySetOptimization=true -Dio.netty.recycler.maxCapacityPerThread=0 -Dlog4j.shutdownHookEnabled=false -Dlog4j2.disable.jmx=true -Dlog4j.skipJansi=true -XX:+Hepath.home=/usr/elasticsearch-5.5.2 -cp /usr/elasticsearch-5.5.2/lib/* org.elasticsearch.bootstrap.Elasticsearch -d
  1. 访问

启动成功后,ES提供REST接口,http端口为9200,Java默认访问端口为9300

集群运维管理

查询集群状态

-- 默认请求到主节点
curl -X GET "localhost:9200/_cluster/state  
-- 接收请求的节点执行,可用于验证当前节点的集群状态是否为最新
curl -X GET "localhost:9200/_cluster/state?local=true 

查询集群健康状态

curl -X GET localhost:9200/_cat/health?v
curl -X GET localhost:9200/_cluster/health?pretty

集群节点信息

curl http://127.0.0.1:9200/_cat/nodes?v
图片

查询索引列表

curl -X GET "localhost:9200/_cat/indices?v"

节点监控

-- 可以全面的查看集群各个节点的各种性能指标情况
curl -X GET "localhost:9200/_nodes/stats?pretty"

查询节点信息

curl -X GET "localhost:9200/_nodes?pretty"

集群磁盘分布情况

curl http://127.0.0.1:9200/_cat/allocation?v

修改索引允许动态映射

-- 修改后插入文档时索引遇到默认字段会自动修改mapping(表接口)
curl -XPUT "http://localhost:9200/index_name/type_name/_mapping" -H 'Content-Type: application/json' -d '{
    "dynamic": true
}'

修改索引为一个副本

curl -XPUT  "http://localhost:9200/index_name/_settings" -H 'Content-Type: application/json' -d '{"number_of_replicas":1}'

ES正在执行的任务

curl -X GET 'localhost:9200/_tasks?pretty'
-- 取消正在执行的任务
curl -X POST 'localhost:9200/_tasks/node_id:task_id/_cancel'
-- 过滤出正在执行的查询任务
curl -X GET 'localhost:9200/_tasks?actions=cluster:*&pretty'
curl -X GET 'localhost:9200/_tasks?actions=*&detailed&pretty'

任务管理API

分片状态及管理

索引恢复进度

curl localhost:9200/_cat/recovery?pretty&v
-- 查询某个具体索引的恢复过程
curl localhost:9200/index_name/_recovery?pretty&v

节点自动分配

查看是否自动副本分配
-- 如修改副本数量后,索引为自动均衡,可通过用此配置查询
curl -XGET 'localhost:9200/_cluster/settings?pretty' -d '{
    "persistent": {},
    "transient": {
        "cluster": {
            "routing": {
                "allocation": {
                    "enable": "all"
                }
            }
        }
    }
}'
设置自动分配分片
curl -XPUT 'localhost:9200/_cluster/settings' -d'{
    "transient": {
        "cluster.routing.allocation.enable": "all"
    }
}'

分片分布情况

curl localhost:9200/_cat/shards

索引分片同步列表

curl 'localhost:9200/_cluster/state?filter_path=metadata.indices.index_name.in_sync_allocations.*,routing_table.indices.index_name.*&pretty'

问题定位

热点线程查询

curl -X GET "localhost:9200/_nodes/node_name1,node_name2/hot_threads"

查询未分配索引的详细解释

curl localhost:9200/_cluster/allocation/explain

查询节点线程池使用

curl -X GET "http://localhost:9200/_cat/thread_pool"

常用语法

ES查询语法:QueryDSL

DSL:Domain specified language:特定领域的语言,使用http构建复杂的请求体进行查询

查询返回语法解释

GET /index_name/type_name/_search
took 耗费了多少毫秒
time_out 是否超时
_shards:数据拆分成了5个分片
hists.total:查询结果的数量
hist.max_score:score的含义,就是document对于一个search的相关度的匹配分数,分数越高,相关度越高
hits.hits:包含了匹配搜索的数据

查询排序

-- 查询index_name索引,按时间排序,默认取前20条
curl -i -XGET 'http://localhost:9200/index_name/_search?sort=createTime:asc?pretty'

批量查询 mget

 查询不同index下的不同document
 GET /_mget 
 {
   "docs"  :[
     {
       "_index":"index_name",
       "_type":"type_name",
       "_id":1
     },{
       "_index":"index_name2",
       "_type":"type_name",
       "_id":2
     }
   ]
 }
 --查询同一个index下的不同document
  GET /index_name/_mget
 {
   "docs"  :[
     {
       "_type":"type_name",
       "_id":1
     },{
       "_type":"type_name",
       "_id":2
     }
   ]
 }

bool查询

bool查询,组合查询
复合子句可以合并多种子句为一个单一的查询,无论是叶子子句还是其他的复合子句。
合并多子句
http://192.168.41.11:9200/index_name/type_name/_search
{
    "query":{
        "bool":{
            "must":{"match":{"type":"1"} },
            "must_not":{"match":{ "blockCode":"5201030003"}},
            "should":{"match":{ "doorName":"Openai大模型"} }
        }
    }
}

分页查询

{
    "query":{
        "bool":{
            "must":[
                {
                    "match":{"blockCode":"5201030003"}
                },
                {
                    "match":{"type":"23"}
                }
            ]
        }
    },
    "size":"2",
    "from":"0",
    "sort":{
        "createdDate":{
            "order":"desc"
        }
    }
}

ES分页from默认从0开始,size默认为10

深分页问题

deep paging:当集群节点众多,且分页查询的页数过大时,会很消耗服务器资源,如分页from1000,size10 的分页请求过来后,会将请求打到各个shard或者replica节点上,去取每个节点去10010条数据到coordinate结点上,10个节点共100100条进行排序选出10条。

超时查询

返回在指定超时时间内查询到的数据,有可能数据没有查询完毕

curl localhost:9200/index_name/index_name/_search?timeout=1s

精确值查询

term过滤:term主要用于精确匹配哪些值,比如数字,日期,布尔值或 not_analyzed的字符串,允许使用多个匹配条件

----条件查询并排序
http://localhost:9200/index_name/type_name/_search
{
  "query":{
    :"match":{
      "residentId":"1234123"
    }
  },
  "sort":[{
    "createdDate":"desc"
  }]
}
-----全文检索
http://localhost:9200/index_name/type_name/_search
{
    "query": {
        "match":{"photoLargeUuid":"84cb5b32 a195229e0a7d"}
    }
}
全文搜索会将查询条件分割进行组合查询按权重排序
---phrase 查询
短语全词匹配

复合查询

GET /item/_search
{
    "query": {
        "bool": {
            "must": [
                {
                    "match": {
                        "brand": {
                            "query": "小米"
                        }
                    }
                },
                {
                    "term": {
                        "title": {
                            "value": "小米"
                        }
                    }
                }
            ]
        }
    }
}

更新语法

post /index_name/type_name/1/update
{
"doc":{
"residentId":"341234123412"
  }
 }

删除语法

-- delete  post 删除ID为796098575183802的记录
curl -x delete http://localhost:9200/index_name/type_name/796098575183802
--delete post  删除该索引index_name,谨慎执行

curl -X DELETE "localhost:9200/index_name?pretty"

统计语法

统计索引条数

curl 'localhost:9200/index_name/_count?pretty'
curl 'localhost:9200/face_picture_index/_count?pretty'
curl 'localhost:9200/index_name/_count?pretty'

聚合统计

按类型进行统计

http://localhost:9200/index_name/type_name/_search
{
    "size":0,
    "aggs": {
        "group_by_type": {
            "terms": {
                "field": "type"
            }
        }
    }
}
-----聚合统计,按月分段,以开门方式为维度进行统计
{
    "size":0,
    "aggs":{
        "group_by_date":{
            "range":{
                "field":"createdDate",
                "ranges":[
                    {"from":1555261319001,
                     "to":1557853319000
                    },{
                    "from":1552582919001,
                    "to":1555261319000
                    },{
                    "from":1550163719000,
                    "to":1552582919000}
                    ]
            },
            "aggs":{
                "group_by_type":{
                    "terms":{
                        "field":"type"
                    }
                }
            }
        }
    }
}

ES优化

1. 慢查询配置

curl -XPUT "http://localhost:9200/index_name/_settings" -H 'Content-Type: application/json' -d'{
    "index.search.slowlog.threshold.fetch.debug": "5s",
    "index.search.slowlog.threshold.query.warn": "5s",
    "index.indexing.slowlog.threshold.index.info": "5s",
    "index.indexing.slowlog.threshold.index.warn": "10s"
}'

配置慢查询日志,将索引中的慢查询,慢索引打印出来

2. 索引配置优化

数据量大的情况下:基于日期轮询的索引可以每天生成一个索引,然后用别名关联,或者使用索引通配符匹配

3. 系统层面优化

  1. 关闭swap,调整max open files
  2. http://dockone.io/article/505
  3. 调整shard数,replica数
  4. elasticsearch三个重要的优化 https://zhaoyanblog.com/archives/319.html

4. 结构优化

不需要排序聚合,不需要在脚本中访问的字段可以禁用doc_valus字段节省存储空间

建议周期性的建立新索引

5. 写入速度优化

  1. 加大 Translog Flush ,目的是降低 Iops(每秒读写数)、Writeblock。但是会降低实时性,需要接受一定概率的数据丢失(服务器断电)
  2. 增加 Index Refresh 间隔,目的是减少 Segment Merge 的次数。
  3. 增长索引刷新时间,默认为1s,index_refresh_interval:120s
  4. 调整 Bulk 线程池和队列。
  5. 优化节点间的任务分布。

6. 定位cup过高

查看节点hot_threads

curl -X GET "localhost:9200/_cat/thread_pool"
curl -X GET "localhost:9200/_nodes/node-241/hot_threads"
curl -X GET "localhost:9200/_nodes/node-241,node-131/hot_threads"

active:当前正在执行任务的线程数量,queue:队列中等待处理的请求数量,rejected:队列已满,请求被拒绝的次数。

7. ES写入数据过慢原因

  1. 随着写入索引数据增多,单个shard数据量太大(超过50GB),导致写入速度变慢

  2. 随着数据写入,segment合并变得频繁,es节点负载变高

8.存储优化

强制段合并

elasticsearch删除数据并未真正从磁盘进行删除已,而是将数据标记为删除,等到段合并时才会清楚标记为删除的数据,强制Elasticsearch进行段合并segment merging,Segment merging要消耗CPU,以及大量的I/O资源,所以一定要在你的ElasticSearch集群处于维护窗口期间,并且有足够的I/O空间的

curl -XPOST 'http://localhost:9200/索引名称/_forcemerge?only_expunge_deletes=true'

9. 节点内存使用率过高原因

分段内存一个Lucene分段就是一个完整的倒排索引,倒排索引由单词词典和倒排列表组成。在 Lucene 中,单词词典中的 FST 结构会被加载到内存。因此每个分段都会占用一定的内存空间。可以通过下面的

API来查看所有节点上的所有分段占用的内存总量:
curl -X GET "localhost:9200/_cat/nodes?v&h=segments.memory"

也可以单独查看每个分段的内存占用量:

curl  -X  GET  "localhost:9200/_cat/segments?v&h=index,shard,segment,size.memory"

查询分片缓存请求大小, 默认为堆1%大小

curl -X GET "localhost:9200/_stats/request_cache?pretty"

查询节点查询缓存占用大小,默认为堆10%大小

curl -X GET "localhost:9200/_cat/nodes?v&h=query_cache.memory_size"

故障处理

1. 如何安全重启elasticsearch?

https://www.elastic.co/guide/cn/elasticsearch/guide/current/_rolling_restarts.html

2. 重启节点后有部分索引分片未能恢复

生产环境中有两台节点,将主节点增加查询最大限制数后重启

indices.query.bool.max_clause_count: 10240

直接docker restart elasticsearch 后,重启elasticsearch后,有一个索引长期yellow,有两个分片长期处于未分配状态,es日志出现以下关键错误日志

primary shard with sync id but number of docs differ: 7728586 (node-205-1, primary) vs 7728583(node-149-1) 

直接重启节点后出现两个节点的某个分片的数据不一致
解决:

将这个有问题的索引修改副本数为0,再修改为1,待分配完后即可恢复

索引恢复(indices.recovery)是ES数据恢复过程,是集群启动过程中最缓慢的过程。集群完全重启,或者Master节点挂掉后,新选出的Master也有可能执行索引恢复过程。
待恢复的是哪些数据?是客户端写入成功,但是未执行刷盘(flush)的Lucene分段。
索引恢复有哪些好处?
保持数据完整性:当节点异常重启时,写入磁盘的数据先到文件系统的缓冲,未必来得及刷盘。如果不通过某种方式将未进行刷盘的数据找回,则会丢失一些数据。
数据副本一致性:由于写入操作在多个分片副本上没有来得及全部执行,副分片需要同步成和主分片完全一致。

3. 生产环境某台ES节点负载高原因:

未找到

4. profile定位查询缓慢原因

curl -X GET "http://localhost:9200/index_name/type_name/_search?pretty" -d'{
"profile":true,
"query":{
     "match":{
        "blockCode":"5203210005"
        }
    }
}'

fielddata=true,以便通过取消倒排索引将fielddata加载到内存中

ES官方解释为在es5.x以后,聚合排序这种操作需使用指定数据结构fieldData进行单独操作,需要单独开启,ES排序field的类型只支持text类型

解决办法如下两步:

第二:mapping修改

PUT my_index/_mapping
{
  "properties": {
    "createTime": { 
      "type":     "text",
      "fielddata": true
    }
  }
}

5. 索引有多个副本但副本分片未自动分配

问题描述:新建索引时设置了0个副本,后来设置为1个,但是集群没有自动分配分片,索引长期为yellow

解决:查看集群设置是否自动分配,是否为未设置自动分配,设置为自动分配

参考及推荐

ES中文使用向导

Elasticsearch学习之集群常见状况处理(干货)

elasticsearch 百亿级数据检索案例与原理

Elasticsearch 集群内应该设置多少个分片

《Elasticsearch 源码解析与优化实战》

你可能感兴趣的:(ElasticSearch学习文档)