SpringCloud(十)——ElasticSearch简单了解(三)数据聚合和自动补全

文章目录

  • 1. 数据聚合
    • 1.1 聚合介绍
    • 1.2 Bucket 聚合
    • 1.3 Metrics 聚合
    • 1.4 使用 RestClient 进行聚合
  • 2. 自动补全
    • 2.1 安装补全包
    • 2.2 自定义分词器
    • 2.3 自动补全查询
    • 2.4 拼音自动补全查询
    • 2.5 RestClient 实现自动补全
      • 2.5.1 建立索引
      • 2.5.2 修改数据定义
      • 2.5.3 补全查询
      • 2.5.4 解析结果

1. 数据聚合

1.1 聚合介绍

聚合(aggregations)可以实现对文档数据的统计、分析、运算。

聚合常见的有三类:

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

参与聚合的字段为以下字段:

  • keyword
  • 数值
  • 日期
  • 布尔

注意,不能是 text 字段

1.2 Bucket 聚合

这里假如我们需要对不同品牌的酒店进行聚合人,那么我们就可以使用桶聚合,桶聚合的例子如下:

GET /hotel/_search
{
  "size": 0,  // 设置size为0,结果中不包含文档,只包含聚合结果
  "aggs": { // 定义聚合
    "brandAgg": { //给聚合起个名字
      "terms": { // 聚合的类型,按照品牌值聚合,所以选择term
        "field": "brand", // 参与聚合的字段
        "order": {
          "_count": "asc"// 按照聚合数量进行升序排列,默认降序
        },
        "size": 20 // 希望获取的聚合结果数量
      }
    }
  }
}

聚合结果如下:
在这里插入图片描述

如果我们需要在一些查询的条件下进行聚合,比如我们只对200元一下的酒店文档进行聚合,那么聚合条件如下:

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

1.3 Metrics 聚合

如果我们需要按照每个品牌的用户的评分的最大值、最小值、平均值等进行排序,那么这就需要用到 Metrics 聚合了,我们使用 stats 查看所有的聚合属性,该聚合的实现如下:

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

聚合结果如下:
在这里插入图片描述

如果我们想要对按照聚合的平均值进行排序,那么DSL语句如下:

GET /hotel/_search
{
  "size": 0, 
  "aggs": {
    "brandAgg": { 
      "terms": { 
        "field": "brand", 
        "size": 20,
        "order": {
          "scoreAgg.avg": "asc"  //按照平均值进行排序
        }
      },
      "aggs": { 
        "scoreAgg": { 
          "stats": {
            "field": "score" 
          }
        }
      }
    }
  }
}

1.4 使用 RestClient 进行聚合

我们以各个酒店的品牌聚合为例,其中java语句与DSL语句的一一对应关系如下:
在这里插入图片描述
使用RestClient进行聚合的代码如下:

    @Test
    void testAgg() throws IOException {
        //1.准备Request对象
        SearchRequest request = new SearchRequest("hotel");
        //2.准备size
        request.source().size(0);
        //3.进行聚合
        request.source().aggregation(AggregationBuilders
                .terms("brandAgg")
                .field("brand")
                .size(10));
        //4.发送请求
        SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);
        //解析聚合结果
        Aggregations aggregations = response.getAggregations();
        //根据名称获取聚合结果
        Terms brandterms = aggregations.get("brandAgg");
        //获取桶
        List<? extends Terms.Bucket> buckets = brandterms.getBuckets();
        // 遍历
        for (Terms.Bucket bucket: buckets){
            // 获取key,也就是品牌信息
            String brandName = bucket.getKeyAsString();
            System.out.println(brandName);
        }
    }

结果如下:
在这里插入图片描述

2. 自动补全

2.1 安装补全包

自动补全我们需要实现的效果是当我们输入拼音的时候,就有一些产品的提示,这种情况下就需要我们对拼音有一定的处理,所以我们在这里下载一个拼音分词器,下载的方式与上面下载 IK 分词器相差不大,都是首先进入容器内部,然后在容器插件目录下进行安装,

# 进入容器内部
docker exec -it es /bin/bash

