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

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,634评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,951评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,427评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,770评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,835评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,799评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,768评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,544评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,979评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,271评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,427评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,121评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,756评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,375评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,579评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,410评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,315评论 2 352