SpringCloud:ElasticSearch之自动补全

news2024/10/6 4:01:45

当用户在搜索框输入字符时,我们应该提示出与该字符有关的搜索项,如图:

在这里插入图片描述

这种根据用户输入的字母,提示完整词条的功能,就是自动补全了。

因为需要根据拼音字母来推断,因此要用到拼音分词功能。

1.拼音分词器

要实现根据字母做补全,就必须对文档按照拼音分词。在GitHub上恰好有elasticsearch的拼音分词插件。地址:https://github.com/medcl/elasticsearch-analysis-pinyin

在这里插入图片描述

安装方式与iK分词器一样,分三步:

​ ①下载解压

​ ②上传到虚拟机中,elasticsearchplugin目录

​ ③重启elasticsearch

​ ④测试

详细安装步骤可以参考IK分词器的安装过程。

测试用法如下:

POST /_analyze
{
  "text": "我爱北京天安门",
  "analyzer": "pinyin"
}

结果:

在这里插入图片描述

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

在这里插入图片描述

测试:

在这里插入图片描述

总结:

如何使用拼音分词器?

  • ①下载pinyin分词器

  • ②解压并放到elasticsearchplugin目录

  • ③重启即可

如何自定义分词器?

  • ①创建索引库时,在settings中配置,可以包含三部分

  • character filter

  • tokenizer

  • filter

拼音分词器注意事项?

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

3.自动补全查询

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

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

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

比如,一个这样的索引库:

// 创建索引库
PUT test
{
  "mappings": {
    "properties": {
      "title":{
        "type": "completion"
      }
    }
  }
}

然后插入下面的数据:

// 示例数据
POST test/_doc
{
  "title": ["Sony", "WH-1000XM3"]
}
POST test/_doc
{
  "title": ["SK-II", "PITERA"]
}
POST test/_doc
{
  "title": ["Nintendo", "switch"]
}

查询的DSL语句如下:

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

4.实现酒店搜索框自动补全

现在,我们的hotel索引库还没有设置拼音分词器,需要修改索引库中的配置。但是我们知道索引库是无法修改的,只能删除然后重新创建。

另外,我们需要添加一个字段,用来做自动补全,将brandsuggestioncity等都放进去,作为自动补全的提示。

因此,总结一下,我们需要做的事情包括:

  1. 修改hotel索引库结构,设置自定义拼音分词器

  2. 修改索引库的nameall字段,使用自定义分词器

  3. 索引库添加一个新字段suggestion,类型为completion类型,使用自定义的分词器

  4. HotelDoc类添加suggestion字段,内容包含brandbusiness

  5. 重新导入数据到hotel

4.1.修改酒店映射结构

代码如下:

// 酒店数据索引库
PUT /hotel
{
  "settings": {
    "analysis": {
      "analyzer": {
        "text_anlyzer": {
          "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": "text_anlyzer",
        "search_analyzer": "ik_smart",
        "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"
      },
      "business":{
        "type": "keyword",
        "copy_to": "all"
      },
      "location":{
        "type": "geo_point"
      },
      "pic":{
        "type": "keyword",
        "index": false
      },
      "all":{
        "type": "text",
        "analyzer": "text_anlyzer",
        "search_analyzer": "ik_smart"
      },
      "suggestion":{
          "type": "completion",
          "analyzer": "completion_analyzer"
      }
    }
  }
}

4.2.修改HotelDoc实体

HotelDoc中要添加一个字段,用来做自动补全,内容可以是酒店品牌、城市、商圈等信息。按照自动补全字段的要求,最好是这些字段的数组。

因此我们在HotelDoc中添加一个suggestion字段,类型为List<String>,然后将brandcitybusiness等信息放到里面。

代码如下:

package cn.itcast.hotel.pojo;

import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

@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 Boolean isAD;
    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();
        // 组装suggestion
        if(this.business.contains("/")){
            // business有多个值,需要切割
            String[] arr = this.business.split("/");
            // 添加元素
            this.suggestion = new ArrayList<>();
            this.suggestion.add(this.brand);
            Collections.addAll(this.suggestion, arr);
        }else {
            this.suggestion = Arrays.asList(this.brand, this.business);
        }
    }
}

4.3.重新导入

重新执行之前编写的导入数据功能,可以看到新的酒店数据中包含了suggestion

在这里插入图片描述

4.4.自动补全查询的JavaAPI

之前自动补全查询的DSL,而没有对应的JavaAPI,这里给出一个示例:

在这里插入图片描述

    @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("h")
                        .skipDuplicates(true)
                        .size(10)
        ));
        // 3.发送请求
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        // 4.解析响应
        System.out.println("response = " + response);
    }

在这里插入图片描述

而自动补全的结果也比较特殊,解析的代码如下:

