ElasticSearch

ElasticSearch

ES的分布式架构:

  • 不同的集群通过不同的名字来区分,默认是“elasticsearch”

  • 每个节点都有名字,通过配置文件来配置

  • 每个节点启动后默认是Master eligible节点,可参加选主流程,成为master节点

  • 只有master节点才能修改集群的状态信息,但是每个节点都保存了集群的状态

    • 集群状态维护了所有的节点信息、所有的索引和其他相关的Mapping和Setting信息、分片的路由信息
    • 为一个集群设置多个Master节点/每个节点只承担Master的单一角色
  • 节点类型:

    • Data Node:可以保存数据的节点,负责保存分片数据,用来做水平扩展
    • Coordinating Node:负责接收Client请求,将请求分发到合适的节点,最终把结果汇集到一起,每个节点默认起到了Coordination Node的职责
    • Hot&Warm Node 降低部署成本,实现Hot&Warm架构。不同的机器配置
      • hot节点新文档写入,ssd
      • warm节点保存老数据,hdd
  • 分片:

    • 主分片:用来解决水平扩展问题,通过主分片可以将数据分布到集群内的所有节点上。一个分片是一个运行的Lucene的实例,且主分片数在索引创建时指定,后续不能修改。除非Reindex
    • 副本分片,用以解决数据高可用的问题,副本分片是主分片的拷贝,副本分片数可以动态调整,增加副本数可以提高读取的吞吐。
    • 7.0开始主分片默认设置成5->1,解决over-sharding的问题(每个分片都是完整的Lucene索引,它需要为索引的每个分段创建一些文件描述符,增加相应的内存开销,且影响搜索结果的相关性打分)应该通过切分成不同的索引来解决数据量过大的问题。
  • 创建/删除索引的请求,只能被Master节点处理。

  • Master Eligible Node&选主流程

    • 一个集群,支持配置多个Master Eligible节点,这些节点可以在必要时(如Master节点宕机)参与选主流程,成为Master节点
    • 每个节点启动后,默认就是一个Master Eligible节点
    • 当集群内第一个Master Eligible节点启动的时候,会将自己选举成Master节点
    • 互相ping对方,Node Id低的会称为被选举的节点
    • 脑裂问题:Node1网络断开,node2、3选举出一个master后,node1恢复网络,继续当做master。
    • 如何避免脑裂:限定一个选举条件,设置quorum(仲裁),只有在Master eligible节点数大于quorum时才能进行选举。7.0开始无需这个配置,让es自己选择可以形成仲裁的节点。https://www.jianshu.com/p/2ed01f0eea9c

分片与集群的故障转移

  • 通过主分片,将数据分布在所有节点上
    • 将一份索引的数据,分散在多个node上
    • 数量在创建索引的时候指定,后续默认不能修改,需要修改则需要重建索引
  • 主分片丢失,副本分片可以Promote成主分片,副本分片数量可以动态调整,每个节点上都有完备的数据,数量增加可以提高读取的吞吐,但是会降低写入性能。
  • 节点挂掉,节点上主分片的副本分片会变成主分片,同时会重新分片副本分片。

文档到分片的路由

  • hash算法确保文档均匀分散到分片中
  • 默认的_routing值是文档id
  • 可以自行指定rount数值
  • 设置index settings后,primary数,不能随意修改

倒排索引

正排:书本的目录/文档id到文档内容和单词的关联

倒排:索引页,列出每一个文章标题再那一页/单词到文档ID的关系

倒排索引包含两部分:

  • 单词词典:记录所有文档的单词,记录单词到倒排列表的关联关系,一般较大,可以通过B+数或者哈希拉链法实现
  • 倒排列表:记录了单词对应的文档结合,由倒排索引项组成
    • 倒排索引项:
      • 文档ID
      • 词频 TF,该单词在文档中出现的次数
      • 位置position,单词在文档中分词的位置
      • 偏移offset,记录单词的开始结束位置

这就是elasticsearch这个单词的倒排列表

es的JSON文档中的每个字段,都有自己的倒排索引,可以指定字段不做索引

  • 在Lucene中,单个倒排索引文件被称为Segment,segment是不可变更的,多个Segments汇总在一起,称为Lucene的Index,对应es中的Shard
  • 新文档写入时,会生成新Segment,查询时会查询所有Segments,并进行汇总,Commit Point会记录所有Segments的信息
  • 将Index buffer写入Segment的过程叫做Refresh,每秒发生一次,所以一秒后es就可以搜索到数据了。Refersh时会将Segment写入缓存以开放查询。
  • 如果有大量数据写入,会产生很多的Segment
  • 为了保证数据不丢失,所以在Index文档时,同时写Transaction Log,默认落盘,每个分片有一个Transaction Log。refresh时,index buffer会被清空,transaction log不会。
  • Flush,会调用Refresh并清空Index Buffer
    • 调用fsync,将Segments写磁盘
    • 清空Transaction Log
    • 默认30分钟调用一次
    • 或者Transaction Log满(512M)

