Elasticsearch高级

文章目录

  • 一.数据聚合
  • 二.RestAPI实现聚合
  • 三.ES自动补全(联想)
  • 四.数据同步
  • 五.elasticsearch集群


一.数据聚合

在ES中的数据聚合(aggregations)可以近似看做成mysql中的groupby分组,聚合可以实现对文档数据的统计、分析、运算,常见的聚合的分类有以下几种:

  • 桶(Bucket)聚合:用来对文档做分组

    • TermAggregation:按照文档字段值分组(即不能够进行分词的字段)

    • Date Histogram:按照日期阶梯分组,例如一周为一组,或者一月为一组

  • 度量(Metric)聚合:用以计算一些值,比如:最大值、最小值、平均值等

    • Avg:求平均值

    • Max:求最大值

    • Min:求最小值

    • Stats:同时求max、min、avg、sum等

  • 管道(pipeline)聚合:其它聚合的结果为基础做聚合(很少用)


1.DSL实现Bucket(桶)聚合

语法:

GET /hotel/_search
{
  "size": 0,  // 设置size为0,结果中不包含文档,只包含聚合结果
  "aggs": { // 定义聚合(带有"s"证明可以定义多个聚合)
    "xxx": { //给聚合起个名字
      "terms": { // 聚合的类型(不能为text)
        "field": "xxx", // 参与聚合的字段
        "size": xxx // 希望获取的聚合结果数量
      }
    }
  }
}

默认情况下,Bucket聚合会统计Bucket内的文档数量,记为_count,并且按照_count降序排序 修改结果排序方式:

GET /hotel/_search
{
  "size": 0, 
  "aggs": {
    "xxx": {
      "terms": {
        "field": "xxx",
        "order": {
          "_count": "asc" // 按照_count升序排列
        },
        "size": 20
      }
    }
  }
}

默认情况下,Bucket聚合是对索引库的所有文档做聚合,我们可以限定要聚合的文档范围,只要添加query条件即可

示例:

GET /hotel/_search
{
  "query": {
    "range": {
      "price": {
        "lte": 200 // 只对200元以下的文档聚合
      }
    }
  }, 
  "size": 0, 
  "aggs": {
    "brandAgg": {
      "terms": {
        "field": "brand",
        "size": 20
      }
    }
  }
}

2.DSL实现Metrics 聚合

例如,我们要求获取每个品牌的用户评分的min、max、avg等值.
我们可以利用stats聚合:

GET /hotel/_search
{
  "size": 0, 
  "aggs": {
    "brandAgg": { 
      "terms": { 
        "field": "brand", 
        "size": 20
      },
      "aggs": { // 是brands聚合的子聚合,也就是分组后对每组分别计算
        "score_stats": { // 聚合名称
          "stats": { // 聚合类型,这里stats可以计算min、max、avg等
            "field": "score" // 聚合字段,这里是score
          }
        }
      }
    }
  }
}

二.RestAPI实现聚合

1.发送聚合DSL语句(其实本质上就是一层一层按照DSL语句组成结构调用API,十分易懂也很简单):

在这里插入图片描述
2.聚合结果解析
在这里插入图片描述

java代码:

@Test
    void aggregation() throws IOException {
        SearchRequest request=new SearchRequest("hotel");

        request.source().size(0);
        request.source().aggregation(AggregationBuilders
                .terms("brandAgg")
                .field("brand")
                .size(10)
        );

        SearchResponse response = client.search(request, RequestOptions.DEFAULT);

        Aggregations aggregations = response.getAggregations();

        Terms terms=aggregations.get("brandAgg");
        List<? extends Terms.Bucket> buckets = terms.getBuckets();

        for (Terms.Bucket bucket : buckets) {
            String key = bucket.getKeyAsString();
            System.out.println(key);
        }
    }

三.ES自动补全(联想)

用途:当用户在搜索框输入字符时,我们应该提示出与该字符(汉字,英文)有关的搜索项

1.拼音分词

要实现根据字母做补全,就必须对文档按照拼音分词。在GitHub上恰好有elasticsearch的拼音分词插件。

下载地址:https://github.com/medcl/elasticsearch-analysis-pinyin

