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

news2025/4/10 16:16:39

//首先我们要在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(' '));
        
        //将分词结果存储到Mongodb
        const 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,'');
            //先按段落分成数据,然后再将文章内的空格去除掉,在段落末尾加上\n
            const 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.coloradmin.cn/o/2328182.html

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

相关文章

【万字总结】前端全方位性能优化指南(完结篇)——自适应优化系统、遗传算法调参、Service Worker智能降级方案

前言 自适应进化宣言 当监控网络精准定位病灶&#xff0c;真正的挑战浮出水面&#xff1a;系统能否像生物般自主进化&#xff1f; 五维感知——通过设备传感器实时捕获环境指纹&#xff08;如地铁隧道弱光环境自动切换省电渲染&#xff09; 基因调参——150个性能参数在遗传算…

不绕弯地解决文件编码问题,锟斤拷烫烫烫

安装python对应库 pip install chardet 检测文件编码 import chardet# 检测文件编码 file_path rC:\Users\AA\Desktop\log.log # 这里放文件和文件绝对路径 with open(file_path, rb) as f:raw_data f.read(100000) # 读取前10000个字节result chardet.detect(raw_data)e…

高密度任务下的挑战与破局:数字样机助力火箭发射提效提质

2025年4月1日12时&#xff0c;在酒泉卫星发射中心&#xff0c;长征二号丁运载火箭顺利升空&#xff0c;成功将一颗卫星互联网技术试验卫星送入预定轨道&#xff0c;发射任务圆满完成。这是长征二号丁火箭的第97次发射&#xff0c;也是长征系列火箭的第567次发射。 执行本次任务…

QT Quick(C++)跨平台应用程序项目实战教程 6 — 弹出框

目录 1. Popup组件介绍 2. 使用 上一章内容完成了音乐播放器程序的基本界面框架设计。本小节完成一个简单的功能。单击该播放器顶部菜单栏的“关于”按钮&#xff0c;弹出该程序的相关版本信息。我们将使用Qt Quick的Popup组件来实现。 1. Popup组件介绍 Qt 中的 Popup 组件…

KisFlow-Golang流式实时计算案例(四)-KisFlow在消息队列MQ中的应用

Golang框架实战-KisFlow流式计算框架专栏 Golang框架实战-KisFlow流式计算框架(1)-概述 Golang框架实战-KisFlow流式计算框架(2)-项目构建/基础模块-(上) Golang框架实战-KisFlow流式计算框架(3)-项目构建/基础模块-(下) Golang框架实战-KisFlow流式计算框架(4)-数据流 Golang框…

leetcode:1582. 二进制矩阵中的特殊位置(python3解法)

难度&#xff1a;简单 给定一个 m x n 的二进制矩阵 mat&#xff0c;返回矩阵 mat 中特殊位置的数量。 如果位置 (i, j) 满足 mat[i][j] 1 并且行 i 与列 j 中的所有其他元素都是 0&#xff08;行和列的下标从 0 开始计数&#xff09;&#xff0c;那么它被称为 特殊 位置。 示…

Cline – OpenRouter 排名第一的CLI 和 编辑器 的 AI 助手

Cline – OpenRouter 排名第一的CLI 和 编辑器 的 AI 助手&#xff0c;Cline 官网&#xff1a;https://github.com/cline/cline Star 37.8k ps&#xff0c;OpenRouter的网址是&#xff1a;OpenRouter &#xff0c;这个排名第一&#xff0c;据我观察&#xff0c;是DeepSeek v3…

Mock.js虚拟接口

Vue3中使用Mock.js虚拟接口数据 一、创建项目 pnpm创建vite的项目,通过 PNPM来简化依赖管理。若还没有安装 PNPM&#xff0c;可以通过 npm来安装&#xff1a; 安装 PNPM npm install -g pnpm//使用国内镜像加速pnpm add -g pnpmlatestpnpm config set registry http://regis…

LoRa模块通信距离优化:如何实现低功耗覆盖30公里无线传输要求

在物联网&#xff08;IoT&#xff09;快速发展的今天&#xff0c;LoRa&#xff08;Long Range&#xff09;技术作为一种基于扩频调制的远距离无线通信技术&#xff0c;因其远距离通信、低功耗和强抗干扰能力等优势&#xff0c;在农业监测、城市智能管理、环境监测等多个领域得到…

