搜索自动补全-elasticsearch实现

1. elasticsearch准备

1.1 拼音分词器

github地址:https://github.com/infinilabs/analysis-pinyin/releases?page=6
必须与elasticsearch的版本相同
在这里插入图片描述第四步,重启es

docker restart es

1.2 定义索引库

PUT /app_info_article
{
  "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":"long"
            },
            "publishTime":{
                "type":"date"
            },
            "layout":{
                "type":"integer"
            },
            "images":{
                "type":"keyword",
                "index": false
            },
            "staticUrl":{
                "type":"keyword",
                "index": false
            },
            "authorId": {
                "type": "long"
            },
            "authorName": {
                "type": "text"
            },
            "title":{
                "type":"text",
                "analyzer":"text_anlyzer",
                "search_analyzer": "ik_max_word", 
                "copy_to": "all"
            },
            "content":{
                "type":"text",
                "analyzer":"text_anlyzer",
                "search_analyzer": "ik_max_word", 
                "copy_to": "all"
            },
            "all":{
              "type": "text",
              "analyzer": "ik_max_word"
            },
            "suggestion":{
              "type": "completion",
              "analyzer": "completion_analyzer"
            }
        }
    }
}

1.3 给索引库添加文档

详情参考我的另一篇博客: xxljob分片广播+多线程实现高效定时同步elasticsearch索引库
app_info_article对应的pojo类

@Data
public class SearchArticleVo {

    // 文章id
    private Long id;
    // 文章标题
    private String title;
    // 文章发布时间
    private Date publishTime;
    // 文章布局
    private Integer layout;
    // 封面
    private String images;
    // 作者id
    private Long authorId;
    // 作者名词
    private String authorName;
    //静态url
    private String staticUrl;
    //文章内容
    private String content;

    //状态
    private int enable;

    //单词自动补全
    private List<String> suggestion;

    public void initSuggestion(){
        suggestion = new ArrayList<String>();
        suggestion.add(this.title);
        suggestion.add(this.authorName);
    }
}

核心代码