在这里插入图片描述

    @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("h")
                        .skipDuplicates(true)
                        .size(10)
        ));
        // 3.发送请求
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        // 4.解析响应
        //System.out.println("response = " + response);
        Suggest suggest = response.getSuggest();
        // 4.1 根据名称获取补全结果
        CompletionSuggestion suggestions = suggest.getSuggestion("suggestions");
        // 4.2 获取options并遍历
        for (CompletionSuggestion.Entry.Option option : suggestions.getOptions()) {
            // 4.3 获取一个option的text,,也就是补全的词条
            String string = option.getText().string();
            System.out.println(string);
        }
    }

在这里插入图片描述

4.5.实现搜索框自动补全

1)在cn.itcast.hotel.web包下的HotelController中添加新接口,接收新的请求:

@GetMapping("suggestion")
public List<String> getSuggestions(@RequestParam("key") String prefix) {
    return hotelService.getSuggestions(prefix);
}

2)在cn.itcast.hotel.service包下的IhotelService中添加方法:

List<String> getSuggestions(String prefix);

3)在cn.itcast.hotel.service.impl.HotelService中实现该方法:

@Override
public List<String> getSuggestions(String prefix) {
    try {
        // 1.准备Request
        SearchRequest request = new SearchRequest("hotel");
        // 2.准备DSL
        request.source().suggest(new SuggestBuilder().addSuggestion(
            "suggestions",
            SuggestBuilders.completionSuggestion("suggestion")
            .prefix(prefix)
            .skipDuplicates(true)
            .size(10)
        ));
        // 3.发起请求
        SearchResponse response = client.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.遍历
        List<String> list = new ArrayList<>(options.size());
        for (CompletionSuggestion.Entry.Option option : options) {
            String text = option.getText().toString();
            list.add(text);
        }
        return list;
    } catch (IOException e) {
        throw new RuntimeException(e);
    }
}

在这里插入图片描述

在这里插入图片描述

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

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

相关文章

【移动端网页布局】移动端网页布局基础概念 ④ ( 物理像素 | 物理像素比 | 代码示例 - 100 像素在 PC浏览器 / 移动端浏览器 显示效果 )

文章目录 一、物理像素 / 物理像素比二、代码示例 - 100 像素在 PC浏览器 / 移动端浏览器 显示效果 一、物理像素 / 物理像素比 移动端 网页开发 与 PC 端开发有很多不同之处 , 在图片处理方向需要采用 二倍图 / 三倍图 / 多倍图 方式进行图片处理 ; 图片处理的方式与如下的 物…

项目支付接入支付宝【沙箱环境】

前言 订单支付接入支付宝&#xff0c;使用支付宝提供的沙箱机制模拟为订单付款。我这里主要记录一下沙箱环境如何接入到系统中&#xff0c;具体细节的实现。按照官方文档来就可以了。 1、使用步骤 这里有几个重要数据要拿到&#xff0c;一个是支付宝的公钥和私钥&#xff0c…

ClickHouse监控系统Prometheus+Grafana

目录 1 PrometheusGrafana概述2 安装Prometheus Grafana3 配置ClickHouse4 配置Grafana 1 PrometheusGrafana概述 ClickHouse 运行时会将一些个自身的运行状态记录到众多系统表中( system.*)。所以我们对于 CH 自身的一些运行指标的监控数据&#xff0c;也主要来自这些系统表。…

docoker笔记

0.安装Docker Docker 分为 CE 和 EE 两大版本。CE 即社区版&#xff08;免费&#xff0c;支持周期 7 个月&#xff09;&#xff0c;EE 即企业版&#xff0c;强调安全&#xff0c;付费使用&#xff0c;支持周期 24 个月。 Docker CE 分为 stable test 和 nightly 三个更新频道…

RabbitMQ【#1】是什么,有什么用

RabbiMQ是什么&#xff1f; RabbitMQ是一种开源的消息队列软件&#xff0c;它实现了高级消息队列协议&#xff08;AMQP&#xff09;并支持多种编程语言。它可以用于将消息从一个应用程序传递到另一个应用程序或进程&#xff0c;并支持分布式系统中的异步消息通信。RabbitMQ的主…

【Linux】System V 共享内存、消息队列、信号量

&#x1f34e;作者&#xff1a;阿润菜菜 &#x1f4d6;专栏&#xff1a;Linux系统编程 system V共享内存介绍 System V 共享内存是一种进程间通信的机制&#xff0c;它允许多个进程共享一块物理内存区域&#xff08;称为“段”&#xff09;。System V 共享内存的优点是效率高&…

AD21 PCB----过滤、捕获、板子边框绘制、精准移动

目录 过滤器和捕获 板子边框绘制 精准移动 过滤器和捕获 板子边框绘制 两种方式均在Mechanical 1 方式一&#xff1a; 第一步&#xff1a;利用PCB的基础图形进行绘制边框 第二步&#xff1a;选中绘制的图形 第三步&#xff1a; 方式二&#xff1a;外部导入 第一步&#x…

SpringCloud 微服务系列——【服务间的通信方式、OpenFeign、Hystrix组件使用】

✅作者简介&#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏…

【UE 粒子系统】电火花粒子效果