# 在线下载并安装
/usr/share/elasticsearch/bin/elasticsearch-plugin install --batch \
    https://github.com/medcl/elasticsearch-analysis-pinyin/releases/download/v7.12.1/elasticsearch-analysis-pinyin-7.12.1.zip

#退出
exit

#重启容器
docker restart es

重启后,使用拼音分词器试试效果,如下:

POST /_analyze
{
  "text": ["你干嘛哎哟"],
  "analyzer": "pinyin"
}

在这里插入图片描述

2.2 自定义分词器

从上面的例子我们可以看出,拼音分词器是将一句话的每个字都进行分开,并且首字母的拼音全部都在一起的,这肯定不是我们想要看到的,我们想要的是对句子进行分词后还能根据词语来创建拼音的索引,所以,这就需要我们自定义分词器了。

首先,我们需要了解分词器的工作步骤,elasticsearch中分词器(analyzer)的组成包含三部分:

  • character filters:在tokenizer之前对文本进行处理。例如删除字符、替换字符
  • tokenizer:将文本按照一定的规则切割成词条(term)。例如keyword,就是不分词;还有ik_smart tokenizer
  • filter:将tokenizer输出的词条做进一步处理。例如大小写转换、同义词处理、拼音处理等

自定义分词器的DSL代码如下:

