仓库链接:https://gitee.com/setekh/search-engine

介绍 📖

Linux平台下使用C++实现的简单搜索引擎 Spark Search

connect

Spark Search 在 2核 4G 华为云 Flexus L实例 上进行部署和测试,能够在资源受限的环境中高效运行。

功能特性 ✨

Spark Search 是一个高效、智能、易用的搜索引擎,能够满足各种搜索需求,同时具备高性能和高可靠性,具有以下主要特性:

关键词推荐

  • 智能推荐:用户输入关键词后,系统会根据离线词典生成相应的推荐词。目前使用最小编辑距离算法实现关键词推荐,帮助用户快速找到相关内容。
  • 大模型推荐:引入大模型(KeyBert)进行关键词推荐,通过上下文理解生成更为精准和相关的推荐词,进一步提升用户体验。

高效网页查询

  • 真实搜索引擎功能:支持类似于真实搜索引擎的网页查询功能。用户可以进行页面跳转,根据查询关键词生成动态摘要,高亮关键词,并可直接点击链接跳转到文章来源站点。

数据库与缓存

  • MySQL 持久化存储:服务端数据库模块使用 MySQL 持久化存储倒排索引库和网页内容库,确保数据的长期保存和管理。
  • Redis 缓存:使用 Redis 对查询时所需的倒排索引库和文章内容信息进行定期缓存,并设计了一定时间范围内随机设置有效期以避免缓存雪崩,提高查询效率。

查询优化

  • 数据库连接池和线程局部存储:引入了数据库连接池和线程局部存储(Thread-Local Storage,TLS),在提高查询效率的同时简化了代码,实现高并发环境下的高效查询。

网络通信

  • Reactor 模型:服务端 Tcp 网络通信模块使用 Reactor 模型,实现高效的 I/O 多路复用,支持高并发连接。
  • 自定义通信协议:通信协议使用 json 封装的自定义格式,确保数据传输的高效和可靠。

用户体验

  • 动态摘要生成:根据用户查询的关键词,动态生成摘要内容,并高亮显示关键词,提升用户的搜索体验。
  • 页面跳转:搜索结果提供直接的链接跳转功能,用户可以方便地访问原始文章内容。

架构概览 🏛️

高层次介绍项目的架构,包括主要组件及其交互方式。

项目文件夹结构 📂

本节将简单介绍 Spark Search 项目的文件夹结构及各文件夹的用途,帮助您快速了解本项目组织方式。

.
├── bin                      # 可执行文件目录
├── build                    # CMake
├── code                     # 源代码目录
│   ├── include              # 公共头文件目录
│   │   ├── helper           # 辅助类
│   │   ├── splittool        # 分词工具
│   │   └── utils            # 通用工具
│   ├── lib                  # 静态和动态库目录
│   ├── project              # 项目模块代码
│   │   ├── offline_database # 离线数据库相关代码
│   │   ├── offline_dict     # 离线词典相关代码
│   │   ├── offline_page     # 离线页面处理相关代码
│   │   ├── online_search    # 在线搜索相关代码
│   │   └── reactor          # Reactor 模型相关代码
│   └── third-party          # 第三方库
├── config                   # 配置文件目录
├── docs                     # 项目文档目录
├── logs                     # 日志文件目录
├── resources                # 资源文件目录
│   ├── corpus               # 语料库
│   │   ├── cn_art           # 中文文章语料库
│   │   └── en_art           # 英文文章语料库
│   ├── data                 # 数据文件
│   ├── dict                 # 词典文件
│   │   ├── pos_dict         # 词性词典
│   │   └── stop_words       # 停用词列表
│   └── pages                # 页面语料文件
│       ├── large            # 大型网页语料
│       └── small            # 小型网页语料
├── test                     # 测试代码和测试用例目录
└── tools                    # 工具目录
    ├── FlameGraph           # FlameGraph 工具
    └── perf                 # perf 工具

Qt 客户端 💻

Qt 实现的简单通信客户端:

  • 原版设计来自组员 海纳百川 👉 https://gitee.com/hatomugi/search-engine
  • 高分辨率电脑优化 👉 https://gitee.com/setekh/search-engine-qtcp-client
connect
recommender
keybert推荐2
webquery

使用说明 📜