@XxlJob("syncIndex")
    public void syncIndex()  {
        //1、获取任务传入的参数   {"minSize":100,"size":10}
        String jobParam = XxlJobHelper.getJobParam();
        Map<String,Integer> jobData = JSON.parseObject(jobParam,Map.class);
        int minSize = jobData.get("minSize"); //分片处理的最小总数据条数
        int size =  jobData.get("size"); //分页查询的每页条数   小分页

        //2、查询需要处理的总数据量  total=IArticleClient.searchTotal()
        Long total = articleClient.searchTotal();

        //3、判断当前分片是否属于第1片,不属于,则需要判断总数量是否大于指定的数据量[minSize],大于,则执行任务处理,小于或等于,则直接结束任务
        int cn = XxlJobHelper.getShardIndex(); //当前节点的下标
        if(total<=minSize && cn!=0){
            //结束
            return;
        }
        //4、执行任务   [index-范围]   大的分片分页处理
        //4.1:节点个数
        int n = XxlJobHelper.getShardTotal();
        //4.2:当前节点处理的数据量
        int count = (int) (total % n==0? total/n :  (total/n)+1);
        //4.3:确定当前节点处理的数据范围
        //从下标为index的数据开始处理  limit #{index},#{count}
        int indexStart = cn*count;
        int indexEnd = cn*count+count-1; //最大的范围的最后一个数据的下标
        //5.小的分页查询和批量处理
        int index =indexStart; //第1页的index

        System.out.println("分片个数是【"+n+"】,当前分片下标【"+cn+"】,处理的数据下标范围【"+indexStart+"-"+indexEnd+"】");
        do {
            //=============================================小分页================================
            //5.1:分页查询
            //5.2:将数据导入ES
            push(index,size,indexEnd);

            //5.3:是否要查询下一页 index+size
            index = index+size;
        }while (index<=indexEnd);
    }


    /**
     * 数据批量导入
     * @param index
     * @param size
     * @param indexEnd
     * @throws IOException
     */
    public void push(int index,int size,int indexEnd)  {

        pool.execute(()->{
            System.out.println("当前线程处理的分页数据是【index="+index+",size="+(index+size>indexEnd? indexEnd-index+1 : size)+"】");
            //1)查询数据库数据
            List<SearchArticleVo> searchArticleVos = articleClient.searchPage(index, index+size>indexEnd? indexEnd-index+1 : size);  //size可能越界
                                                                                                       // 第1页  index=0
                                                                                                       //       indexEnd=6
                                                                                                       // 第2页  index=5
                                                                                                       //       indexEnd-index+=2
            //2)创建BulkRequest - 刷新策略
            BulkRequest bulkRequest = new BulkRequest()
                    //刷新策略-立即刷新
                    .setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE);
            for (SearchArticleVo searchArticleVo : searchArticleVos) {
                //A:创建XxxRequest
                searchArticleVo.initSuggestion();
                IndexRequest indexRequest = new IndexRequest("app_info_article")
                        //B:向XxxRequest封装DSL语句数据
                        .id(searchArticleVo.getId().toString())
                        .source(com.alibaba.fastjson.JSON.toJSONString(searchArticleVo), XContentType.JSON);

                //3)将XxxRequest添加到BulkRequest
                bulkRequest.add(indexRequest);
            }

            //4)使用RestHighLevelClient将BulkRequest添加到索引库
            if(searchArticleVos!=null && searchArticleVos.size()>0){
                try {
                    restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        });
    }

在xxl-job任务调度平台执行一次该任务,文档就被添加进去了
如图
在这里插入图片描述

1.4 自动补全查询

// 自动补全查询
GET /test/_search
{
  "suggest": {
    "title_suggest": {	//设置这个自动查询操作的名称
      "text": "java", // 关键字
      "completion": {
        "field": "suggestion", // 补全查询的字段名
        "skip_duplicates": true, // 跳过重复的
        "size": 10 // 获取前10条结果
      }
    }
  }
}

示例1.
在这里插入图片描述
示例2.
在这里插入图片描述

2. 代码流程

2.1 核心业务代码

AssociateController

@RestController
@RequestMapping(value = "/api/v1/associate")
public class AssociateController {

    @Autowired
    private AssociateService associateService;

    /***
     * 单词自动补全
     */
    @PostMapping(value = "/search")
    public ResponseResult search(@RequestBody UserSearchDto dto) throws IOException {
        return associateService.search(dto);
    }
}

核心search方法

	@Autowired
    private RestHighLevelClient restHighLevelClient;
	/***
     * 单词自动补全
     * @param dto
     * @return
     */
    @Override
    public ResponseResult search(UserSearchDto dto) throws IOException {
        //1)新建一个SearchRequest
        SearchRequest request = new SearchRequest("app_info_article");

        //2)创建一个单词自动补全配置 Suggest,给它取个别名
        request.source().suggest(
                new SuggestBuilder()
                .addSuggestion(
                                //给它取个别名
                        "article_suggest",
                        SuggestBuilders
                                //指定查询的字段
                                .completionSuggestion("suggestion")
                                //去重
                                .skipDuplicates(true)
                                //搜索的前缀
                                .prefix(dto.getSearchWords())
                                .size(10)
                        )
        );

        //4)执行搜索
        SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);

        //5)解析结果集
        CompletionSuggestion suggests = response.getSuggest().getSuggestion("article_suggest");

        //List
        List<Map<String,String>> options = new ArrayList<Map<String,String>>();
        for (CompletionSuggestion.Entry.Option option : suggests.getOptions()) {
            Map<String,String> dataMap = new HashMap<String,String>();
            dataMap.put("associateWords",option.getText().toString());
            options.add(dataMap);

        }
        return ResponseResult.okResult(options);
    }

结果集解析
在这里插入图片描述
在这里插入图片描述

2.2 测试

请求url:http://127.0.0.1:8801/app/search/api/v1/associate/search/
其中/app/search为nginx和gateway处理过

  • 测试1
    在这里插入图片描述

  • 测试2
    在这里插入图片描述
    ps:联想词中的蓝色高亮是前端处理的。

  • 测试3
    在这里插入图片描述

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

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