PUT /test   //针对的是test索引库
{
  "settings": {
    "analysis": {
      "analyzer": { 	//自定义分词器
        "my_analyzer": {	//分词器名称
          "tokenizer": "ik_max_word",
          "filter": "py"	//过滤器名称
        }
      },
      "filter": { 
        "py": { 
          "type": "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"
      }
    }
  }
}

进行测试如下:

POST /test/_doc/1
{
  "id": 1,
  "name": "下雪"
}

POST /test/_doc/2
{
  "id": 2,
  "name": "瞎学"
}

GET /test/_search
{
  "query": {
    "match": {
      "name": "武汉在下雪嘛"
    }
  }
}

查询结果如下:
在这里插入图片描述

2.3 自动补全查询

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

  • 参与补全查询的字段必须是 completion 类型。
  • 字段的内容一般是用来补全的多个词条形成的数组。

首先我们先建立索引库以及索引库约束,

PUT test2
{
  "mappings": {
    "properties": {
      "title":{
        "type": "completion"
      }
    }
  }
}

test2 索引库中添加数据

// 示例数据
POST test2/_doc
{
  "title": ["Sony", "WH-1000XM3"]
}

POST test2/_doc
{
  "title": ["SK-II", "PITERA"]
}

POST test2/_doc
{
  "title": ["Nintendo", "switch"]
}

进行自动补全查询,我们给出一个关键字 s ,对其进行补全查询如下,

GET /test2/_search
{
  "suggest": {
    "title_suggest": {
      "text": "s", // 关键字
      "completion": {
        "field": "title", // 补全查询的字段
        "skip_duplicates": true, // 跳过重复的
        "size": 10 // 获取前10条结果
      }
    }
  }
}

查询结果如下:
在这里插入图片描述

2.4 拼音自动补全查询

如果想要使用拼音自动补全进行查询,那么就必须自定义分词器了,自定义分词器如下:

PUT /test3
{
  "settings": {
    "analysis": {
      "analyzer": { 
        "my_analyzer": {
          "tokenizer": "ik_max_word",
          "filter": "py"
        },
        "completion_analyzer": {
          "tokenizer": "keyword",
          "filter": "py"
        }
      },
      "filter": { 
        "py": { 
          "type": "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": {
      "title": {
        "type": "completion",
        "analyzer": "completion_analyzer"
      }
    }
  }
}

然后创建一个索引库,并添加一些文档,如下:

PUT /test3
{
  "mappings": {
    "properties": {
      "title":{
        "type": "completion"
      }
    }
  }
}

POST test3/_doc
{
  "title": ["上子", "熵字", "下雪"]
}

POST test3/_doc
{
  "title": ["赏金", "秀色", "猎人"]
}

然后就可以根据首字母缩写或者拼音来进行查询了,DSL代码如下:

GET /test3/_search
{
  "suggest": {
    "suggestions": {
      "text": "xx",
      "completion": {
        "field": "title",
        "skip_duplicates": true,
        "size": 10
      }
    }
  }
}

如上,我们输入的是下雪的拼音缩写 xx ,进行查询时,结果如下:
在这里插入图片描述
当然,也可以对拼音进行按顺序的补全查询。

2.5 RestClient 实现自动补全

2.5.1 建立索引

要实现对索引库的内容进行自动补全,我们需要重新创建索引库,我们的索引库需要多出一个 completion 字段的类型,所以删除原有的索引库后创建新的索引库如下:

DELETE /hotel

PUT /hotel
{
  "settings": {
    "analysis": {
      "analyzer": { 
        "my_analyzer": {
          "tokenizer": "ik_max_word",
          "filter": "py"
        },
        "completion_analyzer": {
          "tokenizer": "keyword",
          "filter": "py"
        }
      },
      "filter": { 
        "py": { 
          "type": "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": {
      "id": {
        "type": "keyword"
      },
      "name": {
        "type": "text",
        "analyzer": "ik_max_word",
        "copy_to": "all"
      },
      "address": {
        "type": "keyword",
        "index": false
      },
      "price": {
        "type": "integer"
      },
      "score": {
        "type": "integer"
      },
      "brand": {
        "type": "keyword",
        "copy_to": "all"
      },
      "city": {
        "type": "keyword"
      },
      "starName": {
        "type": "keyword"
      },
      "bussiness": {
        "type": "keyword",
        "copy_to": "all"
      },
      "location": {
        "type": "geo_point"
      },
      "pic": {
        "type": "keyword",
        "index": false
      },
      "all": {
        "type": "text",
        "analyzer": "ik_max_word"
      },
      "suggestion": {
        "type": "completion",
        "analyzer": "completion_analyzer"
      }
    }
  }
}

2.5.2 修改数据定义

除此之外,还需要将 Hotel 的定义进行修改,因为自动补全的字段不止一个字段,所以我们使用列表类型,定义如下:

@Data
@NoArgsConstructor
@ToString
public class HotelDoc {
    private Long id;
    private String name;
    private String address;
    private Integer price;
    private Integer score;
    private String brand;
    private String city;
    private String starName;
    private String business;
    private String location;
    private String pic;
    private List<String> suggestion;

    public HotelDoc(Hotel hotel) {
        this.id = hotel.getId();
        this.name = hotel.getName();
        this.address = hotel.getAddress();
        this.price = hotel.getPrice();
        this.score = hotel.getScore();
        this.brand = hotel.getBrand();
        this.city = hotel.getCity();
        this.starName = hotel.getStarName();
        this.business = hotel.getBusiness();
        this.location = hotel.getLatitude() + ", " + hotel.getLongitude();
        this.pic = hotel.getPic();
        this.suggestion = Arrays.asList(this.brand, this.business);
    }
}

以上定义就是将 brandbusiness 都进行补全的数据结构定义。

之后再按照之前的批量添加将数据库中的数据进行批量新增即可。

2.5.3 补全查询

以下是RestClient与DSL语句的一一对应关系,
在这里插入图片描述
补全查询的语句如下:

    @Test
    void testSuggest() throws IOException{
        //1. 准备Request
        SearchRequest request = new SearchRequest("hotel");
        //2. 准备DSL
        request.source().suggest(new SuggestBuilder().addSuggestion(
                "suggestions",
                SuggestBuilders.completionSuggestion("suggestion")
                        .prefix("hu")
                        .skipDuplicates(true)
                        .size(10)
        ));
        //3. 发起请求
        SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);
        //4. 输出结果
        System.out.println(response);
    }

2.5.4 解析结果

输出的查询结果是一个包含很多形式的信息的Map类型,我们需要对其进行解析,获取其中想要的结果才行,解析的语句与DSL查询的结果对应关系如下:
在这里插入图片描述
解析的结果的语句如下:

    @Test
    void testSuggest() throws IOException{
        //1. 准备Request
        SearchRequest request = new SearchRequest("hotel");
        //2. 准备DSL
        request.source().suggest(new SuggestBuilder().addSuggestion(
                "suggestions",
                SuggestBuilders.completionSuggestion("suggestion")
                        .prefix("hu")
                        .skipDuplicates(true)
                        .size(10)
        ));
        //3. 发起请求
        SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);
        //4. 解析结果
        Suggest suggest = response.getSuggest();
        //4.1 根据补全查询名称,获取补全结果
        CompletionSuggestion suggestions = suggest.getSuggestion("suggestions");
        //4.2 获取options
        List<CompletionSuggestion.Entry.Option> options = suggestions.getOptions();
        //4.3 遍历
        for (CompletionSuggestion.Entry.Option option : options) {
            String text = option.getText().toString();
            System.out.println(text);
        }
    }

处理后的结果输出如下:
在这里插入图片描述

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

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

相关文章

面试官如何考察与CAP相关的理论?

在互联网技术面试中&#xff0c;考察分布式技术已经是面试的标配了。很多招聘信息中&#xff0c;你能发现&#xff0c;一线互联网公司在对候选人的要求中都有“分布式系统设计”这一关键词。无论你是程序员&#xff0c;还是架构师&#xff0c;都要掌握分布式系统设计。 案例背…

vue使用打印组件print-js

项目场景&#xff1a; 由于甲方要求&#xff0c;项目需要打印二维码标签&#xff0c;故开发此功能 开发流程 安装包&#xff1a;npm install print-js --saveprint-js的使用 <template><div id"print" ref"print" ><p>打印内容<p&…

WebSocket 协议及其使用案例

文章目录 前言一、初识 WebSocket 协议1.1 什么是 WebSocket 协议1.2 WebSocket 与 HTTP 的关系1.3 WebSocket 握手的过程1.4 WebSocket 解决了什么问题 二、WebSocket 数据帧格式2.1 WebSocket 数据帧格式图示2.2 各字段的详细说明 三、SpringBoot 项目中引入 WebSocket3.1 创…

python中的文件操作

我们平常对文件的基本操作&#xff0c;大概可以分为三个步骤&#xff08;简称文件操作三步走&#xff09;&#xff1a; ① 打开文件 ② 读写文件 ③ 关闭文件 【注意事项】 注意&#xff1a;可以只打开和关闭文件&#xff0c;不进行任何读写 文件打开 open函数&#xff…

Hibernate(Spring Data)抓取策略

文章目录 示例代码放到最后&#xff0c;使用的是Springboot 项目1. 简介2. Hibernate抓取策略分类2.1 即时加载&#xff08;Eager Loading&#xff09;2.2 延迟加载&#xff08;Lazy Loading&#xff09;2.3 子查询加载&#xff08;Subselect Loading&#xff09;2.4 基于批处理…

排序之选择排序

文章目录 前言一、直接选择排序1、直接选择排序基本思想2、直接选择排序代码实现3、直接选择排序的效率 二、堆排序1、堆排序2、堆排序的效率 前言 选择排序的基本思想就是每一次从待排序的数据元素中选出最小(或最大)的一个元素&#xff0c;存放在序列的起始位置&#xff0c;…

pdfh5在线预览pdf文件

前言 pc浏览器和ios的浏览器都可以直接在线显示pdf文件&#xff0c;但是android浏览器不能在线预览pdf文件&#xff0c;如何预览pdf文件&#xff1f; Github: https://github.com/gjTool/pdfh5 Gitee: https://gitee.com/gjTool/pdfh5 使用pdfh5预览pdf 编写预览页面 <…

PSP - 蛋白质结构预测 OpenFold Multimer 模型训练参数与配置

欢迎关注我的CSDN&#xff1a;https://spike.blog.csdn.net/ 本文地址&#xff1a;https://spike.blog.csdn.net/article/details/132575709 OpenFold Multimer 是用于预测蛋白质多聚体结构的计算方法。基于OpenFold 的单体预测框架&#xff0c;利用深度学习技术&#xff0c;结…

Python Flask Web开发二:数据库创建和使用

前言 数据库在 Web 开发中起着至关重要的作用。它不仅提供了数据的持久化存储和管理功能&#xff0c;还支持数据的关联和连接&#xff0c;保证数据的一致性和安全性。通过合理地设计和使用数据库&#xff0c;开发人员可以构建强大、可靠的 Web 应用程序&#xff0c;满足用户的…

Mysql数据库(1)—索引

索引是什么&#xff1f; 索引是帮助MySQL高效获取数据的排好序的数据结构。常见的索引数据结构包括&#xff1a; 二叉树红黑树Hash表B-Tree mysql索引分类 按逻辑结构分类&#xff1a;B tree索引、Hash索引、Full-text索引。按物理存储分类&#xff1a; &#xff08;1&…

Linux命令awk详细用法

简介 awk 是一种强大的文本处理工具&#xff0c;用于在命令行环境下对文件或数据流进行逐行处理和分析。它是由 Alfred Aho、Peter Weinberger 和 Brian Kernighan 在 1977 年开发的&#xff0c;并以他们三人的姓氏命名。awk 在 Unix/Linux 系统中非常常见&#xff0c;也有 Win…

【Git】在idea中多分支开发如何——合并分支、处理冲突

博主简介&#xff1a;22级计算机科学与技术本科生一枚&#x1f338;博主主页&#xff1a;是瑶瑶子啦每日一言&#x1f33c;: “人间总有一两风&#xff0c;填我十万八千梦” 目录 一、背景二、具体操作 一、背景 我当前开发的分支——hfy我想将subject分支的最新代码拉取&…

银河麒麟V10(Tercel)服务器版安装 Docker

一、服务器环境 ## 查看系统版本&#xff0c;确认版本 cat /etc/kylin-release Kylin Linux Advanced Server release V10 (Tercel)## 操作系统 uname -p aarch64## 内核版本&#xff08;≥ 3.10&#xff09; uname -r 4.19.90-21.2.ky10.aarch64## iptables 版本&#xff08;…

PowerBuilder通过jdbc连接mysql

PowerBuilder,一个古老的IDE,打算陆续发些相关的,也许还有人需要,内容可能涉及其他作者,但基本都是基于本人实践整理,如涉及归属,请联系. 打开PB,菜单Tools--> system options,打开JAVA选项,点击新增文件&#xff08;白色文件图标&#xff09; 重要&#xff1a;需要在这里修…

实体店砍价营销活动制作技巧大公开

砍价营销是一种非常受欢迎的促销方式&#xff0c;可以吸引更多的顾客参与&#xff0c;提高销售量和品牌知名度。乔拓云网为您提供了一个简便而实用的砍价营销活动制作指南&#xff0c;让您轻松打造一场成功的砍价活动。 首先&#xff0c;您需要注册并登录乔拓云网账号&#xff…

简单了解网络传输介质

目录 一、同轴电缆 二、双绞线 三、光纤 四、串口电缆 一、同轴电缆 10BASE前面的数字表示传输带宽为10M&#xff0c;由于带宽较低、现在已不再使用。 50Ω同轴电缆主要用来传送基带数字信号&#xff0c;因此也被称作为基带同轴电缆&#xff0c;在局域网中得到了广泛的应用…

【函数栈帧解析:代码的迷人堆积和无限嵌套】

本章重点 一、何为函数栈帧 二、函数栈帧特性 - 同栈 - 后进先出 三、认识内存空间布局图 四、认识相关寄存器 五、认识相关汇编命令 六、测试代码&#xff1a; 七、函数栈帧全过程 要解决的问题​​​​​​​ 局部变量是怎么创建的&#xff1f;为什么局部变量的值是随机值&am…

echarts图表共用一个 timeline(A表 timeline 同时控制B表)

先看效果: 再看代码(部分): let barOption = {baseOption: {height: 350,timeline: {x: cen

部署项目至服务器

安装conda https://zhuanlan.zhihu.com/p/489499097 个人租借的服务器如何进行端口的开放呢&#xff1f; 防火墙设置&#xff1a; 添加规则设置&#xff1a; 即可&#xff1b; 通常下租借的服务器没有防火墙设置 相关链接&#xff1a; https://blog.csdn.net/weixin_4520…

SAP-MM-冲销凭证布局变更

业务场景&#xff1a; 仓管员在冲销物料凭证时MBST&#xff0c;显示行很少&#xff0c;只有7行&#xff0c;提出需求调整布局为多行&#xff0c;但是MBST没有调整布局功能&#xff0c; 解决&#xff1a;点击“定制本地布局-选项-字体设置”调整字体大小 跟据需求调整字体&…