当前位置: 首页 > news >正文

LinuxC++项目开发日志——基于正倒排索引的boost搜索引擎(4——通过jsoncpp库建立搜索模块)

基于正倒排索引的boost搜索引擎

  • jsoncpp库
    • jsonpp 库介绍
    • 下载与安装
      • 1. 包管理器安装(推荐)
      • 2. 源码编译安装
    • 常用用法示例
      • 1. 解析 JSON 字符串
      • 2. 生成 JSON 数据
      • 3. 从文件读取和写入 JSON
      • 4. 编译方法
    • 注意事项
  • 搜索模块实现流程
    • 一、搜索模块的核心定位与工作流程
    • 二、核心数据结构设计
      • 1. 文档汇总结构:DocSumup_t
      • 2. 搜索核心类:Search
    • 三、关键功能实现详解
      • 1. 初始化:索引实例的单例加载
      • 2. 核心搜索接口:SearchBy ()
      • 3. 文档摘要提取:ExtractDesc ()
    • 四、Jsoncpp 的关键用法总结
    • 五、模块测试与效果验证
      • 1. 编译链接
      • 2. 测试结果示例
    • 六、模块代码
  • 其它更新模块
    • Index.hpp
    • Util.hpp
    • main.cc

jsoncpp库

jsonpp 库介绍

JSONCpp 是一个用于处理 JSON 数据的 C++ 开源库,它提供了解析、生成和操作 JSON 数据的功能。主要特点包括:

  • 支持 JSON 数据的解析(从字符串或文件)
  • 支持 JSON 数据的生成(到字符串或文件)
  • 提供简洁的 API 用于操作 JSON 数据(增删改查)
  • 跨平台,可在 Linux、Windows 等系统上使用

下载与安装

在 Linux 系统中,可以通过包管理器或源码编译两种方式安装:

1. 包管理器安装(推荐)

对于 Ubuntu/Debian 系统:

sudo apt-get update
sudo apt-get install libjsoncpp-dev

对于 Fedora/RHEL 系统:

sudo dnf install jsoncpp-devel

2. 源码编译安装

# 克隆源码仓库
git clone https://github.com/open-source-parsers/jsoncpp.git
cd jsoncpp# 创建构建目录
mkdir build && cd build# 编译安装
cmake ..
make
sudo make install

常用用法示例

下面是 JSONCpp 的一些常见用法示例:

1. 解析 JSON 字符串

#include <json/json.h>
#include <iostream>
#include <string>int main() {std::string jsonStr = "{\"name\":\"John\", \"age\":30, \"isStudent\":false}";// 创建解析器Json::Reader reader;Json::Value root;// 解析 JSON 字符串if (reader.parse(jsonStr, root)) {// 读取数据std::string name = root["name"].asString();int age = root["age"].asInt();bool isStudent = root["isStudent"].asBool();std::cout << "Name: " << name << std::endl;std::cout << "Age: " << age << std::endl;std::cout << "Is Student: " << std::boolalpha << isStudent << std::endl;} else {std::cerr << "Failed to parse JSON: " << reader.getFormattedErrorMessages() << std::endl;return 1;}return 0;
}

2. 生成 JSON 数据

#include <json/json.h>
#include <iostream>
#include <string>int main() {// 创建 JSON 对象Json::Value root;// 添加基本类型数据root["name"] = "Alice";root["age"] = 25;root["scores"] = Json::Value(Json::arrayValue);root["scores"].append(90);root["scores"].append(85);root["scores"].append(95);// 转换为字符串Json::StyledWriter writer;  // 带格式的输出std::string jsonStr = writer.write(root);std::cout << "Generated JSON:" << std::endl;std::cout << jsonStr << std::endl;return 0;
}

3. 从文件读取和写入 JSON

