https://www.elastic.co/guide/cn/elasticsearch/guide/current/_add-an-index.html

索引
—— 保存相关数据的地方。 索引实际上是指向一个或者多个物理 分片 的 逻辑命名空间 。
分片:
—— 是一个底层的 工作单元 ,它仅保存了 全部数据中的一部分
Elasticsearch 是利用分片将数据分发到集群内各处的。分片是数据的容器,文档保存在分片内,分片又被分配到集群内的各个节点里。 当你的集群规模扩大或者缩小时, Elasticsearch 会自动的在各节点中迁移分片,使得数据仍然均匀分布在集群里。
一个分片可以是 主 分片或者 副本 分片。 索引内任意一个文档都归属于一个主分片,所以主分片的数目决定着索引能够保存的最大数据

节点:
—— 一个运行中的 Elasticsearch 实例称为一个 节点,而集群是由一个或者多个拥有相同 cluster.name 配置的节点组成, 它们共同承担数据和负载的压力。当有节点加入集群中或者从集群中移除节点时,集群将会重新平均分布所有的数据。

_index
文档在哪存放
_type
文档表示的对象类别
_id
文档唯一标识


PUT /{index}/{type}/{id}
GET /website/blog/123?pretty
在请求的查询串参数中加上 pretty 参数, 正如前面的例子中看到的,这将会调用 Elasticsearch 的 pretty-print 功能,该功能 使得 JSON 响应体更加可读。但是, _source 字段不能被格式化打印出来。相反,我们得到的 _source 字段中的 JSON 串,刚好是和我们传给它的一样。
curl -i -XGET http://localhost:9200/website/blog/124?pretty
GET /website/blog/123?_source=title,text
GET 请求 会返回整个文档,这个文档正如存储在 _source 字段中的一样。但是也许你只对其中的 title 字段感兴趣。单个字段能用 _source 参数请求得到,多个字段也能使用逗号分隔的列表来指定。

它如何决定这个文档应当被存储在分片 1 还是分片 2 中呢:
shard = hash(routing) % number_of_primary_shards
routing 是一个可变值,默认是文档的 _id ,也可以设置成一个自定义的值。 routing 通过 hash 函数生成一个数字,然后这个数字再除以 number_of_primary_shards (主分片的数量)后得到 余数 。这个分布在 0 到 number_of_primary_shards-1 之间的余数,就是我们所寻求的文档所在分片的位置。
这就解释了为什么我们要在创建索引的时候就确定好主分片的数量 并且永远不会改变这个数量:因为如果数量变化了,那么所有之前路由的值都会无效,文档也再也找不到了。

一个 bool 语句 允许在你需要的时候组合其它语句,无论是 must 匹配、 must_not 匹配还是 should 匹配,同时它可以包含不评分的过滤器(filters):
当使用于 过滤情况 时,查询被设置成一个“不评分”或者“过滤”查询。即,这个查询只是简单的问一个问题:“这篇文档是否匹配?”。回答也是非常的简单,yes 或者 no ,二者必居其一。
对于精确值的查询,你可能需要使用 filter 语句来取代 query,因为 filter 将会被缓存。
当使用于 查询情况 时,查询就变成了一个“评分”的查询。和不评分的查询类似,也要去判断这个文档是否匹配,同时它还需要判断这个文档匹配的有 _多好_(匹配程度如何)。 此查询的典型用法是用于查找以下文档:

match_all
查询简单的 匹配所有文档。在没有指定查询方式时,它是默认的查询:{ "match_all": {}}


match 查询
无论你在任何字段上进行的是全文搜索还是精确查询,match 查询是你可用的标准查询。
如果你在一个全文字段上使用 match 查询,在执行查询前,它将用正确的分析器去分析查询字符串:{ "match": { "tweet": "About Search" }}
multi_match 查询可以在多个字段上执行相同的 match 查询。
range 查询找出那些落在指定区间内的数字或者时间。
term 查询被用于精确值 匹配,这些精确值可能是数字、时间、布尔或者那些 not_analyzed 的字符串,term 查询对于输入的文本不 分析 ,所以它将给定的值进行精确查询。
terms 查询和 term 查询一样,但它允许你指定多值进行匹配。如果这个字段包含了指定值中的任何一个值,那么这个文档满足条件,和 term 查询一样,terms 查询对于输入的文本不分析。它查询那些精确匹配的值(包括在大小写、重音、空格等方面的差异)。
exists 查询和 missing 查询被用于查找那些指定字段中有值 (exists) 或无值 (missing) 的文档。这与SQL中的 IS_NULL (missing) 和 NOT IS_NULL (exists) 在本质上具有共性


