用nodejs连接mongodb数据库对标题和内容的全文本搜索,mogogdb对文档的全文本索引的设置以及用node-rs/jieba对标题和内容的分词

//首先我们要在Nodejs中安装 我们的分词库@node-rs/jieba,这个分词不像jieba安装时会踩非常多的雷,而且一半的机率都是安装失败,node-rs/jieba比jieba库要快20-30%;安装分词库是为了更好达到搜索的效果
这个库直接npm install @node-rs/jieba即可

代码分为三个,将标题,内容分词后插入mongodb数据库,insertContent.js
第二个为搜索代码,对标题和内容进行全文搜索search.js
第三个为页面显示代码,对搜索出来的结果进行显示

//insertContent.js

const {Jieba}=require("@node-rs/jieba");
const {dict}=require("@node-rs/jieba/dict");
const {MongoClient}=require('mongodb');//异步函数插入标题和内容
async function insertDocument(title,text)
{
//连接Mongodb数据库const client=new MongoClient('mongodb://ychj:123456@localhost:27017/?authSource=employees');try{await client.connect();const db=client.db('employees');	//要连接的数据库名const collection=db.collection("blog");	//要连接的集合名//使用jieba分词const jieba=Jieba.withDict(dict);//对标题进行分词const titleWords=jieba.cut(title);//对文本内容进行分词const contentWords=text.split('\n').map(paragraph=>jieba.cut(paragraph).join(' '));//将分词结果存储到Mongodbconst result=await collection.insertOne({"id":1,"title":titleWords.join(' '),"content":contentWords.join('\n')});//后面文本跟了一个'\n'是为了给文章分段落console.log('文档插入成功',result.insertedId);}finally{await client.close();}
}//为什么对标题进行分词,一般搜索文章是搜索标题,分词可以提高搜索率
//如果要对文本进行分词和分段落,那么段落得用\n来标识,不分段落那么出来的文章内容全是一段了
const title="nodejs使用nodejieba";
const text="高性能: Nodejieba的底层实现采用了C++,通过Node.js的插件机制与JavaScript集成,因此具有较高的性能。这使得Nodejieba在处理大规模文本数据时表现出色.\n支持多种分词模式: Nodejieba支持多种分词模式,包括精确模式、搜索引擎模式和新词识别模式。这使得它适用于不同的应用场景,可以根据需求选择合适的分词模式。\n用户自定义词典: 用户可以通过自定义词典来增加或修改分词器的词汇,以适应特定领域或特定项目的需求。这种灵活性使Nodejieba更适用于定制化的分词任务.\n";//插入数据库
insertDocument(title,text).catch(console.error);

//搜索代码
//search.js

