SpringCloud(9)— Elasticsearch聚合和自动补全

news2025/1/15 12:57:29

SpringCloud(9)— Elasticsearch聚合和自动补全

一 数据聚合

1.聚合的分类

聚合(aggregations)可以实现对文档数据的统计,分析,运算。常见的聚合有三种:

1.桶聚合(Bucket)

text 不支持 桶聚合

桶聚合(Bucket)用来对文档做分组,其中比较常见的有:

  • TermAggregation:按照文档的字段值进行分组,类似 MySql 中的 group by
  • Date Histogram:按照日期阶梯分组,例如 一周或者一月 为一组

2.度量聚合(Metric)

text 和 keyword 不支持 度量聚合

度量聚合用于计算一些值,比如最大值,最小值,平均值等。常见的有:

  • Avg:平均值
  • Max:最大值
  • Min:最小值
  • Sum:求和
  • Stats:同时求 Avg, Max, Min, Sum 等

3.管道聚合(pipeline)

管道聚合以其他聚合的结果为基础做聚合

参与聚合的字段类型,不能是 text 类型

一般为 keyword,date,bool,integer 等

2.DSL实现Bucket聚合

以下是语法示例:

GET /【indexName】/_search
{
  "size":"分页值,默认为10,只做聚合不做数据分页时设置为0,则只会返回聚合结果而不会返回文档",
  "aggs": {
    "聚合名称,可自定义": {
      "聚合类型,一般为 terms": {
        "field": "字段名",
        "size": 返回的数据量
      }
    }
  }
}

默认情况下,Bucket 聚合会统计文档数量记为 _count,且按照 _count 进行倒序排序。

如果需要修改的话,则只需要增加 order 属性,并设置排序规则即可

以下是以 brand 为例的聚合示例:

GET /hotel/_search
{
  "size":0,
  "aggs": {
    "brandAgg": {
      "terms": {
        "field": "brand",
        "size": 20,
        "order":{
           "_count":"asc"
        }
      }
    }
  }
}

在这里插入图片描述

默认情况下,Bucket 聚合是对索引库的所有文档做聚合,对内存的消耗非常大。

我们可以通过增加 query 限定聚合的文档范围。

例如,只对 价格(price) 在 200-300 范围内的数据做聚合:

GET /hotel/_search
{
  "query": {
    "range": {
      "price": {
        "gte": 200,
        "lte": 300
      }
    }
  }, 
  "size":0,
  "aggs": {
    "brandAgg": {
      "terms": {
        "field": "brand",
        "size": 20,
        "order":{
           "_count":"asc"
        }
      }
    }
  }
}

3.DSL实现 Metrics 聚合

利用 Stats 聚合,获取指定字段的各项度量值

GET /hotel/_search
{
  "size":0,
  "aggs": {
    "brandAgg": {
      "terms": {
        "field": "brand",
        "size": 20
      },
      "aggs":{           //是 brandAgg 聚合后的子聚合,也就是分组后对每组分别计算
        "score_stats":{  //聚合名称
          "stats": {     //聚合类型,此处可以是 min,max,avg等
            "field": "score"  //聚合的字段值,只能是数值类型,因为只有数组可以进行加减乘除
          }
        }
      }
    }
  }
}

DSL 示例:

GET /hotel/_search
{
  "size":0,
  "aggs": {
    "brandAgg": {
      "terms": {
        "field": "brand",
        "size": 20
      },
      "aggs":{
        "score_stats":{
          "stats": {
            "field": "score"
          }
        }
      }
    }
  }
}

运行 DSL 代码,得到下图右侧的结果,利用 stats 同时计算出了最大值,最小值,和值,平均值以及数量。

在这里插入图片描述

此时如果想要对按照聚合之后的值排序,则应当使用 score_stats 中的属性来定义。

例如,按照 score 的最大值进行排序

GET /hotel/_search
{
  "size":0,
  "aggs": {
    "brandAgg": {
      "terms": {
        "field": "brand",
        "size": 20,
        "order": {
          "score_stats.max": "desc"
        }
      },
      "aggs":{
        "score_stats":{
          "stats": {
            "field": "score"
          }
        }
      }
    }
  }
}

4.RestClient实现聚合

先参考以下对照图

在这里插入图片描述

以下是测试示例:

@Test
public void testAggregationBrand() throws IOException {

    //1.创建 SearchRequest 对象,指定索引库名称
    SearchRequest request = new SearchRequest("hotel");
    //2.去掉文档数据
    request.source().size(0);
    request.source().aggregation(
            AggregationBuilders
                    //设置聚合类型为 term,且为聚合起名
                    .terms("brandAgg")
                    //设置需要聚合的字段
                    .field("brand")
                    //设置返回的数据量
                    .size(20)
                    //设置排序,
                    .order(BucketOrder.aggregation("_count",true))
    );
    //3.发送请求
    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) {
        String brandName = bucket.getKeyAsString();
        Long docCount = bucket.getDocCount();
        System.out.println(brandName+","+docCount);
    }
}

