当前位置: 首页 > news >正文

【从0做项目】Java文档搜索引擎(9)烧脑终章!

   

阿华代码,不是逆风,就是我疯

你们的点赞收藏是我前进最大的动力!!

希望本文内容能够帮助到你!!

目录

文章导读

零:项目结果展示

一:导入

二:问题引入

1:情景引入

2:思考

3:处理设计

(1)问题总结

(2)设计

(3)核心思路

三:代码讲解

1:search方法

2:mergeResult

(1)Pos定位类

(2)看图说话

(3)步骤拆解

四:前后优化结果对比


文章导读

阿华将发布项目复盘系列的文章,旨在:

1:手把手细致带大家从0到1做一个完整的项目,保证每2~3行代码都有详细的注解

2:通过文字+画图的方式,对项目进行整个复盘,更好的理解以及优化项目

3:总结自己的优缺点,扎实java相关技术栈,增强文档编写能力

零:项目结果展示

项目目前已经上线,小伙伴们可以进行使用!!!

Java 文档搜索

简述:在我的搜索引擎网站,用户进行关键字搜索,就可以查询到与这个关键字相关的java在线文档,(包含标题,关键字附近的简述,url),用户点击标题,即可跳转到相关在线文档,适用于JDK17版本。

一:导入

在前文(8)中我们使用停用词表对用户的搜索词句进行了过滤,并且在后端处理正文描述的时候使用正则表达式进行优化,让返回结果更加合理。本篇文章将会有点烧脑~

二:问题引入

1:情景引入

这里我们同样搜索array空格list

惊奇的发现array这个文档返回了两次,什么鬼~~!! 

2:思考

为什么一个文档会返回两次。想后端处理逻辑,我们拿到array这个词,在倒排索引中返回一堆docId;再拿到list这个词,再在倒排索引中返回一堆docId

注:(这里拿到的其实是一个集合,里面有好多Weight对象,对象里包含docId和weight权重,这里这么说是方便大家理解)

思考:那有没有一种可能就是说,一个文档中既包含array,又包含list,所以这个文档被查到了两次,就返回给前端两遍,显然,这种情况是非常有可能的!! 

不多bb直接上图,这里图解可能更清楚。

3:处理设计

(1)问题总结

①一个文档不能出现两次 

②像Array.html这样的文档,同时包含多个分词结果,意味着这个文档的“相关性”更高——所以就应该提高这个文档的权重!!

设计

(2)设计

①去重:把多个分词结果触发出来的文档,按照docId进行去重

②权重合并

(3)核心思路

①把分词结果进行排序处理(按照docId升序排序)

②对于docId相同的情况,进行权重的相加

注意:这里的分词结果可能不止两个,当有多个的时候,每一个分词都对应一个list集合,这里就是多路数组的归并了。

这里不理解的看下面这个图文字

不多bb上图理解

三:代码讲解

1:search方法

不要捉急,我们一点点的看代码

