elasticsearch的搜索补全提示

news2024/11/28 23:41:31

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

拼音分词器

下载 

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

GitHub - medcl/elasticsearch-analysis-pinyin: This Pinyin Analysis plugin is used to do conversion between Chinese characters and Pinyin.

解压

解压到一个文件夹中去

上传 

上传到服务器中,elasticsearch的plugin目录  

重启 

重启elasticsearch  

docker restart es

 测试

POST /_analyze
{
  "text": "如家酒店还不错",
  "analyzer": "pinyin"
}

返回拼音 

自定义分词器

默认的拼音分词器会将每个汉字单独分为拼音,而我们希望的是每个词条形成一组拼音,需要对拼音分词器做个性化定制,形成自定义分词器。

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

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

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

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

自定义分词器 

PUT /myanalyzer
{
  "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"
      }
    }
  }
}
  • analyzer自定义分词器 
  • my_analyzer分词器名称
  • filter自定义tokenizer filter
  • py过滤器名称
  • filter.type过滤器类型,这里是pinyin
  • name分词的字段

 测试

POST /myanalyzer/_analyze
{
  "text": ["华美达酒店还不错"],
  "analyzer": "my_analyzer"
}

结果

自动补全查询 

创建索引库

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

HotelDoc实体

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

导入数据

 @Test
    void testBulkRequest() throws IOException {
        // 批量查询酒店数据
        List<Hotel> hotels = hotelService.list();

        // 1.创建Request
        BulkRequest request = new BulkRequest();
        // 2.准备参数,添加多个新增的Request
        for (Hotel hotel : hotels) {
            // 2.1.转换为文档类型HotelDoc
            HotelDoc hotelDoc = new HotelDoc(hotel);
            // 2.2.创建新增文档的Request对象
            request.add(new IndexRequest("hotel")
                    .id(hotelDoc.getId().toString())
                    .source(JSON.toJSONString(hotelDoc), XContentType.JSON));
        }
        // 3.发送请求
        client.bulk(request, RequestOptions.DEFAULT);
    }

controller类



import cn.itcast.hotel.pojo.PageResult;
import cn.itcast.hotel.pojo.RequestParams;
import cn.itcast.hotel.service.IHotelService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.Map;

@RestController
@RequestMapping("/hotel")
public class HotelController {