bool 查询这种查询将多查询组合在一起,成为用户自己想要的布尔查询。它接收以下参数:
must
文档 必须 匹配这些条件才能被包含进来。
must_not
文档 必须不 匹配这些条件才能被包含进来。
should
如果满足这些语句中的任意语句,将增加 _score ,否则,无任何影响。它们主要用于修正每个文档的相关性得分。
filter
必须 匹配,但它以不评分、过滤模式来进行。这些语句对评分没有贡献,只是根据过滤标准来排除或包含文档。


constant_score 查询也是你工具箱里有用的查询工具。它将一个不变的常量评分应用于所有匹配的文档。它被经常用于你只需要执行一个 filter 而没有其它查询(例如,评分查询)的情况下。
可以使用它来取代只有 filter 语句的 bool 查询。在性能上是完全相同的,但对于提高查询简洁性和清晰度有很大帮助
explain 参数可以让返回结果添加一个 _score 评分的得来依据。
在 Elasticsearch 中,Doc Values 就是一种列式存储结构,默认情况下每个字段的 Doc Values 都是激活的,Doc Values 是在索引时创建的,当字段索引时,Elasticsearch 为了能够快速检索,会把字段的值加入倒排索引中,同时它也会存储该字段的 `Doc Values`。

搜索类型编辑
缺省的搜索类型是 query_then_fetch 。 在某些情况下,你可能想明确设置 search_type 为 dfs_query_then_fetch 来改善相关性精确度
搜索类型 dfs_query_then_fetch 有预查询阶段,这个阶段可以从所有相关分片获取词频来计算全局词频。

文档字段和属性的三个 最重要的设置:
type
字段的数据类型,例如 string 或 date
index
字段是否应当被当成全文来搜索( analyzed ),或被当成一个准确的值( not_analyzed ),还是完全不可被搜索( no )
analyzer
确定在索引和搜索时全文字段使用的 analyzer
_source 字段的确要使用磁盘空间。如果上面的原因对你来说没有一个是重要的,你可以用下面的映射禁用 _source 字段
即使你认为现在的索引设计已经很完美了,在生产环境中,还是有可能需要做一些修改的。
做好准备:在你的应用中使用别名而不是索引名。然后你就可以在任何时候重建索引。别名的开销很小,应该广泛使用。你的应用已经在零停机的情况下从旧索引迁移到新索引了。

结构化搜索
结构化搜索(Structured search) 是指有关探询那些具有内在结构数据的过程。比如日期、时间和数字都是结构化的:它们有精确的格式,我们可以对这些格式进行逻辑操作。比较常见的操作包括比较数字或时间的范围,或判定两个值的大小。

当进行精确值查找时, 我们会使用过滤器(filters)。过滤器很重要,因为它们执行速度非常快,不会计算相关度(直接跳过了整个评分阶段)而且很容易被缓存。
不过现在只要记住:请尽可能多的使用过滤式查询
查询置于 filter 语句内不进行评分或相关度的计算,所以所有的结果都会返回一个默认评分 1
通常当查找一个精确值的时候,我们不希望对查询进行评分计算。只希望对文档进行包括或排除的计算,所以我们会使用 constant_score 查询以非评分模式来执行 term 查询并以一作为统一评分。
删除索引是必须的,因为我们不能更新已存在的映射。


1.
减少刷新频率
2.
代码中减少查询时size 的大小
3.
refresh_interval
ES_MIN_MEM=8g
ES_MAX_MEM=8g
4.
Swapping 是性能的坟墓,完全禁用 swap
它的作用就是允许 JVM 锁住内存,禁止操作系统交换出去。在你的 elasticsearch.yml 文件中,设置如下:
bootstrap.mlockall: true
5.传输客户端(注:Transport Client,下同)与节点客户端(注:Node Client,下同)
6.
可以查看每个节点的状态及集群的健康信息
7.查看分片,查看分片的数量及每个的大小
分片
按着自己的业务需求控制shard数量,shard过多,交互多。。shard过少,单个分片数据容易累积,当单个分片的数据超过30G的时
候就有性能下降的情况,当超过50G的时候,就有明显性能下降的效果。。采用热分离:当数据大小即将超过30G的时候。可以把以前的 数据 转存到其他容器里面去。比如hdfs。
8.
bootstrap.mlockall: true

 

 性能优化的思路:

 

