使用ElasticSearch实现全文检索

文章目录

  • 全文检索
    • 任务描述
    • 技术难点
    • 任务目标
    • 实现过程
      • 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. 前端调用

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

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

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

相关文章

《拉依达的嵌入式\驱动面试宝典》—C/CPP基础篇(三)

《拉依达的嵌入式\驱动面试宝典》—C/CPP基础篇(三) 你好,我是拉依达。 感谢所有阅读关注我的同学支持,目前博客累计阅读 27w,关注1.5w人。其中博客《最全Linux驱动开发全流程详细解析(持续更新)-CSDN博客》已经是 Linux驱动 相关内容搜索的推荐首位,感谢大家支持。 《拉…

调用完BAPI_PO_CREATE1创建采购订单之后,如果不调用BAPI_TRANSACTION_COMMIT,数据库里面没有数

在调用完BAPI_PO_CREATE1创建采购订单之后&#xff0c;如果不调用BAPI_TRANSACTION_COMMIT&#xff0c;那么就无法生成真正的采购订单号&#xff0c;在数据库里面没有数 运行结果 特别注意

linux(CentOS8)安装PostgreSQL16详解

文章目录 1 下载安装包2 安装3 修改远程连接4 开放端口 1 下载安装包 官网下载地址&#xff1a;https://www.postgresql.org/download/ 选择对应版本 2 安装 #yum源 yum -y install wget https://download.postgresql.org/pub/repos/yum/reporpms/EL-8-x86_64/pgdg-redha…

如何通过递延型指标预测项目的长期成果?

递延型指标&#xff08;Deferred Metrics&#xff09;是指那些并不立即反映或直接影响当前操作、决策或行为的指标&#xff0c;而是随着时间的推移&#xff0c;才逐渐显现出影响效果的指标。这类指标通常会在一段时间后反映出来&#xff0c;或者需要一定的周期才能展现其成果或…

Reactor 响应式编程(第四篇:Spring Security Reactive)

系列文章目录 Reactor 响应式编程&#xff08;第一篇&#xff1a;Reactor核心&#xff09; Reactor 响应式编程&#xff08;第二篇&#xff1a;Spring Webflux&#xff09; Reactor 响应式编程&#xff08;第三篇&#xff1a;R2DBC&#xff09; Reactor 响应式编程&#xff08…

力扣-图论-14【算法学习day.64】

前言 ###我做这类文章一个重要的目的还是给正在学习的大家提供方向和记录学习过程&#xff08;例如想要掌握基础用法&#xff0c;该刷哪些题&#xff1f;&#xff09;我的解析也不会做的非常详细&#xff0c;只会提供思路和一些关键点&#xff0c;力扣上的大佬们的题解质量是非…

Leetcode经典题11--加油站

题目描述 在一条环路上有 n 个加油站&#xff0c;其中第 i 个加油站有汽油 gas[i] 升。 你有一辆油箱容量无限的的汽车&#xff0c;从第 i 个加油站开往第 i1 个加油站需要消耗汽油 cost[i] 升。你从其中的一个加油站出发&#xff0c;开始时油箱为空。 给定两个整数数组 gas 和…

前端退出对话框也就是点击右上角的叉,显示灰色界面,已经解决

文章目录 遇到一个前端bug&#xff0c;点击生成邀请码 打开对话框 然后我再点击叉号&#xff0c;退出对话框&#xff0c;虽然退出了对话框&#xff0c;但是显示灰色界面。如下图&#xff1a; 导致界面就会失效&#xff0c;点击任何地方都没有反应。 发现是如下代码的问题&am…

软件需求概述(尊享版)

软件需求与软件分析 软件需求&#xff1a;用户角度&#xff0c;注重软件外在表现 软件分析&#xff1a;开发者角度&#xff0c;注重软件内部逻辑结构 面向对象分析模型 类/对象模型&#xff08;全部的类和对象&#xff09; 对象-关系模型&#xff08;对象之间的静态关系&…

配置Hugging_face国内镜像

目录 随着人工智能技术的蓬勃发展&#xff0c;Huggingface这一开源平台已成为研究者和开发者的宝贵资源&#xff0c;提供了丰富的预训练模型&#xff0c;助力自然语言处理任务的快速推进。然而&#xff0c;对于身处国内的我们而言&#xff0c;访问Huggingface主仓库时&#xff…