#include <json/json.h>
#include <fstream>
#include <iostream>// 从文件读取 JSON
bool readJsonFromFile(const std::string& filename, Json::Value& root) {std::ifstream ifs(filename);if (!ifs.is_open()) {std::cerr << "Failed to open file: " << filename << std::endl;return false;}Json::Reader reader;if (!reader.parse(ifs, root)) {std::cerr << "Failed to parse JSON file: " << reader.getFormattedErrorMessages() << std::endl;return false;}return true;
}// 写入 JSON 到文件
bool writeJsonToFile(const std::string& filename, const Json::Value& root) {std::ofstream ofs(filename);if (!ofs.is_open()) {std::cerr << "Failed to open file: " << filename << std::endl;return false;}Json::StyledWriter writer;ofs << writer.write(root);return true;
}int main() {Json::Value data;// 构建JSON数据data["version"] = "1.0";data["settings"]["theme"] = "dark";data["settings"]["fontSize"] = 14;// 写入文件if (writeJsonToFile("config.json", data)) {std::cout << "JSON data written to config.json" << std::endl;}// 从文件读取Json::Value readData;if (readJsonFromFile("config.json", readData)) {std::cout << "Read from file - Theme: " << readData["settings"]["theme"].asString() << std::endl;}return 0;
}

4. 编译方法

编译使用 JSONCpp 的程序时,需要链接 jsoncpp 库:

g++ your_program.cpp -o your_program -ljsoncpp

注意事项

JSONCpp 有两种 API 风格:旧版的 Json::Reader/Json::Writer 和新版的 Json::CharReader/Json::StreamWriter

搜索模块实现流程

搜索模块是连接用户查询与索引数据的核心桥梁。它需要接收用户输入的关键词,借助之前构建的正倒排索引完成数据检索、权重排序,最终以友好的格式返回结果。本段将详细介绍如何基于 Jsoncpp 库,实现一个高效、可扩展的搜索模块,完成搜索引擎查询流程的闭环。

一、搜索模块的核心定位与工作流程

在整个 Boost 搜索引擎架构中,搜索模块的核心作用是 “翻译” 用户需求:将用户输入的自然语言关键词,转化为对索引数据的查询指令,再将查询到的原始数据(文档 ID、权重、内容等)封装成标准化的 JSON 格式返回。其完整工作流程可分为以下 5 个步骤:

  • 关键词分词:调用分词工具(如 Jieba)将用户输入的长关键词拆分为多个独立的检索词(如 “boost 搜索引擎” 拆分为 “boost”“搜索引擎”);
  • 倒排索引查询:根据每个检索词,查询倒排索引表,获取包含该词的所有文档 ID 及对应权重;
  • 文档权重聚合:对同一文档的多个检索词权重进行累加,得到文档的总相关性权重;
  • 结果排序:按总权重降序排序(权重相同则按文档 ID 升序),确保相关性最高的文档优先返回;
  • 结果封装:通过 Jsoncpp 库将文档的 ID、权重、URL、标题、摘要等信息封装为 JSON 字符串,便于前端解析展示。

二、核心数据结构设计

为了高效管理检索过程中的中间数据和最终结果,设计了两个关键数据结构:DocSumup_t(文档汇总结构)和Search(搜索核心类),分别负责 “临时存储文档检索信息” 和 “实现完整搜索逻辑”。

1. 文档汇总结构:DocSumup_t

该结构体用于暂存单个文档的检索结果,包括文档 ID、总权重、包含的检索词列表,是连接倒排索引查询与结果排序的核心载体。

// 查找关键词文档归总
typedef struct DocSumup
{size_t doc_id_ = 0;          // 文档唯一ID(与正排索引关联)size_t weight_ = 0;          // 文档总权重(多个检索词权重累加)std::vector<std::string> words_; // 文档包含的所有检索词列表
} DocSumup_t;

2. 搜索核心类:Search

Search类是搜索模块的入口,通过组合正倒排索引实例(ns_index::Index),封装了从 “分词” 到 “JSON 返回” 的全流程逻辑。其核心成员与职责如下:

成员变量类型核心职责
rootJson::Value存储最终 JSON 结果的根节点
indexns_index::Index*正倒排索引实例(单例模式,避免重复构建)
成员函数功能核心职责
Search()构造函数初始化索引实例,加载正倒排索引数据
SearchBy()核心搜索接口实现分词、查询、排序、JSON 封装全流程
ExtractDesc()私有辅助函数从文档内容中提取包含检索词的摘要

三、关键功能实现详解

1. 初始化:索引实例的单例加载

在Search类的构造函数中,我们通过单例模式获取ns_index::Index实例,并调用BulidIndex()加载之前构建好的正倒排索引数据。

这样做的好处是避免重复加载索引(索引数据通常较大,重复加载会浪费内存和时间),确保整个程序生命周期内索引只加载一次。

