• ElasticSearch分布式搜索引擎-03


    1、数据聚合

    聚合可以让我们极其方便的实现对数据的统计、分析、运算。查询速度非常快,可以实现近实时搜索效果

    1.1.聚合的种类

    聚合常见的有三类:

    • 桶(Bucket)聚合:用来对文档做分组
      • TermAggregation:按照文档字段值分组,例如按照品牌分组(mysql中的groupby)
      • Date Histogram:按照日期阶梯分组,例如一周为一组
    • 度量(Metric)聚合:用以计算一些值,比如:最大值、最小值等
      • Avg:求平均值
      • Max:求最大值
      • Min:求最小值
      • Stats:同时求max、min、avg、sum等
    • 管道(pipeline)聚合:其他聚合的结果为基础做聚合

    参加聚合的字段必须是:keyword、日期、数值、布尔类型

    1.2.DSL实现聚合

    Bucket聚合语法

    GET /索引库名/_search
    {
    	"size":0, //设置size为0,结果中不包含文档,只包含聚合结果
    	"aggs":{//定义聚合
    		"brandAgg":{//给聚合起个名字
    			"terms":{//聚合的类型,按照品牌值聚合,所以会选择term
    				"field":"brand",//参与聚合的字段
    				"size":20 //希望获取的聚合结果数量
    			}
    		}
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    默认情况下,Bucket聚合会统计Bucket内的文档数量,即为count,并且按照count降序排序。可以指定order属性,自定义聚合的排序方式:

    • 在terms字段里添加“order”:{“_count”:“asc”},按照_count升序排列

    限定聚合范围
    默认情况下,Bucket聚合是对索引库的所有文档做聚合,但真实场景下,用户会输入搜索条件,因此聚合必须是对搜索结果聚合。那么聚合必须添加限定条件。

    我们可以限定要聚合的文档范围,只要添加query条件即可

    GET /hotel/_search
    {
      "query": {
        "range": {
          "price": {
            "lte": 200 // 只对200元以下的文档聚合
          }
        }
      }, 
      "size": 0, 
      "aggs": {
        "brandAgg": {
          "terms": {
            "field": "brand",
            "size": 20
          }
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    Metric聚合语法

    GET /hotel/_search
    {
      "size": 0, 
      "aggs": {
        "brandAgg": { 
          "terms": { 
            "field": "brand", 
            "size": 20
          },
          "aggs": { // 是brands聚合的子聚合,也就是分组后对每组分别计算
            "score_stats": { // 聚合名称
              "stats": { // 聚合类型,这里stats可以计算min、max、avg等
                "field": "score" // 聚合字段,这里是score
              }
            }
          }
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    score_stats聚合是在brandAgg的聚合内部嵌套的子聚合。因为我们需要在每个桶分别计算。

    1.3.RestAPI实现聚合

    2、自动补全

    2.1.拼音分词器

    首先要安装拼音分词器

    POST /_analyze
    {
      "text": "如家酒店还不错",
      "analyzer": "pinyin" //单个字变拼音
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    效果是,单个字的拼音和一句话的首字母缩写展示,没有分词不是理想的搜索结果。

    2.2.自定义分词器

    每个词条形成一组拼音,需要对拼音分词器做个性化定制,形成自定义分词器。

    elasticsearch中分词器(analyzer)的组成包含三部分:

    • character filters:在tokenizer之前对文本进行处理。例如删除字符、替换字符
    • tokenizer:将文本按照一定的规则切割成词条(term)。例如keyword,就是不分词;还有ik_smart
    • tokenizer filter:将tokenizer输出的词条做进一步处理。例如大小写转换、同义词处理、拼音处理等
    PUT /test
    {
      "settings": {
        "analysis": {
          "analyzer": { // 自定义分词器
            "my_analyzer": {  // 分词器名称
              "tokenizer": "ik_max_word",
              "filter": "py"
            }
          },
          "filter": { // 自定义tokenizer filter
            "py": { // 过滤器名称
              "type": "pinyin", // 过滤器类型,这里是pinyin
    		  "keep_full_pinyin": false,
              "keep_joined_full_pinyin": true,
              "keep_original": true,
              "limit_first_letter_length": 16,
              "remove_duplicated_term": true,
              "none_chinese_pinyin_tokenize": false
            }
          }
        }
      },
      "mappings": {
        "properties": {
          "name": {
            "type": "text",
            "analyzer": "my_analyzer",
            "search_analyzer": "ik_smart"
          }
        }
      }
    }
    
    • 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

    总结:

    如何使用拼音分词器?

    • ①下载pinyin分词器
    • ②解压并放到elasticsearch的plugin目录
    • ③重启即可

    如何自定义分词器?

    • ①创建索引库时,在settings中配置,可以包含三部分
    • ②character filter
    • ③tokenizer
    • ④filter

    拼音分词器注意事项?

    • 为了避免搜索到同音字,搜索时不要使用拼音分词器

    2.3.自动补全查询

    elasticsearch提供了Completion Suggester查询来实现自动补全功能。这个查询会匹配以用户输入内容开头的词条并返回。为了提高补全查询的效率,对于文档中字段的类型有一些约束:

    • 参与补全查询的字段必须是completion类型
    • 字段的内容一般是用来补全的多个词条形成的数组。
    // 自动补全查询
    GET /test/_search
    {
      "suggest": {
        "title_suggest": {
          "text": "s", // 关键字
          "completion": {
            "field": "title", // 补全查询的字段
            "skip_duplicates": true, // 跳过重复的
            "size": 10 // 获取前10条结果
          }
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    3、数据同步

    常见的数据同步方案有三种:

    • 同步调用
    • 异步通知
    • 监听binlog

    同步调用

    • hotel-demo对外提供接口,用来修改elasticsearch中的数据
    • 酒店管理服务在完成数据库操作后,直接调用hotel-demo提供的接口,
      请添加图片描述

    异步通知

    • hotel-admin对mysql数据库数据完成增、删、改后,发送MQ消息
    • hotel-demo监听MQ,接收到消息后完成elasticsearch数据修改
      请添加图片描述

    监听binlog

    • 给mysql开启binlog功能
    • mysql完成增、删、改操作都会记录在binlog中
    • hotel-demo基于canal监听binlog变化,实时更新elasticsearch中的内容

    请添加图片描述

    方式一:同步调用

    • 优点:实现简单,粗暴
    • 缺点:业务耦合度高

    方式二:异步通知

    • 优点:低耦合,实现难度一般
    • 缺点:依赖mq的可靠性

    方式三:监听binlog

    • 优点:完全解除服务间耦合
    • 缺点:开启binlog增加数据库负担、实现复杂度高

    4、集群

    单机的elasticsearch做数据存储,必然面临两个问题:海量数据存储问题、单点故障问题。

    • 海量数据存储问题:将索引库从逻辑上拆分为N个分片(shard),存储到多个节点
    • 单点故障问题:将分片数据在不同节点备份(replica )

    ES集群相关概念:

    • 集群(cluster):一组拥有共同的 cluster name 的 节点。
    • 节点(node) :集群中的一个 Elasticearch 实例
    • 分片(shard):索引可以被拆分为不同的部分进行存储,称为分片。在集群环境下,一个索引的不同分片可以拆分到不同的节点中

    解决问题:数据量太大,单点存储量有限的问题。此时,我们把数据分成3片:shard0、shard1、shard2

    • 主分片(Primary shard):相对于副本分片的定义。
    • 副本分片(Replica shard)每个主分片可以有一个或者多个副本,数据和主分片一样。

    数据备份可以保证高可用,但是每个分片备份一份,所需要的节点数量就会翻一倍,成本很高。

    为了在高可用和成本间寻求平衡,我们可以这样做:

    • 首先对数据分片,存储到不同节点
    • 然后对每个分片进行备份,放到对方节点,完成互相备份

    这样可以大大减少所需要的服务节点数量。

    4.1.集群脑裂问题

    请添加图片描述
    默认情况下,集群中的任何一个节点都同时具备上述四种角色。

    但是真实的集群一定要将集群职责分离:

    • master节点:对CPU要求高,但是内存要求第
    • data节点:对CPU和内存要求都高
    • coordinating节点:对网络带宽、CPU要求高

    职责分离可以让我们根据不同节点的需求分配不同的硬件去部署。而且避免业务之间的互相干扰。

    脑裂问题

    • 脑裂是因为集群中的节点失联导致的。
    • 一个集群中,主节点与其它节点失联。此时,其他两个节点会认为主节点宕机,就会重新选主节点。
    • 当两个节点之一的节点当选后,集群继续对外提供服务,这两个节点自成一个集群,宕机的集群自成一个集群,两个数据不同步,出现数据差异。
    • 当网络恢复后,因为集群中有两个master节点,集群状态的不一致,出现脑裂的情况:有两个主节点。

    解决方案

    • 要求选票超过(eligible节点数量+1)/2才能当选为主节点,因此eligible节点数量最好是奇数。
    • 对应配置项是discovery.zen.minimum_master_nodes,在es7.0以后,已经成为默认配置,因此一般不会发生脑裂问题。

    小结

    master eligible节点的作用是什么?

    • 参与集群选主
    • 主节点可以管理集群状态、管理分片信息、处理创建和删除索引库的请求

    data节点的作用是什么?

    • 数据的CRUD

    coordinator节点的作用是什么?

    • 路由请求到其它节点
    • 合并查询到的结果,返回给用户

    4.2集群分布式存储

    当新增文档时,应该保存到不同分片,保证数据均衡。

    原理
    elasticsearch会通过hash算法来计算文档应该存储到哪个分片:
    shard = hash(_routing)% number_of_shards

    • _routing默认是文档的id
    • 算法与分片数量有关,因此索引库一旦创建,分片数量不能修改。

    新增文档流程:
    请添加图片描述

    4.3.集群分布式查询

    elasticsearch的查询分成两个阶段:

    • scatter phase:分散阶段,coordinating node会把请求分发到每一个分片
    • gather phase:聚集阶段,coordinating node汇总data node的搜索结果,并处理为最终结果集返回给用户

    4.4.集群故障转移

    集群的master节点会监控集群中的节点状态,如果发现有节点宕机,会立即将宕机节点的分片数据迁移到其它节点,确保数据安全,这个叫做故障转移。

  • 相关阅读:
    Redis数据库安装、使用、数据类型、常用命令(详解)
    杰理AC632定时任务接口sys_timer_add和usr_timer_add区别详述
    断网情况下,华为init接口持续调用,导致手机耗电严重
    2.6 场效应管放大电路
    区间信息维护与查询【最近公共祖先LCA 】 - 原理
    骚操作:巧用MySQL主从复制延迟拯救误删数据
    排序算法:快速排序(三种排序方式、递归和非递归)
    V90伺服 EPOS模式下回原(详细配置+SCL源代码)
    qiankun微前端实践
    MPCS-480 LSOP-6 IPM正输出图腾极 高速光电耦合器代替TLP2710
  • 原文地址:https://blog.csdn.net/DOVISSSS/article/details/126813023