const {MongoClient}=require('mongodb');
const {Jieba}=require("@node-rs/jieba");
const {dict}=require("@node-rs/jieba/dict");
const fs=require('fs');//搜索函数
async function searchDocuments(words){const client=new MongoClient('mongodb://ychj:123456@localhost:27017/?authSource=employees');try{await client.connect();const db=client.db('employees');	//连接数据库名const collection=db.collection('blog');	//连接集合名//搜索词const cursor=collection.find({$text:{"$search":words}});//转化为数组const docs=await cursor.toArray();//临时随机文件名const outputFile=getRandomFileName();//对大文件的数据流,为什么要用数据流,因为搜索出来的结果如果非常大,如上千条,我们不能存储在内存中,而是存在一个临时的随机文件中//避免占用或撑爆我们的内存,所以直接写入临时文件当中,然后显示 的时候再读取const writableStream=fs.createWriteStream(outputFile);//将读取到的搜索结果存储为json文件格式,用一个数组将其包含当中writableStream.write('[');let isFirst=true;docs.forEach((doc)=>{if(!isFirst){writableStream.write(',\n');}const formattitle=doc.title.replace(/\s+/g,'');//先按段落分成数据,然后再将文章内的空格去除掉,在段落末尾加上\nconst formatcontent=doc.content.split('\n').map(paragraph=>paragraph.replace(/\s+/g,'')).join('\n');const id=doc.id;//将各属性id,title,content组合成对象形式,然后再转化为json格式写入临时的json文件中const result={id:id,title:formattitle,content:formatcontent};writableStream.write(JSON.stringify(result));isFirst=false;});writableStream.write(']');writableStream.end();console.log('所有文档处理完结');}finally{await client.close();}
}//生成临时的随机json文件
function getRandomFileName(){return `output_${Math.random().toString(36).substring(2,9)}.json`;
}//对搜索的词进行分解析和分词,为什么要对搜索的词的要进行分解?因为用户搜索时都是连贯不会分词
//所以我们要对用户输入的词进行分词才能更好搜索出结果来,如果不分词可能搜索不出用户想要的结果
const text='mongodb和jieba';
const jieba=Jieba.withDict(dict);
const CutWords=jieba.cut(text);
const sreachCutWords=CutWords.join(' ');//分词后用空格进行间隔
//生成搜索结果
searchDocuments(sreachCutWords).catch(console.error);

//展示搜索结果页面
//showSearch.js

const http=require('http');
const fs=require('fs');
const readline=require('readline');const server=http.createServer((req,res)=>{if(req.url==="/show"){//这时是用一个简单的方法来获取了临时的随机文件名,生产过程中应该和搜索页面是一起的const outputFile="./output_03b5mml.json";const fileStream=fs.createReadStream(outputFile);	//读取临时文件const rl=readline.createInterface({input:fileStream,crlfDelay:Infinity	//不同操作系统使用不同的换行符,linux;\n,window:\r\n});res.writeHead(200,{"Content-type":'text/html; charset=utf-8'});res.write('<html><body><pre>');//按行读取所有的json文件内容let jsonData='';rl.on('line',line=>{jsonData+=line;});rl.on('close',()=>{try{const records=JSON.parse(jsonData);//解析json文件,并将其转化为对象数组//循环出数组中的每个json文件对象,并发送给http,//当然在实现中你可能是前后端分离的,这里应该是前端收到json文件并解析为对象数组,然后排序插入到前端文档中records.forEach(record=>{res.write(`<div>`);res.write(`ID:${record.id}<br>`);res.write(`标题:${record.title}<br>`);res.write(`内容:${record.content}<br>`);res.write(`</div><hr>`);})}catch(err){console.error('解析JSON数据时出错:',err);res.write('解析json数据时出错。');}res.write('</pre></body></html');res.end();})}
});
server.listen(3000,()=>{console.log('Server is running on http://localhost:3000');
})

在window打开cmd运行showSearch.js,然后在浏览器中输入http://localhost:3000/show 则会显示出搜索结果

对于在Mongodb中设置全文本索引,比如上面代码中的title,content
db.blog.createIndex({“title”:“text”,“content”:“text”});
即设置成功
注意:设置全文本索引的成本非常高,会比普通 的索引 更严重的性能问题,因为所有字符串都会被分解,分词,并保存到一个地方,
拥有全文本索引的集合写入性能都比其他的集合要差,在分片和迁移时速度都较慢,因为要重新的进行索引 ,而且吃内存

搜索出来的结果非常大时,可以采用以下优化策略来提高性能和效率:

  1. 使用流(Stream)处理数据
    对于大文本数据,使用流可以有效减少内存占用,并提高处理速度。流可以让你按块处理数据,而不是一次性将整个数据加载到内存中。在 Node.js 中,可以使用 fs.createReadStream() 和 fs.createWriteStream() 来创建读写流。
  2. 减少 write() 的次数
    频繁调用 write() 方法会显著降低写入速度,并增加内存占用。可以通过缓存一定量的数据,然后一次性写入,来减少 write() 的调用次数。例如,可以设置一个缓存大小,当达到该大小时再执行写入操作。
  3. 使用管道(Pipe)传输数据
    管道(pipe())方法可以将一个流的输出直接传递给另一个流,避免了手动处理事件监听和数据传输。这不仅可以简化代码,还能提高效率。例如,可以将查询结果直接通过管道传输到另一个流中进行处理或存储。
  4. 逐行处理数据
    如果数据是按行分隔的,可以使用 readline 模块逐行读取数据。这样可以避免一次性加载整个文件内容到内存中,从而减少内存占用。逐行处理数据还可以让你在处理每一行时进行必要的格式化或分析。
  5. 使用分块处理
    将大文件分成更小的块进行处理,可以有效避免内存不足的问题。通过定义一个块大小并使用循环读取文件,每次只处理一个块,然后将处理结果写入到目标文件或进行其他操作。
  6. 选择合适的数据处理方法
    在处理大规模数据时,选择合适的数据处理方法至关重要。例如,在统计换行符数量的实验中,使用 indexOf 方法比手动逐字节检查快了大约 10-20%。这表明在某些情况下,使用内置的优化方法可以显著提高性能。

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

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

相关文章

水下声呐探测仪,应急救援中的高效水下定位技术|深圳鼎跃

近年来&#xff0c;随着水域活动增多及自然灾害频发&#xff0c;水下救援需求日益增长。传统人工打捞方法在复杂水域中效率低、风险高&#xff0c;尤其在能见度差、水流湍急或深水区域中&#xff0c;救援难度倍增。 在此背景下&#xff0c;水下声呐探测仪凭借其声波定位与视频…

AI 网关代理 LLMs 最佳实践

作者&#xff1a;付宇轩&#xff08;计缘&#xff09; DeepSeek/QWen 普惠 AI 趋势 随着 DeepSeek-R1 的横空出世&#xff0c;又一次点燃了原本已经有点冷淡的大语言模型市场和话题&#xff0c;并且快速成为了现象级&#xff0c;小到中小学生&#xff0c;大到父母辈都知道了中…

策略模式实际用处,改吧改吧直接用,两种方式

controller RestController RequestMapping("admin/test") RequiredArgsConstructor(onConstructor __(Autowired)) public class TestController {Autowiredprivate VideoFactory VideoFactory;GetMapping("getList")public R getList(){// 第一种方式T…

chromium魔改——修改 navigator.webdriver 检测

chromium源码官网 https://source.chromium.org/chromium/chromium/src 说下修改的chromium源码思路&#xff1a; 首先在修改源码过检测之前&#xff0c;我们要知道它是怎么检测的&#xff0c;找到他通过哪个JS的API来做的检测&#xff0c;只有知道了如何检测&#xff0c;我们…

Muduo网络库实现 [九] - EventLoopThread模块

目录 设计思路 类的设计 模块的实现 私有接口 公有接口 设计思路 我们说过一个EventLoop要绑定一个线程&#xff0c;未来该EventLoop所管理的所有的连接的操作都需要在这个EventLoop绑定的线程中进行&#xff0c;所以我们该如何实现将EventLoop和线程绑定呢&#xff1f;…

UE5学习笔记 FPS游戏制作38 继承标准UI

文章目录 UE的UIUMG的继承继承标准控件创建标准控件继承标准控件的用处 UE的UI 和Untiy有onGui和UGui类似&#xff0c;UE有slateUI和UMG,slateUI是早期只能用C编写的UI&#xff0c;UMG是现在使用的&#xff0c;可以拖拽编辑的UI slateUI是UMG的父类 UMG的继承 我们编写一个控…

C#核心学习(七)面向对象--封装(6)C#中的拓展方法与运算符重载: 让代码更“聪明”的魔法

目录 一、什么是拓展方法&#xff1f; 二、拓展方法有啥用&#xff1f;怎么写拓展方法&#xff1f; 1. ​核心用途 2. ​编写步骤 实现步骤 关键点说明 关键规则 3. ​注意事项 三、什么是运算符重载&#xff1f; 四、运算符重载有啥用&#xff1f;怎么写&#xff1f;…

银行卡归属地查询API接口如何对接?

银行卡归属地查询 API 接口是一种能让开发者通过编程方式获取银行卡归属地等相关信息的工具。借助此接口&#xff0c;开发者可将银行卡归属地查询功能集成到自己的应用程序或系统里&#xff0c;像电商平台、第三方支付公司等都能运用它来提升业务的准确性与安全性。 银行卡归属…

ORM mybits mybits-plus

ORM ORM 即对象关系映射&#xff08;Object Relational Mapping&#xff09;&#xff0c;是一种程序设计技术&#xff0c;用于实现面向对象编程语言里不同类型系统的数据之间的转换。下面从基本概念、工作原理、优势与劣势、常见的 ORM 框架等方面详细介绍 ORM。 常见的orm框架…

网络编程—网络概念

目录 1 网络分类 1.1 局域网 1.2 广域网 2 常见网络概念 2.1 交换机 2.2 路由器 2.3 集线器 2.4 IP地址 2.5 端口号 2.6 协议 3 网络协议模型 3.1 OSI七层模型 3.2 TCP/IP五层模型 3.3 每层中常见的协议和作用 3.3.1 应用层 3.3.2 传输层 3.3.3 网络层 3.3.4…

4月3日工作日志

一个朴实无华的目录 今日学习内容&#xff1a;1.关系数据库 今日学习内容&#xff1a; 1.关系数据库

git commit Message 插件解释说明

- feat - 一项新功能 - fix - 一个错误修复 - docs - 仅文档更改 - style - 不影响代码含义的更改&#xff08;空白、格式化、缺少分号等&#xff09; - refactor - 既不修复错误也不添加功能的代码更改 - perf - 提高性能的代码更改 - build - 影响构建系统或外部依赖项…

ngx_open_file

定义在 src\os\unix\ngx_files.h #define ngx_open_file(name, mode, create, access) \open((const char *) name, mode|create, access) name&#xff1a;文件名&#xff08;通常是一个字符串&#xff09;。mode&#xff1a;文件打开模式&#x…

23种设计模式-行为型模式-责任链

文章目录 简介问题解决代码核心改进点&#xff1a; 总结 简介 责任链是一种行为设计模式&#xff0c;允许你把请求沿着处理者链进行发送。收到请求后&#xff0c;每个处理者均可对请求进行处理&#xff0c;或将其传递给链上的下个处理者。 问题 假如你正在开发一个订单系统。…

注意力机制在大语言模型中的原理与实现总结

注意力机制在大语言模型中的原理与实现总结 1. 章节介绍 在大语言模型的学习中&#xff0c;理解注意力机制至关重要。本章节旨在深入剖析注意力机制的原理及其在大语言模型中的应用&#xff0c;为构建和优化大语言模型提供理论与实践基础。通过回顾神经网络基础及传统架构的局…

kafka消息可靠性传输语义

Kafka提供了多种消息传递语义&#xff0c;以适应不同的业务需求和可靠性要求。以下是Kafka消息传输的可靠性语义及其实现机制&#xff1a; 1. At Most Once&#xff08;至多一次&#xff09; 语义&#xff1a;消息可能会丢失&#xff0c;但不会被重复传递。 实现机制&#xf…

NLP高频面试题(三十三)——Vision Transformer(ViT)模型架构介绍

Transformer架构在自然语言处理领域取得了显著成功&#xff0c;激发了研究人员将其应用于计算机视觉任务的兴趣。Vision Transformer&#xff08;ViT&#xff09;应运而生&#xff0c;成为图像分类等视觉任务中的新兴架构。本文将介绍ViT的基本架构、工作原理&#xff0c;并与传…

Oracle数据库数据编程SQL<3.6 PL/SQL 包(Package)>

包是Oracle数据库中一种重要的PL/SQL程序结构,它将逻辑相关的变量、常量、游标、异常、过程和函数组织在一起,提供了更好的封装性和模块化。在大型项目中,可能有很多模块,而每一个模块又有自己的存过、函数等。而这些存过、函数默认是放在一起的,如果所有的存过函数都是放…

机器学习 分类算法

【实验名称】 实验&#xff1a;分类算法 【实验目的】 1.了解分类算法理论基础 2.平台实现算法 3. 编程实现分类算法 【实验原理】 分类(Categorization or Classification)就是按照某种标准给对象贴标签(label),再根据标签来区分归类。 【实验环境】 OS&#xff1a;Ubuntu16.0…

HTML5 Canvas绘画板项目实战:打造一个功能丰富的在线画板

HTML5 Canvas绘画板项目实战&#xff1a;打造一个功能丰富的在线画板 这里写目录标题 HTML5 Canvas绘画板项目实战&#xff1a;打造一个功能丰富的在线画板项目介绍技术栈核心功能实现1. 画板初始化与工具管理2. 多样化绘画工具3. 事件处理机制 技术要点分析1. Canvas上下文优化…