在线体验 : http://43.139.1.94:9090/index.html

项目 Gitee 链接 : API 文档搜索引擎

1.认识搜索引擎

我们平时查百度, 搜狗的时候, 结果页会显示若干条相关结果 , 每个结果几乎都包含图片, 标题, 描述, 展示 URL以及时间等等.

1.1 搜索引擎的本质

输入一个查询词, 得到若干个结果, 每个搜索结果包含了标题, 描述, 展示 URL , 以及点击 URL...

1.2 实现搜索引擎的核心思路

实现过程中, 我们主要考虑的问题有两个 :

  • 查询出哪些网页和查询词具有一定的相关性.

  • 如何高效的进行搜索.

==============

解决思路 >>

方案一 : 暴力检索

每当用户输入一个查询词, 就拿着这个查询词去所有的网页中遍历一次, 查找出包含该查询词的所有文档.

显然这个方案不满足高效检索, 随着文档数量的增多, 搜索的开销会线性增长.

方案二 : 倒排索引 + 正排索引

倒排索引是一种专门针对搜索引擎场景而设计的数据结构.

因为当前这个项目只是针对 Java 官方文档设计的一个搜索引擎, 总共也就一万多条记录, 所以我们可以提前将 Java官方文档下载到本地, 然后对其进行预处理. 此处的预处理就是构建正排, 倒排索引.
1. 正排索引 : 一个文档包含了哪些词, 描述了一个文档的基本信息, 包括文档标题, 文档正文, 文档 URL 以及文档标题和正文的分词结果.
2. 倒排索引 : 查询词在哪些文档中出现, 描述了一个词的基本信息, 包括这个词分别被哪些文档引用, 这个词在该文档中的相关性/权重, 以及这个词出现的位置等.

Java 官方文档线上链接 : https://docs.oracle.com/javase/8/docs/api/index.html

Java 官方文档下载链接 : https://www.oracle.com/technetwork/java/javase/downloads/index.html

2. Java 官方文档的搜索引擎

2.1 项目核心模块

  1. 索引模块 : 扫描下载到的文档, 分析数据内容构建正排+倒排索引, 并保存到文件中.

  1. 搜索模块: 加载索引. 根据输入的查询词, 基于正排+倒排索引进行检索, 得到检索结果.

  1. web模块: 编写一个简单的页面, 展示搜索结果. 点击搜索结果能跳转到对应的 Java API 文档页面.

2.2 创建 SpringBoot 项目

创建项目具体流程就不再赘述. 引入常用的依赖 : devtools, lombok, Spring Web 以及项目中需要使用到的分词依赖 : ansj.

2.3 认识分词

分词操作是项目中的一个核心操作, 此处仅针对 Java官方文档进行分词, 就只需要考虑英文分词即可. 项目中使用现成的分词库 ansj.

分词库的简单使用示例 : https://blog.csdn.net/weixin_44112790/article/details/86756741

<dependency><groupId>org.ansj</groupId><artifactId>ansj_seg</artifactId><version>5.1.6</version>
</dependency>

代码示例 :

public class TestAnsj {public static void main(String[] args) {String str = "Write a search engine blog today";List<Term> terms = ToAnalysis.parse(str).getTerms();for (Term term : terms) {System.out.print(term.getName() + "/");}}
}

分词结果 (分词库会将所有单词都转成小写):

write/ /a/ /search/ /engine/ /blog/ /today/

2.4 实现索引模块

2.4.1 实现 Parser 类

parser 主要做的工作有 :

  • 构建一个可执行程序.

  • 读取 HTML 文档, 制作并生成索引数据.