减少刷新频率:refresh_interval "不同分片之间的数据同步是一个很大的花费,默认是1s同步,如果我们不要求实时性
修改为60s 其实可以改为-1s 这样就是不刷新,我们需要在查询的时候进行一次索引刷新然后再查询,这个嘛就得看你们用户能容忍多少时间长度了。"

"Swapping 是性能的坟墓,完全禁用 swap
它的作用就是允许 JVM 锁住内存,禁止操作系统交换出去。在你的 elasticsearch.yml 文件中,设置如下:
bootstrap.mlockall: true" "咱目前并没设置:无
Swapping 是性能的坟墓编辑
这是显而易见的, 但是还是有必要说的更清楚一点:内存交换 到磁盘对服务器性能来说是 致命 的。想想看:一个内存操作必须能够被快速执行。

如果内存交换到磁盘上,一个 100 微秒的操作可能变成 10 毫秒。 再想想那么多 10 微秒的操作时延累加起来。 不难看出 swapping 对于性能是多么可怕。

最好的办法就是在你的操作系统中完全禁用 swap。这样可以暂时禁用

最后,如果上面的方法都不合适,你需要打开配置文件中的 mlockall 开关。 它的作用就是允许 JVM 锁住内存,禁止操作系统交换出去。在你的 elasticsearch.yml 文件中,设置如下:
bootstrap.mlockall: true

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


"内存:设置为一个相同的值
ES_MIN_MEM=8g
ES_MAX_MEM=8g" "ES_HEAP_SIZE
ES_HEAP_SIZE=16g
node1:10.20.56.4:ES_HEAP_SIZE=16g
node2:10.20.56.5:ES_HEAP_SIZE=16g
node3:10.20.56.6: ES_HEAP_SIZE=16g


设置 ES_HEAP_SIZE 环境变量,比直接写 -Xmx -Xms 更好一点。
标准的建议是把 50% 的可用内存作为 Elasticsearch 的堆内存,保留剩下的 50%。当然它也不会被浪费,Lucene 会很乐意利用起余下的内存。


"


查看分片,查看分片的数量及每个的大小 "每个index大小:
每index的文档数:
随机在es上直接执行脚本查看took运行时间"


"修改linux系统文件最大打开数
临时生效
ulimit -SHn 65535
:修改当前系统,文件最大打开数为65535" ?


"物理层面
内存:单实例分配32G(多了无济于事,内存锁定,给OS预留)**

硬盘:尽量大,Raid10,SSD**

CPU:配置尽量高*

网络:千兆,最好万兆*
(*代表重要程度,数量越多越重要)" "磁盘在现代服务器上通常都是瓶颈。Elasticsearch 重度使用磁盘,你的磁盘能处理的吞吐量越大,你的节点就越稳定。这里有一些优化磁盘 I/O 的技巧:

使用 SSD。就像其他地方提过的, 他们比机械磁盘优秀多了。
使用 RAID 0。条带化 RAID 会提高磁盘 I/O,代价显然就是当一块硬盘故障时整个就故障了。不要使用镜像或者奇偶校验 RAID 因为副本已经提供了这个功能。
另外,使用多块硬盘,并允许 Elasticsearch 通过多个 path.data 目录配置把数据条带化分配到它们上面。
不要使用远程挂载的存储,比如 NFS 或者 SMB/CIFS。这个引入的延迟对性能来说完全是背道而驰的。
如果你用的是 EC2,当心 EBS。即便是基于 SSD 的 EBS,通常也比本地实例的存储要慢。"



配置索引线程池的大小 "threadpool.search.type: fixed
threadpool.search.size: 120
threadpool.search.queue_size: 5000
只在node1:10.20.56.4上进行了设置,why?

搜索线程池设置的大一点,配置为 int(( 核心数 * 3 )/ 2 )+ 1
官方不建议去改动https://www.elastic.co/guide/cn/elasticsearch/guide/current/dont-touch-these-settings.html
目前建议将10.20.56.4上的该配置去除"



routing值的设置 "意思 就是说在添加数据和查询的时候,添加routing参数, 指定该操作是在哪个分片中,这样就不用去遍历所有的分片 了。
https://www.elastic.co/guide/cn/elasticsearch/guide/cn/routing-value.html当索引一个文档的时候,文档会被存储到一个主分片中。 Elasticsearch 如何知道一个文档应该存放到哪个分片中呢?当我们创建文档时,它如何决定这个文档应当被存储在分片 1 还是分片 2 中呢?

