ElasticSearch 小记
提示:涉及性能的时候,批量的大小很关键。如果你的批量太大,他们会占用过多的内存,如果他们太小,网络开销又会很大。最佳的平衡点,取决于文档的大小— 如果文档很大,每个批量中就少放几篇里 。 如果文档很小,就多放几篇–以及集群的能力。一个拥有强劲机器的大规模集群可以更快地处理更大的批量请求,并且仍然保持良好的搜索服务性能。最后,你需要自定测试,发现适合你用例的最佳点。你可以从像每个批量 1000 篇 小文档这样的值开始(入 日志文件),然后逐步增加数量直到你无法获得明显的性能提升。同时,记得监控你的集群。
elasticsearch 向外扩展的问题思考
第一个原则:当另一个节点加入的时候。ElasticSearch会自动地尝试将分片在所有节点上进行均匀分配。
如何发现其他Elasticsearch节点???
广播 或者 单播
可以同时使用两者。不过默认的配置是仅仅使用广播,因为单播需要一致节点来进行连接。
单播 不会将消息发送给网络上的每个人,而是连接指定列表中的节点。
并非所有的Elasticsearch集群节点需要出现在单播列表中来发现全部的节点,但是必须为每个节点配置足够的地址,让其认识可用的 口口相传节点。
选举主节点和识别错误
一旦集群中的节点发现了彼此,他们会协商谁将成为主节点。主节点负责管理集群的状态,也就是当前的设置和集群中的分片,索引一级节点的状态。在主节点被选举出来之后,他会建立内部的ping机制来确保每个节点在集群中保持活跃和健康,这被称为 错误识别 (fault detection )
集群节点数除以2 再加上1
什么是脑裂
脑裂这个词描述了这样的场景:(通常是在重负荷或者网络存在问题的情况下) Elasticsearch 集群中一个或者多个节点是去了和主节点的通信,开始选举新的主节点,并且继续处理请求。这个时候,可能有两个不同的 Elasticsearch 集群相互独立地运行着。这就是脑裂一次的由来。因为单一的集群已经分裂成了两个不同的部分,和左右大脑类似。为了防止这种情况的发生,你需要根据集群节点的数量来设置 discoverry.zen.minimum_master_nodes 如果节点的数量不变,将其设置为集群节点的总数,否则将节点数除以2 并加1。因为这就意味着如果一个或多个接地那失去了 和其他节点的通信,他们无法选举新的主节点来形成新的集群。因为对于他们不能获得所需的节点的数量超过一半。
错误的识别
现在你的集群有两个节点了。包括一个选举出来的主节点,他需要和集群中所有节点通信,以确保一切正常,这称为错误识别的过程。主节点ping集群中所有其他的节点,而且每个节点也会ping主节点来确认无须选举。
elasticsearch 如何提升性能
合并请求
批量索引,更新,删除
多条搜索 和 多条获取 API 接口
优化lucene分段的处理
刷新和冲刷的阈值
合并以及合并策略
存储和存储限流
充分利用缓存
过滤器和过滤器缓存
分片查询缓存
jvm堆和操作系统缓存
使用预热器让缓存热身
其他的性能权衡
大规模的索引 还是昂贵的搜索
调优脚本 要么 别用他
权衡网络开销 更少的数据 和 更好的分布式 得分
权衡内存 进行 深度分页
elasticsearch 集群管理
改善默认配置
索引模板
默认的映射
分配的感知
基于分片的分配
强制性的分配感知
监控瓶颈
检查集群的健康状态
CPU:慢日志,热线程,和线程池
内存:堆的大小,字段 和 过滤器缓存
操作系统缓存
存储限流
备份你的数据
快照API
将数据备份到共享的文件系统
从备份中恢复
使用资料库插件
elasticsearch 分析数据
1。什么是分析
2。为文档使用分析器
3。分析器,分词器,和分词过滤器
elasticsearch 使用相关性进行搜索
elasticsearch 使用聚集来探索数据
elasticsearch 文档之间的关联关系
副本分片对于可靠性和搜索性能很有好处。技术上而言,一份分片就是一个目录中的文件,Lucene用这些文件存储缩影数据。分片也是Elasticsearch将数据从一个节点移到另一个节点的最小单位。
集群的好处是:性能和稳定性都有好处。 缺点:必须确定节点之间能够足够快速地通信,并且不会产生大脑分裂;
大脑分裂
(集群的2个部分不能彼此交流,都认为对方宕机了)
一份分片是Lucene的索引,一个包含倒排索引的文件目录。倒排索引的结构使得 elasticsearch 在不扫描所有文档的情况下,就能告诉你哪些文档包含特定的词条。
分片有两种。一种是主分片,另一种是副本分片,其中副本分片是主分片的完整副本。副本分片用于搜索,或者是在原有主分片丢失后成为新的主分片。
副本分片可以在运行时候进行添加和移除。但是主分片不可以。
为什么呢?
ES_HEAP_SIZE 设置为 内存总量的一半。 另一半内存用于操作系统的缓存,可以更加快速地访问所存储的数据。
es/elasticsearch的副本和分片的区别
es/elasticsearch的副本和分片的区别
我自己的项目中,生产的部署是
3台2核8G主节点(不存数据)+3台4核16G数据节点
线程池
许多人 喜欢 调整线程池。 无论什么原因,人们都对增加线程数无法抵抗。索引太多了?增加线程!搜索太多了?增加线程!节点空闲率低于 95%?增加线程!
Elasticsearch 默认的线程设置已经是很合理的了。对于所有的线程池(除了 搜索 ),线程个数是根据 CPU 核心数设置的。 如果你有 8 个核,你可以同时运行的只有 8 个线程,只分配 8 个线程给任何特定的线程池是有道理的。
搜索线程池设置的大一点,配置为 int(( 核心数 * 3 )/ 2 )+ 1 。
你可能会认为某些线程可能会阻塞(如磁盘上的 I/O 操作),所以你才想加大线程的。对于 Elasticsearch 来说这并不是一个问题:因为大多数 I/O 的操作是由 Lucene 线程管理的,而不是 Elasticsearch。
此外,线程池通过传递彼此之间的工作配合。你不必再因为它正在等待磁盘写操作而担心网络线程阻塞, 因为网络线程早已把这个工作交给另外的线程池,并且网络进行了响应。
最后,你的处理器的计算能力是有限的,拥有更多的线程会导致你的处理器频繁切换线程上下文。 一个处理器同时只能运行一个线程。所以当它需要切换到其它不同的线程的时候,它会存储当前的状态(寄存器等等),然后加载另外一个线程。 如果幸运的话,这个切换发生在同一个核心,如果不幸的话,这个切换可能发生在不同的核心,这就需要在内核间总线上进行传输。
这个上下文的切换,会给 CPU 时钟周期带来管理调度的开销;在现代的 CPUs 上,开销估计高达 30 μs。也就是说线程会被堵塞超过 30 μs,如果这个时间用于线程的运行,极有可能早就结束了。
人们经常稀里糊涂的设置线程池的值。8 个核的 CPU,我们遇到过有人配了 60、100 甚至 1000 个线程。 这些设置只会让 CPU 实际工作效率更低。
所以,下次请不要调整线程池的线程数。如果你真 想调整 , 一定要关注你的 CPU 核心数,最多设置成核心数的两倍,再多了都是浪费。
确保堆内存最小值( Xms )与最大值( Xmx )的大小是相同的,防止程序在运行时改变堆内存大小, 这是一个很耗系统资源的过程。
把你的内存(少于)一半给 Lucene
一个常见的问题是给 Elasticsearch 分配的内存 太 大了。假设你有一个 64 GB 内存的机器, 天啊,我要把 64 GB 内存全都给 Elasticsearch。因为越多越好啊!
当然,内存对于 Elasticsearch 来说绝对是重要的,它可以被许多内存数据结构使用来提供更快的操作。但是说到这里, 还有另外一个内存消耗大户 非堆内存 (off-heap):Lucene。
Lucene 被设计为可以利用操作系统底层机制来缓存内存数据结构。 Lucene 的段是分别存储到单个文件中的。因为段是不可变的,这些文件也都不会变化,这是对缓存友好的,同时操作系统也会把这些段文件缓存起来,以便更快的访问。
Lucene 的性能取决于和操作系统的相互作用。如果你把所有的内存都分配给 Elasticsearch 的堆内存,那将不会有剩余的内存交给 Lucene。 这将严重地影响全文检索的性能。
标准的建议是把 50% 的可用内存作为 Elasticsearch 的堆内存,保留剩下的 50%。当然它也不会被浪费,Lucene 会很乐意利用起余下的内存。
如果你不需要对分词字符串做聚合计算(例如,不需要 fielddata )可以考虑降低堆内存。堆内存越小,Elasticsearch(更快的 GC)和 Lucene(更多的内存用于缓存)的性能越好。
不要超过 32 GB!
这里有另外一个原因不分配大内存给 Elasticsearch。事实上, JVM 在内存小于 32 GB 的时候会采用一个内存对象指针压缩技术。
在 Java 中,所有的对象都分配在堆上,并通过一个指针进行引用。 普通对象指针(OOP)指向这些对象,通常为 CPU 字长 的大小:32 位或 64 位,取决于你的处理器。指针引用的就是这个 OOP 值的字节位置。
对于 32 位的系统,意味着堆内存大小最大为 4 GB。对于 64 位的系统, 可以使用更大的内存,但是 64 位的指针意味着更大的浪费,因为你的指针本身大了。更糟糕的是, 更大的指针在主内存和各级缓存(例如 LLC,L1 等)之间移动数据的时候,会占用更多的带宽。
Java 使用一个叫作 内存指针压缩(compressed oops)的技术来解决这个问题。 它的指针不再表示对象在内存中的精确位置,而是表示 偏移量 。这意味着 32 位的指针可以引用 40 亿个 对象 , 而不是 40 亿个字节。最终, 也就是说堆内存增长到 32 GB 的物理内存,也可以用 32 位的指针表示。
一旦你越过那个神奇的 ~32 GB 的边界,指针就会切回普通对象的指针。 每个对象的指针都变长了,就会使用更多的 CPU 内存带宽,也就是说你实际上失去了更多的内存。事实上,当内存到达 40–50 GB 的时候,有效内存才相当于使用内存对象指针压缩技术时候的 32 GB 内存。
这段描述的意思就是说:即便你有足够的内存,也尽量不要 超过 32 GB。因为它浪费了内存,降低了 CPU 的性能,还要让 GC 应对大内存。
最优的方案及配置就是8核64G,给32GES,留一半缓存
索引性能技巧
如果你是在一个索引负载很重的环境,比如索引的是基础设施日志,你可能愿意牺牲一些搜索性能换取更快的索引速率。在这些场景里,搜索常常是很少见的操作,而且一般是由你公司内部的人发起的。他们也愿意为一个搜索等上几秒钟,而不像普通消费者,要求一个搜索必须毫秒级返回。
基于这种特殊的场景,我们可以有几种权衡办法来提高你的索引性能
科学的性能测试
性能测试永远是复杂的,所以在你的方法里已经要尽可能的科学。随机摆弄旋钮以及写入开关可不是做性能调优的好办法。如果有太多种 可能 ,我们就无法判断到底哪一种有最好的 效果 。合理的测试方法如下:
在单个节点上,对单个分片,无副本的场景测试性能。
在 100% 默认配置的情况下记录性能结果,这样你就有了一个对比基线。
确保性能测试运行足够长的时间(30 分钟以上)这样你可以评估长期性能,而不是短期的峰值或延迟。一些事件(比如段合并,GC)不会立刻发生,所以性能概况会随着时间继续而改变的。
开始在基线上逐一修改默认值。严格测试它们,如果性能提升可以接受,保留这个配置项,开始下一项
副本(Replia)
为提高查询吞吐量或实现高可用性,可以使用分片副本。
副本是一个分片的精确复制,每个分片可以有零个或多个副本。ES中可以有许多相同的分片,其中之一被选择更改索引操作,这种特殊的分片称为主分片。
当主分片丢失时,如:该分片所在的数据不可用时,集群将副本提升为新的主分片
分片分裂
用户经常在问,为什么 Elasticsearch 不支持 分片分裂(shard-splitting)— 将每个分片分裂为两个或更多部分的能力。 原因就是分片分裂是一个糟糕的想法:
分裂一个分片几乎等于重新索引你的数据。它是一个比仅仅将分片从一个节点复制到另一个节点更重量级的操作。
分裂是指数的。起初你你有一个分片,然后分裂为两个,然后四个,八个,十六个,等等。分裂并不会刚好地把你的处理能力提升 50%。
分片分裂需要你拥有足够的能力支撑另一份索引的拷贝。通常来说,当你意识到你需要横向扩展时,你已经没有足够的剩余空间来做分裂了。
Elasticsearch 通过另一种方式来支持分片分裂。你总是可以把你的数据重新索引至一个拥有适当分片个数的新索引(参阅 重新索引你的数据)。 和移动分片比起来这依然是一个更加密集的操作,依然需要足够的剩余空间来完成,但至少你可以控制新索引的分片个数了。
容量规划
如果一个分片太少而 1000 个又太多,那么我怎么知道我需要多少分片呢? 一般情况下这是一个无法回答的问题。因为实在有太多相关的因素了:你使用的硬件、文档的大小和复杂度、文档的索引分析方式、运行的查询类型、执行的聚合以及你的数据模型等等。
幸运的是,在特定场景下这是一个容易回答的问题,尤其是你自己的场景:
1 基于你准备用于生产环境的硬件创建一个拥有单个节点的集群。
2 创建一个和你准备用于生产环境相同配置和分析器的索引,但让它只有一个主分片无副本分片。
3 索引实际的文档(或者尽可能接近实际)。
4 运行实际的查询和聚合(或者尽可能接近实际)
副本分片
目前为止我们只讨论过主分片,但我们身边还有另一个工具:副本分片。 副本分片的主要目的就是为了故障转移,正如在 集群内的原理 中讨论的:如果持有主分片的节点挂掉了,一个副本分片就会晋升为主分片的角色。
在索引写入时,副本分片做着与主分片相同的工作。新文档首先被索引进主分片然后再同步到其它所有的副本分片。增加副本数并不会增加索引容量。
无论如何,副本分片可以服务于读请求,如果你的索引也如常见的那样是偏向查询使用的,那你可以通过增加副本的数目来提升查询性能,但也要为此 增加额外的硬件资源。
让我们回到那个有着两个主分片索引的例子。我通过增加第二个节点来提升索引容量。 增加额外的节点不会帮助我们提升索引写入能力,但我们可以通过增加副本数在搜索时利用额外的硬件:
搜索性能取决于最慢的节点的响应时间,所以尝试均衡所有节点的负载是一个好想法。 如果我们只是增加一个节点而不是两个,最终我们会有两个节点各持有一个分片,而另一个持有两个分片做着两倍的工作
搜索引擎中大多数使用场景都是增长缓慢相对稳定的文档集合。搜索查找最相关的文档,而不关心它是何时创建的。
数据建模部分-的扩容设计
https://www.elastic.co/guide/cn/elasticsearch/guide/current/overallocation.html
按照时间范围来索引
如果我们为此种类型的文档建立一个超大索引,我们可能会很快耗尽存储空间。日志事件会不断的进来,不会停顿也不会中断。 我们可以使用 scroll 查询和批量删除来删除旧的事件。但这种方法 非常低效 。当你删除一个文档,它只会被 标记 为被删除(参见 删除和更新)。 在包含它的段被合并之前不会被物理删除。
替代方案是,我们使用一个 时间范围索引。你可以着手于一个按年的索引 (logs_2014) 或按月的索引 (logs_2014-10) 。 也许当你的网页变得十分繁忙时,你需要切换到一个按天的索引 (logs_2014-10-24) 。删除旧数据十分简单:只需要删除旧的索引。
这种方法有这样的优点,允许你在需要的时候进行扩容。你不需要预先做任何艰难的决定。每天都是一个新的机会来调整你的索引时间范围来适应当前需求。 应用相同的逻辑到决定每个索引的大小上。起初也许你需要的仅仅是每周一个主分片。过一阵子,也许你需要每天五个主分片。这都不重要——任何时间你都可以调整到新的环境
索引优化
昨日的索引不大可能会改变。 日志事件是静态的:已经发生的过往不会再改变了。如果我们将每个分片合并至一个段(Segment),它会占用更少的资源更快地响应查询。 我们可以通过optimize API来做到。
对还分配在 strong 主机上的索引进行优化(Optimize)操作将会是一个糟糕的想法, 因为优化操作将消耗节点上大量 I/O 并对索引今日日志造成冲击。但是 medium 的节点没有做太多类似的工作,我们可以安全地在上面进行优化。
部署
主要包括三个方面:
后勤方面的考虑,如硬件和部署策略的建议
更适合于生产环境的配置更改
部署后的考虑,例如安全,最大限度的索引性能和备份
JDK8默认垃圾回收器详解
JDK8默认垃圾回收器详解
UseParallelGC 即 Parallel Scavenge + Parallel Old,再查看详细信息
或者能不能从垃圾收集器本身上来解释,serialOld是单线程,parallelOld是多线程,在现在基本都是多核的电脑或服务器上来运行的话,多线程执行效率会更高,
Parallel Scavenge垃圾收集器因为与吞吐量关系密切,也称为 吞吐量收集器(Throughput Collector)
Parallel Scavenge收集器
https://blog.csdn.net/wxy941011/article/details/80653893
Elastic search 分片和副本策略
https://juejin.cn/post/6844903862067789838
shard
1.分片,ES是分布式搜索引擎,每个索引有一个或多个分片,索引的数据被分配到各个分片上,相当于一桶水 用了N个杯子装
2.分片有助于横向扩展,N个分片会被尽可能平均地(rebalance)分配在不同的节点上(例如你有2个节点,4个主分片(不考虑备份),那么每个节点会分到2个分片,后来你增加了2个节点,那么你这4个节点上都会有1个分片,这个过程叫relocation,ES感知后自动完成)
3.分片是独立的,对于一个Search Request的行为,每个分片都会执行这个Request.另外
4.每个分片都是一个Lucene Index,所以一个分片只能存放 Integer.MAX_VALUE - 128 = 2,147,483,519个docs。
replica
1.复制,可以理解为备份分片,相应地有primary shard(主分片)
2.主分片和备分片不会出现在同一个节点上(防止单点故障),默认情况下一个索引创建5个分片一个备份(即5primary+5replica=10个分片)
3.如果你只有一个节点,那么5个replica都无法分配(unassigned),此时cluster status会变成Yellow。replica的作用主要包括:
分片和副本机制
1.一个index中包含多个shard
2.每个shard都是一个最小工作单元,承载部分数据;每个shard都是一个Lucene实例,有完整的建立索引和处理请求的能力
3.增减节点时,shard会自动在nodes中负载均衡
4.primary shard 和 relica shard,每个document只会存在于某一个primary shard以及其对应的replica shard中,不可能存在于多个primary shard中
5.replica shard 是primary shard 的副本,负责容错,以及承担读请求的负载均衡
6.primary shard在创建索引的时候就固定了,relica shard的数量可以随时更改
7.primary shard 和 它对应的replica shard 不能放在同一台机器上,不然起不了容错的作用
shard&replica机制梳理总结
- index包含多个shard
- 每个shard都是一个最小工作单元,承载部分数据,lucene实例,完整的建立索引和处理请求的能力
- 增减节点时,shard会自动在nodes中负载均衡
- primary shard和replica shard,每个document肯定只存在于某一个primary shard以及其对应的replica shard中,不可能存在于多个primary shard
- replica shard是primary shard的副本,负责容错,以及承担读请求负载
- primary shard的数量在创建索引的时候就固定了,replica shard的数量可以随时修改
- primary shard的默认数量是5,replica默认是1,默认有10个shard,5个primary shard,5个replica shard
- primary shard不能和自己的replica shard放在同一个节点上(否则节点宕机,primary shard和副本都丢失,起不到容错的作用),但是可以和其他primary shard的replica shard放在同一个节点上,因此,这个index是由6个shard组成的
多shard 下是如何进行查询
一个 CRUD 操作只对单个文档进行处理,文档的唯一性由 _index, _type, 和 routing values (通常默认是该文档的 _id )的组合来确定。 这表示我们确切的知道集群中哪个分片含有此文档。
搜索需要一种更加复杂的执行模型因为我们不知道查询会命中哪些文档: 这些文档有可能在集群的任何分片上。 一个搜索请求必须询问我们关注的索引(index or indices)的所有分片的某个副本来确定它们是否含有任何匹配的文档。
但是找到所有的匹配文档仅仅完成事情的一半。 在 search 接口返回一个 page 结果之前,多分片中的结果必须组合成单个排序列表。 为此,搜索被执行成一个两阶段过程,我们称之为 query then fetch
所以jdk8选择了parallelOld作为老年代的垃圾收集器
POST _sql/translate
{"query": "SELECT id FROM mtds_production_order_alias WHERE createDt > 1618797600000 ORDER BY id DESC limit 10"
}
https://www.elastic.co/guide/cn/elasticsearch/guide/current/making-text-searchable.html
es课程
第一问:什么是 分片 , 什么是 副本?
什么是动态模板?作用是什么?
索引别名 和 零停机
分片内部原理
在 集群内的原理, 我们介绍了 分片, 并将它 描述成最小的 工作单元 。但是究竟什么 是 一个分片,它是如何工作的? 在这个章节,我们回答以下问题:
为什么搜索是 近 实时的?
为什么文档的 CRUD (创建-读取-更新-删除) 操作是 实时 的?
Elasticsearch 是怎样保证更新被持久化在断电时也不丢失数据?
为什么删除文档不会立刻释放空间?
refresh, flush, 和 optimize API 都做了什么, 你什么情况下应该使用他们?
最简单的理解一个分片如何工作的方式是上一堂历史课。 我们将要审视提供一个带近实时搜索和分析的 分布式持久化数据存储需要解决的问题。
https://www.elastic.co/guide/cn/elasticsearch/guide/current/dynamic-indices.html
动态更新索引
下一个需要被解决的问题是怎样在保留不变性的前提下实现倒排索引的更新?
答案是: 用更多的索引。
索引与分片的比较
被混淆的概念是,一个 Lucene 索引 我们在 Elasticsearch 称作 分片 。 一个 Elasticsearch 索引 是分片的集合。 当 Elasticsearch 在索引中搜索的时候, 他发送查询到每一个属于索引的分片(Lucene 索引),然后像 执行分布式检索 提到的那样,合并每个分片的结果到一个全局的结果集。
refresh_interval
refresh_interval 需要一个 持续时间 值, 例如 1s (1 秒) 或 2m (2 分钟)。 一个绝对值 1 表示的是 1毫秒 --无疑会使你的集群陷入瘫痪。
持久化变更
如果没有用 fsync 把数据从文件系统缓存刷(flush)到硬盘,我们不能保证数据在断电甚至是程序正常退出之后依然存在。为了保证 Elasticsearch 的可靠性,需要确保数据变化被持久化到磁盘。
这个行为可以通过设置 durability 参数为 async 来启用
这个选项可以针对索引单独设置,并且可以动态进行修改。如果你决定使用异步 translog 的话,你需要 保证 在发生crash时,丢失掉 sync_interval 时间段的数据也无所谓。请在决定前知晓这个特性。
段合并
由于自动刷新流程每秒会创建一个新的段 ,这样会导致短时间内的段数量暴增。而段数目太多会带来较大的麻烦。 每一个段都会消耗文件句柄、内存和cpu运行周期。更重要的是,每个搜索请求都必须轮流检查每个段;所以段越多,搜索也就越慢。
Elasticsearch通过在后台进行段合并来解决这个问题。小的段被合并到大的段,然后这些大的段再被合并到更大的段
在这种情况下,使用optimize优化老的索引,将每一个分片合并为一个单独的段就很有用了;这样既可以节省资源,也可以使搜索更加快速:
结构化搜索
结构化搜索(Structured search) 是指有关探询那些具有内在结构数据的过程。比如日期、时间和数字都是结构化的:它们有精确的格式,我们可以对这些格式进行逻辑操作。比较常见的操作包括比较数字或时间的范围,或判定两个值的大小。
文本也可以是结构化的。如彩色笔可以有离散的颜色集合: 红(red) 、 绿(green) 、 蓝(blue) 。一个博客可能被标记了关键词 分布式(distributed) 和 搜索(search) 。电商网站上的商品都有 UPCs(通用产品码 Universal Product Codes)或其他的唯一标识,它们都需要遵从严格规定的、结构化的格式。
精确值查找
当进行精确值查找时, 我们会使用过滤器(filters)。过滤器很重要,因为它们执行速度非常快,不会计算相关度(直接跳过了整个评分阶段)而且很容易被缓存。我们会在本章后面的 过滤器缓存 中讨论过滤器的性能优势,不过现在只要记住:请尽可能多的使用过滤式查询。
term 查询数字
我们首先来看最为常用的 term 查询, 可以用它处理数字(numbers)、布尔值(Booleans)、日期(dates)以及文本(text)。
在 Elasticsearch 的查询表达式(query DSL)中,我们可以使用 term 查询达到相同的目的。 term 查询会查找我们指定的精确值。作为其本身, term 查询是简单的。它接受一个字段名以及我们希望查找的数值:
{"term" : {"price" : 20}
}
POST _sql/translate
{"query": "SELECT id FROM mtds_production_order_alias WHERE createDt > 1618797600000 ORDER BY id DESC limit 10"
}
由于倒排索引表自身的特性,整个字段是否相等会难以计算,如果确定某个特定文档是否 只(only) 包含我们想要查找的词呢?首先我们需要在倒排索引中找到相关的记录并获取文档 ID,然后再扫描 倒排索引中的每行记录 ,查看它们是否包含其他的 terms 。
可以想象,这样不仅低效,而且代价高昂。正因如此, term 和 terms 是 必须包含(must contain) 操作,而不是 必须精确相等(must equal exactly)
存在查询
第一件武器就是 exists 存在查询。这个查询会返回那些在指定字段有任何值的文档,让我们索引一些示例文档并用标签的例子来说明:
缺失查询
这个 missing 查询本质上与 exists 恰好相反:它返回某个特定 无 值字段的文档,与以下 SQL 表达的意思类似:
搜索服务平台建议对批量创建/更新接口的请求文档数量进行限制,并重新优化通过MQ同步数据的方式的代码,结合22号CRM同步90万条数据导致搜索服务平台OOM的情况。
阿里云ES集群建议升级数据节点配置,ES属于计算密集型服务,提升CPU核数和内存都能让集群性能得到显著提升,以目前出现的性能瓶颈来看,也确实是CPU算力和内存不足。建议升级数据节点核数和内存大小和新增两个数据节点(现有两个数据节点升级到4核16G,新增两个4核16G数据节点)
ElasticSearch 核心概念
我们类比我们熟悉的 mysql 数据库:对比如下
ES -> mysql
索引index -> 表
文档 document -> 行(记录)
字段 fields -> 列
同样的,类比关系型数据库,文档相当于一行记录,是最小的数据存储单位。一个索引可以包含无数个文档,可以说索引是由文档组成的。在ES中,数据是以JSON格式进行存储的,如下就是一个完整的文档数据:
{"_index" : "miop_search_role_2020-8-3", // 数据所在的索引名称"_type" : "_doc","_id" : "1","_score" : 1.0,"_source" : { // 如果我们在indexing的时候把source存储起来 查询的时候原始数据就会在这里展示"birthday" : "1998-05-20","lastUpdateDt" : "2020-08-03T16:25:34.651","name" : "九号测试","remark" : "admin","id" : "1","createDt" : "2020-08-03T16:25:34.651","age" : 18}
}
注:早些版本的ES中还存在一个_type的概念,相当于我们理解的表,后来在7.x以后的版本中已经将此概念移除。
倒排索引
往ES中写入数据的过程也是创建倒排索引的过程,我们如何去快速理解倒排索引呢?比如我们要插入两条数据,其中有一个字段content的内容分别是He lost his cellphone yesterday ,He emailed me yesterday,如下所示
这是因为ES对数据进行了拆词处理,它会将一段文本内容拆成若干份,每一份叫做一个词项。在ES中,只有text文本类型的字段可以被分词。不仅写入的时候会对文本进行分词,searching检索的时候也同样会对搜索内容进行分词。
假若我们对content进行查询,查询内容是He brought cellphone yesterday,ES首先对查询的内容进行分词,得到用户要搜索的所有词条,然后拿着这些词条去倒排索引列表中进行匹配。找到这些词条就能找到包含这些词条的所有文档的编号,最后根据这些编号去文档列表中找到文档.
假如上述查询内容能被分词为:He、 brought 、 cellphone 、yesterday,然后ES会把这些词与倒排索引进行匹配:
根据上面的匹配结果,我们就可以检索出包含我们查询内容的文档是0、1。
注:searching和indxing时进行的分词是相互独立的操作,如上述的例子,如果我们单独检索brought这个文本,是搜不到结果的,因为没有在倒排索引中维护这个词项,这也是很多业务系统发现查询结果和期望结果不一致的主要原因之一.
索引别名
别名是ES中很好用的一个功能,它可以方便我们管理查询我们的多个索引。例如,我有两个数据量不同的索引,一个百万级,一个亿级,我想将两个索引合并在一起查询,那我们就可以给这两个索引设置相同的别名。我们查询的时候使用别名进行查询即可。
在搜索服务平台中,我们将索引的粒度划分成了日、月、年。在创建索引的时候,根据日期粒度的不同,搜索服务平台就可能会在每一天、每一个月或者每一年产生不同的索引,并且公用一个索引别名,这有点类似传统数据库中的分库。这么做的原因是为了方便后期业务的扩展,比如业务突然增长导致之前规划的分片数量不够,我们就可以在新的索引上进行配置,同时和旧索引共用一个别名既可以查询旧数据,也可以查询新的数据
注:多个索引公用一个别名进行查询时,查询的字段类型必须是一致的,比如字段name在index1中的类型是text,而在index2中的类型是keyword,查询是会抛异常的
索引模板
索引模板的作用如其名称,就是为了统一规范一个索引的一些公共配置(如分配配置、字段映射)。比如下面的索引模板,我们就规定了它的分片数量,匹配该模板的索引名称规则,以及索引的刷新时间等:
{"production_order_template" : {"order" : 0,"index_patterns" : ["production_order_*" // 匹配该条索引模板的索引名称],"settings" : {"index" : {"number_of_shards" : "2", // 主分片数量"number_of_replicas" : "2", // 副分配数量"refresh_interval" : "5s" // 刷新时间 既数据写入磁盘的时间间隔}},"mappings" : {"properties" : {"relationNo" : {"type" : "keyword"},"orderType" : {"type" : "keyword"},"serviceOrderStatus" : {"type" : "integer"},"customerSupplyMatching" : {"type" : "keyword"},"specialButton" : {"type" : "integer"},"drawingVariable" : {"type" : "integer"},"purchaseOrderItem" : {"type" : "keyword"},"orgId" : {"type" : "keyword"},"customerPhone" : {"type" : "keyword"},"expectDeliveryDt" : {"type" : "date"},"planDeliveryDt" : {"type" : "date"},"estateAbbreviation" : {"type" : "keyword"},"remark" : {"search_analyzer" : "ik_smart","analyzer" : "ik_smart","type" : "text"}}},"aliases" : { }}
}
1. 为什么接入搜索服务平台要创建索引模板?可不可以不创建?
不行。
很多人在接入搜索服务平台之前都很好奇,既然ES的Dynamic Mapping那么好用那么灵活,我们为什么还需要在创建索引之前先建一个索引模板?
建立索引模板主要的目的是为了规范业务索引的字段映射,以及统一管理索引分片配置。例如,在接入业务前期,想要直接预估索引的数据规模是很困难的,而一个索引能够承载的数据量主要和分片数量有关,分片数量越多(前提集群节点数量也足够多)能够承载的查询能力越大。如果我们前期误把数据量估小了,或者估大了,想要改就很蛋疼了。因为像分片设置,和字段映射属性,一旦创建了就不可修改,想要修改,你就得重新indxing。按照搜索平台的设计,索引会以年、月、日进行划分,如果哪天发现分片不够用,我们就可以通过改索引模板的方式来让未来的索引使用新的分片配置。同时,由于公用一个索引别名的不同索引字段类型必须一致才能进行查询,建立索引模板也是为了规范这些字段的映射关系。
2. 为什么写入数据后查询不到,而是过了一会儿才看到写入的数据?
ES写入数据成功后并不是马上刷到磁盘的,而是暂时写到内存的一个缓冲区,ES会周期地将缓冲区的数据刷入磁盘(这其实是lunce的机制)。因此返回写入成功后并不能马上查询到数据是正常的。所以,请根据具体的业务场景来使用ES,它并不太适合用来做缓存。
refreshInterval
你可以用它来在创建/更新模板的时候通过设置refreshInterval属性来控制索引的刷新频率
4. 业务需要增加字段,可不可以不更改索引模板?如果更改,需要重新同步索引数据吗?
增加字段是否需要更改索引模板视情况而定,比如你需要增加的是不用拿来查询的字段,那就不需要更改索引模板,让ES自己Dynamic Mapping即可。但是我还是强烈建议业务方在增加字段的时候更改索引模板,以免后续接手项目的小伙伴一脸懵逼:为什么模板才几个字段,但是查询出来的结果有几十个字段?并且,如果你不能保证新增字段以后一定不被查询,那还是现在麻烦点,更改一下索引模板吧。
如果更改索引模板,需要重新同步索引数据么?
这个其实分两种情况,一种是单纯的新增字段,是不需要重新同步的;第二种是你更改了某个字段的类型(比如从integer改成long),那就需要重新同步了。这是必须的,因为同一个别名下查询的字段类型必须一致,而且索引一旦创建,字段映射不可修改(ES就是这么蛋疼)。想要避免这种情况,建议业务方在定义字段类型的时候尽量做到向下兼容,比如能定义成long的就不要定义成integer,能定义成double的就不要定义成float等。
5.我刚刚同步了几十万条数据,为什么我看到ES上只有1万条?
如果你指看到的1万条是下面这样:
{"took" : 3,"timed_out" : false,"_shards" : {"total" : 26,"successful" : 26,"skipped" : 0,"failed" : 0},"hits" : {"total" : {"value" : 10000,// 一共1万条记录"relation" : "gte"},"max_score" : 1.0,"hits" : [...]}
}
那是因为ES默认的总窗口大小就是1万条,如果你想查看全部记录数,可以加上track_total_hits=true这个参数,比如
查询命令:
GET mtds_production_order_alias/_search?track_total_hits=true
{"took" : 3,"timed_out" : false,"_shards" : {"total" : 26,"successful" : 26,"skipped" : 0,"failed" : 0},"hits" : {"total" : {"value" : 235726,"relation" : "gte"},"max_score" : 1.0,"hits" : [...]}
}
集群相关
分片(shard):把索引库拆分为多份,分别放在不同的节点上,比如有3个节点,3个节点的所有数据内容加在一起是一个完整的索引库。分别保存到三个节点上,目的为了水平扩展,提高吞吐量。
备份(replica):每个shard的备份。
简称
shard = primary shard(主分片)
replica = replica shard(备份节点)
磁盘阵列或者NAS的raid0+1
索引的一些操作:
集群健康
GET /_cluster/health
创建索引
PUT /index_test
{
“settings”: {
“index”: {
“number_of_shards”: “2”,
“number_of_replicas”: “0”
}
}
}
查看索引
GET _cat/indices?v
删除索引
DELETE /index_test
lucene总结
ElasticSearch 小记相关推荐
- elasticsearch配置小记
2019独角兽企业重金招聘Python工程师标准>>> elasticsearch配置小记 博客分类: 搜索引擎,爬虫 基于 elasticsearch 1.4.4 版本.安装方式为 ...
- Elasticsearch搜索与排序经验小记
最近维护公司的APP搜索项目,在实际需求中,领导对搜索关心两方面,第一要搜出来,第二排序要符合人的搜索习惯,最近一段时间的搜索经验记录下来分享一下. '牛奶木瓜' 是怎么搜出来的? 先来说说Elast ...
- elasticsearch 复杂查询小记
以下接口调用都基于5.5版本 JSON 文档格式 {"_index": "zipkin-2017-09-06","_type": " ...
- Docker部署Elasticsearch集群
来源:https://www.cnblogs.com/lixuebin/p/10814052.html 参考文档: https://hub.docker.com/r/library/elasticse ...
- Elasticsearch学习之路(一)
一.前序 1.1正向索引和倒排索引 ** 正向索引通常用于数据库中,在搜索引擎领域使用的最多的就是倒排索引 ** 通过例子表示: 我爱编程, 我爱编程,我是小码农 1.1.1 正向索引 假设我们使用m ...
- 2021年大数据ELK(二十五):添加Elasticsearch数据源
全网最详细的大数据ELK文章系列,强烈建议收藏加关注! 新文章都已经列出历史文章目录,帮助大家回顾前面的知识重点. 目录 添加Elasticsearch数据源 一.Kibana索引模式 添加Elast ...
- 2021年大数据ELK(十九):使用FileBeat采集Kafka日志到Elasticsearch
全网最详细的大数据ELK文章系列,强烈建议收藏加关注! 新文章都已经列出历史文章目录,帮助大家回顾前面的知识重点. 目录 使用FileBeat采集Kafka日志到Elasticsearch 一.需求分 ...
- 2021年大数据ELK(十七):Elasticsearch SQL 订单统计分析案例
全网最详细的大数据ELK文章系列,强烈建议收藏加关注! 新文章都已经列出历史文章目录,帮助大家回顾前面的知识重点. 目录 订单统计分析案例 一.案例介绍 二.创建索引 三.导入测试数据 四.统计不同支 ...
- 2021年大数据ELK(十六):Elasticsearch SQL(职位查询案例)
全网最详细的大数据ELK文章系列,强烈建议收藏加关注! 新文章都已经列出历史文章目录,帮助大家回顾前面的知识重点. 目录 职位查询案例 一.查询职位索引库中的一条数据 二.将SQL转换为DSL 三.职 ...
最新文章
- python 图像分析自然纹理方向与粗细代码_python skimage图像处理(二)
- Xilinx Select IO的介绍
- 权重初始化时除以前一层的神经元个数开方的意义
- 装车机器人_15秒装车!行李智能分拣机器人亮相厦门机场
- 计算机应用技术滨江计划,杭州高新区(滨江)列出干货满满的“计划表”
- 罗盘时钟代码(转载)
- 服务稳定性及应用防护方案
- cname 别名记录 解析过程_云解析是什么?需要购买吗?
- Vmware虚拟机不能使用键盘的解决方法
- Oracle 10g学习笔记(一)
- python工资一般多少西安-python西安薪资
- 廖雪峰python教程-Python简介
- excel合并两列内容_必看!Excel数据合并的这3个小技巧,千万要学会……
- java鼠标点击按钮事件_Java学习——GUI编程(鼠标单击按钮事件)
- 中国涂料工业协会:世界十大涂料品牌2011年度报告
- 【Python】盘点全网下载量Top100的Python库
- 小游戏赛道如何加速流量增长?
- 编辑器如何加载多张图片
- 2022劳务员-岗位技能(劳务员)考试试题及答案
- 卸载cuda,以及N卡驱动
热门文章
- 分布式session的6种解决方案
- 微信小程序 promise 化
- java.sql.SQLException: Parameter index out of range (5 > number of parameters, which is 4).
- golang 学习笔记
- vue_ form表单 v-model
- Maven依赖的Scope去除部署不需要的jar 包(打包)
- 妙趣横生的算法--二叉树
- POJ 1183 反正切函数的应用(数学代换,基本不等式)
- Java线程面试题TOP50
- Nginx模块开发—Nginx代码规范