分词

Character Fileter+Tokenizer+Token Filter

URI Search

GET /movies/_search?q=2012&df=title&sort=year:desc&from=0&size=10&timeout=1s

  • q指定查询语句,使用Query String Syntax
  • df默认字段,不指定时会对所有字段进行查询
  • sort 排序 / from和size用于分页
  • profile 可以查看查询是如何被执行的

Term v.s. Phrase

  • Beautiful Mind等效于Beautiful OR Mind
    • q=title:Beautiful Mind, 其中Beautiful是指定title字段的查询,Mind是泛查询
    • q=title:(Beautiful Mind)
  • “Beautiful Mind”,等效于Beautiful AND Mind。是Phrase查询,还要求前后顺序保持一致

分组与引号

  • title:(Beautiful Mind),title中有Beautiful或有Mind
  • title:“Beautiful Mind”,Phrase查询,title中有Beautiful Mind,而且顺序必须一致

布尔操作

  • AND / OR / NOT 或 && / || / !
    • 必须大写
    • title:(matrix NOT reloaded)

分组

  • +表示must
  • -表示must_not
  • title:(+matrix -reloaded)

范围查询

  • 区间表示:[]闭区间,{}开区间
    • year:{2019 TO 2018}
    • year:[* TO 2018]
    • kibana中 } 会导致dev tool出错,用%7D代替
  • 算数符号
    • year:>2010
    • year:(>2010 && <=2018)
    • year:(+>2010 && +<=2018)

通配符查询

  • ?代表1个字符,*代表0个或多个字符
    • title:mi?d
    • title:be*

正则表达

  • title:[bt]oy

模糊匹配与近似查询

  • title:beautifl~1
  • title:“lord rings”~2

Request Body & Query DSL

  • 将查询语句通过HTTP Request Body发送给Elasticsearch
  • Query DSL
POST /movies,404_idx/_search?ignore_unavailable=true
{
    "profile":true,
    "from":10,
    "size":20,//分页,获取靠后的翻页成本高
    "sort":[{"order_date":"desc"}],//排序
    "query":{
        "match_all":{}
    }
}
  • 最好在“数字型”与“日期型”字段上排序
  • 因为对于多值类型或分析过的字段排序,系统会选一个值,无法得知该值

source filtering

#Last或Christmas出现
GET /comments/_doc/_search
{
    "query":{
        "match":{
            "comment":"Last Christmas"
        }
    }
}
#Last和Christmas同时出现
GET /comments/_doc/_search
{
    "query":{
        "match":{
            "comment":{
                "query":"Last Christmas",
                "operator":"AND"
            }
        }
    }
}
#slop中间可以有一个其它的字符进入
GET /comments/_doc/_search
{
    "query":{
        "match_phrase":{
            "comment":{
                "query":"Song Last Christmas",
                "slop":1
            }
        }
    }
}

Mapping

  • 定义索引中的字段的名称

  • 最好为Mapping加入Meta信息,进行版本管理

  • 定义字段的数据类型,例如字符串,数字,布尔

  • 字段,倒排索引的相关配置

  • Mapping会把JSON文档映射出Lucene所需要的扁平格式

  • 一个Mapping属于一个索引的Type

    • 每个文档都属于一个Type
    • 一个Type有一个Mapping敌营
    • 7.0开始无需指定type信息
  • Mapping的简单类型:

    • Text/Keyword :full-text 表示字段内容会被分析,而 keywords 表示字段值只能作为一个精确值查询。
      • text适用于全文本字段,会被分词,默认不支持聚合分析及排序
      • keyword使用与id,枚举及不需要分词的文本,比如电话号码,性别等需要精确匹配的,可以sorting和aggregations
      • 默认会喂文本类型设置成text,并且设置一个keywords的子字段。
    • Date
    • Integer/Floating
    • Boolean
    • IPV4&IPV6

Dynamic Mapping

  • 当索引不存在时,会自动创建索引,如果没有定义Mappings,会根据文档信息,推算出字段的类型

  • 当设置为true,一旦有新字段写入,会同时更新Mapping

  • 设置为false,mapping不会更新,也无法被索引,信息会出现在_source中

  • 设置为Strict,文档写入失败

  • 已有的字段,一旦已经有数据写入了,就不能修改字段定义,除非Reindex重建索引

  • mappings下的某个字段设置index为false,则不被索引,无法搜索。

Index Template

  • 帮助你设定Mappings和Settings,并按照一定的规则,自动匹配到新创建的索引之上
    • 模板仅在一个索引被新创建时,才会产生作用,修改模板不会影响已创建的索引
    • 可以设定多个索引模板,这些设置会被merge
    • 可以指定order的数值,控制merging的过程,order高的会覆盖低的设置,优先级最高的是用户指定的Settings和Mappings