首先这肯定不会是随机的,否则将来要获取文档的时候我们就不知道从何处寻找了。实际上,这个过程是根据下面这个公式决定的:

shard = hash(routing) % number_of_primary_shards
routing 是一个可变值,默认是文档的 _id ,也可以设置成一个自定义的值。 routing 通过 hash 函数生成一个数字,然后这个数字再除以 number_of_primary_shards (主分片的数量)后得到 余数 。这个分布在 0 到 number_of_primary_shards-1 之间的余数,就是我们所寻求的文档所在分片的位置。

 

在 路由一个文档到一个分片中 中, 我们解释过如何定制参数 routing ,它能够在索引时提供来确保相关的文档,比如属于某个用户的文档被存储在某个分片上。 在搜索的时候,不用搜索索引的所有分片,而是通过指定几个 routing 值来限定只搜索几个相关的分片:

GET /_search?routing=user_1,user2
这个技术在设计大规模搜索系统时就会派上用场,我们在 扩容设计 中详细讨论它。
目前咱数据量不大,分片也比较少,目前的改动派不上用场。
"



"optimize

随着时间的推移,ElasicSearch中每个shard的数据也会越来越多,索引越来越大,而生成的segment(在每个shard中,每个索引文件实际是由多个sgment文件组成)也会越来越多。而segment越多的话,则查询的性能越差,所以通过调用optimize命令,将多个segment合并成更少数量的segment(最少为一个),从而来提高查询性能" "optimize API编辑
optimize API大可看做是 强制合并 API 。它会将一个分片强制合并到 max_num_segments 参数指定大小的段数目。 这样做的意图是减少段的数量(通常减少到一个),来提升搜索性能。

警告
optimize API 不应该 被用在一个动态索引————一个正在被活跃更新的索引。后台合并流程已经可以很好地完成工作。 optimizing 会阻碍这个进程。不要干扰它!

在特定情况下,使用 optimize API 颇有益处。例如在日志这种用例下,每天、每周、每月的日志被存储在一个索引中。 老的索引实质上是只读的;它们也并不太可能会发生变化。

在这种情况下,使用optimize优化老的索引,将每一个分片合并为一个单独的段就很有用了;这样既可以节省资源,也可以使搜索更加快速:

POST /logstash-2014-10/_optimize?max_num_segments=1
https://www.elastic.co/guide/cn/elasticsearch/guide/cn/merge-process.html
参考:https://www.elastic.co/guide/cn/elasticsearch/guide/cn/merge-process.html
目前来看,用不上"



" max_num_segments

段数优化。要全面优化索引,将其设置为1。默认设置只需检查是否需要执行一个合并,如果需要,则执行它。【经过测试,该值越小,查询速度越快】" "由于自动刷新流程每秒会创建一个新的段 ,这样会导致短时间内的段数量暴增。而段数目太多会带来较大的麻烦。 每一个段都会消耗文件句柄、内存和cpu运行周期。更重要的是,每个搜索请求都必须轮流检查每个段;所以段越多,搜索也就越慢。

Elasticsearch通过在后台进行段合并来解决这个问题。小的段被合并到大的段,然后这些大的段再被合并到更大的段。
https://www.elastic.co/guide/cn/elasticsearch/guide/cn/merge-process.html
POST /logstash-2014-10/_optimize?max_num_segments=1

同上"


一个 Node 最好不要多于三个 shards 同上

index.merge.scheduler.max_thread_count "机械磁盘在并发 I/O 支持方面比较差,所以我们需要降低每个索引并发访问磁盘的线程数。这个设置允许 max_thread_count + 2 个线程同时进行磁盘操作,也就是设置为 1 允许三个线程。

对于 SSD,你可以忽略这个设置,默认是 Math.min(3, Runtime.getRuntime().availableProcessors() / 2) ,对 SSD 来说运行的很好。
如果你使用的是机械磁盘而非 SSD,你需要添加下面这个配置到你的 elasticsearch.yml 里:

index.merge.scheduler.max_thread_count: 1
参考设置:https://www.elastic.co/guide/cn/elasticsearch/guide/current/indexing-performance.html"


RequestCache "在默认情况下Request Cache是关闭的,我们需要手动开启。
开启缓存后,我们需要在那些需要缓存的搜索请求上加上request_cache=true这个参数才能使我们的查询请求被缓存