效果 步骤 1. 新建一个粒子系统&#xff0c;命名为“SparkParticles” 再新建一个材质&#xff0c;命名为“SparkParticleMaterial” 2. 打开“SparkParticleMaterial”&#xff0c;将混合模式改为半透明&#xff0c;着色模型为无光照 然后添加如下节点 3. 打开“SparkParticl…

输入输出练习

文章目录 1. AB(1)2. AB(2)3. AB(3)4. AB(4)计算一系列数的和5. AB(5) 计算一系列数的和6. AB(6)7. AB(7)8. 字符串排序(1)9. 字符串排序(2)10 字符串排序(2)11. 注意数据范围 1. AB(1) import java.util.Scanner;// 注意类名必须为 Main, 不要有任何 package xxx 信息 public …

差分运算放大电路原理解析

差分运算放大电路&#xff0c;对共模信号得到有效抑制&#xff0c;而只对差分信号进行放大&#xff0c;因而得到广泛的用。 注&#xff1a; &#xff08;1&#xff09;共模信号   共模信号&#xff08;common mode signal&#xff09;是指同时作用于多个电路或电子设备上的信…

1.10和1.11和1.12、Makefile

1.10和1.11和1.12、Makefile 1.10、Makefile(1)1.10.1、什么是Makefile1.10.2、Makefile的文件命名和规则实际操作 1.11、Makefile(2)1. 工作原理&#xff08;1.10.3&#xff09;实际操作 1.12、Makefile(3)1. 变量2. 模式匹配3. 函数实际操作①实现变量和模式匹配②实现函数操…

Vue(简介、前期配置、Vue展示、模板语法)

一、简介 1. 什么是Vue&#xff1f; 2. Vue特点 采用组件化模式&#xff0c;提高代码复用率、且让代码更好维护 组件化&#xff1a;每一部分直接就是大盒子组件&#xff08;创建一个单独的Vue文件&#xff09;&#xff0c;直接可以修改单独封装的组件部分代码 Vue使用声明式…

为什么需要内网穿透技术?

随着互联网技术的快速发展&#xff0c;企业和个人越来越依赖于网络资源&#xff0c;而内网穿透技术正是解决远程访问内网资源的关键。本文将详细介绍内网穿透的概念及其重要性&#xff0c;以帮助您了解为什么我们需要使用内网穿透技术。 目录 一、内网穿透技术简介 二、为什…

Java中List排序的3种方法

在某些特殊的场景下&#xff0c;我们需要在 Java 程序中对 List 集合进行排序操作。比如从第三方接口中获取所有用户的列表&#xff0c;但列表默认是以用户编号从小到大进行排序的&#xff0c;而我们的系统需要按照用户的年龄从大到小进行排序&#xff0c;这个时候&#xff0c;…

2 变量运算符-基本数据类型讲解【Go语言教程】

2 变量运算符-基本数据类型讲解【Go语言教程】 2.1 变量 2.1.1 声明变量方式 指定变量类型&#xff0c;声明后若不赋值&#xff0c;使用默认值 类型推导 通过: 多变量声明 全局变量定义 在函数外部定义的就是全局变量 变量变量名值数据类型 注意&#xff1a;如果go程序报错&…

UE4/5多人游戏详解(七、自定义委托,实现寻找会话和加入会话的函数,通过Steam进行两台电脑的联机)

目录 可能出现问题&#xff08;在六部分的测试可能无法连接的问题【在末尾加上了&#xff0c;怕有人没看见在这里写一下】&#xff09; 自定义委托 调整位置 创建更多的委托和回调函数给菜单&#xff1a; 多播和动态多播 代码&#xff1a; 委托变量 代码&#xff1a; 回…

( “树” 之 BST) 109. 有序链表转换二叉搜索树 ——【Leetcode每日一题】

二叉查找树&#xff08;BST&#xff09;&#xff1a;根节点大于等于左子树所有节点&#xff0c;小于等于右子树所有节点。 二叉查找树中序遍历有序。 109. 有序链表转换二叉搜索树 给定一个单链表的头节点 head &#xff0c;其中的元素 按升序排序 &#xff0c;将其转换为高度…

Linux: 进程间通信机制

文章目录 1. 前言2. 进程间通信机制2.1 管道2.1.1 匿名管道2.1.2 popen() 和 pclose()2.1.3 命名管道 FIFO 2.2 消息队列2.3 共享内存2.4 信号量2.5 网络套接字2.6 UNIX套接字2.7 信号 3. 参考资料 1. 前言 限于作者能力水平&#xff0c;本文可能存在谬误&#xff0c;因此而给…

基于格密码的LWE问题

LWE LWE问题&#xff0c; Learning With Errors&#xff0c;带有安全性证明的第一个版本是由Oded Regev 在2005年提出&#xff0c;Kawachi等给出了效率的改进&#xff0c;接着一些效率方面非常重要的改进由Peikert等提出。 格理论知识 格密码学&#xff08;Lattice-based Cr…