相关文章

vim操作手册

vim分为插入模式、命令模式、底行模式。 插入模式&#xff1a;编辑模式 命令模式&#xff1a;允许使用者通过命令&#xff0c;来进行文本的编辑控制 底行模式&#xff1a;用来进行让vim进行包括但不限于shell进行交互 w&#xff1a;保存 wq&am…

AI Agent: Agent框架+7个实例

何谓Agent Agent 作为一种新兴的人工智能技术&#xff0c;正在受到越来越多的关注。要说清楚什么是 Agent&#xff0c;先得看看人工智能的本质是什么。 人工智能这个名称来自它试图通过计算机程序或机器来模拟、扩展和增强人类智能的 一些方面。在这个定义中&#xff0c;“人…

Java进阶学习笔记20——枚举

认识枚举&#xff1a; 枚举是一种特殊的类。 枚举类的格式&#xff1a; 说明&#xff1a; 第一行是罗列枚举的对象名称。只能写合法的标识符&#xff08;名称&#xff09;&#xff0c;多个名称用逗号隔开。 这些名称本质上都是常量&#xff0c;每个变量都会记住枚举类的一个…

z3-加法器实验

补码器加减法&#xff0c;运算方法简介 我们要知道什么是补码的加法&#xff0c;我们为什么要用补码的加法&#xff1f; 补码的加法其实就是将两个补码形式的二进制数字直接相加&#xff0c;处理的时候忽略超出固定位数的进位。补码的加法运算和无符号二进制数的加法操作一样&…

哈希双指针