注意1:上面的参数size:0非常重要必须强制指定才能被缓存,否则请求是不会缓存的。
注意2(重要):在使用script执行查询时一定要指定request_cache=false,因为脚本的执行结果是不确定的(比如使用random函数或使用了当前时间作为参数),这种情况下应该避免使用缓存

当一个查询发送到ES集群的某个节点上时,这个节点会把该查询扩散到其他节点并在相应分片上执行,我们姑且把在分片上执行的结果叫“本地结果集“,这些本地结果集最终会汇集到最初请求到达的那个协调节点,这些“分片级”的结果集会合并成“全局”结果集返回给调用端。
Request Cache模块就是为了缓存这些“分片级”的本地结果集,但是目前只会缓存查询中参数size=0的请求,所以就不会缓存hits 而是缓存 hits.total,aggregations和suggestions
缓存失效
Request Cache是非常智能的,它能够保证和在近实时搜索中的非缓存查询结果一致。这句话读起来很难懂,简单解释下。
我们都知道ES是一个“near real-time”(近实时)搜索引擎,为什么是近实时搜索呢,那是因为当我们向ES发送一个索引文档请求到这个文档变成Searchable(可搜索)默认的时间是1秒,我们可以通过index.refresh_interval参数来设置刷新时间间隔,也就是说我们在执行一个搜索请求时实际上数据是有延迟的。回到刚才的问题,刚才那句话其实指的就是:ES能保证在使用Request Cache的情况下的搜索结果和不使用Request Cache的近实时搜索结果相同,那ES是如何保证两者结果相同的呢?继续……

Request Cache缓存失效是自动的,当索引refresh时就会失效,也就是说在默认情况下Request Cache是每1秒钟失效一次(注意:分片在这段时间内确实有改变才会失效)。也就是说当一个文档被索引到该文档变成Searchable之前的这段时间内,不管是否有请求命中缓存该文档都不会被返回,正是是因为如此ES才能保证在使用Request Cache的情况下执行的搜索和在非缓存近实时搜索的结果一致。如果我们把索引刷新时间设置得越长那么缓存失效的时间越长,如果缓存被写满将采用LRU策略清除。当然我们也可以手动设置参数indices.request.cache.expire指定失效时间,但是基本上我们没必要去这样做,因为缓存在每次索引refresh时都会自动失效。
下面的命令可以手动清除缓存"


doc_values "https://www.elastic.co/guide/cn/elasticsearch/guide/cn/docvalues-intro.html

doc values是一个我们再三重复的重要话题了,你是否意识到一些东西呢?
搜索时,我们需要一个“词”到“文档”列表的映射
排序时,我们需要一个“文档”到“词“列表的映射,换句话说,我们需要一个在倒排索引的基础上建立的“正排索引”
这里的“正排索引”结构通常在其他系统中(如关系型数据库)被称为“列式存储”。本质上,它是在数据字段的一列上存储所有value,这种结构在某些操作上会表现得很高效,比如排序。

在ES里这种“列式存储”就是我们熟悉的“doc values”,默认情况下它是被启用的,doc values在index-time(索引期)被创建:当一个字段被索引时,ES会把“词”加入到倒排索引中,同时把这些词也加入到面向“列式存储”的doc values中(存储在硬盘上)。
doc values通常被应用在以下几个方面:
基于一个字段排序
基于一个字段聚合
执行某些filter上(如:geolocation filter)
在script(脚本)中引用了一个或多个字段
由于doc values在索引期被序列化到硬盘上,我们可以利用操作系统去快速的访问它们,关于doc values在磁盘上是如何被管理的


所有的字段都默认支持doc values,如果你确定你不需要在某个字段上排序或者聚合或者在脚本中访问,你可以disable掉:


doc values支持绝大部分字段类型,除了“analyzed”类型的string字段。

因为文档值默认启用,你可以选择对你数据集里面的大多数字段进行聚合和排序操作。但是如果你知道你永远也不会对某些字段进行聚合、排序或是使用脚本操作?

尽管罕见,但当这些情况出现时,你还是希望有办法来为特定的字段禁用文档值。这回为你节省磁盘空间(因为文档值再也没有序列化到磁盘),也许还能提升些许索引速度(因为不需要生成文档值)。"

 

posted on 2020-06-17 20:17  xuxu_dragon  阅读(260)  评论(0编辑  收藏  举报