learning_notes

学习笔记

View project on GitHub

特性操作

  1. 手动或者自动生成id

POST /shop/product #自动,必须是post PUT /shop/product/4 #手动制定

  1. 定制源返回结果

GET /shop/product/4?_source=name #只返回name列

  1. delete操作不会立即删除,只是标记删除,如果数据多了,才会删除

  2. primary shard和replica 同步更新的时候是并发同步,版本较后的如果先到,版本前面的后到,就会丢弃

  3. 完整数据更新流程

    1. 客户端发送数据给任意节点,这个节点就变为协调节点
    2. 根据路由算法,默认根据_id%shard数量算doc存到那个shard #所以不能更改shard数量
    3. 协调节点发送数据给可以处理的shard节点
    4. shard判断是post还是put操作,如果是post操作,把上一个版本的数据取出来,内存中修改好全量数据,部分更新,旧版本标记为delete
    5. 把数据存入buffer,默认1s将数据刷入index segment(NTR的原因) ,同时将数据同步给replica ,返给协调节点为成功
    6. 协调节点把数据返回给客户端
  4. version并发控制

?version=1 ?version=1&version_type=external

version_type=external,唯一的区别在于,_version,只有当你提供的version与es中的_version一模一样的时候,才可以进行修改,只要不一样,就报错;当version_type=external的时候,只有当你提供的version比es中的_version大的时候,才能完成修改

  1. 手动制定路由值(默认:_id)

也可以在发送请求的时候,手动指定一个routing value,比如说put /index/type/id?routing=user_id

手动指定routing value是很有用的,可以保证说,某一类document一定被路由到一个shard上去,那么在后续进行应用级别的负载均衡,以及提升批量读取的性能的时候,是很有帮助的

  1. quorum机制

consistency,one(primary shard),all(all shard),quorum(default) put /index/type/id?consistency=quorum

one:要求我们这个写操作,只要有一个primary shard是active活跃可用的,就可以执行 all:要求我们这个写操作,必须所有的primary shard和replica shard都是活跃的,才可以执行这个写操作 quorum:默认的值,要求所有的shard中,必须是大部分的shard都是活跃的,可用的,才可以执行这个写操作

  1. timeout机制 达到timeout时间,就先返回一部分数据

  2. deep paging 原理 GET /_search?size=10&from=20 协调节点,从所有的shard上分别取出来10条,然后合并排序,再取出来10条,这个才是结果

  3. _all query string查询原理 在搜索的时候,没有对某个field指定搜索,就默认搜索_all field,其中是包含了所有field的值的

es在新建一个doc的时候,会将各个字段的值,合并到_all字段中去

  1. 精准匹配(exact )和全文匹配 查询倒排索引,排序正排索引 建立倒排索引的时候,以对值进行拆分词语后(分词)进行匹配,也可以通过缩写、时态、大小写、同义词等进行匹配

  2. _mapping

  • 往es里面直接插入数据,es会自动建立索引,同时建立type以及对应的mapping
  • mapping中就自动定义了每个field的数据类型
  • 不同的数据类型(比如说text和date),可能有的是exact value,有的是full text
  • exact value,在建立倒排索引的时候,分词的时候,是将整个值一起作为一个关键词建立到倒排索引中的;full text,会经历各种各样的处理,分词,normaliztion(时态转换,同义词转换,大小写转换),才会建立到倒排索引中
  • 同时呢,exact value和full text类型的field就决定了,在一个搜索过来的时候,对exact value field或者是full text field进行搜索的行为也是不一样的,会跟建立倒排索引的行为保持一致;比如说exact value搜索的时候,就是直接按照整个值进行匹配,full text query string,也会进行分词和normalization再去倒排索引中去搜索
  • 可以用es的dynamic mapping,让其自动建立mapping,包括自动设置数据类型;也可以提前手动创建index和type的mapping,自己对各个field进行设置,包括数据类型,包括索引行为,包括分词器,等等

mapping,就是index的type的元数据,每个type都有一个自己的mapping,决定了数据类型,建立倒排索引的行为,还有进行搜索的行为

  1. 是否建立索引设置

    analyzed not_analyzed no

        "publisher_id": {
          "type": "text",
          "index": "not_analyzed"
        }
    
  2. filter和query

    filter,仅仅只是按照搜索条件过滤出需要的数据而已,不计算任何相关度分数,对相关度没有任何影响 query,会去计算每个document相对于搜索条件的相关度,并按照相关度进行排序

  3. query bool must,must_not,should,filter

  4. 字符串排序问题

    通常解决方案是,将一个string field建立两次索引,一个分词,用来进行搜索;一个不分词,用来进行排序


  "mappings": {
    "article": {
      "properties": {
        "title": { #分词
          "type": "text", 
          "fields": {
            "raw": {  #原始数据
              "type": "string",
              "index": "not_analyzed" #不分词
            }
          },
          "fielddata": true
        },
  1. term frequency/inverse document frequency算法,简称为TF/IDF算法

    TF:各个词条出现的频率 IDF:搜索文本中的各个词条在整个索引的所有文档中出现了多少次,出现的次数越多,就越不相关

   #分析一个document是如何被匹配上的

    GET /test_index/test_type/6/_explain
    {
      "query": {
        "match": {
          "test_field": "test hello"
        }
      }
    }
  1. scoll滚动搜索

可以先搜索一批数据,然后下次再搜索一批数据(根据上一次返回的_scroll_id),以此类推,直到搜索出全部的数据来

看起来挺像分页的,但是其实使用场景不一样。分页主要是用来一页一页搜索,给用户看的;scoll主要是用来一批一批检索数据,让系统进行处理的

  1. reindex(重建索引) 类型一旦建立,无法修改,比如date改成string 使用别名+scoll+bulk

  2. 倒排索引的结构

  • 包含这个关键词的document list
  • 包含这个关键词的所有document的数量:IDF(inverse document frequency)
  • 这个关键词在每个document中出现的次数:TF(term frequency)
  • 这个关键词在这个document中的次序
  • 每个document的长度:length norm
  • 包含这个关键词的所有document的平均长度

    倒排索引不可变的好处

  • 不需要锁,提升并发能力,避免锁的问题
  • 数据不变,一直保存在os cache中,只要cache内存足够
  • filter cache一直驻留在内存,因为数据不变
  • 可以压缩,节省cpu和io开销

倒排索引不可变的坏处:每次都要重新构建整个索引

  1. 再次优化的写入流程
  • 数据写入buffer缓冲和translog日志文件
  • 每隔一秒钟,buffer中的数据被写入新的segment file,并进入os cache,此时segment被打开并供search使用
  • buffer被清空
  • 重复1~3,新的segment不断添加,buffer不断被清空,而translog中的数据不断累加
  • 当translog长度达到一定程度的时候,commit操作发生
    • buffer中的所有数据写入一个新的segment,并写入os cache,打开供使用
    • buffer被清空
    • 一个commit ponit被写入磁盘,标明了所有的index segment
    • filesystem cache中的所有index segment file缓存数据,被fsync强行刷到磁盘上
    • 现有的translog被清空,创建一个新的translog

      基于translog和commit point,如何进行数据恢复

      fsync+清空translog,就是flush,默认每隔30分钟flush一次,或者当translog过大的时候,也会flush

      POST /my_index/_flush,一般来说别手动flush,让它自动执行就可以了

      translog,每隔5秒被fsync一次到磁盘上。在一次增删改操作之后,当fsync在primary shard和replica shard都成功之后,那次增删改操作才会成功

      但是这种在一次增删改时强行fsync translog可能会导致部分操作比较耗时,也可以允许部分数据丢失,设置异步fsync translog