Elasticsearch之基础概念

前言

曾用Elasticsearch完成全文搜索的需求,当时只为业务使用未做深入研究,这两天有时间便翻阅了官方文档和相关的博文,对es也有了更多的理解,将自己的所学和理解做下总结

一、es和Lucene中的专有名词

cluster 集群

cluster就是一个及以上个node的集合,它们一起存储你的所有数据,提供跨节点的搜索和索引能力,集群通过一个唯一的名字来标识. 默认情况下,当你在同一个网络环境启动一个及以上node时,它们会自动加入并形成一个名为elasticsearch的集群. 对于外部调用,es暴露了两个端口

  • 9200 供rest api使用,官方推荐
  • 9300 es节点内部使用, 官方不推荐外部使用,目前java client也用了这个端口,以后会转移到9200
node 节点

一个node就是一个es实例,每个节点都可以

  • 存储数据
  • 参与索引(添加)数据
  • 搜索
index 索引

等同于关系型数据库中的表,用来存储Document

document 文档

等同于关系型数据库表中的行,文档由字段组成,创建index时可以指定对字段的分析方式(analyzer,search_analyzer等,类似于关系型数据库中给字段添加索引),如果一个字段被指定不分析("index" : false),那么不能使用它来搜索相关操作

filed 字段

一个document由一个或多个field组成,Field也是Lucene中数据索引的最小定义单位.

term和term dictionary

Lucene中索引和搜索的最小单位,一个field由一个或多个term组成,term是field经analyzer(分词)产生,term dictionary即term字典,是根据条件查找term的基本索引

segment

一个index会有一个或多个sub-index构成,sub-index被称为segment.Lucene中的数据写入会先写内存的一个buffer,当buff内数据到达一定量后会被flush称为一个segment,每个segment都有自己独立的索引,可被独立查询,*但是数据永远不能被修改*,Lucene是近实时查询的,原因就在 *数据从写入到被flush为segment需要一段时间,在此期间此数据是查询不到的*,segment也会定期合并

shard 分片

es中的shard用来解决节点的容量上限问题,通过将index分为多个分片(默认为一个也就是不分片),一个或多个node共同存储该index的所有数据实现水平拓展(类似于关系型数据库中的分表)它们共同持有该索引的所有数据,默认通过hash(文档id)决定数据的归属

replicas 副本

replicas主要为了以下两个目的

  1. 由于数据只有一份,如果一个node挂了,那存在上面的数据就都丢了,有了replicas,只要不是存储这条数据的node全挂了,数据就不会丢
  2. 通过在所有replicas上并行搜索提高搜索性能.由于replicas上的数据是近实时的(near realtime),因此所有replicas都能提供搜索功能,通过设置合理的replicas数量可以极高的提高搜索吞吐量

eg,如果指定了replicas=2,那么对于一条数据它共有三份,一份称为primary shard,另外两份称为 replicas shard. 这三个统称为replicas group(副本组)

二、倒叙索引的魅力

es的搜索功能是基于lucene,而lucene搜索的基本原理就是倒叙索引

什么是倒叙索引

借用在网上找到的图片,个人认为是最好理解的

文档中的句子被划分为一个个term(term 用来表示一个单词或词语, 取决于使用的分词方式), 倒叙索引中存储着term,term的出现频率(tf,term frequency)和出现位置( 倒叙索引中的单词是按顺序排列的,这张图没有体现出来),请注意 这里的文档内容是document中的一个字段,也就是说每个被索引了的字段都有自己的倒叙索引

一次简单的搜索流程

假设我们搜索谷歌地图之父,搜索流程会是这样

  1. 分词,分词插件将句子分为3个term 谷歌,地图,之父
  2. 将这3个term拿到倒叙索引中去查找(会很高效,比如二分查找),如果匹配到了就拿对应的文档id,获得文档内容
但是,如何确定结果顺序?

这里要引入_score的概念,对于term的匹配,lucene会对其打分,得分越高,排名越靠前.这里要介绍几个相关的概念

  • TF(term frequency),词频,term在当前document中出现的频率,一个term在当前document中出现5次要比出现1次更相关,打分也会更高
  • IDF(inverse doucment frequency),逆向文档频率,term在所有document中出现的频率,这个频率越高,该term对应的分值越低
  • 字段长度归一值,简单来说就是字段越短,字段的权重越高, 比如 term 在匹配 我123我123456时,我123的得分会更高.
搜索就这么简单吗?

当然不是,es的搜索时基于lucene的,但是lucene是单机的,es是分布式的,这就意味着es必定会更复杂,举例来说

  • es是有shard这个概念的,那么搜索时要到一个index上的所有shard上去查,这样相当于将搜索膨胀了shard的个数倍,es是如何做优化的?
  • es还有replicas这个概念,那么如何充分利用replicas来实现并行搜索,提高搜索吞吐量的?

这里说下自己对单机和分布式的理解,打个比方,做饭

  1. 给2个人做饭,一个人(单机)就够了,压力很小,随便购买点食材就可以了,偶尔一次没做好也没问题
  2. 给5个人做饭,一个人(单机)也能行,有点压力,购买食材要仔细考虑了,偶尔一次没做好可能会被抱怨
  3. 给50个人做饭,一个人(单机)已经不够了,要多人(分布式)合作了,有人负责采购,有人负责做,可以身兼多职,多人合作完成,一次没做好也会影响50个人一天的生活,已经不可接受了
  4. 给5000个人做饭,只能是多人(分布式)了,到了这个程度,不可能再身兼多职了,每个人都分工明确,所有事情都会预先安排好,买什么食材,什么时候买,饭点是什么时候都需要很精确.这时候如果发生了很小的问题比如饭点晚了10分钟,很可能整个集体就垮掉了.