文章目录 一、哈希1.1两数之和1.2字母异位词分组1.3最长子序列 二、双指针2.1[移动零](https://leetcode.cn/problems/move-zeroes/description/?envTypestudy-plan-v2&envIdtop-100-liked)2.2[盛最多水的容器](https://leetcode.cn/problems/container-with-most-water/d…

新人攻略:避开这3大坑,让老员工主动带你飞!

进入职场的新人们&#xff0c;常常会感到困惑和挑战。他们可能会发现自己在与老员工的交流中遇到难题&#xff0c;甚至发现老员工并不愿意花费时间和精力去指导他们。这背后的原因是什么呢&#xff1f;又该如何改善这一现象呢&#xff1f;本文将从新员工的角度出发&#xff0c;…

C# WPF入门学习(二)——创建一个demo工程

本期任务&#xff1a;创建一个按钮&#xff0c;点击之后在控制台打印文本&#xff0c;设置背景图片、圆角按钮加分。 一、创建WPF项目 创建工程 1. 打开VS 我用的2019 2. 打开界面 3. 选择创建项目 4. 选择C#中的WPF框架 5. 填写项目名称和选择路径 新项目就创建好了&#…

彩虹聚合二级域名DNS管理系统源码v1.3

聚合DNS管理系统可以实现在一个网站内管理多个平台的域名解析&#xff0c; 目前已支持的域名平台有&#xff1a;阿里云、腾讯云、华为云、西部数码、CloudFlare。 本系统支持多用户&#xff0c;每个用户可分配不同的域名解析权限&#xff1b;支持API接口&#xff0c; 支持获…

(Java面试题分享)万里长征-03-搜狐

万里长征-03-搜狐 ⚙ 以下内容基于GPT-4o模型 问题 1.LeetCode103 二叉树的锯齿形层序遍历 103. 二叉树的锯齿形层序遍历 - 力扣&#xff08;LeetCode&#xff09; 2.LeetCode5 最长回文子串 5. 最长回文子串 - 力扣&#xff08;LeetCode&#xff09; 3.Kafka为何那么快 …

Win32 API

个人主页&#xff1a;星纭-CSDN博客 系列文章专栏 : C语言 踏上取经路&#xff0c;比抵达灵山更重要&#xff01;一起努力一起进步&#xff01; 一.Win32 API 1.Win32 API介绍 Windows这个多作业系统除了协调应⽤程序的执⾏、分配内存、管理资源之外&#xff0c;它同时也是…

【达梦系列】IFUN_DATETIME_MODE 导致【无效的客户端版本】

问题描述 在项目开发时&#xff0c;应用程序连接达梦数据库报错&#xff1a;无效的客户端版本。这个问题在没有调整达梦数据参数之前是正常的&#xff0c;调整之后就不对了&#xff0c;但是又不清楚到底是哪个参数的问题。因为调整达梦参数时&#xff0c;用了一个达梦的参数调…

python数据分析——字符串和文本数据2

参考资料&#xff1a;活用pandas库 1、字符串格式化 &#xff08;1&#xff09;格式化字符串 要格式化字符串&#xff0c;需要编写一个带有特殊占位符的字符串&#xff0c;并在字符串上调用format方法向占位符插入值。 # 案例1 varflesh wound s"Its just a {}" p…

求斐波那契数列第n项的值

本期介绍&#x1f356; 主要介绍&#xff1a;什么是斐波那契数列&#xff0c;递归实现求斐波那契数列第n项值&#xff0c;递归法为什么不适合求斐波那契数&#xff0c;用迭代法实现求斐波那契数列的值&#x1f440;。 文章目录 1. 斐波那契数列是什么&#xff1f;2. 题目2. 递归…

Java开发大厂面试第26讲:生产环境如何排查问题和优化 JVM?

通过前面几个课时的学习&#xff0c;相信你对 JVM 的理论及实践等相关知识有了一个大体的印象。而本课时将重点讲解 JVM 的排查与优化&#xff0c;这样就会对 JVM 的知识点有一个完整的认识&#xff0c;从而可以更好地应用于实际工作或者面试了。 我们本课时的面试题是&#x…

【气象常用】间断时间序列图

效果图&#xff1a; 主要步骤&#xff1a; 1. 数据准备&#xff1a;随机数组 2. 图像绘制&#xff1a;绘制间断的时间序列 详细代码&#xff1a;着急的直接拖到最后有完整代码 步骤一&#xff1a;导入库包及图片存储路径并设置中文字体为宋体&#xff0c;西文为新罗马&…

Foxit PDF Editor Pro福昕PDF编辑器Pro:重塑您的文档编辑体验

在信息爆炸的时代&#xff0c;PDF文件因其跨平台、格式稳定等特性&#xff0c;成为我们日常工作与学习中不可或缺的一部分。然而&#xff0c;面对这些文件时&#xff0c;许多人都会遇到一个共同的难题&#xff1a;如何高效、专业地编辑PDF内容&#xff1f;今天&#xff0c;我要…

企业内网开源OA服务器(办公自动化系统),搭建O2OA基于Linux(openEuler、CentOS8)

本实验环境为openEuler系统(以server方式安装)&#xff08;CentOS8基本一致&#xff0c;可参考本文) 目录 知识点实验下载安装O2OA安装mysql配置O2OA 知识点 “O2OA” 是一个开源的、基于Java的办公自动化&#xff08;Office Automation&#xff09;系统。其名称中的“O2OA”…

CnosDB:深入理解时序数据质量函数

在CnosDB中&#xff0c;我们设计并实现了计算数据质量的多个指标&#xff0c;这些指标可以从多个维度评估时序数据的质量&#xff0c;对于时间戳列&#xff0c;我们考虑数据的缺失点、冗余点和延迟点。对于值列&#xff0c;我们考虑数据的异常值、范围、变化、速度和加速度。 C…

【对角线遍历】python

没啥思路 class Solution:def findDiagonalOrder(self, mat: List[List[int]]) -> List[int]:mlen(mat)nlen(mat[0])ret[]if len(mat)0:return retcount0#mn-1是对角线总数while count<mn-1:#x和y的和刚好是count数#偶数为右上走if count%20:xcount if(count<m)else (…

(二十一)【Jmeter】定时器作用域

简述 由于在性能测试中,要模拟用户操作时间差,需要设置操作之间的等待时间,Jmeter中有定时器,那么在使用定时器之前,需要了解定时器的工作原理,是否符合我们业务场景的执行要求? 该文主要讲解Jmeter中定时器作用范围,本次文主要使用两种简单模型来进行说明,可以基于这…