Rust之抽空学习系列(四)—— 编程通用概念(下)

Rust之抽空学习系列&#xff08;四&#xff09;—— 编程通用概念&#xff08;下&#xff09; 1、函数 函数用来对功能逻辑进行封装&#xff0c;能够增强复用、提高代码的可读 以下是函数的主要组成部分&#xff1a; 名称参数返回类型函数体 1.1、函数名称 在Rust中&…

电脑游戏运行时常见问题解析:穿越火线提示“unityplayer.dll丢失”的修复指南

电脑游戏运行时常见问题解析&#xff1a;穿越火线提示“unityplayer.dll丢失”的修复指南 在探索电脑游戏的无限乐趣时&#xff0c;我们时常会遇到一些不期而遇的挑战。今天&#xff0c;我们将聚焦于一个常见的游戏运行错误——穿越火线&#xff08;或其他使用Unity引擎的游戏…

Mac系统下 jdk和maven 安装教程

一、jdk安装教程 1、先去官网选择对应版本下载 官网网址&#xff1a;Java SE | Oracle Technology Network | Oracle 中国 这里我选择的是jdk8的版本&#xff0c;如果你们想下载更高的版本就选择其他版本&#xff0c;目前大部分公司和教程使用jdk8的版本比较多。 点击macos&a…

Python -- Linux中的Matplotlib图中无法显示中文 (中文为方框)

目的 用matplotlib生成的图中文无法正常显示 方法 主要原因: 没找到字体 进入windows系统的C:\Windows\Fonts目录, 复制自己想要的字体 粘贴到Linux服务器中对应python文件所处的文件夹内 设置字体: 设置好字体文件的路径在需要对字体设置的地方设置字体 效果 中文正常显…

Python中的self关键字详解

文章目录 Python中的self关键字详解一、引言二、self的基本概念1、定义类和实例 三、self在方法调用中的角色2、调用其他方法 四、使用示例3、继承中的self 五、总结 Python中的self关键字详解 一、引言 在Python的面向对象编程中&#xff0c;self是一个至关重要的概念&#x…

LabVIEW热电偶传感器虚拟仿真实验系统

在教学和科研领域&#xff0c;实验设备的更新和维护成本较高&#xff0c;尤其是在经济欠发达地区&#xff0c;设备的短缺和陈旧化严重影响了教学质量。基于LabVIEW的热电偶传感器虚拟仿真实验系统能够通过模拟实验环境&#xff0c;提供一个成本低廉且效果良好的教学和研究平台。…

优选算法《双指针》

在学习了C/C的基础知识之后接下来我们就可以来系统的学习相关的算法了&#xff0c;这在之后的笔试、面试或竞赛都是必须要掌握的&#xff1b;在这些算法中我们先来了解的是一些非常经典且较为常用的算法&#xff0c;在此也就是优选出来的算法&#xff0c;接下来在每一篇章中我们…

分布式数据库 OceanBase 的前世今生

文章目录 分布式数据库的开端OceanBase 2022 年度发布会为什么“小就是大”&#xff1f;商业化进程按下“加速键”向国际输出中国技术 OceanBase 2024 年度发布会为什么要做云数据库&#xff1f;2 年服务超 700 客户崭露头角一体化云数据库简化数据栈产品力和生态力是未来制胜关…

ubuntu 磁盘空间满,找不到占用文件的目录

解决方法&#xff1a; 检查磁盘空间&#xff1a; 执行 df -h 查看各分区磁盘使用情况。 查找大文件或目录&#xff1a; 执行 du -sh /* 2>/dev/null 查找根目录下的大文件或目录&#xff0c;再逐一进入子目录使用相同命令查找。 清理缓存和临时文件&#xff1a; 清理 /t…

图的基本概念|存储

图的基本概念 图的定义 图G由顶点集V和边集E组成&#xff0c;记为G&#xff08;V&#xff0c;E) 其中V(G)表示图G中顶点的有限非空集&#xff1b;E&#xff08;G)表示图G中顶点之间的关系&#xff08;边&#xff09;集合。 若V{ v 1 , v 2 , … , v n v_{1},v_{2},\dots,v_{n…