Search() : index(ns_index::Index::GetInstance())
{index->BulidIndex(); // 加载正倒排索引(从磁盘或内存)
}

2. 核心搜索接口:SearchBy ()

SearchBy()是搜索模块的对外接口,接收用户关键词和输出 JSON 字符串的引用,返回 “是否查询成功” 的布尔值。其内部逻辑可拆解为 4 个关键步骤:

步骤 1:关键词分词
调用工具类ns_util::JiebaUtile的CutPhrase方法,将用户输入的关键词拆分为多个检索词。例如,用户输入 “linux jsoncpp 使用”,会被拆分为[“linux”, “jsoncpp”, “使用”]。

// 分词:将关键词拆分为独立检索词
std::vector<std::string> Segmentation;
ns_util::JiebaUtile::CutPhrase(keywords, Segmentation);

步骤 2:倒排索引查询与权重聚合

遍历每个检索词,通过index->QueryByWord(word)查询倒排索引表,获取包含该词的所有文档(InvertedElem)。随后用哈希表(doc_map)按文档 ID 聚合权重 —— 同一文档的多个检索词权重累加,同时记录文档包含的检索词。

这里使用哈希表的原因是快速按文档 ID 去重:哈希表的键为文档 ID,值为DocSumup_t,可确保同一文档只被处理一次,避免重复累加权重。

std::unordered_map<size_t, DocSumup_t> doc_map; // 按文档ID聚合结果
for(auto& word : Segmentation)
{// 查询当前检索词的倒排索引列表ns_index::InvertedList* list = index->QueryByWord(word);if(list == nullptr){Log(LogModule::DEBUG) << word << "-not find!"; // 检索词无匹配文档continue;}// 遍历倒排索引,聚合文档权重for(ns_index::InvertedElem e : *list){doc_map[e.doc_id_].doc_id_ = e.doc_id_;       // 记录文档IDdoc_map[e.doc_id_].weight_ += e.weight_;      // 累加权重doc_map[e.doc_id_].words_.push_back(e.word_); // 记录检索词}
}

步骤 3:结果排序

将哈希表中的DocSumup_t数据转移到向量(inverted_elem_all)中,再通过std::sort按 “权重降序、ID 升序” 排序。这样能确保相关性最高的文档排在最前面,同时避免权重相同时结果顺序混乱。

// 哈希表数据转移到向量(便于排序)
std::vector<DocSumup_t> inverted_elem_all;
for(auto& e : doc_map)
{inverted_elem_all.push_back(std::move(e.second)); // 移动语义,减少拷贝开销
}// 排序:权重降序,权重相同则ID升序
std::sort(inverted_elem_all.begin(), inverted_elem_all.end()
,[](DocSumup_t i1, DocSumup_t i2)-> bool{return i1.weight_ == i2.weight_ ? i1.doc_id_ < i2.doc_id_ : i1.weight_ > i2.weight_;
});

步骤 4:JSON 结果封装

1遍历排序后的文档列表,通过 Jsoncpp 库构建 JSON 结构:
对每个文档,创建Json::Value临时节点(tempvalue);

2调用index->QueryById(e.doc_id_)查询正排索引,获取文档的 URL、标题、内容;

3调用ExtractDesc()提取文档摘要(包含检索词的片段);

4将doc_id、weight、url、title、desc等字段存入临时节点,并添加到 JSON 根节点(root);

5最后通过Json::StyledWriter将根节点转换为格式化的 JSON 字符串,存入out参数返回。

// 写入json串
for(DocSumup_t& e : inverted_elem_all)
{Json::Value tempvalue;tempvalue["doc_id"] = e.doc_id_;       // 文档IDtempvalue["weight"] = e.weight_;       // 文档总权重// 查询正排索引,获取文档详细信息ns_index::Forword_t* ft = index->QueryById(e.doc_id_);if(!ft){Log(DEBUG) << e.doc_id_ << "-id not find!";continue;}tempvalue["url"] = ft->url_;           // 文档URLtempvalue["title"] = ft->title_;       // 文档标题tempvalue["desc"] = ExtractDesc(ft->content_, e.words_[0]); // 文档摘要root.append(tempvalue); // 临时节点添加到根节点
}// JSON格式化并输出
Json::StyledWriter writer;
out = writer.write(root);

3. 文档摘要提取:ExtractDesc ()