自定义分词器

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

  • character filters:在tokenizer之前对文本进行处理。例如删除字符、替换字符

  • tokenizer:将文本按照一定的规则切割成词条(term)。例如keyword,就是不分词;还有ik_smart

  • tokenizer filter:将tokenizer输出的词条做进一步处理。例如大小写转换、同义词处理、拼音处理等

在这里插入图片描述

我们可以在创建索引库时,通过settings来配置自定义的analyzer(分词器):

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
        }
      }
    }
  }
}

拼音分词器适合在创建倒排索引的时候使用,但不能在搜索的时候使用(原因是搜索时会把文本转换为多个拼音和分词(如果添加了tokenizer分词的话),按照拼音搜索就会和倒排索引库里面的拼音匹配(包括拼音一致但是词义不一致的词),这就会导致搜索产生歧义)。

因此字段在创建倒排索引时应该用my_analyzer分词器;字段在搜索时应该使用ik_smart分词器(使用ik_smart时识别不了拼音,es会默认使用创建索引库时指定的分词器)

PUT /test
{
  "settings": {
    "analysis": {
      "analyzer": {
        "my_analyzer": {
          "tokenizer": "ik_max_word", "filter": "py"
        }
      },
      "filter": {
        "py": { ... }
      }
    }
  },
  "mappings": {
    "properties": {
      "name": {
        "type": "text",
        "analyzer": "my_analyzer",
        "search_analyzer": "ik_smart"
      }
    }
  }
}

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

  • 参与补全查询的字段必须是completion类型。

  • 字段的内容一般是用来补全的多个词条形成的数组。

在这里插入图片描述

查询语法如下:

在这里插入图片描述
3.RestAPI实现自动补全

请求参数构造的API:
在这里插入图片描述
结果解析:
在这里插入图片描述
案例:实现酒店搜索页面输入框的自动补全

业务层代码:

 public List<String> getSuggestions(String prefix) {
        try {
            SearchRequest request=new SearchRequest("hotel");

            request.source().suggest(new SuggestBuilder().addSuggestion("suggestions",
                    SuggestBuilders.completionSuggestion("suggestion")
                            .prefix(prefix)
                            .skipDuplicates(true)
                            .size(10)
                    ));

            SearchResponse response = client.search(request, RequestOptions.DEFAULT);

            Suggest suggest = response.getSuggest();

            CompletionSuggestion completionSuggestion = suggest.getSuggestion("suggestions");

            List<CompletionSuggestion.Entry.Option> options = completionSuggestion.getOptions();

            List<String> suggestionList=new ArrayList<>(options.size());
            for (CompletionSuggestion.Entry.Option option : options) {
                String text = option.getText().toString();

                suggestionList.add(text);
            }
            return suggestionList;
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

四.数据同步

数据同步问题分析

elasticsearch中的酒店数据来自于mysql数据库,因此mysql数据发生改变时,elasticsearch也必须跟着改变,这个就是elasticsearch与mysql之间的数据同步。

方案一:同步调用(不推荐使用)

在这里插入图片描述

方案二:异步通知(推荐使用)

在这里插入图片描述

方案三:监听binlog(推荐使用)

在这里插入图片描述

总结:

方式一:同步调用

  • 优点:实现简单,粗暴

  • 缺点:业务耦合度高

方式二:异步通知

  • 优点:低耦合,实现难度一般

  • 缺点:依赖mq的可靠性

方式三:监听binlog

  • 优点:完全解除服务间耦合

  • 缺点:开启binlog增加数据库负担、实现复杂度高

案例:利用MQ实现mysql与elasticsearch数据同步

1.在hotel-demo引入amqp依赖

		<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-amqp</artifactId>
        </dependency>

2.编写RabbitMQ的连接信息(yaml文件中,省略)

3.编写常量RabbitMQ的交换机,队列,Routing_Key的值

package cn.itcast.hotel.constants;

public class RabbitMQConstants {
    /**
     * 交换机
     */
    public static final String HOTEL_EXCHANGE="hotel.topic";
    /**
     * 新增或修改业务队列
     */
    public static final String HOTEL_INSERT_QUEUE="hotel.insert.queue";
    /**
     * 删除业务队列
     */
    public static final String HOTEL_DELETE_QUEUE="hotel.delete.queue";
    /**
     * 新增或修改业务ROUTING_KEY
     */
    public static final String HOTEL_INSERT_KEY="hotel.insert";
    /**
     * 修改业务的ROUTING_KEY
     */
    public static final String HOTEL_DELETE_KEY="hotel.delete";
}

4.定义交换机,队列,绑定交换机和队列,以及声明Routing_Key

package cn.itcast.hotel.mq;

import cn.itcast.hotel.constants.RabbitMQConstants;
import cn.itcast.hotel.service.IHotelService;
import org.springframework.amqp.rabbit.annotation.Exchange;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.QueueBinding;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class HotelListener {
    @Autowired
    private IHotelService iHotelService;
    /**
     * 监听新增或修改的消息
     * @param id
     */
    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(name = RabbitMQConstants.HOTEL_INSERT_QUEUE),
            exchange = @Exchange(name = RabbitMQConstants.HOTEL_EXCHANGE),
            key = RabbitMQConstants.HOTEL_INSERT_KEY
    ))
    public void listenHotelInsertOrUpdate(Long id){
        iHotelService.insertById(id);
    }

    /**
     * 监听删除的消息
     * @param id
     */
    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(name = RabbitMQConstants.HOTEL_DELETE_QUEUE),
            exchange = @Exchange(name = RabbitMQConstants.HOTEL_EXCHANGE),
            key = RabbitMQConstants.HOTEL_DELETE_KEY
    ))
    public void listenHotelDelete(Long id){
        iHotelService.deleteById(id);
    }
}