需要注意:使用 AggregationBuilders 来构建一个 aggregation 对象

二 自动补全

1.拼音分词器的使用

GitHub地址:elasticsearch-analysis-pinyin

安装步骤:

  1. 下载指定版本(与 es 版本保持一致,文档使用 v7.12.1)的 elasticsearch-analysis-pinyin
  2. 解压并上传至 es 容器挂载插件的目录(与 ik分词器 同一个目录)
  3. 重启 es 容器
  4. 测试
GET /_analyze
{
  "text":["如家"],
  "analyzer": "pinyin"
}

返回一下结果说明分词器安装成功,且成功分词

在这里插入图片描述

2.自定义分词器

1.分词器的构成

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

在这里插入图片描述

自定义分词器时不一定三部分都需要。根据实际业务需求即可。例如以下示例,只有 tokenizer 和 filter两部分,并没有 character

2.自定义分词器的实现

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

因为自定义分词器是在创建索引库时指定,所以自定义分词器只针对当前的索引库生效

以下是语法示例:

PUT /【indexName】
{
  "settings": {
    "analysis": {
      "analyzer": {
        "自定义分词器的名称":{
          "tokenizer":"分词器名称",
          "filter":"分词器名称"
        }
      }
    }
  }
}

实现示例:

PUT /test
{
  "settings": {
    "analysis": {
      "analyzer": {
        "my_analyzer":{
          "tokenizer":"ik_max_word",
          "filter":"pinyin"
        }
      }
    }
  }
}

以上这种默认实现会将汉字分为一个一个的拼音,这并非我们想要的。参考文档,设置其他相关参数。

以下是实现示例:

PUT /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
        }
      }
    }
  }
}
  • my_analyzer:自定义的分词器名称
  • py:自定义的分词器名称

3.拼音分词器注意事项

拼音分词器是和在创建倒排索引时使用,但不能在搜索时使用(会搜到同音词),因此字段在创建索引时应该使用创建的分词器,字段在搜索时应该使用 ik_smart 分词器

PUT /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"
      }
    }
  }
}

3.自动补全查询

1.Completion Suggester

elasticsearch 提供了 Completion Suggester 查询来实现自动补全,这个查询会匹配以用户输入的内容开头的词条并返回。

为了提高查询提高效率,需要堆文档中的字段做一些约束:

  • 要求查询字段必须为 completion 类型
  • 字段的内容一般是用来补全的多个词条形成的数据

在这里插入图片描述

2.语法示例

GET /test/_search
{
  "suggest": {
    "自定义suggest名称": {
      "text": "YOUR TEXT",
      "completion":{
        "field":"字段名",        // 补全查询的字段
        "skip_duplicates":true, //跳过重复的
        "size":10               // 获取前10条结果
      }
    }
  }
}

三 实现搜索的自动补全

1.修改原有的数据结构

使用自定义分词器,并且增加 suggestion 字段,用于实现自动补全

PUT /hotel
{
  "settings": {
    "analysis": {
      "analyzer": {
        "text_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": {
      "suggestion":{
        "type": "completion",
        "analyzer": "completion_analyzer"
      },
      "all":{
        "type": "text",
        "analyzer": "text_analyzer",
        "search_analyzer": "ik_smart"
      },
      "id":{
        "type": "keyword"
      },
      "name":{
        "type": "text",
        "copy_to": "all", 
        "analyzer": "text_analyzer",
        "search_analyzer": "ik_smart"
      },
      "address":{
        "type": "keyword",
        "index": false
      },
      "price":{
        "type": "double"
      },
      "score":{
        "type": "integer"
      },
      "brand":{
        "type": "keyword",
        "copy_to": "all"
      },
      "city":{
        "type": "keyword",
        "copy_to": "all"
      },
      "starName":{
        "type": "keyword",
        "copy_to": "all"
      },
      "business":{
        "type": "keyword",
        "copy_to": "all"
      },
      "location":{
        "type": "geo_point"
      },
      "pic":{
        "type": "keyword",
        "index": false
      },
      "isAD":{
        "type": "boolean"
      }
    }
  }
} 

2.重新导入数据

修改实体类与文档的对应关系,重新导入数据

@Data
@NoArgsConstructor
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 Object distance;
    /**
    * 新增自动补全字段
    */
    private List<String> suggestion;

    /**
     * 广告
     */
    public Boolean isAD;

    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();
        //处理广告字段(isAD)格式
        if (hotel.getIsAD() == 1) {
            this.isAD = true;
        } else {
            this.isAD = false;
        }
        //处理自动补全信息
        List<String> list =new ArrayList<>();

        list.add(hotel.getName());
        list.add(hotel.getBrand());

        //商圈信息含有"/"时视为多个,做切割处理
        String business = hotel.getBusiness();
        if (business.contains("/")) {
            String[] businessArr = business.split("/");
            Collections.addAll(list,businessArr);
        }

        this.setSuggestion(list);

    }
}