在search方法中我们使用mergeResult方法来进行合并,这里的参数传递,可以理解成把所有查到的docId相关文档作为参数进行传参,实际上传的是一个双重集合,这个集合中装的全都是Weight对象

    public List<Result> search(String query){//1:对query分词List<Term> oldTerms = ToAnalysis.parse(query).getTerms();//未过滤的分词结果集合List<Term> terms = new ArrayList<>();//过滤后的分词结果集合//针对分词结果,使用暂停词表进行过滤for(Term term : oldTerms){if(stopWords.contains(term.getName())){continue;}terms.add(term);}//2:对分词查倒排List<List<Weight>> termResult = new ArrayList<>();
//        List<Weight> allTermResult = new ArrayList<>();for (Term term : terms){String word = term.getName();List<Weight> invertedList = index.getInverted(word);//如果查不到就返回一个nullif(invertedList == null){continue;}
//            allTermResult.addAll(invertedList);//把集合中所有Weight对象都扔到allTermResult中termResult.add(invertedList);}//3:[合并]对多个分词结果处发出的相同文档,进行权重合并List<Weight> allTermResult = mergeResult(termResult);//4: 按权重降序排序allTermResult.sort(new Comparator<Weight>() {@Overridepublic int compare(Weight o1, Weight o2) {return o2.getWeight() - o1.getWeight();//降序排列}});//5:查正排,构造出想要的Result,返回结果List<Result> results = new ArrayList<>();for(Weight weight : allTermResult){//对每一个Weight都构建result,可能最后的结果会很多,但是用户一般只看第一页查询出来的信息,一般懒得翻页DocInfo docInfo = index.getDocInfo(weight.getDocId());//获取当前Weight对应的文档信息Result result = new Result();result.setTitle(docInfo.getTitle());result.setUrl(docInfo.getUrl());
//            result.setDesc(docInfo.getContent());//很明显把正文全部返回不合理result.setDesc(GenDesc(docInfo.getContent(),terms));//搞个正文简述,这个词前60个字符为起始,往后截取160个results.add(result);}return results;}

2:mergeResult

(1)Pos定位类

用来描述,我们Weight对象所在的位置

    static class Pos{public int row;public int col;public Pos(int row , int col){this.row = row;this.col = col;}}

(2)看图说话

搞一个优先级队列,比较规则就是,docId值更小的往里面放

(3)步骤拆解

①对每一路按docId的升序给Weight对象排个序

②new一个集合用来存放最后的Weight对象的合集

③把每一行的第一个元素放进队列中(初始化)

④优先级队列的比较规则是docId升序排列,放的是Pos对象也就是Weight对象的位置!!

⑤当队列不为空时,循环弹出元素Pos,找到对应的Weight对象,将这个Weight对象与我们target集合中最后一个位置的Weight对象进行对比看是不是同一个对象,若不是则直接加入集合,若是则合并权重。

⑥指针移动

喵喵喵~~妙脆角!跟着我的注解,看着图,敲一遍代码会更清楚内部的一个逻辑!

 private List<Weight> mergeResult(List<List<Weight>> source) {//把多路合并成一路//1:先给每一路按升序排个序for (List<Weight> curRow : source){curRow.sort(new Comparator<Weight>() {@Overridepublic int compare(Weight o1, Weight o2) {return o1.getDocId()- o2.getDocId();}});}//2:借优先级队列合并多路List<Weight> target = new ArrayList<>();PriorityQueue<Pos> queue = new PriorityQueue<>(new Comparator<Pos>() {@Overridepublic int compare(Pos o1, Pos o2) {Weight w1 = source.get(o1.row).get(o1.col);//用下标找到Weight对象Weight w2 = source.get(o2.row).get(o2.col);return w1.getDocId() - w2.getDocId();}});//2.1:初始化队列——把每一行第一个元素放到队列当中for(int row = 0 ; row < source.size() ; row++){queue.offer(new Pos(row,0));}//2.2:循环取队首元素(也就是当前若干行中最小的元素)while(!queue.isEmpty()){Pos curMinPos = queue.poll();Weight curWeight = source.get(curMinPos.row).get(curMinPos.col);//2.3:检查当前的Weight对象,与上一个插入到target中的对象是否是相同的对象,这里可以用Weight对象中的docId作为比较依据if(target.size() > 0){Weight lastWeight = target.get(target.size()-1);if(lastWeight.getDocId() == curWeight.getDocId()){//文档id若相等则合并int weightSum = lastWeight.getWeight() + curWeight.getWeight();lastWeight.setWeight(weightSum);}else{//文档id不相等就直接入targettarget.add(curWeight);}}else{//若当前的target为空,就直接加入target.add(curWeight);}//2.4:考虑移动光标,当前元素处理完了之后,要把对应的这个元素光标往后移动,取这一行的下一个元素Pos newpos = new Pos(curMinPos.row , curMinPos.col+1);if(newpos.col > source.get(newpos.row).size() - 1){//说明光标已经超出这一行的范围了,到达末尾了,这一行就处理完了continue;//直接进入下一次循环}//否则把新的坐标扔到队列当中queue.offer(newpos);}return target;}

四:前后优化结果对比

暴减500条结果,说明有200多个结果都是重复的。

至此Java文档搜索引擎博客讲解就结束了,这里的图解和测试,花费了阿华很大的精力,希望这个系列能够帮助到你~~塔塔开!

相关文章:

【从0做项目】Java文档搜索引擎(9)烧脑终章!

阿华代码&#xff0c;不是逆风&#xff0c;就是我疯 你们的点赞收藏是我前进最大的动力&#xff01;&#xff01; 希望本文内容能够帮助到你&#xff01;&#xff01; 目录 文章导读 零&#xff1a;项目结果展示 一&#xff1a;导入 二&#xff1a;问题引入 1&#xff1a;情…...

python: SQLAlchemy (ORM) Simple example using mysql in Ubuntu 24.04

mysql sql script: create table School 表 (SchoolId char(5) NOT NULL comment主鍵primary key&#xff0c;學校編號,SchoolName nvarchar(500) NOT NULL DEFAULT comment 學校名稱,SchoolTelNo varchar(8) NULL DEFAULT comment電話號碼,PRIMARY KEY (SchoolId) #主…...

如何为自己的 PDF 文件添加密码?在线加密 PDF 文件其实更简单

随着信息泄露和数据安全问题的日益突出&#xff0c;保护敏感信息变得尤为重要。加密 PDF 文件是一种有效的手段&#xff0c;可以确保只有授权用户才能访问或修改文档内容。本文将详细介绍如何使用 CleverPDF 在线工具为你的 PDF 文件添加密码保护&#xff0c;确保其安全性。 为…...

echarts 折线图动态基准线设置超出基准线标红

基准线属性&#xff1a;markLine 线条标红关键属性&#xff1a;visualMap 小于&#xff1a; lt (less than) 大于&#xff1a;gt (greater than) 小于等于&#xff1a;lte (Less than or equal to) 大于等于&#xff1a;gte (Greater than or equal to) 1、基础应用——2条基准…...

Part 3 第十二章 单元测试 Unit Testing

概述 第十二章围绕单元测试展开&#xff0c;阐述了单元测试的实践与重要性&#xff0c;通过对比其他测试类型&#xff0c;突出其特点&#xff0c;还介绍了单元测试的最佳实践、避免的反模式以及与测试替身相关的内容&#xff0c;为编写高质量单元测试提供指导。 章节概要 1…...

C++与Python:两种编程语言的区别

C和Python都是当今编程领域广泛使用的语言&#xff0c;它们各有特色&#xff0c;适用于不同的开发场景。本文将从语言特性、性能、学习难度、应用领域等多个方面探讨C与Python之间的区别。 一、语言特性 类型系统&#xff1a; C&#xff1a;是一种静态类型语言&#xf…...

Springboot 高频面试题

以下是Spring Boot的高频面试题及答案和底层原理解释&#xff1a; 基础概念 什么是Spring Boot&#xff0c;其主要特点是什么&#xff1f; 答案&#xff1a; Spring Boot本质上是一个建立在Spring框架之上的快速应用开发框架。其主要特点包括&#xff1a; 启动器&#xff1a;一…...

常用电脑,护眼软件推荐 f.lux 3400K | 撰写论文 paper

常用电脑&#xff1f;平均每天用 5 个小时&#xff1f;你就要考虑用一个护眼软件了&#xff0c;对皮肤也好。因为电脑屏幕有辐射&#xff0c;比如蓝光。 f.lux 作为一款专业护眼软件&#xff0c;值得使用。之前用了三年的 Iris Pro&#xff0c;现在 f.lux 做的更好了。 使用…...

MacOS下使用Ollama本地构建DeepSeek并使用本地Dify构建AI应用

目录 1 大白话说一下文章内容2 作者的电脑配置3 DeepSeek的本地部署3.1 Ollamal的下载和安装3.2 选择合适的deepseek模型3.3 安转deepseek 4 DifyDeepSeek构建Al应用4.1 Dify的安装4.1.1 前置条件4.1.2 拉取代码4.1.3 启动Dify 4.2 Dify控制页面4.3 使用Dify实现个“文章标题生…...

如何有效利用MYSQL的连接数

连接数配置2500~3000 依然发现连接不够用&#xff1f; -- 查看当前最大连接数 SHOW VARIABLES LIKE MAX_CONNECTIONS; -- 查看当前总链接数 SHOW STATUS LIKE Threads_connected; -- 查看当前进程明细 SHOW PROCESSLIST; 合理设置以下参数&#xff1a; 1. MySQL 的参数设置 …...

调用click.getchar()时Windows PyCharm无法模拟键盘输入

文章目录 问题描述解决方案参考文献 问题描述 调用 click.getchar() 时&#xff0c;Windows PyCharm 无法模拟键盘输入 解决方案 Run → Edit Configurations… → Modify options → Emulate terminal in output console 参考文献 Terminal emulator | PyCharm Documentati…...

使用Hardhat实现ERC20 代币合约详解

ERC20 代币合约详解 &#x1f4b0; 1. 合约概览 // SPDX-License-Identifier: MIT pragma solidity ^0.8.20;import "openzeppelin/contracts/token/ERC20/ERC20.sol";contract MyToken is ERC20 {constructor() ERC20("MyToken", "MTK") {_min…...

清华大学《DeepSeek与AI幻觉》(无套路免费分享)

随着人工智能技术的飞速发展&#xff0c;以DeepSeek为代表的国产大模型正逐渐成为各行各业的重要工具。然而&#xff0c;AI在生成内容时常常会出现“幻觉”——即生成与事实不符、逻辑断裂或脱离上下文的内容。 清华大学新闻与传播学院与人工智能学院联合推出的这篇教程《Deep…...

代码随想录算法【Day52】

Day51 101. 孤岛的总面积 思路 从周边找到陆地然后 通过 dfs或者bfs 将周边靠陆地且相邻的陆地都变成海洋&#xff0c;然后再去重新遍历地图 统计此时还剩下的陆地 代码 #include <iostream> #include <vector> using namespace std; int dir[4][2] {-1, 0, …...

Spark 和 Flink

Spark 和 Flink 都是目前流行的大数据处理引擎&#xff0c;但它们在架构设计、应用场景、性能和生态方面有较大区别。以下是详细对比&#xff1a; 1. 架构与核心概念 方面Apache SparkApache Flink计算模型微批&#xff08;Micro-Batch&#xff09;为主&#xff0c;但支持结构…...

Unity结合Vuforia虚拟按键实现AR机械仿真动画效果

零、最终效果 待上传 一、资源准备 1、Vuforia Vuforia版本不能高于10.17.4&#xff08;往上的版本虚拟按键功能被删除&#xff09; 2、Unity Unity版本必须要高于2022.3.x&#xff0c;不然使用Vuforia插件时会出现bug 二、主要内容 1、添加虚拟按钮 2、为虚拟按钮设置…...

PL/SQL 异常处理

目录 一、命名的系统异常 1.常见命名的系统异常 2.预定义的系统异常数量以及描述 3.处理命名的系统异常的一般步骤 二、程序员定义的异常 1.概念 2.自定义异常的定义与抛出 3.自定义异常的处理 三、未命名的系统异常 1.概述 2.处理未命名的系统异常的方法 3.使用场景 …...

【自学笔记】Spring Boot框架技术基础知识点总览-持续更新

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 Spring Boot框架技术基础知识点总览一、Spring Boot简介1.1 什么是Spring Boot&#xff1f;1.2 Spring Boot的主要特性 二、Spring Boot快速入门2.1 搭建Spring Boo…...

Redis 缓存穿透、击穿、雪崩:问题与解决方案

在使用 Redis 作为缓存中间件时&#xff0c;系统可能会面临一些常见的问题&#xff0c;如 缓存穿透、缓存击穿 和 缓存雪崩。这些问题如果不加以解决&#xff0c;可能会导致数据库压力过大、系统响应变慢甚至崩溃。本文将详细分析这三种问题的起因&#xff0c;并提供有效的解决…...

第一个CMAKE项目hello cmake

#注意&#xff01; 这篇文章是为WINDWOS用户写的 #请检查你的电脑上已经安装了MINGW和CMAKE 快速检查方法如下 C:\Users\Basicoperation>g --version g (x86_64-win32-seh-rev1, Built by MinGW-Builds project) 14.2.0 Copyright (C) 2024 Free Software Foundation, Inc. …...

龙虎榜——20250610

上证指数放量收阴线&#xff0c;个股多数下跌&#xff0c;盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型&#xff0c;指数短线有调整的需求&#xff0c;大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的&#xff1a;御银股份、雄帝科技 驱动…...

生成xcframework

打包 XCFramework 的方法 XCFramework 是苹果推出的一种多平台二进制分发格式&#xff0c;可以包含多个架构和平台的代码。打包 XCFramework 通常用于分发库或框架。 使用 Xcode 命令行工具打包 通过 xcodebuild 命令可以打包 XCFramework。确保项目已经配置好需要支持的平台…...

中南大学无人机智能体的全面评估!BEDI:用于评估无人机上具身智能体的综合性基准测试

作者&#xff1a;Mingning Guo, Mengwei Wu, Jiarun He, Shaoxian Li, Haifeng Li, Chao Tao单位&#xff1a;中南大学地球科学与信息物理学院论文标题&#xff1a;BEDI: A Comprehensive Benchmark for Evaluating Embodied Agents on UAVs论文链接&#xff1a;https://arxiv.…...

uni-app学习笔记二十二---使用vite.config.js全局导入常用依赖

在前面的练习中&#xff0c;每个页面需要使用ref&#xff0c;onShow等生命周期钩子函数时都需要像下面这样导入 import {onMounted, ref} from "vue" 如果不想每个页面都导入&#xff0c;需要使用node.js命令npm安装unplugin-auto-import npm install unplugin-au…...

高等数学(下)题型笔记(八)空间解析几何与向量代数

目录 0 前言 1 向量的点乘 1.1 基本公式 1.2 例题 2 向量的叉乘 2.1 基础知识 2.2 例题 3 空间平面方程 3.1 基础知识 3.2 例题 4 空间直线方程 4.1 基础知识 4.2 例题 5 旋转曲面及其方程 5.1 基础知识 5.2 例题 6 空间曲面的法线与切平面 6.1 基础知识 6.2…...

EtherNet/IP转DeviceNet协议网关详解

一&#xff0c;设备主要功能 疆鸿智能JH-DVN-EIP本产品是自主研发的一款EtherNet/IP从站功能的通讯网关。该产品主要功能是连接DeviceNet总线和EtherNet/IP网络&#xff0c;本网关连接到EtherNet/IP总线中做为从站使用&#xff0c;连接到DeviceNet总线中做为从站使用。 在自动…...

NFT模式:数字资产确权与链游经济系统构建

NFT模式&#xff1a;数字资产确权与链游经济系统构建 ——从技术架构到可持续生态的范式革命 一、确权技术革新&#xff1a;构建可信数字资产基石 1. 区块链底层架构的进化 跨链互操作协议&#xff1a;基于LayerZero协议实现以太坊、Solana等公链资产互通&#xff0c;通过零知…...

MySQL中【正则表达式】用法

MySQL 中正则表达式通过 REGEXP 或 RLIKE 操作符实现&#xff08;两者等价&#xff09;&#xff0c;用于在 WHERE 子句中进行复杂的字符串模式匹配。以下是核心用法和示例&#xff1a; 一、基础语法 SELECT column_name FROM table_name WHERE column_name REGEXP pattern; …...

UR 协作机器人「三剑客」:精密轻量担当(UR7e)、全能协作主力(UR12e)、重型任务专家(UR15)

UR协作机器人正以其卓越性能在现代制造业自动化中扮演重要角色。UR7e、UR12e和UR15通过创新技术和精准设计满足了不同行业的多样化需求。其中&#xff0c;UR15以其速度、精度及人工智能准备能力成为自动化领域的重要突破。UR7e和UR12e则在负载规格和市场定位上不断优化&#xf…...

C++ Visual Studio 2017厂商给的源码没有.sln文件 易兆微芯片下载工具加开机动画下载。

1.先用Visual Studio 2017打开Yichip YC31xx loader.vcxproj&#xff0c;再用Visual Studio 2022打开。再保侟就有.sln文件了。 易兆微芯片下载工具加开机动画下载 ExtraDownloadFile1Info.\logo.bin|0|0|10D2000|0 MFC应用兼容CMD 在BOOL CYichipYC31xxloaderDlg::OnIni…...