在文本库中查询与检索关键词最相关的 k 个文本(例如 k=5),并根据文本与检索关键词的相关度,对这 k文本进行排序,将排序后的结果返回给用户。 利用 TF-IDF 模型,为文本库中的文本创建索引(如倒排索引),用户输入的关键词可以是一个或多个;对于返回的结果文本,需同时显示各检索关键词在结果文本中的出现频度信息,系统内支持返回结果文本的查看,支持文本库的动态装载和处理;支持停用词的管理和维护,停用词是指在没有检索价值的单词,整个过程用C++语言实现完整代码
时间: 2023-12-14 13:40:22 浏览: 93
以下是基于TF-IDF模型实现文本检索的C++代码示例:
```c++
#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
#include <unordered_map>
#include <algorithm>
#include <cmath>
#include <string>
#include <cstring>
using namespace std;
// 定义一个结构体,用于存储文档信息
struct Document {
int id; // 文档ID
string content; // 文档内容
unordered_map<string, int> tf; // 存储该文档中各词的词频
unordered_map<string, double> tf_idf; // 存储该文档中各词的TF-IDF值
};
// 定义一个结构体,用于存储查询结果
struct SearchResult {
int id; // 文档ID
double score; // 相似度得分
unordered_map<string, int> tf; // 存储该文档中各查询关键词的词频
};
// 定义一个类,用于实现文本检索
class TextSearch {
public:
TextSearch() {}
// 从文件中读取文档并处理
void loadDocuments(string filename) {
ifstream infile(filename); // 打开文件
string line, word;
int id = 0;
while (getline(infile, line)) { // 逐行读取
if (line.empty()) continue; // 遇到空行跳过
Document doc;
doc.id = id++; // 记录文档ID
doc.content = line; // 记录文档内容
stringstream ss(line);
while (ss >> word) { // 逐词处理
if (stopwords_.count(word)) continue; // 如果该词为停用词,则跳过
++doc.tf[word]; // 统计该词出现次数
++df_[word]; // 统计包含该词的文档数
}
docs_.emplace_back(doc); // 将处理好的文档存入向量中
}
infile.close(); // 关闭文件
computeIDF(); // 计算IDF值
computeTFIDF(); // 计算TF-IDF值
}
// 设置停用词
void setStopWords(vector<string> stopwords) {
for (auto& word : stopwords) {
stopwords_.emplace(word);
}
}
// 检索关键词
vector<SearchResult> search(vector<string> query, int k) {
// 统计查询关键词的词频
unordered_map<string, int> query_tf;
for (auto& word : query) {
if (stopwords_.count(word)) continue; // 如果该词为停用词,则跳过
++query_tf[word];
}
// 计算查询关键词的TF-IDF值
unordered_map<string, double> query_tf_idf;
double query_norm = 0.0; // 保存查询关键词的模长
for (auto& q : query_tf) {
if (!df_.count(q.first)) continue; // 如果文本库中没有包含该词,则跳过
double tf_idf = (1.0 + log(q.second)) * idf_[q.first]; // 计算该词的TF-IDF值
query_tf_idf[q.first] = tf_idf; // 存储该词的TF-IDF值
query_norm += tf_idf * tf_idf; // 累加平方后的TF-IDF值
}
query_norm = sqrt(query_norm); // 计算查询关键词的模长
// 计算相似度得分
vector<SearchResult> results;
for (auto& doc : docs_) {
SearchResult res;
res.id = doc.id;
double dot_product = 0.0; // 记录文档与查询关键词的点积
double doc_norm = 0.0; // 记录文档的模长
for (auto& q : query_tf_idf) {
if (!doc.tf.count(q.first)) continue; // 如果该文档中没有包含该词,则跳过
dot_product += q.second * doc.tf_idf[q.first]; // 计算文档与查询关键词的点积
doc_norm += doc.tf_idf[q.first] * doc.tf_idf[q.first]; // 累加平方后的TF-IDF值
res.tf[q.first] = doc.tf[q.first]; // 记录文档中各查询关键词的词频
}
doc_norm = sqrt(doc_norm); // 计算文档的模长
res.score = dot_product / (query_norm * doc_norm); // 计算相似度得分
if (res.score > 0.0) results.emplace_back(res); // 如果得分大于0,则将查询结果存入向量中
}
// 对查询结果进行排序
sort(results.begin(), results.end(), [](const SearchResult& a, const SearchResult& b) {
return a.score > b.score;
});
// 返回前k个查询结果
if (results.size() > k) results.resize(k);
return results;
}
private:
vector<Document> docs_; // 存储文档信息的向量
unordered_map<string, int> df_; // 存储各词在文本库中出现的文档数
unordered_map<string, double> idf_; // 存储各词的IDF值
unordered_set<string> stopwords_; // 存储停用词
// 计算IDF值
void computeIDF() {
for (auto& p : df_) {
idf_[p.first] = log(docs_.size() * 1.0 / p.second);
}
}
// 计算TF-IDF值
void computeTFIDF() {
for (auto& doc : docs_) {
double doc_norm = 0.0; // 保存文档的模长
for (auto& p : doc.tf) {
if (!idf_.count(p.first)) continue; // 如果文本库中没有包含该词,则跳过
double tf_idf = (1.0 + log(p.second)) * idf_[p.first]; // 计算该词的TF-IDF值
doc.tf_idf[p.first] = tf_idf; // 存储该词的TF-IDF值
doc_norm += tf_idf * tf_idf; // 累加平方后的TF-IDF值
}
doc_norm = sqrt(doc_norm); // 计算文档的模长
for (auto& p : doc.tf_idf) {
p.second /= doc_norm; // 对每个TF-IDF值进行归一化
}
}
}
};
int main() {
TextSearch ts;
ts.setStopWords({"the", "and", "a", "an", "of", "to", "in", "that", "it", "with", "for", "as", "on"});
ts.loadDocuments("documents.txt");
vector<string> query = {"apple", "pie"};
int k = 5;
vector<SearchResult> results = ts.search(query, k);
cout << "Results for query: ";
for (auto& q : query) cout << q << " ";
cout << endl;
for (auto& res : results) {
cout << "Document " << res.id << ", score: " << res.score << ", relevant terms: ";
for (auto& tf : res.tf) {
cout << tf.first << ": " << tf.second << " ";
}
cout << endl;
}
return 0;
}
```
在上述代码中,我们首先定义了一个`Document`结构体,用于存储文档信息;另外还定义了一个`SearchResult`结构体,用于存储查询结果。然后我们定义了一个`TextSearch`类,用于实现文本检索功能。在该类中,我们定义了一个`docs_`向量,用于存储文档信息;`df_`和`idf_`分别用于存储各词在文本库中出现的文档数和各词的IDF值;`stopwords_`用于存储停用词。在该类中,我们实现了以下几个方法:
- `loadDocuments`:从文件中读取文档并处理。在该方法中,我们首先打开文件,然后逐行读取文件内容。对于每一行,我们首先创建一个`Document`对象,然后逐词处理该行的内容。如果该词为停用词,则跳过;否则,我们统计该词在该文档中出现的次数,并且统计包含该词的文档数。处理完毕后,我们将该文档存入`docs_`向量中。在处理完所有文档后,我们调用`computeIDF`方法计算各词的IDF值,然后调用`computeTFIDF`方法计算各文档中各词的TF-IDF值。
- `setStopWords`:设置停用词。在该方法中,我们将传入的停用词存入`stopwords_`中。
- `search`:检索关键词。在该方法中,我们首先统计查询关键词的词频,并计算查询关键词的TF-IDF值。然后,我们遍历所有文档,对于每个文档,我们计算文档与查询关键词的相似度得分,并将得分存入查询结果中。最后,我们对查询结果按得分进行排序,并返回前k个查询结果。
- `computeIDF`:计算IDF值。在该方法中,我们遍历所有词,计算各词在文本库中出现的文档数,并计算各词的IDF值,将结果存入`df_`和`idf_`中。
- `computeTFIDF`:计算TF-IDF值。在该方法中,我们遍历所有文档,对于每个文档,我们遍历该文档中出现的所有词,计算各词的TF-IDF值,并将结果存入`tf_idf`中。然后,我们计算该文档的模长,并对每个TF-IDF值进行归一化。
以上是基于TF-IDF模型实现文本检索的C++代码示例,希望能够对你有所帮助!
阅读全文