当前位置:   article > 正文

elasticsearch学习笔记(基本语法与原理)_es scan 原理

es scan 原理

一,利用管道读入文件

1.首先需要安装附件文本抽取插件:Ingest Attachment Processor Plugin官方插件
2. 创建管道:

PUT http://localhost:9200/_ingest/pipeline/attachment("attachment"表示管道ID)
 {
    "description": "Extract attachment information",
    "processors": [
        {
            "attachment": {//创建文件抽取预处理器
                "field": "data",//表示base64编码后的文件 存放的属性
                "ignore_missing": true
            }
        },
        {//创建base64编码后移除无用的 data 属性  的预处理器,_source中将不会返回field为 "data"的属性
            "remove": {
                "field": "data"
            }
        }
    ]
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  1. 建立文档映射结构
PUT http://localhost:9200/book(这里"book"为索引名)

{
  "mappings": {
    "idx": {
      "properties": {
        "id": {
          "type": "keyword"
        },
        "title": {
          "type": "text",
          "analyzer": "ik_max_word"
        },
        "desc": {
          "type": "text",
          "analyzer": "ik_max_word"
        },
        "path": {
          "type": "keyword"
        },
        "create_time": {
          "type": "date",
          "format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis"
        },
        "update_time": {
          "type": "date",
          "format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis"
        },
        "attachment": {//一下为固定写法
          "properties": {
            "content": {
              "type": "text",
              "analyzer": "ik_max_word"
            }
          }
        }
      }
    }
  }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  1. 最后在结果中获取"attachment.content"(固定写法)就是文件内容

二,elasticsearch中的分页

1.form+size 浅分页

假如有10个主分片,现在要取第10001-10010条数据,from 10001 size 10,
那么就会从各个分片取10010条数据,一共1010010条数据,返回给协调节点,协调节点又冲1010010条数据取10条,一共舍弃100090条;
所以,当深度分页的时候就会性能很差;

2.scroll和scroll-scan

scroll的作用不是用于实时查询数据,因为他会对es做多次请求,不可能做到实时查询。它的作用主要是用来查询大量数据或全部数据。

scroll查询原理是在第一次查询的时候一次性生成一个快照,根据上一次的查询的id来进行下一次的查询,这个就类似于关系型数据库的游标,然后每次滑动都是根据产生的游标id进行下一次查询,这种性能比上面说的分页性能要高出很多,基本都是毫秒级的。
注意:scroll不支持跳页查询。 使用场景:对实时性要求不高的查询,例如微博或者头条滚动查询.

 初始查询:

curl -XGET 'localhost:9200/index/type/_search?scroll=1m' -d '
{
    "query": {
        "match" : {
            "title" : "elasticsearch"
        }
    }
}
    后续查询:

curl -XGET  'localhost:9200/_search/scroll'  -d'
{
    "scroll" : "1m", 
    "scroll_id" : "c2Nhbjs2OzM0NDg1ODpzRlBLc0FXNlNyNm5JWUc1" 
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

注意:

1,scroll设置的一分钟,会随着每次的滚屏而刷新。此处不是指整个查询限时为1分钟,而是到下一次滚屏还有1分钟的时间。

2,后续请求时url中不应该有index和type,这些都在初始请求中,只需要使用scroll_id和scroll两个参数即可,其中scroll_id可以放在url中也可以放在请求体中.

第一次请求时es会生成一个初始查询时索引的快照,并将旧的数据保护在手边,所以第一次查询之后对文档的一些改动不会影响查询结果。后续的每次请求都会记住哪些结果已经返回了,下一次继续返回剩下的,直到hits里的数据为空。但是scroll按照默认的进行排序依旧会是有消耗的,所以我们继续引入scan查询。

深度分页代价最高的就是全局排序,使用scan只需要把search_type设置成scan就可以禁用全局排序,如下:

GET /old_index/_search?search_type=scan&scroll=1m 
{
"query": { "match_all": {}},
"size": 1000
}

GET /_search/scroll?scroll=1m 
c2Nhbjs1OzExODpRNV9aY1VyUVM4U0NMd2pjWlJ3YWlBOzExOTpRNV9aY1VyUVM4U0 <2>
NMd2pjWlJ3YWlBOzExNjpRNV9aY1VyUVM4U0NMd2pjWlJ3YWlBOzExNzpRNV9aY1Vy
UVM4U0NMd2pjWlJ3YWlBOzEyMDpRNV9aY1VyUVM4U0NMd2pjWlJ3YWlBOzE7dG90YW
xfaGl0czoxOw==
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

扫描式滚屏和标准滚屏的区别有以下几点:

  1. scan结果没有排序,返回结果是doc在es中的顺序。

  2. scan初始查询的结果中hits中不会有数据

  3. 因为没有排序,所以也不会支持聚合的一些操作

  4. scan中size被应用到每一个分片上,所以我们在每次滚屏是最多获得size * number_of_primary_shards(size*主分片数) 个document

3. scroll-after的方式

search_after
分页的方式是根据上一页的最后一条数据来确定下一页的位置,同时在分页请求的过程中,如果有索引数据的增删改查,这些变更也会实时的反映到游标上。但是需要注意,因为每一页的数据依赖于上一页最后一条数据,所以无法跳页请求。

4.三者区别

(1) from / size :
该查询的实现原理类似于mysql中的limit,比如查询第10001条数据,那么需要将前面的10000条都拿出来,进行过滤,最终才得到数据。(性能较差,实现简单,适用于少量数据,数据量不超过10w)。
(2) scroll:该查询实现类似于消息消费的机制,首次查询的时候会在内存中保存一个历史快照以及游标(scroll_id),记录当前消息查询的终止位置,下次查询的时候将基于游标进行消费(性能良好,维护成本高,在游标失效前,不会更新数据,不够灵活,一旦游标创建size就不可改变,适用于大量数据导出或者索引重建)
(3) search_after: 性能优秀,类似于优化后的分页查询,历史条件过滤掉数据。

三,elasticsearch原理

1. 读数据过程

可以通过doc id 来查询,会根据doc id进行hash,判断出来当时把doc id分配到了哪个shard上面去,从那个shard去查询。

  1. 客户端发送请求到任意一个node,成为coordinate node

  2. coordinate node 对doc id进行哈希路由,将请求转发到对应node,此时会使用round-robin随机轮询算法,在primary shard 以及其所有replica中随机选择一个,让读请求负载均衡。

  3. 接收请求的node返回document给coordinate node。

  4. coordinate node返回document给客户端。

2. 索引数据过程

es最强大的是做全文检索

  1. 客户端发送请求到一个coordinate node。

  2. 协调节点将搜索请求转发到所有的shard对应的primary shard 或 replica shard ,都可以。

  3. query phase:每个shard将自己的搜索结果(其实就是一些doc id)返回给协调节点,由协调节点进行数据的合并、排序、分页等操作,产出最终结果。

  4. fetch phase:接着由协调节点根据doc id去各个节点上拉取实际的document数据,最终返回给客户端。

写请求是写入primary shard,然后同步给所有的replica shard
读请求可以从primary shard 或者 replica shard 读取,采用的是随机轮询算法。

3.写数据

3.1写数据过程

在这里插入图片描述

  1. 客户端选择一个node发送请求过去,这个node就是coordinating node(协调节点)

  2. coordinating node 对document进行路由,将请求转发给对应的node(有primary shard)

  3. 实际的node上的primary shard 处理请求,然后将数据同步到replica node。

  4. coordinating node如果发现 primary node和所有replica node都搞定之后,就返回响应结果给客户端。

3.2 写数据底层原理

在这里插入图片描述
1、先写入内存buffer,在buffer里的时候数据是搜索不到的;同时将数据写入translog日志文件。

如果buffer快满了,或者到一定时间,就会将内存buffer数据refresh 到一个新的segment file中,但是此时数据不是直接进入segment file磁盘文件,而是先进入os cache。这个过程就是 refresh。

每隔1秒钟,es将buffer中的数据写入一个新的segment file,每秒钟会写入一个新的segment file,这个segment file中就存储最近1秒内 buffer中写入的数据。

2、但是如果buffer里面此时没有数据,那当然不会执行refresh操作,如果buffer里面有数据,默认1秒钟执行一次refresh操作,刷入一个新的segment file中。

操作系统里面,磁盘文件其实都有一个东西,叫做os cache,即操作系统缓存,就是说数据写入磁盘文件之前,会先进入os cache,先进入操作系统级别的一个内存缓存中去。只要buffer中的数据被refresh 操作刷入os cache中,这个数据就可以被搜索到了

3、为什么叫es是准实时的?NRT,全称 near real-time。默认是每隔1秒refresh一次的,所以es是准实时的,因为写入的数据1s之后才能被看到。

可以通过es的restful api或者 java api,手动执行一次 refresh操作,就是手动将buffer中的数据刷入os cache中,让数据立马就可以被搜索到。只要数据被输入os cache中,buffer 就会被清空了,因为不需要保留buffer了,数据在translog里面已经持久化到磁盘去一份了。

4、重复上面的步骤,新的数据不断进入buffer和translog,不断将buffer数据写入一个又一个新的segment file中去,每次refresh完buffer清空,translog保留。

随着这个过程的推进,translog会变得越来越大。当translog达到一定长度的时候,就会触发commit操作。

5、commit操作发生的第一步,就是将buffer中现有的数据refresh到os cache中去,清空buffer。然后将一个commit point写入磁盘文件,里面标识者这个commit

point 对应的所有segment file,同时强行将os cache中目前所有的数据都fsync到磁盘文件中去。最后清空现有 translog日志文件,重启一个translog,此时commit操作完成。

6、这个commit操作叫做flush。默认30分钟自动执行一次flush,但如果translog过大,也会触发flush。flush操作就对应着commit的全过程,我们可以通过es api,手动执行flush操作,手动将os cache中数据fsync强刷到磁盘上去。

7、translog日志文件的作用是什么?

执行commit 操作之前,数据要么是停留在buffer中,要么是停留在os cache中,无论是buffer 还是os cache都是内存,一旦这台机器死了,内存中的数据就全丢了。

所以需要将数据对应的操作写入一个专门的日志文件translog中,一旦此时机器宕机了,再次重启的时候,es会自动读取translog日志文件中的数据,恢复到内存buffer和os cache中去。

8、translog其实也是先写入os cache的,默认每隔5秒刷一次到磁盘中去,所以默认情况下,可能有5s的数据会仅仅停留在buffer或者translog文件的os cache中,如果此时机器挂了,会丢失5秒钟的数据。但是这样性能比较好,最多丢5秒的数据。也可以将translog设置成每次写操作必须是直接fsync到磁盘,但是性能会差很多。

9、es第一是准实时的,数据写入1秒后就可以搜索到:可能会丢失数据的。有5秒的数据,停留在buffer、translog os cache 、segment file os cache中,而不在磁盘上,此时如果宕机,会导致5秒的数据丢失。

10、总结::数据先写入内存buffer,然后每隔1s,将数据refresh到 os cache,到了 os cache数据就能被搜索到(所以我们才说es从写入到能被搜索到,中间有1s的延迟)。
每隔5s,将数据写入到translog文件(这样如果机器宕机,内存数据全没,最多会有5s的数据丢失),translog达到一定程度,或者默认每隔30min,会触发commit操作,将缓冲区的数据都flush到segment file磁盘文件中。
数据写入 segment file之后,同时就建立好了倒排索引。

四,删除和更新

如果是删除操作,commit的时候会生成一个 .del文件,里面将某个doc标识为 deleted状态,那么搜索的时候根据 .del文件就知道这个doc是否被删除了。

如果是更新操作,就是将原来的doc标识为deleted状态,然后重新写入一条数据。

buffer 每refresh一次,就会产生一个segment file,所以默认情况下是1秒钟一个segment file,这样下来segment file会越来越多,此时会定期执行merge。

每次merge的时候,会将多个segment file合并成一个,同时这里会将标识为 deleted的doc给物理删除掉,然后将新的segment file写入磁盘,这里会写一个

commit point,标识所有新的 segment file,然后打开segment file供搜索使用,同时删除旧的segment file。

参考资料

面试官:你能说说 Elasticsearch 查询数据的工作原理是什么吗?

elasticsearch原理

elasticsearch经典面试题

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小丑西瓜9/article/detail/529200
推荐阅读
相关标签
  

闽ICP备14008679号