一、简介
可以处理PB级数据的大型分布式集群技术;
由全文检索、数据分析以及分布式技术结合而成:如lucene(全文检索)、分布式数据库(mycat)等;
对用户而言,是开箱即用的,非常简单;
ES提供的功能,如全文检索、同义词处理、相关度排名、复杂数据分析、海量数据的近实时处理;
二、应用场景
维基百科使用ES提供带有高亮片段的全文搜索,还有 search-as-you-type 和 did-you-mean 的建议;
卫报使用ES将网络社交数据结合到访问日志中,实时的给它的编辑者提供公众对于新文章的反馈;
Stack Overflow将地理位置查询融入全文检索中,并且使用more-like-this接口去查找相关问题的答案;
Github使用ES对1300亿行代码进行查询;
三、基本概念
ES存储和检索的是json文档;
在ES中,每个字段的所有数据都是默认被索引的,即每个字段都为了快速检索设置的专用倒排索引;
文档:指定了唯一ID的JSON对象;
文档元数据:index:文档在哪存放、type:文档表示的对象类别、id:文档唯一标识;比如website/blog/1;
四、集群内原理
•ElastiSearch如何通过管理多节点来提高扩容性和可用性?
一、概念:
节点:一个运行中的ES实例。
集群:一个或者多个拥有相同cluster.name配置的节点。
主节点:从节点中选举产生,负责管理集群内的所有变更。
空集群:不包含任何的数据和索引的单独节点。
二、ES集群的重要指标:集群健康。
•可用curl -X GET “localhost:9200/_cluster/health”命令查看。
•status字段指示着当前集群在总体上是否正常工作:
•green:所有的主分片的副本分片都正常运行。
•yellow:所有的主分片都正常运行,但不是所有的副本分片都正常运行。
•red:有主分片没能正常运行。
三、举例说明ES集群的水平拓容和节点的失效处理:
在包含一个空节点的集群内创建名为blogs的索引,分配3个主分片和一个副本分片。
此时集群处于yellow状态。
当第二个节点加入到集群后,3个副本分片将会分配到这个节点上。
此时系统处于green状态。
当第三个节点加入到集群后,Node1和Node2上各有一个分片被迁移到了Node3。
我们这个拥有6个分片的索引可以最大拓容到6个节点。
主分片的数目在索引创建时就确定下来了,如果我们想要更多的拓容,可以调整副本分片的数目,比如我们把副本数从1改为2。
此时集群处于上图的状态,每个节点包含三个切片。
如果关闭主节点,集群会选取一个新的主节点。
新的主节点会将丢失的主分片在node2和node3上对应的副本分片提升为主分片。
五、映射和分析
一、倒排索引
•ES使用一种称为倒排索引的结构,它适用于快速的全文搜索。
•假设我们有两个文档,每个文档的content域包含如下内容:
•The quick brown fox jumped over the lazy dog
•Quick brown foxes leap over lazy dogs in summer
二、分析器
•分析包含下面的过程:
•将一块文本分成适合于倒排索引的词条
•将这些词条统一为标准格式以提高它们的“可搜索性”
•分析器执行上面的工作。分析器实际上将三个功能封装到一个包里。
•字符过滤器:在分词前整理字符串。例如用来除去HTML,或者将&转换成‘and’
•分词器:将文本拆分成词条
•Token过滤器:改变词条(例如,小写化 Quick ),删除词条(例如, 像 a`, `and`, `the 等无用词),或者增加词条(例如,像 jump 和 leap 这种同义词)。
三、排序相关性
•Fuzzy查询会计算与关键词的拼写相似程度;terms查询会计算找到的内容与关键词组成部分的百分比; relevance会计算全文本字段的值相对于全文本检索词的相似度。
•每个文档都有相关性评分,用一个正浮点数_score来表示,_score的评分越高,相关性越高。
•ES的相似度算法:TF/IDF
•检索词频率:检索词在改字段出现的频率,出现的频率越高,相关性越高
•反向文档频率:每个检索词在索引中出现的频率,频率越高,相关性越低。检索词出现在多数文档中会比出现在少数文档中的权重更低。
六、分布式文档存储
一、路由规则
•shard = hash(routing) % number_of_primary_shards
•routing:默认是文档id
•number_of_primary_shards:主分片的数量
二、主副本交互
1.客户端向Node1发送新建、索引或者删除请求。
2.节点使用文档的 _id 确定文档属于分片 0 。请求会被转发到 Node 3,因为分片 0 的主分片目前被分配在 Node 3 上。
3. Node 3 在主分片上面执行请求。若成功,它将请求并行转发到 Node 1 和 Node 2 的副本分片上。当所有副本分片都报告成功, Node 3 将向协调节点报告成功,协调节点向客户端报告成功。
三、局部更新
局部更新多了一步:检查文档是否被另一进程修改,若在被修改,它会重试步骤 3 ,超过 retry_on_conflict 次后放弃。
七、执行分布式索引
一、查询阶段
1.客户端发送一个search请求到Node3,Node3会创建一个大小为from+size空优先队列。
2.Node3将查询请求转发到索引的每个主分片或副本分片中。每个分片在本地执行查询并添加结果到大小为from+size的本地优先队列中。
3.每个分片返回各自优先队列中所有文档的ID和排序值给协调节点,也就是Node 3,它合并这些值到自己的优先队列中来产生一个全局排序后的结果列表。
二、取回阶段
1.协调节点辨别出哪些文档需要被取回并向相关的分片提交多个GET请求。
2.每个分片加载并丰富文档,如果有需要的话,接着返回给协调节点。
3.一旦所有的文档都被取回了,协调节点返回结果给客户端。
八、分片内部原理
•为什么搜索是近实时的?
•为什么文档的CRUD操作是实时的?
•ES怎样保证更新的持久化在断电时也不丢失数据?
•为什么删除文档不会立刻释放空间?
•refresh、flush、和optimize API都做了什么,什么情况下使用它们?
一、使文本可搜索
•为每个字段建立倒排索引,在ES中会包含更多的信息。比如在对应的文档中一个具体词项出现的总次数、词项在文档中的顺序、每个文档的长度、文档的平均长度。ES利用这些信息决定哪些词、哪些文档更重要。
•ES中的倒排索引是不可改变的:
•不需要锁
•缓存在内存中
•其它缓存,在索引的生命周期内始终有效。
•倒排索引允许数据被压缩
•那么如何更新索引?
二、动态更新索引
•ES基于Lucene,该库引入了按段搜索的概念,每一段都是一个倒排索引。
•1.新文档被搜集到内存索引缓存
•2.不时地,缓存被提交:
•一个新的段被写入磁盘
•一个包含新段名字的提交点被写入磁盘
•磁盘同步-所有在文件系统缓存中等待的写入都刷新到磁盘
•3.新的段被开启,使它包含的文档可搜索
•4.内存缓存被清空,等待接受新的文档
三、近实时搜索
•磁盘瓶颈:提交新的段到磁盘需要fsync来确保段被写入磁盘。每次索引一个文档都去执行一次同步磁盘操作会造成很大的性能问题。
•解决之道:文件系统缓存。新段会被先写到文件系统缓存,稍后被刷新到磁盘。只要文件已经在缓存中,就可以像其它文件一样被打开和读取了。
•refresh API:默认情况下每个分片每秒刷新一次,这意味着文档的变化在一秒之内对搜索可见。
四、持久化变更
•两次提交之间变化的文档咋办?ES增加了一个translog机制。
•一个文档被索引后,就会被添加到内存缓冲区,并且追加到translog
•Translog提供所有还没有被刷到磁盘的操作的一个持久化记录。ES重启时,它会从磁盘中使用最后一个提交点去恢复已知的段,并且会重放 translog 中所有在最后一次提交后发生的变更操作。
•translog 也被用来提供实时 CRUD 。当你试着通过ID查询、更新、删除一个文档,它会在尝试从相应的段中检索之前, 首先检查 translog 任何最近的变更。
五、段合并
•每秒创建一个段,段数量暴增,拖慢搜索速度。
•ES解决方法:小段变大段,大段变更大的段。
•当索引的时候,刷新操作会创建新的段并将段打开以供搜索。
•合并进程选择一小部分大小相似的段,并且在后台将它们合并到更大的段中。并不会中断索引和搜索。
•optimize API:强制合并。
九、文档更新及冲突解决
一、文档更新
•在ES中文档是不可变的。若更新,需要重建索引后者进行替换。
•调用update API时,ES的执行过程:
•1.从旧文件构建JSON
•2.更改旧文档
•3.删除旧文档
•4.索引一个新文档
•删除文档不会立即将文档从磁盘中删除,将文档标记为已删除状态,在段合并阶段清理标记为已删除的文档。
二、冲突解决
•悲观并发控制:这种方法被关系型数据库广泛使用,假定有变更冲突可能发生,因此阻塞访问资源防止冲突。
•乐观并发控制:ES中使用的这种方法假定冲突是不可能发生的,并且不会阻塞正在尝试的操作。如果愿数据在读写当中被修改,更新将会失败。
•当文件创建、更新或删除时,新版本的文档必须复制到集群中的其他节点,由于ES是异步和并发的,意味着复制请求到达目的节点时可能是乱序的。
•每个文档文档有个_version的版本号,当文件被修改时版本号递增。如果旧版本的文档在新版本之后到达,可以被简单的忽略。