【文档搜索引擎】在内存中构造出索引结构(下)
文章目录
- 4.保存到磁盘中
- 为什么要保存在磁盘中
- 怎么保存
- 操作步骤
- 1. 前期准备
- 2. 主要操作
- 5. 将磁盘中的数据加载到内存中
- Parser 类完整源码
- Index 类完整源码
4.保存到磁盘中
为什么要保存在磁盘中
索引本来是存储在内存中的,为什么要将其保存在硬盘中?
- 因为创建索引是比较耗时的
因此我们不应该在服务器启动的时候,才构建索引(启动服务器就可能会拖慢很多很多)
- 通常的做法是:把这些耗时的操作,单独去进行执行
- 单独执行完了之后,再让线上服务器直接加载这个构造好的索引
怎么保存
文本实质上就是字符串,我们就可以把字符串直接保存在文件中。我们就需要把内存中的索引结构变成一个“字符串”,然后写文件即可
- 变成字符串的过程就是——序列化
- 对应的特定结构的字符串,反向解析成一些结构化数据(类/对象/基础数据结构)——反序列化
序列化和反序列化有很多现成的通用方法,此处咱们就直接使用 JSON 格式来进行序列化/反序列化——jackson
- 通过
Maven
仓库,引入依赖
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.18.2</version>
</dependency>
操作步骤
1. 前期准备
引入一个 jackson
里面会用到的核心对象
private ObjectMapper objectMapper = new ObjectMapper();
- 之后就通过这个对象,完成后续的序列化和反序列化操作
创建一个文件指定存放的目录
private static final String INDEX_PATH =
"/Users/yechiel/Desktop/Byte/code_world/Gitee/java_doc_searcher";
2. 主要操作
使用两个文件,分别保存正排和倒排
- 先判定一下索引对应的目录是否存在,不存在就创建
- 然后在索引中分别创建两个文件:
forwardIndexFile
(正排文件)、invertedIndexFile
(倒排文件) - 使用
writeValue
方法,将文件进行写入
public void save(){ // 使用两个文件,分别保存正排和倒排 // 1. 先判断一下,索引对应的目录是否存在,不存在就创建 File indexPathFile = new File(INDEX_PATH); if(!indexPathFile.exists()){ indexPathFile.mkdirs(); } File forwardIndexFile = new File(INDEX_PATH + "fordword.txt"); File invertedIndexFile = new File(INDEX_PATH + "inverted.txt"); try { // 第一个参数:写到哪个文件里 第二个:对哪个对象进行写入 objectMapper.writeValue(forwardIndexFile, forwardIndex); objectMapper.writeValue(invertedIndexFile, invertedIndex); }catch (IOException e) { e.printStackTrace(); }
}
mkdirs()
可以一次嵌套创建多级目录writeValue
方法会报错,要在两个操作外面加上try-catch
。这里调用这个方法就不用我们再将文件变成字符串,然后再写入文件,这里直接进行写入就方便了很多
5. 将磁盘中的数据加载到内存中
public void load(){ System.out.println("加载索引开始!"); // 1. 设置加载索引的路径(和前面保存的路径一样) File forwardIndexFile = new File(INDEX_PATH + "forward.txt"); File invertedIndexFile = new File(INDEX_PATH + "inverted.txt"); try{ // 第一个参数:从哪里读 第二个参数:当前读到的数据,按照什么类型进行解析 forwardIndex = objectMapper.readValue(forwardIndexFile, new TypeReference<ArrayList<DocInfo>>() {}); invertedIndex = objectMapper.readValue(invertedIndexFile, new TypeReference<HashMap<String, ArrayList<Weight>>>() {});}catch (IOException e){ e.printStackTrace(); } System.out.println("加载索引结束!");
}
readValue
就会直接读取到文件内容,并且把文件内容按照这里指定的类型进行解析- 看见这个类型是
ArrayList<>
,然后就预期文件里面的 jason 也是代大括号的数组 - 然后看到每一个元素又是
DocInfo
,我们的readValue
就期望,我们的数据里面的大括号里面的每一个字段都得和DocInfo
是相对应的- 这个对应关系我们是可以保证的,因为前面存入磁盘的时候,就是用
objectMapper
的writeValue()
来去把对象生成 JSON 然后保存的 - 生成的时候就是按照每一个属性名为
key
来去存的,所以下面解析的时候也是和上面相对应的,根据得到的 JSON 中的每一个 key 的值,来去找到对应对象中的属性,然后给其赋值
- 这个对应关系我们是可以保证的,因为前面存入磁盘的时候,就是用
- 看见这个类型是
这里需要将这个这个结构的字符串,转换成一个 ArrayList<DocInfo>
类型的对象,jakson 专门提供了一个辅助工具类—— TypeReference<>
- 这是一个带有泛型参数的类,我们通过这个类的泛型参数,来指定我们实际要转换的类型
forwardIndex = objectMapper.readValue
(forwardIndexFile, new TypeReference<ArrayList<DocInfo>>() {});
- 这里相当于创建了一个匿名内部类的实例(后面 new 的部分)
- 创建一个匿名内部类,这个类实现了
TypeReference
- 同时再创建一个这个匿名内部类的实例
- 创建这个实例的最主要目的,就是为了把
ArrayList<DocInfo>
这个类型信息,告诉readValue
方法
- 创建一个匿名内部类,这个类实现了
在 java
中,并不能直接把一个类型作为方法的参数,而是必须得传一个具体的对象,正因为这个语法限制,我们就必须得绕一个弯。通过一个专门的泛型类,再搭配泛型参数,才能完成这个过程
Parser 类完整源码
package com.glg.javadoc_searcher;import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;public class Parser {// 先指定一个加载文档的路径private static final String INPUT_PATH = "/Users/yechiel/Desktop/Byte/code_world/docs";// 创建一个 Index 实例private Index index = new Index();public void run(){// 整个 Parser 的入口// 1. 根据指定的路径,枚举出该路径中所有的文件(HTML),这个过程需要把所有子目录中的文件都获取到ArrayList<File> fileList = new ArrayList<>();enumFile(INPUT_PATH, fileList);/*for(File file : fileList){System.out.println(file);}System.out.println(fileList.size());
*/// 2. 针对上面罗列出的文件路径,打开路径,读取文件内容,进行解析,并构建索引for(File f : fileList) {// 通过这个方法来解析单个 HTML 文件System.out.println("开始解析: "+ f.getAbsolutePath());parseHTML(f);}// 3. 把在内存中构造好的索引数据结构,保存到指定的文件中index.save();}private void parseHTML(File f) {// 1. 解析出 HTML 的标题String title = parseTitle(f);// 2. 解析出 HTML 对应的 URLString url = parseUrl(f);// 3. 解析出 HTML 对应的正文(有了正文才有后续的描述)String content = parseContent(f);// 4. 将解析出来的这些信息,加入到索引当中index.addDoc(title,url,content);}// 用来解析 HTML 里面的标题信息private String parseTitle(File f) {String name = f.getName();return name.substring(0, name.length() - ".html".length());}// 用来解析 HTML 里面的 URL 信息private String parseUrl(File f) {String part1 = "https://docs.oracle.com/javase/8/docs/";String part2 = f.getAbsolutePath().substring(INPUT_PATH.length());return part1 + part2;}// 用来解析 HTML 里面的正文信息public String parseContent(File f) {//先按照一个字符一个字符的方式来读取,以 < 和 > 来控制拷贝数据的开关StringBuilder content = new StringBuilder();try {FileReader fileReader = new FileReader(f);// 加上一个是否要进行拷贝的开关boolean isCopy = true;// 还得准备一个保存结果的 StringBuilder//StringBuilder content = new StringBuilder();while (true) {// 注意:此处的 read() 返回值是 int,不是 char// 按理说,应该是依次读一个字符,返回 char 就够了呀?// 此处使用 int 作为返回值,主要是为了表示一些非法情况// 比如说读到了文件末尾,继续读,就会返回 -1// 我们就可以根据返回的 -1 判断读完了int ret= fileReader.read();if(ret == -1) {// 表示文件读完了break;}// 这个结果不是 -1,那么就是一个合法的字符了char c = (char)ret;if(isCopy){// 开关打开的状态,遇到普通字符就应该拷贝到 StringBuilder 中if(c == '<'){// 关闭开关isCopy = false;continue;}if(c == '\n' || c == '\r'){// 为了去掉换行,把换行/回车替换成空格c = ' ';}// 其他字符,直接进行拷贝即可,把结果拷贝到最终的 StringBuilder 中content.append(c);}else {// 开关关闭的状态,暂时不拷贝,直到遇到 >if(c == '>'){isCopy = true;}}}fileReader.close();} catch (IOException e) {e.printStackTrace();}return content.toString();}// 第一个参数表示我们从哪个参数开始进行递归遍历// 第二个参数表示递归得到的结果private void enumFile(String inputPath, ArrayList<File> fileList) {File rootPath = new File(inputPath);// 把当前目录中,所包含的目录名全部获取到// listFiles 能够获取到 rootPath 当前目录下所包含的文件/目录(一层目录,不会进入子文件)File[] files = rootPath.listFiles();for(File f : files) {// 此时我们就根据当前 f 的类型,来决定是否要进行递归// 若 f 是一个普通文件,就把 f 加入到 fileList 结果中// 若 f 是一个目录,就递归调用 enumFile 方法,来进一步地获取子目录中的内容if(f.isDirectory()) {enumFile(f.getAbsolutePath(),fileList);}else {if (f.getAbsolutePath().endsWith(".html"))fileList.add(f);}}}public static void main(String[] args) {// 通过 main 方法,来实现整个制作索引的过程Parser parser = new Parser();parser.run();}
}
Index 类完整源码
package com.glg.javadoc_searcher;import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.ansj.domain.Term;
import org.ansj.splitWord.analysis.ToAnalysis;import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;// 通过这个类,在内存中构造索引结构
public class Index {private static final String INDEX_PATH = "/Users/yechiel/Desktop/Byte/code_world/Gitee/java_doc_searcher/";private ObjectMapper objectMapper = new ObjectMapper();// 使用数组下标表示 docIdprivate ArrayList<DocInfo> forwardIndex = new ArrayList<>();// 使用一个 哈希表 来表示倒排索引// key 就是词 value 就是一簇和这个词相关的文章private HashMap<String, ArrayList<Weight>> invertedIndex = new HashMap<>();// 这个类要提供的方法// 1. 给定一个 docId,在正排索引中,查询文档的详细信息public DocInfo getDocInfo(int docId){return forwardIndex.get(docId);}// 2. 给定一个词,在倒排索引中,查询哪些文档和这个词关联// 仔细思考这里的返回值,单纯的返回一个整数的 List 是否可行呢?这样不太好(返回整数是因为 List 里面存的是文档 id)// 词和文档之间是存在一定的“相关性”的(文档和词的相关性有强有弱),不是单一的依次排列// 所以我们再创建一个 Weight 类来处理 文档id 和 文档与词 的相关性权重public List<Weight> getInverted(String term){return invertedIndex.get(term);}// 3. 往索引中新增一个文档public void addDoc(String title, String url, String content){// 新增文档操作,需要同时给正排索引和倒排索引新增信息// 构建正排索引DocInfo docInfo = buildForward(title, url, content);// 构建倒排索引buildInverted(docInfo);}// 实现倒排索引private void buildInverted(DocInfo docInfo) {// 直接使用内部类,词频统计class WordCnt {public int titleCount;public int contentCount;}// 通过一个内部类,将两个数据装到一起了,变成一个 HashMap,更方便遍历// 这个数据结构用来统计词频HashMap<String, WordCnt> wordCntHashMap = new HashMap<>();// 3.1 针对文档标题进行分词List<Term> terms = ToAnalysis.parse(docInfo.getTitle()).getTerms();// 3.2 遍历分词结果,统计每个词出现的次数for(Term term : terms){// 先判断一下 term 是否存在String word = term.getName();WordCnt wordCnt = wordCntHashMap.get(word);if(wordCnt == null) {// 如果不存在,就创建一个新的键值对,插入进去,titleCount 设为 1WordCnt newWordCnt = new WordCnt();newWordCnt.titleCount = 1;newWordCnt.contentCount = 0;wordCntHashMap.put(word, newWordCnt);}// 如果存在,就找到之前的值,然后把对应的 titleCount + 1wordCnt.titleCount++;}// 3.3 针对正文页进行分词terms = ToAnalysis.parse(docInfo.getContent()).getTerms();// 3.4 遍历分词结果,统计每个词出现的次数for(Term term : terms) {String word = term.getName();WordCnt wordCnt = wordCntHashMap.get(word);if(wordCnt == null) {WordCnt newWordCnt = new WordCnt();newWordCnt.titleCount = 0;newWordCnt.contentCount = 1;wordCntHashMap.put(word, newWordCnt);}else{wordCnt.contentCount++;}}// 3.5 把上面的结果汇总到一个 HashMap 里面// 最终文档的权重,就设定成标题中出现的次数 * 10 + 正文中出现的次数// 3.6 遍历刚才这个 HashMap,依次来更新倒排索引中的结构// 将 Map 转换成 Set 进行遍历(Map 不能直接进行遍历)for(Map.Entry<String, WordCnt> entry : wordCntHashMap.entrySet()) {// 先根据这里的词,去倒排索引中查一查// 倒排索引中的一个值——倒排拉链List<Weight> invertedList = invertedIndex.get(entry.getKey());// 判断是不是存在的(空的)if(invertedList == null) {// 如果为空,就插入一个新的键值对ArrayList<Weight> newInvertedList = new ArrayList<>();// 把新的文档(当前的 DocInfo)构造成 Weight 对象,插入进来Weight weight = new Weight();weight.setDocId(docInfo.getDocId());// 权重计算公式:标题中出现的次数 * 10 + 正文中出现的次数weight.setWeight(entry.getValue().titleCount * 10 + entry.getValue().contentCount);newInvertedList.add(weight);invertedIndex.put(entry.getKey(), newInvertedList);}else{// 如果非空,就把当前这个文档,构造出一个 Weight 对象,插入到倒排拉链的后面Weight weight = new Weight();weight.setDocId(docInfo.getDocId());// 权重计算公式:标题中出现的次数 * 10 + 正文中出现的次数weight.setWeight(entry.getValue().titleCount * 10 + entry.getValue().contentCount);invertedList.add(weight);}}}private DocInfo buildForward(String title, String url, String content) {DocInfo docInfo = new DocInfo();docInfo.setDocId(forwardIndex.size());docInfo.setTitle(title);docInfo.setUrl(url);docInfo.setContent(content);forwardIndex.add(docInfo);return docInfo;}// 4. 把内存中的索引结构保存到磁盘中public void save(){long beg = System.currentTimeMillis();// 使用两个文件,分贝保存正排和倒排System.out.println("保存索引开始!");// 先判断一下,索引对应的目录是否存在,不存在就创建File indexPathFile = new File(INDEX_PATH);if(!indexPathFile.exists()){indexPathFile.mkdirs();}File forwardIndexFile = new File(INDEX_PATH + "fordword.txt");File invertedIndexFile = new File(INDEX_PATH + "inverted.txt");try {// 第一个参数:写到哪个文件里 第二个:对哪个对象进行写入objectMapper.writeValue(forwardIndexFile, forwardIndex);objectMapper.writeValue(invertedIndexFile, invertedIndex);}catch (IOException e) {e.printStackTrace();}long end = System.currentTimeMillis();System.out.println("保存索引完成!消耗时间为:" + (end - beg) + "ms");}// 5. 把磁盘中的索引数据加载到内存中public void load(){long beg = System.currentTimeMillis();System.out.println("加载索引开始!");// 设置加载索引的路径(和前面保存的路径一样)File forwardIndexFile = new File(INDEX_PATH + "forward.txt");File invertedIndexFile = new File(INDEX_PATH + "inverted.txt");try{// 第一个参数:从哪里读 第二个参数:当前读到的数据,按照什么类型进行解析forwardIndex = objectMapper.readValue(forwardIndexFile, new TypeReference<ArrayList<DocInfo>>() {});invertedIndex = objectMapper.readValue(invertedIndexFile, new TypeReference<HashMap<String, ArrayList<Weight>>>() {});}catch (IOException e){e.printStackTrace();}long end = System.currentTimeMillis();System.out.println("加载索引结束!消耗时间为:" + (end - beg) + "ms");}}
相关文章:
【文档搜索引擎】在内存中构造出索引结构(下)
文章目录 4.保存到磁盘中为什么要保存在磁盘中怎么保存操作步骤1. 前期准备2. 主要操作 5. 将磁盘中的数据加载到内存中Parser 类完整源码Index 类完整源码 4.保存到磁盘中 为什么要保存在磁盘中 索引本来是存储在内存中的,为什么要将其保存在硬盘中? …...
旅游资源系统|Java|SSM|VUE| 前后端分离
【技术栈】 1⃣️:架构: B/S、MVC 2⃣️:系统环境:Windowsh/Mac 3⃣️:开发环境:IDEA、JDK1.8、Maven、Mysql5.7 4⃣️:技术栈:Java、Mysql、SSM、Mybatis-Plus、VUE、jquery,html 5⃣️数据库可…...
如何用细节提升用户体验?
前端给用户反馈是提升用户体验的重要部分,根据场景选择不同的方式可以有效地提升产品的易用性和用户满意度。以下是常见的方法: 1. 视觉反馈 用户执行了某些操作后,需要即时确认操作结果。例如:按钮点击、数据提交、页面加载等。…...
容器设计模式:Sidecar
文章目录 容器设计模式:Sidecar 模式1. 什么是 Sidecar 模式?2. Sidecar 模式的原理2.1 工作机制2.2 常见用途 3. Sidecar 模式示例示例:日志收集 4. Sidecar 模式的架构图图例: 5. Sidecar 模式的优点6. Sidecar 模式的局限性7. …...
深入剖析MyBatis的架构原理
架构设计 简要画出 MyBatis 的架构图 >> Mybatis 的功能架构分为哪三层? API 接口层 提供给外部使用的接口 API,开发人员通过这些本地 API 来操纵数据库。接口层一接收到调用请求就会调用数据处理层来完成具体的数据处理。MyBatis 和数据库的…...
深入C语言文件操作:从库函数到系统调用
引言 文件操作是编程中不可或缺的一部分,尤其在C语言中,文件操作不仅是处理数据的基本手段,也是连接程序与外部世界的重要桥梁。C语言提供了丰富的库函数来处理文件,如 fopen、fclose、fread、fwrite 等。然而,这些库…...
【Linux】shell脚本二
2、接收用户的参数 shell脚本已经内设了用于接收用户输入参数的变量,变量之间可以使用空格隔开。 如:./test.sh one two three four $0:对应的是当前shell脚本程序的名称,即test.sh$#:对应的是总共有几个参数&#…...
从万维网到人工智能:改变生活的11项技术里程碑
1984 年 1 月 24 日,苹果公司推出了 Macintosh 128K,从此永远改变了个人电脑的面貌。 史蒂夫・乔布斯(Steve Jobs)这款小巧且用户友好的电脑向全世界引入了图形用户界面,标志着个人技术发展历程中的一个关键时刻。 从…...
Hyperledger Fabric 2.x 环境搭建
Hyperledger Fabric 是一个开源的企业级许可分布式账本技术(Distributed Ledger Technology,DLT)平台,专为在企业环境中使用而设计,与其他流行的分布式账本或区块链平台相比,它有一些主要的区别。 环境准备…...
【Maven】自定义Maven插件
场景: 1、自定义一个插件目标 timer,用于显示当前日期时间。 2、将 timer 绑定到 validate 阶段。 调研 1、maven-clean-plugin 下载 maven-clean-plugin 插件的源码,在本地使用 IDEA 打开 可以看到,maven-clean-plugin 插件是…...
修改vscode中emmet中jsx和tsx语法中className的扩展符号从单引号到双引号 - HTML代码补全 - 单引号双引号
效果图 实现步骤 文件 > 首选项 > 设置搜索“”在settings.json中修改,增加 "emmet.syntaxProfiles": {"html": {"attr_quotes": "single"},"jsx": {"attr_quotes": "double","…...
数据结构day3作业
一、完整功能【顺序表】的创建 【seqList.h】 #ifndef __SEQLIST_H__ #define __SEQLIST_H__#include <stdio.h> #include <string.h> #include <stdlib.h>//宏定义,线性表的最大容量 #define MAX 30//类型重定义,表示要存放数据的类…...
pydub AudioSegment实现音频重采样 - python 实现
DataBall 助力快速掌握数据集的信息和使用方式,会员享有 百种数据集,持续增加中。 需要更多数据资源和技术解决方案,知识星球: “DataBall - X 数据球(free)” -------------------------------------------------------------…...
C++多线程常用方法
在 C 中,线程相关功能主要通过头文件提供的类和函数来实现,以下是一些常用的线程接口方法和使用技巧: std::thread类 构造函数: 可以通过传入可调用对象(如函数指针、函数对象、lambda 表达式等)来创建一…...
【网络安全】Web Timing 和竞争条件攻击:揭开隐藏的攻击面
Web Timing 和竞争条件攻击:揭开隐藏的攻击面 在传统的 Web 应用中,漏洞的发现和利用通常相对容易理解。如果代码存在问题,我们可以通过发送特定输入来强制 Web 应用执行非预期的操作。这种情况下,输入和输出之间往往有直接关系&…...
12月最新编程语言排行榜
“岁末将至,2024年的编程世界又发生了哪些变化?是Python依然稳坐王座,还是有新语言杀出重围?让我们一起看看12月最新编程语言排行榜,寻找未来技术的风向标。” 今年,哪些编程语言成为行业焦点?…...
迭代器模式
迭代器模式 迭代器模式(Iterator Pattern)是一种行为设计模式,它提供了一种方法来访问一个聚合对象中的各个元素,而又不暴露其内部的表示。这种模式允许你逐个访问对象中的元素,而无需知道其底层的数据结构。迭代器模…...
探秘 WB 实验:AI 助力攻克操作难关
在生物学研究的浩瀚领域中,WB 实验犹如一座关键的灯塔,照亮了我们探索蛋白质世界的道路。今天,就让我们一同深入了解 WB 实验的全貌,以及 AI 如何在其中发挥神奇作用,帮助我们应对实际操作中的重重挑战。 WB 实验&…...
labelimg使用指南
YOLOv8目标检测(一)_检测流程梳理:YOLOv8目标检测(一)_检测流程梳理_yolo检测流程-CSDN博客 YOLOv8目标检测(二)_准备数据集:YOLOv8目标检测(二)_准备数据集_yolov8 数据集准备-CSDN博客 YOLOv8目标检测(三)_训练模型:YOLOv8目标检测(三)_训…...
车载终端_智能车载终端定制_农机/出租车/叉车/驾培车载终端MTK方案
车载终端集成了先进的技术和卓越的性能,采用了联发科的高效低功耗ARM处理器,具备八核架构,主频高达2.0GHz,基于12nm制程工艺,不仅性能强劲,而且功耗控制出色。基本配置为4GB内存与64GB存储,用户…...
Unity中Pico实现透视
1.参照Pico官方【透视 | PICO 开发者平台】文档设置。 2.额外的需要将主相机的post processing禁用。...
elk部署与实战案例
**ELK Stack** 是一个非常强大的日志处理和分析平台,由 **Elasticsearch**、**Logstash** 和 **Kibana** 三个组件组成。它被广泛应用于日志收集、搜索、分析和可视化。ELK 可以处理大量数据,并帮助用户从中提取有价值的信息。以下是一个从部署到实际应用…...
Isaac Gym, Sim, Lab
本文仅为个人学习笔记,文章参考请见参考资料部分,主要目的是进行多场景并行仿真测试,笔记中大部分内容都是针对于这个目标。 参考资料 常见问题 — Isaac Lab 文档 https://github.com/isaac-sim/IsaacLab 一. Gym, Sim, Lab 之间的关系 Is…...
活着就好20241217
亲爱的朋友们,大家早上好!🌞 今天是17号,星期二,2024年12月的第十七天,同时也是第50周的第八天,农历甲辰[龙]年十一月初十三日。在这晨光熹微的美好时刻,愿那温暖而明媚的阳光轻轻拂…...
第十六章:IO流 (java.io包中)
一、理解 1. 简单而言:流就是内存与存储设备之间传输数据的通道、管道。 2. 分类: (1) 按方向 ( 以 JVM 虚拟机为参照物 ) 【重点】 输入流:将 < 存储设备 > 中的内容读入到 < 内存 > 中。 输出流:将 < 内…...
Introduction to NoSQL Systems
What is NoSQL NoSQL database are no-tabular非數據表格 database that store data differently than relational tables 其數據的存儲方式與關係型表格不同 Database that provide a mechanism機制 for data storage retrieval 檢索 that is modelled in means other than …...
【JVM】JVM基础教程(四)
上一章:【JVM】JVM基础教程(三)-CSDN博客 目录 自动垃圾回收 方法区的回收 方法区回收条件 手动触发回收 堆回收 如何判断堆上的对象可以回收? 可以给对象引用赋值null,切断引用 引用计数法 循环引用缺点 查…...
前端实现在线预览excel文件
在前端开发中,经常会遇到需要在线预览各种文件的需求。本文将介绍如何使用前端技术实现在线预览 Excel 文件的功能。 一、基于微软office服务的excel预览 获取要预览的 Excel 文件的 URL(例如存储在 OneDrive 或 SharePoint 上的文件)。 使…...
Python 写的《桌面时钟》屏保
原代码: # 日历式时钟 # 导入所需的库 # 作者:Hoye # 日期:2024年12月16日 # 功能:显示当前日期、星期、时间,并显示模拟时钟 import tkinter as tk from tkinter import ttk import time import math import sysdef …...
计算机视觉单阶段实例分割实践指南与综述
概述 原文地址:https://towardsdatascience.com/single-stage-instance-segmentation-a-review-1eeb66e0cc49 实例分割是一项具有挑战性的计算机视觉任务,需要预测对象实例及其每像素分割掩码。这使其成为语义分割和目标检测的混合体。 自 Mask R-CNN …...
Axios结合Typescript 二次封装完整详细场景使用案例
Axios 是一个基于 promise 的 HTTP 客户端,用于浏览器和 node.js。二次封装 Axios 主要是为了统一管理 HTTP 请求,例如设置统一的请求前缀、头部、超时时间,统一处理请求和响应的格式,以及错误处理等。 以下是一个使用 TypeScrip…...
C++面试:HTTP1.0/1.1,HTTP2.0,HTPP3.0的区别
1.你对HTTP1.0/1.1,HTTP2.0,HTPP3.0有什么了解? 答:HTTP1.0: ①属于无连接式,每次发送HTTP请求都需要建立TCP连接。 ②会造成发送时的对头阻塞,当上一个请求没有应答,当前的请求就会…...
使用 Docker Compose 部署 Redis 主从与 Sentinel 高可用集群
文章目录 使用 Docker Compose 部署 Redis 主从与 Sentinel 高可用集群Redis 主从架构简介Redis Sentinel 简介配置文件1. 主节点配置 (redis-master.conf)2. 从节点配置 (redis-slave1.conf 和 redis-slave2.conf)redis-slave1.confredis-slave2.conf3. Sentinel 配置 (sentin…...
【Java】4、虚拟机 JVM
目录 Java内存区域详解(重点) JVM垃圾回收详解(重点) 类文件结构详解 类加载过程详解 类加载器详解(重点) 最重要的JVM参数总结 JDK监控和故障处理工具总结 JVM线上问题排查和性能调优案例 参考: JVM 核心技术 32 讲 深入浅出 Java 虚拟机...
Vue3之组合式API详解
Vue 3引入了一种新的API风格——组合式API(Composition API),旨在提升组件的逻辑复用性和可维护性。本文将详细阐述Vue 3中的组合式API,包括其定义、特点、使用场景、优势等,并给出具体的示例代码。 一、定义 组合式…...
Flutter编译Module was compiled with an incompatible version of Kotlin错误解决
文章目录 编译报错如下解决方法修复方案 编译报错如下 e: C:/Users/YUAN/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib/1.9.20/e58b4816ac517e9cc5df1db051120c63d4cde669/kotlin-stdlib-1.9 .20.jar!/META-INF/kotlin-stdlib-jdk8.kotlin_module:…...
Uniapp插件如何通过NFC读取多种证卡信息?
nfc读卡uniapp插件,由中软高科进行开发,主要是通过NFC读取居民身份证、港澳台居住证、外国人居住证、护照等证卡的信息。经过多个版本的升级更新,目前性能已趋于稳定,并且读卡速度较之最初版本有了大的提升。 注意事项 测试使用的…...
本地docker镜像改名字
如果你想修改本地 Docker 镜像的名字,可以通过创建该镜像的新标签(tag)来实现。Docker 中没有直接修改镜像名字的命令,但可以通过重新打标签的方式实现类似的效果。以下是具体步骤: 查看当前镜像: docker…...
VS Code 远程连接 SSH 服务器
文章目录 一、安装 Remote - SSH 扩展并连接远程主机二、免密连接远程主机1. 生成 SSH 密钥对2. 将公钥复制到远程服务器3. 配置 SSH 客服端4. 连接测试 随着技术的不断迭代更新,在 Linux 系统中使用 Vim、nano 等基于 Shell 终端的编辑器(我曾经也是个 …...
艾体宝案例丨CircleCI 助力 ANA Systems 打造高效 CI/CD 模型
在现代软件开发领域,效率和可靠性是企业在竞争中取胜的关键。本文将深入探讨 ANA Systems 如何通过引入业界领先的 CI/CD 平台——CircleCI,克服传统开发流程的瓶颈,实现开发运营效率的全面提升。同时,本文还将详细解析 CircleCI …...
vue 上传组件 vxe-upload 实现拖拽调整顺序
vue 上传组件 vxe-upload 实现拖拽调整顺序,通过设置 drag-sort 参数就可以启用拖拽排序功能 官网:https://vxeui.com/ 图片拖拽排序 <template><div><vxe-upload v-model"imgList" mode"image" multiple drag-sor…...
Elasticsearch的一些介绍
你想问的可能是 **Elasticsearch**,以下是关于它的一些介绍: ### 概述 Elasticsearch是一个基于Apache Lucene库构建的开源分布式搜索和分析引擎,采用Java语言编写,具有高性能、可扩展性和易用性等特点,可用于各种数据…...
从源码构建安装Landoop kafka-connect-ui
背景 部署Landoop kafka-connect-ui最简单的办法还是通过docker来部署,我们之前的kafka-connect-ui就是通过docker部署的,但是,最近发现个问题:当使用docker部署且防火墙使用的是firewalld的情况下,就会出现端口冲突。…...
MybatisPlus-扩展功能
代码生成 在使用MybatisPlus以后,基础的Mapper、Service、PO代码相对固定,重复编写也比较麻烦。因此MybatisPlus官方提供了代码生成器根据数据库表结构生成PO、Mapper、Service等相关代码。只不过代码生成器同样要编码使用,也很麻烦。 这里…...
发布/部署WebApi服务器(IIS+.NET8+ASP.NETCore)
CS软件授权注册系统-发布/部署WebApi服务器(IIS.NET8ASP.NETCore) 目录 本文摘要VS2022配置发布VS2022发布WebApiIIS服务器部署WebApi 将程序文件复制到云服务器添加网站配置应用程序池配置dns域名配置端口阿里云ECS服务器配置19980端口配置https协议 (申请ssl证书)测试WebAp…...
【2025最新计算机毕业设计】基于SpringBoot+Vue城市中小学体育场馆预约系统【提供源码+答辩PPT+文档+项目部署】
一、项目技术架构: 本项目是一款城市中小学体育场馆预约系统的设计与实现。 该SpringBootVue的城市中小学体育场馆预约系统,后端采用SpringBoot架构,前端采用VueElementUI实现页面的快速开发,并使用关系型数据库MySQL存储系统运行…...
Spring Security 6 系列之二 - 基于数据库的用户认证和认证原理
之所以想写这一系列,是因为之前工作过程中使用Spring Security,但当时基于spring-boot 2.3.x,其默认的Spring Security是5.3.x。之后新项目升级到了spring-boot 3.3.0,结果一看Spring Security也升级为6.3.0,关键是其风…...
vue中打包dist文件内static 和 assets 的区别
背景 在Vue.js项目中,assets 和 static 是两个用于存放静态资源的文件夹,但它们在使用方式和处理机制上有所不同 用途 assets: assets 文件夹通常用于存放那些需要在构建过程中被Webpack处理的静态资源。这些资源可以包括图片、字体、样式文件&#…...
Big Model weekly | 第49期
点击蓝字 关注我们 AI TIME欢迎每一位AI爱好者的加入! 01 Magnetic Preference Optimization: Achieving Last-iterate Convergence for Language Models Alignment 自我对弈方法在多个领域增强模型能力方面展现出了显著的成功。在基于人类反馈的强化学习࿰…...
Node.js内置模块
1.内置模块 Node.js的中文网参考手册:https://nodejs.cn//api 帮助文档 API文档:查看对应的模块,左边是模块,右边是模块的成员 源码:https://github.com/nodejs/node/tree/main/lib 查看 例如: http.js 创建web服务器的模块 -->进入源码中,搜索…...