使用ElasticSearch实现全文检索

news2024/12/19 3:16:58

文章目录

  • 全文检索
    • 任务描述
    • 技术难点
    • 任务目标
    • 实现过程
      • 1. java读取Json文件,并导入MySQL数据库中
      • 2. 利用Logstah完成MySQL到ES的数据同步
      • 3. 开始编写功能接口
        • 3.1 全文检索接口
        • 3.2 查询详情
      • 4. 前端调用

全文检索

任务描述

  • 在获取到数据之后如何在ES中进行数据建模,以方便之后搜索接口的实现
  • 接下来,要考虑的问题是,如何实现MySQL和ES的数据同步
  • 接下来是技术实现,要如何实现基于关键词进行全文检索和对于某一条数据的查询详情
  • 在接口实现之后,前端调用后端暴露的接口来进行数据获取,并在页面进行展示

技术难点

  • 数据同步
  • ES的检索的实现
  • 精确定位MySQL表中的数据

任务目标

  • 根据关键词进行全文检索
  • 查询详情

实现过程

1. java读取Json文件,并导入MySQL数据库中

public List<Workticket> getWorkticket(){
        ObjectMapper objectMapper = new ObjectMapper();
        List<Workticket> jsonObjects = null;
        try {
            jsonObjects = objectMapper.readValue(new File("D:\\data_hanchuan\\workticket.json"), List.class);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return jsonObjects;
    }

​ 上述代码将json文件的数据封装成对象,然后调用MP的批量增加方法(deviceService.saveBatch(list);),将其添加到hanchuan数据库中

2. 利用Logstah完成MySQL到ES的数据同步

【注】Logstash、ES以及Kibana必须版本一致

主要参考logstash这篇博客,完成从MySQL到ES的数据同步。下面是其中的一张表的 .conf文件(几张表就对应几个conf文件)

input {
	stdin {}
	jdbc {
		type => "jdbc"
		 # 数据库连接地址
		jdbc_connection_string => "jdbc:mysql://localhost:3306/hanchuan?characterEncoding=UTF-8&autoReconnect=true&allowPublicKeyRetrieval=true"
		 # 数据库连接账号密码;
		jdbc_user => "root"
		jdbc_password => "root"
		 # MySQL依赖包路径;
		jdbc_driver_library => "D:\apply_soft\elasticsearch_all_soft\logstash-7.6.1\bin\result\mysql-connector-j-8.0.31.jar"
		 # the name of the driver class for mysql
		jdbc_driver_class => "com.mysql.jdbc.Driver"
		 # 数据库重连尝试次数
		connection_retry_attempts => "3"
		 # 判断数据库连接是否可用,默认false不开启
		jdbc_validate_connection => "true"
		 # 数据库连接可用校验超时时间,默认3600S
		jdbc_validation_timeout => "3600"
		 # 开启分页查询(默认false不开启);
		jdbc_paging_enabled => "true"
		 # 单次分页查询条数(默认100000,若字段较多且更新频率较高,建议调低此值);
		jdbc_page_size => "3000"
		 # statement为查询数据sql,如果sql较复杂,建议配通过statement_filepath配置sql文件的存放路径;
		 # sql_last_value为内置的变量,存放上次查询结果中最后一条数据tracking_column的值,此处即为ModifyTime;
		 # statement_filepath => "mysql/jdbc.sql"
		statement => "SELECT id,defective_appearance,leakage_type,anbiao1,subsystem,duty_group,anbiao2,defective_why,
						elimination_person,department,accept_describe,accept_group from defect where id > :sql_last_value order by id desc"

		 # 是否将字段名转换为小写,默认true(如果有数据序列化、反序列化需求,建议改为false);
		lowercase_column_names => false
		 # Value can be any of: fatal,error,warn,info,debug,默认info;
		sql_log_level => warn
		 #
		 # 是否记录上次执行结果,true表示会将上次执行结果的tracking_column字段的值保存到last_run_metadata_path指定的文件中;
		record_last_run => true
		 # 需要记录查询结果某字段的值时,此字段为true,否则默认tracking_column为timestamp的值;
		use_column_value => true
		 # 需要记录的字段,用于增量同步,需是数据库字段
		tracking_column => "id"

		 # record_last_run上次数据存放位置;
		last_run_metadata_path => "result/defect/last_id.txt"
		 # 是否清除last_run_metadata_path的记录,需要增量同步时此字段必须为false;
		clean_run => false
		 #
		 # 同步频率(分 时 天 月 年),默认每分钟同步一次;
		schedule => "* * * * *"
	}
}
 
filter {
 
   mutate {  
   	//挑选其中的一个字段充当title字段
       rename => {"defective_appearance" => "title"}	
    //将其id值设置为”数据库表名001_id“ 方便之后查询详情接口的实现
       update => {"id" => "defect001_%{id}"}
    // 将其他字段填充到message字段当中
       add_field => {
           "message" =>["%{title};%{leakage_type};%{anbiao1};%{subsystem};%{duty_group};%{anbiao2};%{defective_why};%{elimination_person};%{department};%{accept_describe};%{accept_group};"]
		}
	//将多余字段删除,使表的结构始终呈现为{id,title,message}形式
       remove_field => ["leakage_type","anbiao1","subsystem","duty_group","anbiao2","defective_why","elimination_person","department","accept_describe","accept_group"]
	}
         
}

output {

	elasticsearch {
		# host => "192.168.1.1"
		# port => "9200"
		# 配置ES集群地址
		hosts => ["localhost:9200"]
		# 索引名字,必须小写
		index => "hanchuan001"
	}
	stdout {
		codec => json_lines
	}
}

最终我们ES中的数据结构就是下面这个样子

在这里插入图片描述

3. 开始编写功能接口

3.1 全文检索接口
@Override
    public MetaTotal searchAllHighLight(String msg, int pageNo, int pageSize) throws IOException {
        if (pageNo <= 1) {
            pageNo = 1;
        }
        SearchRequest request = new SearchRequest(resultIndex);
//      进行搜索
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        boolQueryBuilder.must(QueryBuilders.matchQuery("message", msg))
                        .should(QueryBuilders.matchQuery("title", msg));

//        sourceBuilder.size(2000);

//        分页
        sourceBuilder.from(pageNo);
        sourceBuilder.size(pageSize);


//        进行高亮设置
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        HighlightBuilder.Field field = new HighlightBuilder.Field("message")
                .preTags("<span style='color:red'>")
                .postTags("</span>");
        HighlightBuilder.Field field1 = new HighlightBuilder.Field("title")
                .preTags("<span style='color:red'>")
                .postTags("</span>");
        highlightBuilder.field(field).field(field1);

        sourceBuilder.query(boolQueryBuilder);
        sourceBuilder.highlighter(highlightBuilder);

//        加入到request中
        request.source(sourceBuilder);

        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        List<Meta> list = new ArrayList<>();
        for (SearchHit hit : response.getHits().getHits()) {
            //----进行高亮字段的替换
            Map<String, HighlightField> highlightFields = hit.getHighlightFields();
            HighlightField message = highlightFields.get("message");
            HighlightField title = highlightFields.get("title");

//          未高亮之前的结果
            Map<String, Object> sourceAsMap = hit.getSourceAsMap();
//            1.找到message中出现关键字的地方进行高亮替换
            if (message != null) {
                Text[] fragments = message.fragments();
                String n_mess = "";
                for (Text text : fragments) {
                    n_mess += text;
                }
                sourceAsMap.put("message", n_mess);
            }
//            2.找到title中出现关键字的地方进行高亮替换
            if (title != null) {
                Text[] fragments = title.fragments();
                String n_title = "";
                for (Text text : fragments) {
                    n_title += text;
                }
                sourceAsMap.put("title", n_title);
            }
            //----结束----

            Meta meta = new Meta();
            try {
                BeanUtils.populate(meta, hit.getSourceAsMap());
            } catch (IllegalAccessException e) {
                throw new RuntimeException(e);
            } catch (InvocationTargetException e) {
                throw new RuntimeException(e);
            }
            list.add(meta);
        }
        MetaTotal metas = new MetaTotal();
        metas.setList(list);
        metas.setTotal(response.getHits().getTotalHits().value);
        System.out.println(metas.getTotal() + "总记录数");
        return metas;
    }

在业务逻辑代码写好之后在控制层暴露接口

	@ResponseBody
    @GetMapping("/search/{keyword}/{pageNo}/{pageSize}")

    public Result searchByMsg(@PathVariable String keyword,
                              @PathVariable int pageNo,
                              @PathVariable int pageSize) throws IOException {
        MetaTotal metas = service.searchAllHighLight(keyword,pageNo,pageSize);

        Page<Meta> page = new Page<>(pageNo,pageSize);
        page.setRecords(metas.getList());
        page.setTotal(metas.getTotal());
        return new Result().code(200).message("查询成功").data("list",metas.getList()).data("total",metas.getTotal());
    }
3.2 查询详情

根据前端传递的id值,进行解析,找到对应的数据库表,进行详情查看。

	@RequestMapping("/details/{id}")
    @ResponseBody
    public Result look_details2(@PathVariable("id") String id, Map<String,Object> map){
        String[] str = id.split("001_");

        if (str[0].equals("defect")){

            Defect defect = defectService.getById(str[1]);
            return new Result().code(200).message("详情结果").data("details",defect);
        } else if (str[0].equals("device")) {
            Device device = deviceService.getById(str[1]);
            return new Result().code(200).message("详情结果").data("details",device);
        } else if (str[0].equals("riskcontroller")) {
            Riskcontroller riskcontroller = riskControllerService.getById(str[1]);
            return new Result().code(200).message("详情结果").data("details",riskcontroller);
        }else if (str[0].equals("security")) {
            Security security = securityService.getById(str[1]);
            return new Result().code(200).message("详情结果").data("details",security);
        }else if (str[0].equals("workticket")) {
            Workticket workticket = workticketService.getById(str[1]);
            return new Result().code(200).message("详情结果").data("details",workticket);
        }
        return new Result().code(500).message("查询失败");
    }

4. 前端调用

在这里插入图片描述
在这里插入图片描述

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

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

相关文章

CTFHUB-web(SSRF)

内网访问 点击进入环境&#xff0c;输入 http://127.0.0.1/flag.php 伪协议读取文件 /?urlfile:///var/www/html/flag.php 右击查看页面源代码 端口扫描 1.根据题目提示我们知道端口号在8000-9000之间,使用bp抓包并进行爆破 POST请求 点击环境&#xff0c;访问flag.php 查看页…

数据结构 ——前缀树查词典的实现

数据结构 ——前缀树查词典的实现 一、前缀树的概念 前缀树是一种多叉树结构&#xff0c;主要用于存储字符串。每个节点代表一个字符&#xff0c;路径从根节点到叶节点表示一个完整的字符串。前缀树的关键特征是 共享前缀&#xff0c;也就是说&#xff0c;如果两个字符串有相…

React里循环tab列表,并实现点击切换class

介绍 在 React 框架里&#xff0c;通过循环去显示 tab列表的标题&#xff0c;并且添加点击事件&#xff0c;当前点击的tab高亮显示。就像 vue 里 通过 v-for 显示列表并且点击时添加 activeClass 一样。 实现效果 代码 主要通过 map方法来实现列表的循环显示&#xff0c;然后…

selenium 在已打开浏览器上继续调试

关闭浏览器&#xff0c;终端执行如下指令&#xff0c;--user-data-dir换成自己的User Data路径 chrome.exe --remote-debugging-port9222 --user-data-dir"C:\Users\xxx\AppData\Local\Google\Chrome\User Data" 会打开浏览器&#xff0c;打开百度&#xff0c;如下状…

Pytest-Bdd vs Behave:选择最适合的 Python BDD 框架

Pytest-Bdd vs Behave&#xff1a;选择最适合的 Python BDD 框架 Pytest BDD vs Behave&#xff1a;选择最适合的 Python BDD 框架BDD 介绍Python BDD 框架列表Python BehavePytest BDDPytest BDD vs Behave&#xff1a;关键区别Pytest BDD vs Behave&#xff1a;最佳应用场景结…

B站bilibili视频转文字字幕下载方法

本文将讲述介绍一种使用本地工具如何快速的下载B站的字幕为本地文本文件的方法。 通常获取B站字幕需要在浏览器中安装第三方插件&#xff0c;通过插件获取字幕。随着大模型&#xff0c;生成式AI&#xff0c;ChatGPT的应用&#xff0c;B站也提供了AI小助手对视频的内容进行总结…

ElasticSearch的自动补全功能(拼音分词器、自定义分词器、DSL实现自动补全查询、RestAPI实现自动补全查询)

文章目录 1. 什么是自动补全2. 拼音分词器2.1 初识拼音分词器2.2 下载拼音分词器2.3 安装拼音分词器2.4 测试拼音分词器 3. 自定义分词器3.1 拼音分词器存在的问题3.2 分词器&#xff08;analyzer&#xff09;的组成3.3 如何自定义分词器3.4 拼音分词器的可选参数3.5 配置自定义…

day12 接口测试 ——入门→精通→实战(1)

【没有所谓的运气&#x1f36c;&#xff0c;只有绝对的努力✊】 目录 1、接口测试分类 1.1 内部接口&#xff1a; 1.2 外部接口&#xff1a; 2、目前接口架构设计 2.1、基于SOAP架构&#xff0c; 2.2、基于RPC架构&#xff0c; 2.3、基于RestFul架构&#xff0c; 2.3.1…

54、库卡机器人轴的软限位设置

步骤1&#xff1a;将用户组改为“专家”。 步骤2&#xff1a;点击“投入运行”----“售后服务”-----“软件限位开关” 步骤3&#xff1a;就可以针对每个轴修改对应的角度值&#xff0c;然后点击“保存”。

PHP+MySQL 学生信息管理系统

目录 MySQL建表指令 主页面展示 主页面源代码如下 增&#xff1a;添加学生信息 添加html如下 html&#xff1a;主要用于显示网页内容 成功添加后回显 ​编辑 增加php如下 删&#xff1a;删除学生信息 删除html如下 成功删除后回显 删除php如下 改&#xff1a;修改学…

【第三节】Git 基本操作指南

目录 前言 一、获取与创建项目 1.1 git init 1.2 git clone 二、基本快照操作 2.1 git add 2.2 git status 2.3 git diff 2.4 git commit 2.5 git reset HEAD 三、 文件管理 3.1 git rm 3.2 git mv 四、Git 文件状态 5.1 工作目录 5.2 暂存区 5.3 本地仓库 5…

【第六节】Git Flow:分支管理模型与工作流程

一、Git Flow 简介 1.1 什么是 Git Flow Git Flow 是一种基于 Git 的分支管理模型&#xff0c;旨在帮助团队更好地管理和发布软件。它由 Vincent Driessen 在 2010 年提出&#xff0c;通过一套标准的分支命名和工作流程&#xff0c;使开发、测试和发布过程更加有序和高效。不过…

Windows 与 Linux 下 Ping IPv6 地址 | 常用网络命令

注&#xff1a;本文为网络命令相关文章合辑。 未整理去重。 一、IPv6 概述 IPv6 即 “Internet 协议版本 6”&#xff0c;因 IPv4 地址资源面临耗尽问题而被引入以替代 IPv4。IPv6 则提供了理论上多达 2 128 2^{128} 2128 个地址&#xff0c;有效解决地址不足困境。 IPv6 具…

GB28181系列三:GB28181流媒体服务器ZLMediaKit

我的音视频/流媒体开源项目(github) GB28181系列目录 目录 一、ZLMediaKit介绍 二、 ZLMediaKit安装、运行(Ubuntu) 1、安装 2、运行 3、配置 三、ZLMediaKit使用 一、ZLMediaKit介绍 ZLMediaKit是一个基于C11的高性能运营级流媒体服务框架&#xff0c;项目地址&#xf…

【深度学习】深刻理解Swin Transformer

Swin Transformer 是一种基于 Transformer 的视觉模型&#xff0c;由 Microsoft 研究团队提出&#xff0c;旨在解决传统 Transformer 模型在计算机视觉任务中的高计算复杂度问题。其全称是 Shifted Window Transformer&#xff0c;通过引入分层架构和滑动窗口机制&#xff0c;S…

uniCloud云开发视频教程-从基础入门到项目开发实战-uniapp进阶课文章管理系统(云函数/云数据库/云存储)

大家好&#xff0c;我是爱搞知识的咸虾米。 今天给大家带来一门uniCloud基础入门到项目开发实战的课程。 视频学习地址&#xff1a;https://www.bilibili.com/video/BV1PP411E7qG/ 开始学习这门课之前&#xff0c;最好先学习一下uniapp零基础入门这套课&#xff0c;相信很多同…

GLB格式转换为STL格式

GLB与STL格式简介 GLB格式 GLB代表“GL传输格式二进制文件”&#xff08;GL Transmission Format Binary&#xff09;。GLB主要用于共享3D数据&#xff0c;包含三维模型、场景、光源、材质、节点层次和动画等详细信息&#xff0c;是一种标准化的文件格式&#xff0c;适用于多…

Qt编译MySQL数据库驱动

目录 Qt编译MySQL数据库驱动 测试程序 Qt编译MySQL数据库驱动 &#xff08;1&#xff09;先找到MySQL安装路径以及Qt安装路径 C:\Program Files\MySQL\MySQL Server 8.0 D:\qt\5.12.12 &#xff08;2&#xff09;在D:\qt\5.12.12\Src\qtbase\src\plugins\sqldrivers\mysql下…

MySQL通过binlog日志进行数据恢复

记录一次阿里云MySQL通过binlog日志进行数据回滚 问题描述由于阿里云远程mysql没有做安全策略 所以服务器被别人远程攻击把数据库给删除&#xff0c;通过查看binlog日志可以看到进行了drop操作&#xff0c;下面将演示通过binlog日志进行数据回滚操作。 1、查询是否开始binlog …

如何在 Ubuntu 22.04 上安装和使用 Rust 编程语言环境

简介 Rust 是一门由 Mozilla 开发的系统编程语言&#xff0c;专注于性能、可靠性和内存安全。它在没有垃圾收集的情况下实现了内存安全&#xff0c;这使其成为构建对性能要求苛刻的应用程序&#xff08;如操作系统、游戏引擎和嵌入式系统&#xff09;的理想选择。 接下来&…