导入数据完成,使用 DSL 语句进行测试

GET /hotel/_search
{
  "suggest": {
    "textSuggestion": {
      "text": "s",
      "completion": {
        "field": "suggestion",
        "skip_duplicates":true,
        "size":10
      }
    }
  }
}

3.RestClient实现自动补全

先看格式对照

在这里插入图片描述

编写测试代码,实现自动补全

@Test
void testSuggestion() throws IOException {
    //1.创建 SearchRequest 对象
    SearchRequest searchRequest=new SearchRequest("hotel");
    //2.构造 DSL 语句
    searchRequest.source().suggest(
            new SuggestBuilder().addSuggestion("textSuggestion",
                    SuggestBuilders.completionSuggestion("suggestion")
                            .prefix("bj")
                            .skipDuplicates(true)
                            .size(10)
            ));
    //3.发送请求
    SearchResponse response = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
    //4.处理数据
    Suggest suggest = response.getSuggest();
    CompletionSuggestion suggestion= suggest.getSuggestion("textSuggestion");

    for (CompletionSuggestion.Entry.Option option : suggestion.getOptions()) {
        String text = option.getText().toString();
        System.out.println(text);
    }
}

解析结果实际按照Json格式去逐层解析:

在这里插入图片描述
完结撒花!!!

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

磁场传感器调研报告

目录 一.磁场传感器 二.磁场传感器工作原理 2.1霍尔效应原理 2.2霍尔传感器工作原理 三.磁场传感器分类介绍 3.1磁阻敏感器 3.2磁性液体加速度传感器 3.3磁性液体水平传感器 四.磁性传感器的应用 4.1汽车 4.2消费类电子产品 4.3工业智能控制和自动化 五、总结 一.…

iftop工具(网卡流量监控软件)的使用

直接运行iftop&#xff0c;不加任何参数 界面显示 界面上面显示的是类似刻度尺的刻度范围&#xff0c;为显示流量图形的长条作标尺用的。 中间的< >这两个左右箭头&#xff0c;表示的是流量的方向。 TX&#xff1a;发送流量 RX&#xff1a;接收流量 TOTAL&#xff1a;总…

open-local部署之后k8s的kube-scheduler挂掉问题

搭建一套k8s集群之后&#xff0c;本地存储化方案选择了阿里巴巴的open-local&#xff0c;没部署open-local&#xff0c;k8s 的kube-scheduler一切正常&#xff0c;只要按照官方文档部署了open-local&#xff0c;k8s的kube-scheduler就会挂掉&#xff0c;不是被kill掉&#xff…

Go的并发模型

Go的并发模型 文章目录Go的并发模型一、GO并发模型的三要素1.1 操作系统的用户空间和内核空间1.2 线程模型的实现&#xff08;1&#xff09;用户级线程模型&#xff08;2&#xff09;内核级线程模型&#xff08;3&#xff09;两级线程模型1.3 GO线程实现模型MPG二、什么是gorou…

选择题

目录 1058:选择题 输入格式&#xff1a; 输出格式&#xff1a; 输入样例&#xff1a; 输出样例&#xff1a; 代码长度限制: 时间限制: 内存限制: 思路: 1.选择题结构体 1.2 选择题结构体代码 2.判断选择题是否做对函数 2.1 判断选择题是否做对函数代码: 3.选择题的输入…

【并发】深入理解JMM并发三大特性(二)

t【并发】深入理解JMM&并发三大特性&#xff08;二&#xff09; 我们在上一篇文章中提到了JMM内存模型&#xff0c;并发的三大特性&#xff0c;其中对可见性做了详细的讲解&#xff01; 这一篇文章&#xff0c;将会站在硬件层面继续深入讲解并发的相关问题&#xff01; …

将整数字符串转成整数值

题目&#xff1a; 给定一个字符串 str&#xff0c;如果str符合日常书写的整数形式&#xff0c;并且属于 32 位整数的范围&#xff0c;返回 str 所代表的整数值&#xff0c;否则返回 0 。 举例&#xff1a; str "123" 返回 123 str "023" 返回 23 …

springboot整合之统一异常处理

特别说明&#xff1a;本次项目整合基于idea进行的&#xff0c;如果使用Eclipse可能操作会略有不同&#xff0c;不过总的来说不影响。 springboot整合之如何选择版本及项目搭建 springboot整合之版本号统一管理 springboot整合mybatis-plusdurid数据库连接池 springboot整合…