分布式就是这样,会将很小的问题无限放大,原本微不足道的问题放到分布式上会引起整个系统的崩溃

三、实际操作一下

使用docker-compose创建一个双节点es集群

docker-compose.yml

version: '3'
services:
  elasticsearch:
    image: elasticsearch:6.5.0
    container_name: elasticsearch
    environment:
      - cluster.name=docker-cluster
    ports:
      - 9200:9200
    networks:
      - esnet

  elasticsearch2:
    image: elasticsearch:6.5.0
    container_name: elasticsearch2
    environment:
      - cluster.name=docker-cluster
      - "discovery.zen.ping.unicast.hosts=elasticsearch"
    networks:
      - esnet
networks:
    esnet:
复制代码

在docker-compose.yml目录下执行docker-compose up就完成集群的启动了.docker-compose的使用可以参考这篇文章 下面看下集群的信息

λ curl http://127.0.0.1:9200/_cluster/health?pretty=true
{
  "cluster_name" : "docker-cluster",
  "status" : "green",
  "timed_out" : false,
  "number_of_nodes" : 2,
  "number_of_data_nodes" : 2,
  "active_primary_shards" : 0,
  "active_shards" : 0,
  "relocating_shards" : 0,
  "initializing_shards" : 0,
  "unassigned_shards" : 0,
  "delayed_unassigned_shards" : 0,
  "number_of_pending_tasks" : 0,
  "number_of_in_flight_fetch" : 0,
  "task_max_waiting_in_queue_millis" : 0,
  "active_shards_percent_as_number" : 100.0
}
复制代码
  1. 可以看到集群名称就是我们再docker-compose.yml中设置的docker-cluster
  2. status为green,es中集群有三个状态,在shard级别状态来说
  • green 正常状态 primary shard和replicas shard分配正常,集群运行正常
  • yellow 异常状态 primary shard分配正常,部分replicas shard未分配,集群仍然可以运行
  • red 错误状态 某个分片未被分配,与该shard相关操作无法执行,系统运行异常

index级别状态由最坏的shard级别状态控制,cluster级别状态又由最坏的index级别状态控制.可以说是坏事传千里

由于我们还没有创建索引,其他参数先不介绍

创建索引

以图书为例,我们创建一个索引,(对于需要创建多个的类似的索引,可以使用index template),包含书名,作者两个字段,如果要使用中文需要添加分词插件,这里为了简单只使用英文.使用postman来请求

这里我们设置book这个index分为 3个shard,每个shard有 1份replicas,为什么要设置 1个replicas呢? 我们只有2个节点,1个replicas shard+1个primary shard正好保证对于一条数据,每个节点上都有一份,如果设置了 "number_of_replicas": 2那么就会有1个replicas shard没办法分配,出现unassigned shard问题,参见 es未分配分片导致集群状态报黄

再来查看集群信息

{
  "cluster_name" : "docker-cluster",
  "status" : "green",
  "timed_out" : false,
  "number_of_nodes" : 2,
  "number_of_data_nodes" : 2,
  "active_primary_shards" : 3,
  "active_shards" : 6,
  "relocating_shards" : 0,
  "initializing_shards" : 0,
  "unassigned_shards" : 0,
  "delayed_unassigned_shards" : 0,
  "number_of_pending_tasks" : 0,
  "number_of_in_flight_fetch" : 0,
  "task_max_waiting_in_queue_millis" : 0,
  "active_shards_percent_as_number" : 100.0
}
复制代码

可以看到

  • 我们现在有3个primary shard,总shard数为6=3 priamry shard + 3 replicas shard,
  • 2个data_node(es中节点是带有角色的,后面会讲到)
shard分布

上图格式为 index shard下标 shard状态 shard中的doc数量 数据量 节点ip地址 节点名称(查询返回字段含义时使用GET /_cat/shards?help,其他命令类似) 如下图, 请注意这里primary shard都分配在master node,而replicas shard都分布在普通节点只是巧合,shard的分布是随机的

插入数据

如果插入数据时不指定id,es会生成一个uuid作为其id

更新数据
  1. 通过id更新字段,最简单的更新方式了
  2. 通过id使用动态脚本更新字段,es支持多种脚本语言比如painless,groovy,但是要注意脚本的消耗很高,要慎用,对于会多次使用的脚本使用带参数的脚本而非动态脚本,后者有最大数量限制,超过后es会拒绝执行 通过将变量作为参数 params 传递,我们可以查询时动态改变脚本无须重新编译

3 带参数的脚本

  • 上面三个示范是按顺序执行的,可以看到每执行一个_version是会自增的(用户也可以指定),和其他框架相同,es的_version也是用来处理并发情况的,这点后面会介绍.

  • _shard中展示了各shard的执行结果,对于这条数据 我们共有2=1 primary shard + 1replicas shard份,都执行成功了

  • _seq_no 和_version类似,严格递增的序列号,保证后写入doc的_seq_no大于先写入doc的_seq_no

  • _primary_term 每当priamry shard重新分配时,这个字段就会自增1

这些字段的详细信息请参考Elasticsearch内核解析 - 数据模型篇

删除数据

查询

查询是es使用的重点,也是难点.es提供了多种查询方式,,上面的删/改也都可以利用查询,例如 update by qery 这些属于对api的应用,参见es官方文档

四、总结

本文介绍了es的基本概念,介绍了倒叙索引的概念,构建了一个es集群并执行了基本的crud操作,希望读者看完能够对es有基本的了解.


以下为参考的文章

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值