用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.pswp.cn/news/899999.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/899999.shtml
英文地址,請注明出處:http://en.pswp.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上下文優化…