    @Autowired
    private IHotelService hotelService;
	// 搜索酒店数据


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

service类


import cn.itcast.hotel.mapper.HotelMapper;
import cn.itcast.hotel.pojo.Hotel;
import cn.itcast.hotel.pojo.HotelDoc;
import cn.itcast.hotel.pojo.PageResult;
import cn.itcast.hotel.pojo.RequestParams;
import cn.itcast.hotel.service.IHotelService;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;

import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.geo.GeoPoint;
import org.elasticsearch.common.unit.DistanceUnit;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.functionscore.FunctionScoreQueryBuilder;
import org.elasticsearch.index.query.functionscore.ScoreFunctionBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.elasticsearch.search.suggest.Suggest;
import org.elasticsearch.search.suggest.SuggestBuilder;
import org.elasticsearch.search.suggest.SuggestBuilders;
import org.elasticsearch.search.suggest.completion.CompletionSuggestion;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class HotelService extends ServiceImpl<HotelMapper, Hotel> implements IHotelService {

    @Autowired
    private RestHighLevelClient client;

   

    @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/975690.html

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

相关文章

儿童玩具音乐芯片方案,6通道midi播放语音芯片,WT588F02B-8S

随着科技的不断进步&#xff0c;儿童玩具行业也在不断演化。如今&#xff0c;儿童们期待的不仅仅是有趣的外观&#xff0c;还有令人惊叹的音乐和声音效果。为了满足这一需求&#xff0c;深圳唯创知音研发了WT588F02B-8S&#xff0c;一款创新的6通道MIDI播放语音芯片&#xff0c…

手写Mybatis:第18章-一级缓存

文章目录 一、目标&#xff1a;一级缓存二、设计&#xff1a;一级缓存三、实现&#xff1a;一级缓存3.1 工程结构3.2 一级缓存类图3.3 一级缓存实现3.3.1 定义缓存接口3.3.2 实现缓存接口3.3.3 创建缓存KEY3.3.4 NULL值缓存key 3.4 定义缓存机制、占位符和修改配置文件3.4.1 定…

Jrebel与Xrebel教学

简介 JRebel和XRebel是两个非常有用的工具&#xff0c;可以显著提升Java开发人员的生产力和应用程序性能。 JRebel是一个强大的Java开发工具&#xff0c;它允许开发人员在不重新启动应用程序的情况下进行代码修改和调试。传统上&#xff0c;每次修改Java代码都需要重新编译和重…

bat批处理——统计当前文件夹下的所有文件名

一、在当前文件夹下建立XX.txt文件&#xff0c;将指令dir *.* /b/s>test.txt写到XX.txt文件中 测试文件夹目录及文件结构图&#xff1a; 指令说明&#xff1a; dir *.* /b/s>test.txt /*** 此部分为注释内容* dir 获取当前目录下的目录及文件* *.* 对文件进行筛选&…

ShopXO商城系统文件上传0Day代审历程

Git仓库&#xff1a; https://github.com/gongfuxiang/shopxo简介&#xff1a; 两天攻防中&#xff0c;某政局内网横向发现多网段服务器&#xff0c;该服务器搭建了ShopXO商城系统(后来发现是开发临时搭建的&#xff0c;准备做二开用的)。结果花了30来秒审了个垃圾Day拿下该服…

应用于激光雷达、 激光测距、 脉冲测量的高精度时间测量(TDC)电路MS1205N

MS1205N 是一款高精度时间测量 (TDC) 电路&#xff0c;具有四通 道、多脉冲的采样能力、高速 SPI 通讯、多种测量模式&#xff0c;适合 于激光雷达和激光测距。 主要特点 ◼ 单精度模式 60ps ◼ 双精度模式 30ps ◼ 非校准测量范围 3.5ns(0ns) 至 25μs ◼ 单…

【LeetCode】202. 快乐数 - hash表 / 快慢指针

目录 2023-9-5 09:56:15 202. 快乐数 2023-9-5 09:56:15 关键是怎么去判断循环&#xff1a; hash表&#xff1a; 每次生成链中的下一个数字时&#xff0c;我们都会检查它是否已经在哈希集合中。 如果它不在哈希集合中&#xff0c;我们应该添加它。如果它在哈希集合中&#x…

docker安装mysql、clickhouse、oracle等各种数据库汇总

1&#xff1a;docker 安装mongo数据库并使用 官网&#xff1a;https://www.mongodb.com/docs/manual/ 安装 &#xff1a;https://www.zhihu.com/question/54602953/answer/3047452434?utm_id0 安装2&#xff1a;https://www.duidaima.com/Group/Topic/ArchitecturedDesign/91…

MySQL 全局锁、表级锁、行锁详解

前言 MySQL 里面的锁大致可以分成全局锁、表级锁和行锁三类&#xff0c;全局锁和表级锁是在server层实现的。 全局锁 全局锁就是对整个数据库实例加锁。MySQL 提供了一个加全局读锁的方法&#xff0c;命令是 Flush tables with read lock (FTWRL)。当你需要让整个库处于只读状…

华为产业链爆发,这次是系统级的革命

华为Mate60手机爆火&#xff0c;让产业链随之振奋。我们看到&#xff0c;这种改变将是持久的、系统的。 可能在未来20年&#xff0c;这种影响会持续。 01 华为产业链有多长 客观而言&#xff0c;华为产业链可以看作是由多个领域的企业和组织组成的网络&#xff0c;其中包括半…

Linux内核源码分析 (B.1)内核内存布局和堆管理

Linux内核源码分析 (B.1)内核内存布局和堆管理 文章目录 Linux内核源码分析 (B.1)内核内存布局和堆管理一、Linux内核内存布局二、堆管理 一、Linux内核内存布局 64位Linux一般使用48位来表示虚拟地址空间&#xff0c;45位表示物理地址。通过命令&#xff1a;cat/proc/cpuinfo。…

HTML5-4-表单

文章目录 表单属性表单标签输入元素文本域&#xff08;Text Fields&#xff09;密码字段单选按钮&#xff08;Radio Buttons&#xff09;复选框&#xff08;Checkboxes&#xff09;按钮&#xff08;button&#xff09;提交按钮(Submit)label标签 文本框&#xff08;textarea&am…

叉积方法,求点与线段的相对位置

叉积可以用来判断一个点在一条线段的哪个方向。 线段两个端点坐标为 A(x1, y1), B(x2, y2)&#xff0c; 假设点 P 的坐标为 (px, py)&#xff0c; 则向量 AP 和 BP 的坐标表示为&#xff1a; AP (px - x1, py - y1) BP (x2 - px, y2 - py) 叉积的计算公式为&#xff1a; (py…

基于jeecg-boot的flowable流程自定义业务退回撤回或驳回到发起人后的再次流程提交

更多nbcio-boot功能请看演示系统 gitee源代码地址 后端代码&#xff1a; https://gitee.com/nbacheng/nbcio-boot 前端代码&#xff1a;https://gitee.com/nbacheng/nbcio-vue.git 在线演示&#xff08;包括H5&#xff09; &#xff1a; http://122.227.135.243:9888 主要…

神仙级python入门教程(非常详细),从0到精通,从看这篇开始!

毫无疑问&#xff0c;Python 是当下最火的编程语言之一。对于许多未曾涉足计算机编程的领域「小白」来说&#xff0c;深入地掌握 Python 看似是一件十分困难的事。其实&#xff0c;只要掌握了科学的学习方法并制定了合理的学习计划&#xff0c;Python 从 入门到精通只需要一个月…

骨传导和入耳式哪个危害大一点?入耳式和骨传导哪种好?

骨传导和入耳式这两种耳机虽然都存在一定的危害&#xff0c;但是入耳式耳机对人体的危害要更大一点。 入耳式耳机直接塞进耳朵这种佩戴方式&#xff0c;会阻塞外部声音的进入&#xff0c;长时间使用可能会导致耳道感染&#xff0c;还可能对听力造成损伤&#xff0c;而骨传导耳…

RecyclerView源码解析(二):结合LinearLayout分析绘制流程

RecyclerView源码解析&#xff08;二&#xff09;:结合LinearLayout分析绘制流程 封面&#xff1a; 导言 上篇文章中主要已经介绍了RecyclerView的View的三大工作流程&#xff08;onMeasure&#xff0c;onLayout&#xff0c;onDraw&#xff09;&#xff0c;实际上看了上篇文章…

数学思维导图怎么绘制?这个详细绘制方法了解一下

数学思维导图怎么绘制&#xff1f;数学思维导图是数学学习中的一种重要辅助工具。在复杂的数学问题中&#xff0c;思维导图可以帮助学生更好地理解和组织各个知识点&#xff0c;从而更好地解决问题。在绘制数学思维导图时&#xff0c;有很多工具可供选择&#xff0c;下面就给大…

港陆证券:政策累积效应催生A股普涨行情 北证50指数创最大单日涨幅

周一&#xff0c;在活泼资本商场政策继续推出、不断累积的布景下&#xff0c;A股商场迎来久别的普涨行情。金融、白酒与资源类板块集体发力&#xff0c;带动沪深主板指数高开高走。北交所商场体现更为亮眼&#xff0c;北证50指数收盘大涨5.92%&#xff0c;创该指数前史最大单日…

CSS中图片旋转超出父元素解决办法

下面的两种解决办法都会导致图片缩小&#xff0c;可以给图片进行初始化的宽高设置 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge">…