FFmpeg简单使用:过滤器 ---- h264_mp4toannexb

H264有两种封装方式&#xff1a;字节流AnnexB格式 AVCC格式。 1. AnnexB格式 ---- 用于实时播放 开始前缀&#xff08;00000001或000001&#xff09;&#xff0b;NALU数据  绝大部分编码器的默认输出格式   一共有两种起始码start_code    ①3字节0x000001  单帧多s…

C++面向对象特性——多态

C面向对象之多态什么是多态&#xff1f;为什么使用多态&#xff1f;虚函数的定义虚函数的实现机制哪些函数不能被设置为虚函数&#xff1f;虚函数的访问指针访问引用访问对象访问成员函数中的访问构造函数和析构函数中访问纯虚函数抽象类虚析构函数重载、隐藏、覆盖菱形继承虚拟…

spring boot文档阅读笔记——01

目录标题一、文档地址二、第一个spring boot例子三、 Starters&#xff08;spring boot 官方提供的启动器&#xff09;四、SpringBootApplication注释&#xff08;一&#xff09;EnableAutoConfiguration&#xff08;二&#xff09;ComponentScan五、devtools&#xff08;热插拔…

当项目经理看世界杯决赛时…

12月18日&#xff0c;2022卡塔尔世界杯决赛&#xff0c;阿根廷在点球大战中击败卫冕冠军的法国队&#xff0c;捧走大力神杯。这场跌宕起伏的“巅峰对决”&#xff0c;给大家呈现了一场精彩绝伦的比赛。 当阿根廷2-0领先七十多分钟的时候&#xff0c;都以为这局稳了&#xff0c…

跨平台应用开发进阶(五十一):HTML5(富文本内容)连续数字、字母不自动换行问题分析及解决

文章目录一、前言二、问题分析三、解决方法3.1 对 input 标签设置3.2 对 input 标签内的 p 标签设置四、延伸阅读 顶部状态栏穿透问题五、拓展阅读一、前言 项目开发过程中&#xff0c;涉及在Web端维护富文本内容&#xff0c;通过APP端查看的相关的功能&#xff0c;功能描述大…

repo init详解

首先选择manifest源&#xff0c;一般直接使用清华或中科大的镜像源 repo init -u https://aosp.tuna.tsinghua.edu.cn/platform/manifest是清华提供的镜像源 repo init -u git://mirrors.ustc.edu.cn/aosp/platform/manifest是中国科学技术大学的镜像源 repo init推荐使用-b 分…

未来汽车产业新生态高峰论坛在深圳举行

【2022年12月22日发自深圳】汽车产业正面临百年未有之大变局&#xff0c;以数字化技术为特征的智能网联汽车已经成为全球汽车产业转型升级的战略方向。汽车的属性也从一个机械化的交通工具转变成与各个生态相互连通的移动终端和数字空间。12月21日&#xff0c;由工业和信息化部…

【C++初阶】模板进阶

文章目录非类型模板参数模板特化函数模板特化类模板特化全特化偏特化模板的分离编译模板总结所有测试的代码非类型模板参数 模板参数分类类型形参与非类型形参 1.类型形参即&#xff1a;出现在模板参数列表中&#xff0c;跟在class或者typename之类的参数类型名称。 2.非类型形…

创建城市人口总量趋势图

创建城市人口总量趋势图学习目标使用数据人口总量趋势方程数据导入对数据进行处理fct_reorder2的应用对数据进行整理对图像进行可视化操作使用fct_reorder2去掉趋势点内容小结学习目标 我们所采用的学习内容来自B站的Lizongzhang老师的R语言的学习分享 今天学习的主要内容是关…

数据集说明:COCO的两个数据集COCO-stuff和COCO-Caption

数据集图片数量比较 COCO-Caption有33万张图、50万个caption COCO-Stuff有16.4万张图 172个类别(80thing、91stuff、1个未标注类) COCO-stuff的具体类别说明 COCO-Stuff contains 172 classes:80 thing, 91 stuff, and 1 class unlabeled. The 80 thing classes are the same …

群晖nas部署python项目

事件起因是因为想再硬盘里下载小姐姐&#xff0c;在线播放会卡顿很不爽&#xff0c; 开始用一些在线爬的网站&#xff0c;网速非常慢&#xff0c;我发现自己有nas 如果把项目部署再nas上 通过命令行下载就好了 我就开始检索资料&#xff0c;发现网上的都是一些过时的文章&#…

分布式系统关键路径延迟分析实践

作者 | 月色如海 导读 随着对用户体验的不断追求&#xff0c;延迟分析成为大型分布式系统中不可或缺的一环。本文介绍了目前在线服务中常用的延迟分析方法&#xff0c;重点讲解了关键路径分析的原理和技术实现方案&#xff0c;实践表明此方案效果显著&#xff0c;在耗时优化方面…