用户不需要查看完整文档内容,因此我们需要从文档中提取包含检索词的片段作为摘要,提升阅读效率。ExtractDesc()函数的实现逻辑如下:

忽略大小写查找检索词:使用std::search结合自定义谓词(tolower(a) == tolower(b)),在文档内容中找到检索词的位置; 控制摘要长度:以检索词为中心,向前截取 50 个字符、向后截取 100 个字符(避免摘要过长或过短);

边界处理:若检索词靠近文档开头 / 结尾,从文档起始 / 结尾开始截取,避免数组越界。

std::string ExtractDesc(std::string& content, std::string word)
{// 忽略大小写查找检索词auto it = std::search(content.begin(),content.end(),word.begin(),word.end(),[](char a, char b)->bool{return std::tolower(a) == std::tolower(b);});if(it == content.end()) // 未找到检索词(理论上不会发生){Log(LogModule::DEBUG) << "ExtractDesc fail!";return "NONE!";}const int pre_step = 50;  // 向前截取长度const int back_step = 100;// 向后截取长度int pos = it - content.begin(); // 检索词在文档中的位置// 边界处理:避免起始位置为负数int start = pos - pre_step > 0 ? pos - pre_step : 0;// 边界处理:避免结束位置超过文档长度int end = pos + back_step >= content.size() ? content.size() - 1 : pos + back_step;return content.substr(start, end - start) + std::string("..."); // 拼接省略号
}

四、Jsoncpp 的关键用法总结

在本模块中,Jsoncpp 主要用于 “构建 JSON 结构” 和 “格式化 JSON 字符串”,核心 API 用法如下:

功能需求Jsoncpp API示例代码
创建 JSON 节点Json::ValueJson::Value tempvalue;
为节点设置键值对重载[]运算符 + 直接赋值tempvalue[“url”] = ft->url_;
向数组节点添加元素Json::Value::append()root.append(tempvalue);
格式化 JSON 字符串(带缩进)Json::StyledWriter::write()out = writer.write(root);
格式化 JSON 字符串(紧凑)Json::FastWriter::write()Json::FastWriter writer; out = writer.write(root);

五、模块测试与效果验证

1. 编译链接

由于代码依赖 Jsoncpp 库,编译时需通过-ljsoncpp链接库文件,示例 Makefile 如下:

