第一章 简介
segment被创建后不会再被修改;文档删除后,删除信息单独保存在一个文件中,segment本身并没有被修改;segement合并期间,无用信息会被删掉,比如被删除的文档;
norm: 存储文档的归一化结果,基于文档的加权值(boost)计算得出;
term vector: ?
doc values: 应对分组、排序、聚合,建立的正排索引;
(文档转为倒排索引,查询串转为用于搜索的term),都是analysis过程(分析过程):1.字符映射器(character mapper)(例如HTML文本的去标签处理);2.分词器(tokenizer); 3.过滤器(filter): 小写过滤器,ASCII过滤器, 同义词过滤器(把词条转换为同义词条),stemming过滤器;
有些查询可以不被分析,比如前缀查询(prefix query)不会被分析,匹配查询(match query)会被分析;
索引与query要采用同样的分析器;
模糊查询(fuzzy): 可以指定和query串的最大编辑距离是几个字母
ES中的索引可能由一个或多个Lucene索引构成(分片、复制);类型:为不同的文档类型提供不同的映射;分片数在索引创建时指定好之后就无法改变;主分片宕机后master会从副本中选一个作为新的主分片;
ES集群,是对等架构(P2P)设计,可避免单点故障;
集群启动过程:节点配置文件中指定集群名称,启动时会向网络中发送广播请求,同集群名称的其他节点会响应;集群中只有一个节点会被选为master节点;用户查询请求可以发送给任意节点,这个节点会转发给所有该索引的主分片节点,各自在各自分片上查询和打分,结果返回给该节点进行合并和排序,最后返回给用户;
master把所有索引的主分片都落实后,集群进入黄色状态;副本分片都落实后(找到或者复制完毕),集群进入绿色状态;
集群节点之间的故障检测是通过互相ping实现的;
bulk API,一次发送一批请求;DSL是一种查询语言;查询里的文档过滤,是不影响评分的前提下过滤文档;
第二章 查询DSL
评分公式包括:1. 文档d命中查询q的词项越多,分越高;2.对于每个query和文档匹配上的词:该词在d的这个字段中的TF越高,分越高;该词的IDF越高,分越高;该词的权重越高,分越高;该文档d的这个字段的长度越短,分越高;
_explain可以看到查询的评分计算过程;
前置过滤的过滤结果可以被缓存起来供后续查询使用;前置过滤是过滤-->查询-->返回结果; 后置过滤是查询-->过滤-->返回结果; 原则:开销最大的操作最好移动到链条的尾部;所以,如果过滤器执行很快开销很小异域缓存,则用前置过滤好;如果过滤器执行很慢开销很大难于缓存,则用后置过滤好;
match对查询进行分析(分词等操作),term对查询不分析(可以查数组字段里是否包含某个标签);prefix对查询不分析;
dis_max查询,可以让最高得分的查询子句在打分中起决定作用;打分=max(各子查询的得分)+tie_breaker*(非最高得分子查询的得分之和);tie_breaker如果设为0则只考虑最高得分子查询;
simple_query_string查询,可以对错误的查询有容错功能;
模糊查询:fuzzy, more_like_this等;
自定义打分:function_score等;
位置敏感查询:两个词之间不能超过几个词的距离:match_phrase
must是必须有才召回,should是有的话加分没有也行;
聚合:可以使用HyperLogLog+算法实现近似计数;百分比聚合,可以用于分析数据分布(观察方差和噪声);
第三章 没啥用
查询二次评分:系统自带的第一次评分,有些像召回粗排阶段;用户自定义的第二次评分(召回结果之后),有些像Ranking阶段精排;
多匹配控制;重要词项聚合;分档分组;文档关系;啥意思?
第四章 改善用户搜索体验
改正用户拼写错误:suggestor; 用户输入某个查询,系统能给出一个纠错词/短语的列表;
提升查询效果的例子:1.multi_match+指定字段权重,可以让title中出现过查询词的doc比正文中出现过查询词的doc,排名更高;2.bool+must+should+match_phrase+slop, 引入短语查询,让两个查询词离得够近才加分;3.用filter过滤掉包含垃圾字符的;4.可以设置boost_factor将短语查询的权重提高;5.设置ngram可以实现查询拼写纠错;6.切面处理(facet)?
第五章 分布式索引
数据量很少的时候,可以只使用一个分片,因为没必要扩容,多分片查询跨节点再合并的网络开销反而大;
多分片,可以使用路由,把关联性强的数据(比如同一用户)放到同一分片,查询时减少网络开销;多索引,是建立多份索引,查询的时候可以只查某个索引(比如把日志索引按照天来划分成多份索引)
分片的目的是为了解决单节点容量不够的问题(扩容);副本的目的是为了提升查询吞吐量和容错容灾;
往索引里添加文档的时候,指定路由字符串;查询的时候,指定路由字符串;两个路由字符串一样时,才会起到效果(查询只被一个分片执行);
使用_search_shards可以看到查询被哪些分片所执行;
allocation.awareness属性,可以设置同一个节点(机架)上的ES们具有相同的值,建立索引时系统就会考虑容灾而把主分片和副本分片尽量分散到不同值的ES里去;即具有相同值的ES节点不会同时包含某一分片的主本和副本; same_shard属性可以阻止主本和副本在同一台物理机上放。
都是可以配置的:每个ES节点允许的总分片数;每个物理机允许的总分片数;磁盘占用空间的上限(比如超过85%就不再分配新分片);主动搬走(磁盘超过90%,系统自动把其上的分片搬出去)
查询执行preference: 1. _primary:限制查询只在主分片上运行(如果提前知道该索引的所有主分片都在某个机架,可以不用麻烦其他机架的副本了);2._primary_first: 比_primary多了个不行则查副本的功能;3._local:优先在查询到达的这个节点上运行;4._only_node:只在指定的节点上查询;5._prefer_node:比_only_node多了不行则查其他节点的功能(_local上的分片不够全的时候); 6._shards:只查指定的那些分片; 7.自定义字符串:相同的字符串的查询,每次都会被发送到相同的分片集合上去执行;
以上可用于提高性能,或者debug; ES的默认行为是负载均衡,分片的所有主本和副本都有均匀的概率被访问。
第六章 底层索引控制
可以为每个字段配置不同的相似度模型;TF-IDF, BM25, ...
store类型:NIO类型的可以多线程同时访问且性能不大降;MMap的适合内存大的机器,读的时候会将整个文件映射到虚拟地址空间,缓存在内存,访问快;内存类型只将索引存储在内存里,不持久化;
索引segment的合并,可以配置选择3种不同的策略;有的参数会让合并优先选择被删文档多的segment;
索引segment合并对I/O消耗大,因此有一些参数来控制I/O最大使用量;
过滤器缓存:可限制内存使用上限;
字段数据缓存:查询涉及非倒排数据时的用到。可以选择哪些值可加载到缓存中,例如词频在某个区间的才缓存;默认是第一次读取时加载,可设置更激进的加载策略(一旦数据有更新就加载)
缓存可以手动用命令清除;
通过circuit breaker,设置当查询到来时,如果估计其使用内存太大,就拒不执行;
第六章 管理ElasticSearch
把node.master和node.data都设为false时,该节点讲只处理查询请求;
脑裂:10个节点,断了3个节点,但这3个节点彼此能通信,则这3个节点会选举出新的主节点,导致7个节点的集群和3个节点的集群出现;避免:设置要选主需要的最少候选master互联的数量,可设为集群机器总数的一半+1
第七章 提高性能
使用doc values比使用字段缓存,省内存;(为什么?)
堆大小可以超过32GB是,指针就得是64位得了,反而增大了内存开销;小而多次的垃圾回收调用,比大的一次性垃圾回收更推荐,因为太大的垃圾回收容易block住线程;jstat -gcutil和jmap -dump,为什么都不准?尽量避免swap到磁盘;
使用_bench和"competitors",可以让ES去对比N种查询方式的快慢;
可以看到集群里的热点线程;
分片有时也可以加速查询,一个分片在一台机器上时是串行处理的;
很小的索引:可以存到所有节点上,只一个分片,但是N个副本(N=节点数目)
高负载情况下的优化:1. 选择合适的存储(mmapfs, niofs, simplefs,... 默认是default_fs,根据文件的类型来选择最佳的文件系统,即niofs和mmapfs的混合); 2.索引刷新频率:索引实时性和查询性能的权衡;3.线程池调优;4.段合并:段太多了查询肯定变慢,合并太激进了硬盘吃不消,可以I/O限流;5.数据分布:尽量均衡;
高查询情况下的优化:1.过滤器缓存和分片查询缓存;2.静态、不分词的字段移到过滤器,可以利用上缓存;3.使用路由把关联性强的数据放到相同的分片;4.并行查询:索引如果只有一个很大的分片,查询无法多机并行,性能反而变差;5.字段数据缓存和doc values; 6。控制size和shard_size,聚合的时候能只查top就只查top减少数量上的压力;
高索引吞吐量下的优化:1.bulk索引;2.doc values与索引速度的取舍;3.控制文档的字段,尽可能存储少的字段;5.调整translog日志,太大了故障恢复时慢,太小了总得写磁盘(默认是达到512MB或者够30分钟就flush一次; flush和fsync的区别: flush是把内存缓冲区里的数据刷到磁盘的segment文件里,fsync是把translog刷到磁盘(默认5秒一次));6.使用SSD,别使用远程存储;7.提供给索引的内存缓存量
慢查询和慢索引日志:可以设置时间阈值,超过多少秒的就记录到日志里,便于后续分析;