ES聚合分析

  • 通过聚合,我们会得到一个数据的概览,是分析和总结全套的数据,而不是寻找单个文档
    • 西湖区和拱墅区的客房数量
    • 不同的价格区间,可预订的经济酒店和5星级酒店的数量
  • 高性能,只要一条语句,就可以从es得到分析结果,无需客户端自行分析。
  • 分类
    • bucket aggregation:
      一些列满足特定条件的文档集合, 类似于SQL的group
    • metric aggregation:一些满足特定条件的文档集合。(最大/最小/平均值),类似于SQL的COUNT.
    • pipeline aggregation 对其他的聚合结果进行二次聚合
    • matrix aggregration 支持对多个字段的操作并提供一个结果矩阵

相关性和相关性算分

  • 根据文档和查询语句的匹配程度
  • 打分的本质是排序,需要把最符合用户需求的文档排在前面。ES5之前,默认的相关性算分采用TF-IDF,现在采用BM25
  • 多个shard下,如果每个shard包含指定搜索条件的document数量不均匀的情况下,会导致在某个shard上document数量少的时候,计算该指定搜索条件的document的相关性评分要虚高。导致该document比实际真正想要返回的document的评分要高。
    • 词频TF
    • 逆文档频率IDF:搜索的词在所有文档中出现的次数越少,相关性越高
    • 搜索的词占文档总长度比例越大,相关性越高
    • 匹配字段越多,得分越高。

bool 查询

一个或者多个查询子句的组合

​ Bool查询对应Lucene中的BooleanQuery,它由一个或者多个子句组成,每个子句都有特定的类型。

  • must

    返回的文档必须满足must子句的条件,并且参与计算分值

  • filter

    返回的文档必须满足filter子句的条件。但是不会像Must一样,参与计算分值

  • should

    返回的文档可能满足should子句的条件。在一个Bool查询中,如果没有must或者filter,有一个或者多个should子句,那么只要满足一个就可以返回。minimum_should_match参数定义了至少满足几个子句。

  • must_nout

    返回的文档必须不满足must_not定义的条件。

Index Alias

为索引定一个别名,操作都通过别名来完成

搜索建议 Suggester API

自动补全或者纠错,提高匹配程度

  • 将输入的文本分解为Token,然后在索引的字典里查找相似的Term并返回
  • 类别:
    • Term Suggester,对每个分词进行分析,改动多少字符就可以和另外一个词一致,提供一个分数
      • Missing -如索引中已经存在,就不提供建议
      • Popular - 推荐出现频率更高的词
      • Always - 无论是否存在都提供建议
    • Phrase Suggester,新增了一些参数,比如Max Errors,最多可以拼错的terms数
    • Complete Suggester,自动补全,每输入一个字符就要查询,比较耗性能
    • Context Suggester 自动补全的扩展

跨集群搜索

痛点:单集群水平扩展时,节点数不能无限增加,集群的元信息(节点、索引、集群状态)会在每个节点都存储,导致更新压力变大。

跨集群搜索——Cross Cluster Search

  • 允许任何节点扮演federated节点,以轻量的方式,将搜索请求进行代理
  • 不需要以Client Node的形式加入其它集群
  • 每个集群配置相同的索引名

分布式搜索

  • 先到Coordination节点,随机选择分片,发送请求,每个分片进行查询排序,返回排序后的文档id
  • Coordination节点会把每个分片的id列表重新排序然后分页,再根据id去相应的分片获取详细的文档数据。

避免深度分页Search After

  • 可以实时获取下一页文档信息
    • 不指定特定页数(From)
    • 只能往下翻
  • 第一步搜索指定sort,并且保证值是唯一的(加入id)
  • 然后使用上一次,最后一个文档的sort值进行查询
  • Scroll API:适合需要全部文档的时候
    • 创建一个快照,有新的数据写入的话无法被查到
    • 每次查询后,输入上一次的Scroll Id
  • Regular:需要实时获取顶部的部分文档的场景
  • Pagination:需要深度分页,则选用Search After

并发读写

es采用的是乐观并发控制,类似cas。

父子文档

Reindex 重建索引

API

  • 查看集群健康状态:/_cluster/health
  • 查看节点信息:/_cat/nodes?v
  • 获取一个文档:GET /users/_doc/1
  • Index/Create:index如果已存在,则删除老的再新增,Create如果已存在则返回错误
  • _bulk:多个操作合并
  • _mget:批量读取
  • _msearch:批量查询
  • /_search:集群上所有的索引
  • /index1/_serarch:index的索引

LSM Tree

https://www.jianshu.com/p/5c846e205f5f

你可能感兴趣的:(ElasticSearch)