OpenCV 从入门到精通(day_05)

1. 模板匹配 1.1 什么是模板匹配 模板匹配就是用模板图&#xff08;通常是一个小图&#xff09;在目标图像&#xff08;通常是一个比模板图大的图片&#xff09;中不断的滑动比较&#xff0c;通过某种比较方法来判断是否匹配成功。 1.2 匹配方法 rescv2.matchTemplate(image, …

OpenRouter开源的AI大模型路由工具,统一API调用

简介 ‌OpenRouter是一个开源的路由工具‌&#xff0c;它可以绕过限制调用GPT、Claude等国外模型。以下是对它的详细介绍&#xff1a; 一、主要功能 OpenRouter专注于将用户请求智能路由到不同的AI模型&#xff0c;并提供统一的访问接口。它就像一个“路由器”&#xff0c;能…

zabbix监控网站(nginx、redis、mysql)

目录 前提准备&#xff1a; zabbix-server主机配置&#xff1a; 1. 安装数据库 nginx主机配置&#xff1a; 1. 安装nginx redis主机配置&#xff1a; 1. 安装redis mysql主机配置&#xff1a; 1. 安装数据库 zabbix-server&#xff1a; 1. 安装zabbix 2. 编辑配置文…

蓝桥杯冲刺

例题1&#xff1a;握手问题 方法1&#xff1a;数学推理(简单粗暴&#xff09; 方法2&#xff1a;用代码实现方法1 #include<iostream> using namespace std; int main() {int result 0;for (int i 1; i < 49; i){for (int j i 1; j < 50; j){//第i个人与第j个…

Spring Security(maven项目) 3.1.0

前言&#xff1a; 通过实践而发现真理&#xff0c;又通过实践而证实真理和发展真理。从感性认识而能动地发展到理性认识&#xff0c;又从理性认识而能动地指导革命实践&#xff0c;改造主观世界和客观世界。实践、认识、再实践、再认识&#xff0c;这种形式&#xff0c;循环往…

C# 从代码创建选型卡+表格

private int tabNum 1; private int sensorNum 5; private void InitializeUI() {// 创建右侧容器面板Panel rightPanel new Panel{Dock DockStyle.Right,Width 300,BackColor SystemColors.ControlDark,Parent this};// 根据防区数量创建内容if (tabNum &g…

OpenCV 从入门到精通(day_02)

1. 边缘填充 为什么要填充边缘呢&#xff1f;我们以下图为例&#xff1a; 可以看到&#xff0c;左图在逆时针旋转45度之后原图的四个顶点在右图中已经看不到了&#xff0c;同时&#xff0c;右图的四个顶点区域其实是什么都没有的&#xff0c;因此我们需要对空出来的区域进行一个…

Ceph异地数据同步之-RBD异地同步复制(上)

#作者&#xff1a;闫乾苓 文章目录 前言基于快照的模式&#xff08;Snapshot-based Mode&#xff09;工作原理单向同步配置步骤单向同步复制测试双向同步配置步骤双向同步复制测试 前言 Ceph的RBD&#xff08;RADOS Block Device&#xff09;支持在两个Ceph集群之间进行异步镜…

【C++】STL库_stack_queue 的模拟实现

栈&#xff08;Stack&#xff09;、队列&#xff08;Queue&#xff09;是C STL中的经典容器适配器 容器适配器特性 不是独立容器&#xff0c;依赖底层容器&#xff08;deque/vector/list&#xff09;通过限制基础容器接口实现特定访问模式不支持迭代器操作&#xff08;无法遍历…

一周学会Pandas2 Python数据处理与分析-编写Pandas2 HelloWord项目

锋哥原创的Pandas2 Python数据处理与分析 视频教程&#xff1a; 2025版 Pandas2 Python数据处理与分析 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili 我们首先准备一个excel文件&#xff0c;用来演示pandas操作数据集(数据的集合)。excel文件属于数据集的一种&#xf…

【易订货-注册/登录安全分析报告】

前言 由于网站注册入口容易被机器执行自动化程序攻击&#xff0c;存在如下风险&#xff1a; 暴力破解密码&#xff0c;造成用户信息泄露&#xff0c;不符合国家等级保护的要求。短信盗刷带来的拒绝服务风险 &#xff0c;造成用户无法登陆、注册&#xff0c;大量收到垃圾短信的…