# 编译器设置
CXX := g++
CXXFLAGS := -std=c++17
LDFLAGS := 
LIBS := -lboost_filesystem -lboost_system -ljsoncpp# 目录设置
SRC_DIR := .
BUILD_DIR := build
TARGET := main# 自动查找源文件
SRCS := $(wildcard $(SRC_DIR)/*.cc)
OBJS := $(SRCS:$(SRC_DIR)/%.cc=$(BUILD_DIR)/%.o)
DEPS := $(OBJS:.o=.d)# 确保头文件依赖被包含
-include $(DEPS)# 默认目标
all: $(BUILD_DIR) $(TARGET)# 创建构建目录
$(BUILD_DIR):@mkdir -p $(BUILD_DIR)# 链接目标文件生成可执行文件
$(TARGET): $(OBJS)$(CXX) $(OBJS) -o $@ $(LDFLAGS) $(LIBS)@echo "✅ 构建完成: $(TARGET)"# 编译每个.cc文件为.o文件
$(BUILD_DIR)/%.o: $(SRC_DIR)/%.cc$(CXX) $(CXXFLAGS) -MMD -MP -c $< -o $@# 清理构建文件
clean:rm -rf $(BUILD_DIR) $(TARGET)@echo "🧹 清理完成"# 重新构建
rebuild: clean all# 显示项目信息
info:@echo "📁 源文件: $(SRCS)"@echo "📦 目标文件: $(OBJS)"@echo "🎯 最终目标: $(TARGET)"# 伪目标
.PHONY: all clean rebuild info# 防止与同名文件冲突
.PRECIOUS: $(OBJS)

2. 测试结果示例

若用户输入关键词后,搜索模块返回的 JSON 结果如下(格式化后):

[{"desc" : "deadlock. Programs often deal with such issues by splitting different               kinds of work between different executors.                        ...","doc_id" : 3474,"title" : "Synchronization","url" : "https://www.boost.org/doc/libs/1_89_0/doc/html/thread/synchronization.html","weight" : 1},{"desc" : "ost/parser/search.hpp&gt; Header &lt;boost/parser/split.hpp&gt; Header &lt;boost/parser/subrange.hpp&gt; Header &lt;boost/parser/transcode_view.hpp&gt...","doc_id" : 3479,"title" : "Chapter\u00a025.\u00a0Boost.Parser","url" : "https://www.boost.org/doc/libs/1_89_0/doc/html/parser.html","weight" : 1}
]

测试搜索模块:

在这里插入图片描述

六、模块代码

#pragma once
#include "Log.hpp"
#include "Util.hpp"
#include "common.h"
#include "Index.hpp"
#include <algorithm>
#include <cctype>
#include <cstddef>
#include <cstdio>
#include <ctime>
#include <jsoncpp/json/json.h>
#include <string>
#include <unistd.h>
#include <unordered_map>
#include <vector>namespace ns_search
{//查找关键词文档归总typedef struct DocSumup{size_t doc_id_ = 0;size_t weight_ = 0;std::vector<std::string> words_;}DocSumup_t;class Search : NonCopyable{public:Search() : index(ns_index::Index::GetInstance()){index->BulidIndex();}bool SearchBy(std::string keywords, std::string& out){//分词std::vector<std::string> Segmentation;ns_util::JiebaUtile::CutPhrase(keywords, Segmentation);//查找std::vector<DocSumup_t> inverted_elem_all;std::unordered_map<size_t, DocSumup_t> doc_map;//debug// for(auto& e : Segmentation)// {//     cout << e << " - " ;// }cout << endl;//debugfor(auto& word : Segmentation){static size_t t = 0;ns_index::InvertedList* list = index->QueryByWord(word);if(list == nullptr){Log(LogModule::DEBUG) << word << "-not find!";//sleep(1);continue;}//cout << t << "次循环," << word << "-找到" << endl;for(ns_index::InvertedElem e : *list){doc_map[e.doc_id_].doc_id_ = e.doc_id_;doc_map[e.doc_id_].weight_ += e.weight_;doc_map[e.doc_id_].words_.push_back(e.word_);}}//哈稀表的内容插入整体数组for(auto& e : doc_map){inverted_elem_all.push_back(std::move(e.second));}//判断是否找到if(inverted_elem_all.empty()){Log(LogModule::INFO) << keywords << " Not Find!";return false;}//权重排序std::sort(inverted_elem_all.begin(), inverted_elem_all.end(),[](DocSumup_t i1, DocSumup_t i2)-> bool{return i1.weight_ == i2.weight_ ? i1.doc_id_ < i2.doc_id_ : i1.weight_ > i2.weight_;});//写入json串for(DocSumup_t& e : inverted_elem_all){Json::Value tempvalue;tempvalue["doc_id"] = e.doc_id_;tempvalue["weight"] = e.weight_;ns_index::Forword_t* ft = index->QueryById(e.doc_id_);if(!ft){Log(DEBUG) << e.doc_id_ << "-id not find!";//sleep(1);continue;}tempvalue["url"] = ft->url_;tempvalue["title"] = ft->title_;tempvalue["desc"] = ExtractDesc(ft->content_, e.words_[0]);root.append(tempvalue);}//写入字符串带出参数Json::StyledWriter writer;out = writer.write(root);return true;}private:std::string ExtractDesc(std::string& content, std::string word){auto it = std::search(content.begin(),content.end(),word.begin(),word.end(),[](char a, char b)->bool{return std::tolower(a) == std::tolower(b);});if(it == content.end()){Log(LogModule::DEBUG) << "ExtractDesc fail!";return "NONE!";}const int pre_step = 50;const int back_step = 100;int pos = it - content.begin();int start = pos - pre_step > 0 ? pos - pre_step : 0;int end = pos + back_step >= content.size() ? content.size() - 1 : pos + back_step;return content.substr(start, end - start) + std::string("...");}public:~Search() = default;private:Json::Value root;ns_index::Index* index;};
};

其它更新模块

Index.hpp

#pragma once
#include "Log.hpp"
#include "Util.hpp"
#include "common.h"
#include <boost/algorithm/string/case_conv.hpp>
#include <cstddef>
#include <cstring>
#include <fstream>
#include <string>
#include <unistd.h>
#include <unordered_map>
#include <utility>
#include <vector>namespace  ns_index
{//正排索引typedef struct ForwordElem{std::string title_;std::string content_;std::string url_;size_t doc_id_ = 0;void Set(std::string title, std::string content, std::string url, size_t doc_id){title_ = title;content_ = content;url_ = url;doc_id_ = doc_id;}}Forword_t;typedef struct InvertedElem{size_t doc_id_ = 0;std::string word_;size_t weight_ = 0;void Set(size_t doc_id, std::string word, size_t weight){doc_id_ = doc_id;word_ = word;weight_ = weight;}}Inverted_t;typedef std::vector<Inverted_t> InvertedList;class Index : public NonCopyable{private:Index() = default;public:static Index* GetInstance(){static Index index;return &index;}public:Forword_t* QueryById(size_t id){if(id < 0 || id >= Forword_Index_.size()){Log(LogModule::DEBUG) << "id invalid!";return nullptr;}return &Forword_Index_[id];}InvertedList* QueryByWord(std::string word){auto it = Inverted_Index_.find(word);if(it == Inverted_Index_.end()){Log(LogModule::DEBUG) << word << " find fail!";return nullptr;}return &it->second;}size_t count = 0;bool BulidIndex(){if(isInit_)return false;size_t estimated_doc = 10000;size_t estimeted_words = 100000;Forword_Index_.reserve(estimated_doc);Inverted_Index_.reserve(estimeted_words);std::ifstream in(Tragetfile, std::ios::binary | std::ios::in);if(!in.is_open()){Log(LogModule::ERROR) << "Targetfile open fail!BulidIndex fail!";return false;}Log(LogModule::INFO) << "索引开始预加载...";std::string singlefile;while (std::getline(in, singlefile)){bool b = BuildForwordIndex(singlefile);if(!b){Log(LogModule::DEBUG) << "Build Forword Index Error!";continue;}b = BuildInvertedIndex(Forword_Index_.size() - 1);if(!b){Log(LogModule::DEBUG) << "Build Inverted Index Error!";continue;}count++;if(count % 1000 == 0){Log(LogModule::INFO) << "索引加载中,当前进度:" << count;//debug//break;}}in.close();isInit_ = true;Log(LogModule::INFO) << "索引加载完毕!--" << count;return true;}~Index() = default;private:typedef struct DocCount{size_t title_cnt_ = 0;size_t content_cnt_ = 0;}DocCount_t;bool BuildForwordIndex(std::string& singlefile){sepfile.clear();bool b = ns_util::JiebaUtile::CutDoc(singlefile, sepfile);if(!b)return false;// if(count == 764)// {//     Log(LogModule::DEBUG) << "Index Url: " << sepfile[2]; // }if(sepfile.size() != 3){Log(LogModule::DEBUG) << "Segmentation fail!";return false;}Forword_t ft;ft.Set(std::move(sepfile[0]), std::move(sepfile[1]), std::move(sepfile[2]), Forword_Index_.size());// if(count == 764)// {//     Log(LogModule::DEBUG) << "Index Url: " << ft.url_; // }Forword_Index_.push_back(std::move(ft));return true;}bool BuildInvertedIndex(size_t findex){Forword_t ft = Forword_Index_[findex];std::unordered_map<std::string, DocCount_t> map_s;titlesegmentation.clear();ns_util::JiebaUtile::CutPhrase(ft.title_, titlesegmentation);for(auto& s : titlesegmentation){boost::to_lower(s);map_s[s].title_cnt_++;}contentsegmentation.clear();ns_util::JiebaUtile::CutPhrase(ft.content_, contentsegmentation);for(auto& s : contentsegmentation){boost::to_lower(s);map_s[s].content_cnt_++;//cout << s << "--";// if(strcmp(s.c_str(), "people") == 0)// {//     Log(LogModule::DEBUG) << "意外的people!";//     cout << ft.content_ << "------------end!";//     sleep(100);// }}const int X = 10;const int Y = 1;for(auto& p : map_s){Inverted_t it;it.Set(findex, p.first, p.second.title_cnt_ * X + p.second.content_cnt_ * Y);InvertedList& list = Inverted_Index_[p.first];list.push_back(std::move(it));}return true;}private:std::vector<Forword_t> Forword_Index_;std::unordered_map<std::string, InvertedList> Inverted_Index_;bool isInit_ = false;//内存复用,优化时间std::vector<std::string> sepfile;std::vector<std::string> titlesegmentation;std::vector<std::string> contentsegmentation;};
};

Util.hpp

#pragma once
#include "Log.hpp"
#include "common.h"
#include "cppjieba/Jieba.hpp"
#include <boost/algorithm/string/classification.hpp>
#include <boost/algorithm/string/split.hpp>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>
namespace ns_util
{class FileUtil : public NonCopyable{public:static bool ReadFile(std::string path, std::string* out){std::fstream in(path, std::ios::binary | std::ios::in);if(!in.is_open()){Log(LogModule::DEBUG) << "file-" << path << "open fail!";return false;}std::stringstream ss;ss << in.rdbuf();*out = ss.str();in.close();return true;}};class JiebaUtile : public NonCopyable{public:static cppjieba::Jieba* GetInstace(){static cppjieba::Jieba jieba_(DICT_PATH, HMM_PATH, USER_DICT_PATH, IDF_PATH, STOP_WORD_PATH);return &jieba_;}static bool CutPhrase(std::string& src, std::vector<std::string>& out){try{GetInstace()->CutForSearch(src, out, true);}catch (const std::exception& e){Log(LogModule::ERROR) << "CutString Error!" << e.what();return false;}catch (...){Log(ERROR) << "Unknow Error!";return false;}return true;}static bool CutDoc(std::string& filestr, std::vector<std::string>& out){try{boost::split(out, filestr, boost::is_any_of("\3"));}catch (const std::exception& e){Log(LogModule::ERROR) << "std Error-" << e.what();return false;}            catch(...){Log(LogModule::ERROR) << "UnKnown Error!";return false;}return true;}private:JiebaUtile() = default;~JiebaUtile() = default;};};

main.cc

#include "Log.hpp"
#include "common.h"
#include "Parser.h"
#include "Search.hpp"
#include <cstdio>
#include <cstring>
#include <string>
const bool INIT = false;int main()
{if(INIT){Parser parser(Orignaldir, Tragetfile);parser.Init();}ns_search::Search search;while(true){char buffer[1024];std::string out;cout << "Please Enter KeyWords: ";std::fgets(buffer, sizeof(buffer)-1, stdin);if(strlen(buffer) > 0 && buffer[strlen(buffer) - 1] == '\n'){buffer[strlen(buffer) - 1] = '\0';}if(strcmp(buffer, "QUIT!") == 0){Log(LogModule::DEBUG) << "quit main!";break;}search.SearchBy(std::string(buffer), out);cout << out << endl;}return 0;
}
http://www.dtcms.com/a/403149.html

相关文章:

  • LVS三种模式及原理
  • 有招聘网站策划的吗济南网站开发招聘
  • 【多线程】互斥锁(Mutex)是什么?
  • 18.1 Python+AI一键生成PPT!ChatPPT核心技术深度解析
  • 影响网站权重的因素有哪些wordpress 仪表盘 渗透
  • Nginx反向代理与缓存功能-第一章
  • 精读《C++20设计模式》——创造型设计模式:构建器系列
  • SpringCloud高可用集群搭建及负载均衡配置实战
  • AI产品独立开发完全指南:技术栈选择、案例分析与商业化路径
  • Jenkins+Tomcat持续集成教程
  • 哪里有免费建设网站承德在线
  • 【金融保研复习】知识点与可能的题目
  • 基于ZYNQ的ARM+FPGA+yolo AI火灾实时监测与识别系统
  • 【Python语法基础学习笔记】常用函数
  • Uniapp运行时错误修复报告
  • PHP 8.0+ 高级特性深度探索:架构设计与性能优化
  • 网站管理建设总结大数据营销的概念
  • 顺德品牌网站建设辽宁建设工程信息网上
  • Oracle Clint11g安装
  • Gerkin+unittest(python)实现自动化
  • MySQL基础语法大全
  • 从企业实战中学习Appium自动化(二)
  • Unity 使用ADB工具打包Apk 安装到Android手机或平板
  • 一、移动零,复写零,快乐数
  • React资源合集
  • sem是什么职业邢台做网站建设优化制作公司
  • 福建省建设执业资格注册中心网站企业建设网站注意点
  • 配置Modbus TCP转RS485模块读取温度数据
  • OSPF LSA/ 路由种类
  • 算法面试(5)------NMS(非极大值抑制)原理 Soft-NMS、DIoU-NMS 是什么?