项目涉及到的第三方库 📦

  1. 部分第三方库已经存放在 code/third-party 文件夹内
    • tinyxml2 xml文件解析库,已编译成静态库
    • spdlog 日志库,已编译成静态库
    • cppjieba 中文分词库
    • nlohmann/json json解析库
    • simhash google用于进行文本去重的算法,使用jenkins 作为hash函数
    • fmt 文本格式化输出库头文件,spdlog 库中也有内置的该库
  2. Redis 数据库相关
    • redis
    sudo apt-get install redis-server
    • hiredis
    sudo apt-get install libhiredis-dev
    • redis++
    git clone https://github.com/sewenew/redis-plus-plus.git cd redis-plus-plus mkdir build cd build cmake .. -DCMAKE_BUILD_TYPE=Release make sudo make install
  3. MySQL 数据库相关
    • mysql
    sudo apt-get install mysql-server
    • MySQL Connector/C++
    sudo apt-get install libmysqlcppconn-dev
  4. 编译速度优化
    • ccache
      bash sudo apt-get install ccache

安装步骤 🚀

  1. 克隆项目 git clone https://gitee.com/setekh/search-engine cd search-engine
  2. 安装依赖
    确保你已经安装了所有必要的第三方库(参考上面的安装指令)。
  3. 编译项目 mkdir build cd build cmake .. make
  4. 根据环境修改配置文件
    所有项目配置文件中的相对路径都是相对于bin文件夹下
    • logger_config.json 日志系统设置
    • split_tool_config.json 分词工具设置
    • dict_config.json 离线词典生成设置
    • pagelib_config.json 网页库生成设置
    • online_config.json 在线搜索引擎设置
  5. 运行项目
    bash cd ../bin ./SparkSearch

火焰图生成教程 🔥

为了分析程序性能并发现瓶颈,可以生成火焰图。以下是生成火焰图的步骤:

  1. 安装 perf 和 FlameGraph 工具 🛠️
   sudo apt-get install linux-tools-common linux-tools-generic
   git clone https://github.com/brendangregg/FlameGraph.git
  1. 自动化脚本使用教程 🚀
    为了简化火焰图的生成过程,已经提供了一个自动化生成火焰图的脚本,位置在 tools/perf/generate_flamegraph.sh ,使用前请修改目录:
   # 定义目录
   BIN_DIR="/home/setekh/code/search-engine/bin"
   PERF_DIR="/home/setekh/code/search-engine/tools/perf"
   FLAMEGRAPH_DIR="/home/setekh/code/search-engine/tools/FlameGraph"
  1. 火焰图将生成在 flamegraph.svg 文件中,可以使用浏览器打开查看。 flamegraph

Doxygen文档生成 📊

  1. 下载自定义主题 doxygen-awesome-css 🥰 https://github.com/jothepro/doxygen-awesome-css
  2. 生成引用关系图、函数调用关系图等需要额外安装 graphviz sudo apt-get install doxygen graphviz
  3. 执行 doxygen 指令生成文档,文章存储在 docs 文件夹内 cd ./tools doxygen Doxyfile

数据库设计 🗄️

本项目使用 Redis 和 MySQL 作为数据存储,以支持高效的搜索和内容管理。以下是数据库的设计和相关说明。

Redis 缓存设计

Redis 用于缓存倒排索引和文章内容信息,以加快搜索速度。

  1. 倒排索引缓存
  • invert_index:<关键词>
  • :格式为 文章id,tfidf,文章id,tfidf,...,例如:52,0.030392 缓存时间设置为10~15min 示例:
   invert_index:中国 -> 52,0.030392
  1. 文章内容缓存
  • 文章内容
    • doc:<docid>:content
    • 文章内容
  • 文章链接
    • doc:<docid>:url
    • 文章链接
  • 文章标题
    • doc:<docid>:title
    • 文章标题
    缓存时间设置为5~10min 示例:
   doc:38:content -> 文章内容
   doc:38:url -> 文章链接
   doc:38:title -> 文章标题

MySQL 数据库设计

MySQL 用于持久化存储倒排索引和文章内容信息,以确保数据的完整性和可管理性。

  1. 倒排索引表
  • 表名:inverted_index
  • 字段:
    • word:关键词
    • docids:包含关键词的文章 ID 列表
    • tfidfs:对应文章的 tf-idf 值列表
  1. 文章内容表
  • 表名:pages
  • 字段:
    • docid:文章 ID
    • title:文章标题
    • url:文章链接
    • content:文章内容

通信协议 📡

本项目的通信协议使用 JSON 封装自定义格式,主要用于关键词推荐和网页查询功能。以下是具体的通信协议说明。

网页查询格式