public class Parser {// 指定一个加载文档的路径private static final String INPUT_PATH = "D:/software-download/Java-Official-document/jdk-8u351-docs-all/docs/api";// 整个 Parser 类的入口public void run() {long beg = System.currentTimeMillis();System.out.println("索引制作开始!");// 1. 根据指定的本地文档路径, 枚举出该路径中所有的 html 文件.ArrayList<File> fileList = new ArrayList<>();enumFile(INPUT_PATH, fileList);// 2. 针对这些 html 文件的路径, 打开文件, 读取文件内容, 并解析, 并构建索引.for(File f : fileList) {System.out.println("开始解析: " + f.getAbsolutePath());// 解析每个 HTML 文件parseHTML(f);}// 3. TODO 将在内存中构造好的索引数据结构, 保存到指定文件中.(涉及 Index 类)long end = System.currentTimeMillis();System.out.println("索引制作完成! 消耗时间: " + (end - beg));}/*** 枚举指定路径下的所有文件* @param rootPath 从哪个目录开始进行递归遍历* @param fileList 递归得到的结果集*/private void enumFile(String rootPath, ArrayList<File> fileList) {File rootFile = new File(rootPath);// 获取到 rootPath 当前目录下所包含的文件/目录File[] files = rootFile.listFiles();for(File f : files) {// 如果 f 是一个目录, 就进行递归// 如果 f 是一个普通文件, 就加入到 fileList 中if(f.isDirectory()) {enumFile(f.getAbsolutePath(), fileList);} else {// endsWith() 表示字符串以什么结尾if(f.getAbsolutePath().endsWith(".html")) {fileList.add(f);}}}}private void parseHTML(File f) {// 1. 解析出 HTML 文件的标题String title = parseTitle(f);// 2. 解析出 HTML 文件的 URLString url = parseUrl(f);// 3. 解析出 HTML 文件的正文(后续再处理描述)String content = parseContent(f);// String content = parseContentByRegex(f); 后续记得要将其改成正则表达式的版本.// 4. TODO 把解析出来的 HTML 文件的具体信息加入到索引中.(涉及 Index 类)}private String parseTitle(File f) {// 获取标题不必读取到 <title> 标签中的内容, 只需拿文件名即可String name = f.getName();return name.substring(0, name.length() - ".html".length());}//Java API 文档存在两份 : 线上文档,本地文档// 这两文件路径的后缀很相似, 因此就可以拿着这两个路径的关键部分进行拼接, 就可以得到线上文档的网络路径了private String parseUrl(File f) {// 线上文档String part1 = "https://docs.oracle.com/javase/8/docs/api";// 线下文档String part2 = f.getAbsolutePath().substring(INPUT_PATH.length());String result = (part1 + part2).replaceAll("\\\\", "/");return result;}private String parseContent(File f) {// 按照字符来读取, 以正文中标签的 < 和 > 作为控制拷贝数据的开关try(FileReader fileReader = new FileReader(f)) {// 拷贝数据的开关boolean isCopy = true;// 用来保存结果StringBuilder content = new StringBuilder();while(true) {// 一次读一个字符, 返回值为 int 是为了处理一些非法情况, 如果读到了末尾, 就会返回 -1int ret = fileReader.read();if (ret == -1) {// 文件读完了break;}char c = (char) ret;if(isCopy) {// 开关处于打开状态if(c == '<') {// 遇到 <, 就关闭开关isCopy = false;continue;}// 优化 : 将换行符转换成空格if(c == '\n' || c == '\r') {c = ' ';}// 其他字符, 就进行拷贝content.append(c);} else {// 开关处于关闭状态if(c == '>') {// 遇到 >, 就关闭开关isCopy = true;}}}return content.toString();} catch (IOException e) {e.printStackTrace();}return "";}
}

【Parser 类的一些实现细节】