5.在hotel-admin重复操作1,2,3

6.当执行增删改操作,发送消息到交换机中

	@PostMapping
    public void saveHotel(@RequestBody Hotel hotel) {
        hotelService.save(hotel);

        rabbitTemplate.convertAndSend(RabbitMQConstants.HOTEL_EXCHANGE, RabbitMQConstants.HOTEL_INSERT_KEY, hotel.getId());
    }

    @PutMapping()
    public void updateById(@RequestBody Hotel hotel) {
        if (hotel.getId() == null) {
            throw new InvalidParameterException("id不能为空");
        }
        hotelService.updateById(hotel);
        rabbitTemplate.convertAndSend(RabbitMQConstants.HOTEL_EXCHANGE, RabbitMQConstants.HOTEL_INSERT_KEY, hotel.getId());
    }

    @DeleteMapping("/{id}")
    public void deleteById(@PathVariable("id") Long id) {
        hotelService.removeById(id);
        rabbitTemplate.convertAndSend(RabbitMQConstants.HOTEL_EXCHANGE, RabbitMQConstants.HOTEL_DELETE_KEY, id);
    }

7.在hotel-demo处理消息(业务层实现)

public void insertById(Long id) {
        try {
            Hotel hotel = getById(id);

            HotelDoc hotelDoc = new HotelDoc(hotel);

            IndexRequest request = new IndexRequest("hotel").id(hotel.getId().toString());

            request.source(JSON.toJSONString(hotelDoc), XContentType.JSON);

            client.index(request, RequestOptions.DEFAULT);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }


    public void deleteById(Long id) {
        try {
            DeleteRequest request=new DeleteRequest("hotel").id(id.toString());

            client.delete(request, RequestOptions.DEFAULT);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

五.elasticsearch集群

1.ES集群结构

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

  • 海量数据存储问题:将索引库从逻辑上拆分为N个分片(shard),存储到多个节点

  • 单点故障问题:将分片数据在不同节点备份(replica )

在这里插入图片描述

2.ES集群的节点角色

elasticsearch中集群节点有不同的职责划分:

在这里插入图片描述

每一个节点其实都包含了四种节点类型

elasticsearch中的每个节点角色都有自己不同的职责,因此建议集群部署时,每个节点都有独立的角色。
在这里插入图片描述
3.ES集群的脑裂

默认情况下,每个节点都是master eligible节点,因此一旦master节点宕机,其它候选节点会选举一个成为主节点。当主节点与其他节点网络故障时,可能发生脑裂问题。

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

4.ES集群的分布式存储

当新增文档时,应该保存到不同分片,保证数据均衡,那么coordinating node(协调节点)如何确定数据该存储到哪个分片呢?

elasticsearch会通过hash算法来计算文档应该存储到哪个分片:

在这里插入图片描述


新增文档流程:

在这里插入图片描述


elasticsearch的查询分成两个阶段:

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

在这里插入图片描述


5.ES集群的故障转移

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/212869.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【JavaScript手撕代码】call、apply、bind

修改this指向 方法参数返回值作用callthisArg, arg1, arg2, ...&#xff0c;注意&#xff0c;call接收的参数是一个参数列表函数返回值调用一个函数&#xff0c;将其 this 值设置为提供的值&#xff0c;并为其提供指定的参数。applythisArg, [arg1, arg2, ...]&#xff0c;请注…

Chat-GPT原理

GPT原理 核心是基于Transformer 架构 英文原文&#xff1a; ​ Transformers are based on the “attention mechanism,” which allows the model to pay more attention to some inputs than others, regardless of where they show up in the input sequence. For exampl…

数据结构中的二分查找(折半查找)

二分法&#xff1a;顾名思义&#xff0c;把问题一分为2的处理&#xff0c;是一种常见的搜索算法&#xff0c;用于在有序数组或这有序列表中查找指定元素的位置&#xff0c;它的思想是将待搜索的区间不断二分&#xff0c;然后比较目标值与中间元素的大小关系&#xff0c;然后确定…

基于51单片机的十字路口交通灯_5s黄灯倒计时闪烁

基于51单片机十字路口交通灯_5s黄灯闪烁 &#xff08;程序仿真仿真视频&#xff09; 仿真&#xff1a;proteus 7.8 程序编译器&#xff1a;keil 4/keil 5 编程语言&#xff1a;C语言 设计编号&#xff1a;J006 功能要求 交通灯运行状态&#xff1a; &#xff08;1&…

[c++]——string类____详细初步了解string类的运用

在成为大人的路上喘口气. 目录 &#x1f393;标准库类型string &#x1f393;定义和初始化string对象 &#x1f4bb;string类对象的常见构造 &#x1f4bb;string类对象的不常见构造 &#x1f4bb;读写string对象 &#x1f393; string类对象的修改操作 &#x1f4…

题目:DNA序列修正(蓝桥OJ 3904)

题目描述&#xff1a; 解题思路&#xff1a; 从左到右扫描第一条 DNA 序列和第二条 DNA 序列的每一个位置&#xff0c;检查它们是否互补。 如果某个位置不互补&#xff0c;我们需要寻找第二条 DNA 序列中后续位置的碱基&#xff0c;看是否可以通过交换使这两个位置都互补。如果…

博途PLC数组指针应用(SCL)

CODESYS数组类型变量使用介绍 https://rxxw-control.blog.csdn.net/article/details/131375218https://rxxw-control.blog.csdn.net/article/details/131375218 博途PLC数组类型变量使用介绍还可以查看下面文章博客: https://rxxw-control.blog.csdn.net/article/details/1…

模板可变参数/包装器

一、什么是模板可变参数 1、对比函数可变参数 可变参数即参数的数量是不确定的&#xff0c;底层根据用户传入的数量&#xff0c;开一个数组存储对应的参数。 2、基本形式 args -- argument 参数 [0,n]个参数 // Args是一个模板参数包&#xff0c;args是一个函数形参参数包…

Kubernetes基础(十)-自动伸缩

1 介绍 Kubernetes提供了多种自动伸缩机制&#xff0c;主要常见的有&#xff1a; HPA&#xff08;Horizontal Pod Autoscaling&#xff09;VPA&#xff08;Vertical Pod Autoscaler&#xff09;CA&#xff08;Cluster Autoscaler&#xff09;CPA&#xff08;Custom Pod Autos…

HTML_web扩展标签

1.表格标签 2.增强表头表现 4.表格属性&#xff08;实际不常用&#xff09; 结构标签&#xff1a; 合并单元格&#xff1a; 更多请查看主页

TEMU三季度销售额或达50亿美金,多多跨境已成第二增长引擎

2023年11月28日&#xff0c;拼多多发布了2023年第三季度业绩报告。 报告显示&#xff0c;三季度的收入为688.4亿元&#xff0c;同比增长93.9%&#xff0c;按照美国通用会计准则&#xff0c;实现净利润155.4亿元&#xff0c;净利润率达到22.6%。 拼多多将近翻倍的业绩成长&…

C语言结构体详解(二)(能看懂文字就能明白系列)文章很长,慢慢品尝

系列文章目录 第一章 结构体的介绍和基本使用 &#x1f31f; 个人主页&#xff1a;古德猫宁- &#x1f308; 信念如阳光&#xff0c;照亮前行的每一步 文章目录 系列文章目录&#x1f308; *信念如阳光&#xff0c;照亮前行的每一步* 前言前面一篇文章主要介绍了结构体的基础…

c语言-联合体和枚举

文章目录 一、联合体1. 联合体类型的声明和创建2. 联合体的特点3. 联合体大小的计算4.总结 二、枚举1. 枚举类型的声明2. 枚举类型的优点3. 枚举类型的使用 一、联合体 &#xff08;1&#xff09; 像结构体⼀样&#xff0c;联合体也是由一个或者多个成员构成&#xff0c;这些成…

JAVA代码优化:CommandLineRunner(项目启动之前,预先加载数据)

CommandLineRunner接口是Spring Boot框架中的一个接口&#xff0c;用于在应用程序启动后执行一些特定的代码逻辑。它是一个函数式接口&#xff0c;只包含一个run方法&#xff0c;该方法在应用程序启动后被自动调用。可以帮助我们在应用程序启动后自动执行一些代码逻辑&#xff…

ElementPlus中 使用ElLoading.service, spinner: ‘el-icon-loading‘不生效

let downloadLoadingInstance ElLoading.service({ text: "正在下载数据&#xff0c;请稍候",spinner: el-icon-loading, background: "rgba(0, 0, 0, 0.7)", })使用以上代码时&#xff0c;加载的圆圈出不来&#xff0c;使用f12查看&#xff0c;即使能出…

ssl下载根证书和中间证书

为了保证客户端和服务端通过HTTPS成功通信&#xff0c;您在安装SSL证书时&#xff0c;也需要安装根证书和中间证书。本文介绍如何获取根证书和中间证书。 使用说明 如果您的业务用户通过浏览器访问您的Web业务&#xff0c;则您无需关注根证书和中间证书&#xff0c;因为根证书…

团队怎么高效制作问卷?

制作调查问卷时并不是一个人就能单独完成&#xff0c;通常情况下&#xff0c;完成一份调查问卷往往需要一个团队的成员参与&#xff0c;相互协作&#xff0c;共同完成。不过&#xff0c;多人协作经常会遇到协作壁垒&#xff0c;导致效率低下&#xff0c;那团队怎么才能高效协作…

【Linux】第二十四站:模拟实现C语言文件标准库

文章目录 一、实现细节1.需要实现的函数2.fopen的实现3.fclose4.fwrite5.测试6.缓冲区的实现7.FILE中缓冲区的意义 二、完整代码 一、实现细节 1.需要实现的函数 #include "mystdio.h"int main() {_FILE* fp _fopen("test.txt","w");if(fp N…

2023年5月电子学会青少年软件编程 Python编程等级考试一级真题解析(判断题)

2023年5月Python编程等级考试一级真题解析 判断题(共10题,每题2分,共20分) 26、在编写较长的Python程序时,所有代码都不需要缩进,Python会自动识别代码之间的关系 答案:错 考点分析:考查python代码书写格式规范,python编写较长的程序时,需要明确严格的缩进,不然有…

医美店会员管理系统预约小程序作用是什么

医美在美业中占据着一定地位&#xff0c;爱美使然和经济独立、悦己消费下&#xff0c;不少女性会前往医美机构做脸部整容、嫩肤补水等服务&#xff0c;如美容院一样都是具备本地外地属性的&#xff0c;因此在如今互联网盛行下&#xff0c;商家需要借势线上破解难题及增强生意效…