请求格式

  • query_id:1 表示关键词推荐, 2 表示网页查询
  • pageNum:当前请求查询的页数,点击上一页或下一页的时候会发送新请求
  • itemsPerPage:客户端每页所请求的网页数量

请求示例:

{
    "query_id": 2,
    "msg": "人性化CNNIC",
    "pageNum": 10,
    "itemsPerPage": 5
}

响应格式

  • msgID:与 query_id 对应,1 表示关键词推荐, 2 表示网页查询
  • maxPage:用于设置客户端查询页码上限
  • queryWords:返回查询消息的分词结果,用于客户端高亮关键词
  • files:存储文章标题、动态摘要和 URL 信息

响应示例:

{
    "msgID" : 2,
    "maxPage": 3,
    "queryWords" : [
        "人性化",
        "CNNIC"
    ],
    "files": [
        {
            "title": "404, not found",
            "summary": "未找到你搜索的内容",
            "url": ""
        }
    ]
}

关键词推荐格式

请求格式

请求示例:

{
    "query_id": 1,
    "msg": "keyWord"
}

响应格式

响应示例:

{
    "msgID" : 1,
    "msg": [
        "keyWord1",
        "keyWord2",
        "keyWord3"
    ]
}

项目目前存在的问题 🛠

  1. 编译速度:引入 spdlog 库后,代码编译速度大幅降低。这可能是由于该库的复杂性和模板使用所导致的。
  2. 关键词推荐:在线关键词推荐使用简单的最小编辑距离算法,推荐的关键词之间并无语义关联,导致推荐的相关性较低。
  3. 代码冗余:在线网页查询模块涉及数据库操作部分的代码逻辑存在冗余,增加了维护和扩展的难度。
  4. 日志打印:部分关键模块缺少日志打印功能。由于 spdlog 的编译速度慢,当前尽可能避开了该库的使用。
  5. 词典不足:用于生成词典的语料可能过少,尤其是英文相关的检索和推荐性能不佳,影响了系统的整体效果。
  6. 性能测试:缺少压测过程来明确服务端性能瓶颈,无法准确评估系统在高并发情况下的表现。
  7. 字符串操作:涉及大量字符串操作,从火焰图中可以看到大量 CPU 消耗在创建和复制 string 上,可能需要优化不必要的复制操作。

未来计划与改进 🌟

  1. 编译优化🚀
  • 优化 spdlog 的使用,研究使用更高效的编译选项或替代方案,减少编译时间。
  • 引入预编译头文件以加速编译过程。
  1. 改进关键词推荐🔍
  • 引入更先进的算法,如基于 Word2Vec 或 BERT 的语义关联推荐,提升推荐的相关性和智能性。
  • 增加语料库的数量和多样性,特别是英文语料,提升推荐效果。
  1. 重构代码结构🛠
  • 优化在线网页查询模块的数据库操作代码逻辑,消除冗余,提升代码可维护性和性能。
  • 增加代码模块化程度,简化代码结构。
  1. 加强日志管理📑
  • 重新评估日志框架,选择性能和编译速度均衡的日志库。
  • 增加关键模块的日志打印,提升系统的可监控性和可调试性。
  1. 增强词典构建📚
  • 扩展用于生成词典的语料库,增加多语言支持,提升搜索引擎在多语言环境下的表现。
  • 使用爬虫技术定期更新语料库,保持词典的时效性和准确性。
  1. 性能测试与优化⚙️
  • 开展系统的压测,找出性能瓶颈,并针对性地进行优化。
  • 采用性能分析工具,进一步优化 CPU 和内存的使用。
  1. 优化字符串操作🔧
  • 减少不必要的字符串复制和创建,使用更高效的数据结构和算法。
  • 研究使用 std::string_view 等现代 C++ 技术,减少内存分配和拷贝。

感谢 🙏

特别感谢以下组员在项目开发过程中所做的贡献:

感谢大家的共同努力,使 Spark Search 成为一个高效、智能、易用的搜索引擎!

许可证 📄

该项目使用 MIT 许可证。详情请参阅 LICENSE

联系方式 ✉️

如果你有任何问题或建议,请通过以下方式联系我们:

  • 邮箱:756435658@qq.com
  • 个站:https://blog.setekh.fun/
  • Gitee:https://gitee.com/setekh

感谢你对 Spark Search 的支持! 🎉

(❁´◡`❁)编程笨蛋萌新也想折腾博客!
最后更新于 2025-06-20