Spring Boot 项目 - API 文档搜索引擎相关推荐

  1. 企业级SpringBoot教程 (十)用spring Restdocs创建API文档

    这篇文章将带你了解如何用spring官方推荐的restdoc去生成api文档.本文创建一个简单的springboot工程,将http接口通过Api文档暴露出来.只需要通过 JUnit单元测试和Spri ...

  2. Spring Boot 3.0.0-M1 Reference Documentation(Spring Boot中文参考文档) 9-16

    9. 数据 Spring Boot与多个数据技术集成,包括SQL和NoSQL. 9.1. SQL数据库 Spring Framework提供扩展支持用于与SQL数据工作,从使用JdbcTemplate ...

  3. SpringBoot 第十篇: 用spring Restdocs创建API文档

    这篇文章将带你了解如何用spring官方推荐的restdoc去生成api文档.本文创建一个简单的springboot工程,将http接口通过Api文档暴露出来.只需要通过 JUnit单元测试和Spri ...

  4. java B2B2C 源码 多级分销Springcloud多租户电子商城系统(十)用spring Restdocs创建API文档...

    这篇文章将带你了解如何用spring官方推荐的restdoc去生成api文档.本文创建一个简单的springboot工程,将http接口通过Api文档暴露出来.只需要通过 JUnit单元测试和Spri ...

  5. 企业级 SpringBoot 教程 (十)用spring Restdocs创建API文档

    这篇文章将带你了解如何用spring官方推荐的restdoc去生成api文档.本文创建一个简单的springboot工程,将http接口通过Api文档暴露出来.只需要通过 JUnit单元测试和Spri ...

  6. java B2B2C springmvc mybatis仿淘宝电子商城系统(十)用spring Restdocs创建API文档

    这篇文章将带你了解如何用spring官方推荐的restdoc去生成api文档.本文创建一个简单的springboot工程,将http接口通过Api文档暴露出来.只需要通过 JUnit单元测试和Spri ...

  7. Showdoc 搭建项目 API 文档系统

    showdoc 是 PHP 开发的一款 api 文档系统,因此所需环境和普通 PHP 项目一致 准备环境: php nginx composer //注意更换国内镜像,否则速度会很慢,甚至失败 创建项 ...

  8. API 文档搜索引擎

    项目简介 该项目主要实现了在前端页面的搜索框内输入需要搜索的 Java API 文档的关键字,对后端发出请求,后端将处理后的结果返回给前端展示,并且按照一定的权重排序展示出来. 开发环境:IDEA.T ...

  9. springboot实战pdf_Java程序员中秋节福利发送:Spring boot+Redis实战文档「PDF」

    中秋节越来越近了,平日里,各大公司拼员工拼技术拼实力:到了节日,则要拼奖金.拼福利.拼假期,还要拼创意.今天,小编为大家也准备了一份中秋节礼物,让我们一起来看看礼物是啥吧! Spring boot文档 ...

最新文章

  1. AI4U:以用户友好为目标,智源重大研究方向“机器学习”学者候选人发布
  2. 5、ORDER BY:对查询结果排序
  3. VTK:插值相机用法实战
  4. Spring和石英:多作业计划服务
  5. Apollo进阶课程⑯丨Apollo感知之旅——感知概貌
  6. python字符串驻留机制_python的内存驻留机制(小数据池)
  7. Unity3D 场景编辑器扩展学习笔记-Editor
  8. 苹果手机屏幕镜像_苹果手机还能一键投屏?点一下小屏变大屏幕,看剧是真畅快...
  9. echarts横向柱形图显示不同类别所占整体百分比
  10. 安防意识增强 澳洲迈向新发展
  11. 语音服务器登录失败,设置语音邮件用户被锁定前的登录失败次数:Exchange 2013 帮助 | Microsoft Docs...
  12. Qt(C++)调用工业相机Basler的SDK使用示例
  13. MBA心路历程第一天 —— 开始行动
  14. TLB和cache的关系
  15. INTERSECT –谓词中被低估的双向
  16. JQuery获取当前元素本身
  17. 多种方式解决Java控制台报错 java.util.LinkedHashMap cannot be cast to.....
  18. 五种IO模型和nginx的web模块
  19. [易飞]累计组成用量=组成用量/(底数*标准用量)
  20. 安装vs 2013 与打包项目生成安装包

热门文章

  1. 小木虫网站登录返回404
  2. android环信聊天界面上面显示昵称,【环信征文】在android中5分钟实现环信昵称头像的显示...
  3. Scanpy(四)使用ingest和BBKNN整合数据
  4. 2022-08-22 第六小组 瞒春 学习笔记
  5. 《大学》《中庸》全文及翻译 (转载)
  6. 计算机运算器发展趋势,2020计算器市场发展现状及及前景分析
  7. Google Chrome 源码下载
  8. SGVision与FX3U通讯
  9. 乐视账号服务器关闭,乐视手机账号登陆不了最新解决方法,包括恢复出厂后无法登陆问题...
  10. bootstrap check failure [2] of [2]: max virtual memory areas vm.max_map_count [65530] is too low, in