BYD汽车知识图谱查询系统开发记录

Heart Lv462

数据结构实验课的大作业要求做一个知识图谱相关的项目,想了想决定拿 BYD 汽车的数据来做,毕竟最近比亚迪挺火的,数据也比较好找。

整个系统分成两个版本,一个是 CLI 终端版,另一个是带 Web 界面的版本。CLI 版本主要是为了快速验证数据结构的设计,Web 版本则是为了展示效果好看一点。

数据结构设计

知识图谱的核心就是实体和关系。在这个项目里,实体主要有三类:车型(Model)、系列(Series)、技术(Tech)。车型属于某个系列,同时搭载某些技术,这就构成了实体之间的关系。

实体结构体定义

首先是系列的结构体,比较简单,就是 ID、名称和描述:

1
2
3
4
5
struct Series {
int id;
string name;
string description;
};

技术实体也差不多:

1
2
3
4
5
struct Tech {
int id;
string name;
string description;
};

车型是最复杂的,除了基本信息外,还要存储它和系列、技术之间的关系。这里用 series_id 关联所属系列,用 vector<int> 存储搭载的技术 ID 列表:

1
2
3
4
5
6
7
8
9
10
11
12
struct Model {
int id;
string name;
int series_id;
double price;
int range;
string power_type;
string body_type;
int seats;
int year;
vector<int> tech_ids;
};

存储结构选择

数据存储用了 unordered_map,也就是哈希表。选择哈希表的原因是查询操作比较频繁,需要根据 ID 快速找到对应的实体,哈希表的平均查找时间复杂度是 O(1),比线性查找快很多。

1
2
3
unordered_map<int, Series> series_map;
unordered_map<int, Tech> tech_map;
unordered_map<int, Model> model_map;

如果用 vector 存储然后遍历查找,时间复杂度是 O(n),数据量大的时候会明显变慢。虽然这个项目数据量不大,但既然是数据结构课的作业,还是得用点合适的数据结构。

关系查询算法

查询某个系列下的所有车型,需要遍历 model_map,筛选出 series_id 匹配的车型:

1
2
3
4
5
6
7
8
9
vector<Model> getModelsBySeries(int series_id) {
vector<Model> result;
for (auto& pair : model_map) {
if (pair.second.series_id == series_id) {
result.push_back(pair.second);
}
}
return result;
}

这个操作的时间复杂度是 O(n),如果要优化可以额外维护一个 series_idmodel_id 列表的映射,但考虑到数据量不大就没做。

查询搭载某项技术的所有车型也是类似的思路,遍历所有车型,检查 tech_ids 里有没有目标技术:

1
2
3
4
5
6
7
8
9
10
vector<Model> getModelsByTech(int tech_id) {
vector<Model> result;
for (auto& pair : model_map) {
auto& ids = pair.second.tech_ids;
if (find(ids.begin(), ids.end(), tech_id) != ids.end()) {
result.push_back(pair.second);
}
}
return result;
}

搜索功能

搜索功能用的是简单的字符串匹配,遍历所有车型,检查名称里是否包含关键词:

1
2
3
4
5
6
7
8
9
vector<Model> searchModels(const string& keyword) {
vector<Model> result;
for (auto& pair : model_map) {
if (pair.second.name.find(keyword) != string::npos) {
result.push_back(pair.second);
}
}
return result;
}

string::find 返回子串的位置,如果找不到返回 string::npos。这个搜索是大小写敏感的,如果要做大小写不敏感的搜索,需要先把字符串都转成小写再比较。

数据文件解析

数据存储用的是纯文本文件,格式是用方括号标记数据类型,每行一条记录,字段用逗号分隔:

1
2
3
4
5
6
7
8
9
10
[SERIES]
1,王朝系列,传承中华文化的经典系列
2,海洋系列,面向年轻群体的时尚系列

[TECH]
101,DM-i超级混动,高效节能的插电混动技术
102,刀片电池,安全性能优异的磷酸铁锂电池

[MODEL]
1001,秦PLUS,1,9.98,120,PHEV,轿车,5,2023,101,102

解析的时候先读取整个文件,然后按行处理。遇到方括号开头的行就切换当前的数据类型,其他行按逗号分割后填充到对应的结构体里:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
void loadData(const string& filename) {
ifstream file(filename);
string line;
string current_type;

while (getline(file, line)) {
if (line.empty()) continue;

if (line[0] == '[') {
current_type = line.substr(1, line.find(']') - 1);
continue;
}

vector<string> fields = split(line, ',');

if (current_type == "SERIES") {
Series s;
s.id = stoi(fields[0]);
s.name = fields[1];
s.description = fields[2];
series_map[s.id] = s;
}
// ... 其他类型类似
}
}

split 函数是自己写的,用 stringstream 实现字符串按分隔符切割:

1
2
3
4
5
6
7
8
9
vector<string> split(const string& s, char delimiter) {
vector<string> tokens;
string token;
istringstream tokenStream(s);
while (getline(tokenStream, token, delimiter)) {
tokens.push_back(token);
}
return tokens;
}

CLI 版本

CLI 版本的交互就是经典的菜单式,输入数字选择功能。实现了查看车型列表、按系列筛选、搜索、查看详情这些基本功能。

比较有意思的是 ASCII 关系图谱的展示,用字符画的方式把系列、车型、技术之间的关系画出来。虽然看起来比较简陋,但是能直观地看到数据之间的关联。

Web 版本

Web 版本用了 cpp-httplib 这个 header-only 的 HTTP 库,写起来还挺方便的,不用折腾编译依赖。服务端提供 RESTful API,前端用原生 JS 调用。

前端页面没用什么框架,就是纯 HTML + CSS + JS。样式参考了一些汽车官网的设计,深色主题看起来比较有科技感。

API 设计比较简单,GET 请求获取数据,POST 请求添加数据。返回 JSON 格式,前端解析后渲染到页面上。

遇到的问题

中文编码是个坑。Windows 下控制台默认是 GBK,源文件是 UTF-8,数据文件也是 UTF-8,三者混在一起就容易乱码。最后的解决方案是统一用 UTF-8,然后在 Windows 下设置控制台代码页。

还有就是 httplib 在 Windows 下编译需要链接 ws2_32 库,一开始忘了加链接选项,报了一堆 undefined reference。

总结

这个项目算是把数据结构课学的东西用上了,哈希表用来做快速查找,向量用来存储动态数组,字符串处理用来解析数据文件。虽然是个课程作业,但是做完还是挺有成就感的。

代码放在 GitHub 上了:BYD-Automotive-Knowledge-Graph-Query-System

  • Title: BYD汽车知识图谱查询系统开发记录
  • Author: Heart
  • Created at : 2025-12-20 14:00:00
  • Updated at : 2026-01-02 20:29:49
  • Link: https://yhalo-wyh.github.io/2025/12/20/BYD汽车知识图谱查询系统开发记录/
  • License: This work is licensed under CC BY-NC-SA 4.0.
Comments