【发布时间】:2018-05-07 21:31:52
【问题描述】:
我陷入了优化问题。我有一个庞大的数据库(大约 1600 万个条目),它代表不同用户对不同项目给出的评级。从这个数据库中,我必须评估不同用户之间的相关性度量(即我必须实现一个相似度矩阵)。幸好这个相关矩阵是对称的,所以我只需要计算一半。
例如,让我关注矩阵的第一列:总共有 135k 用户,所以我保持一个用户固定,我找到了这个用户和所有其他用户之间的所有共同评分项目(使用 for 循环) .如果我将单个用户与 20k 其他用户而不是 135k 进行比较,也会出现时间问题。
我的方法如下:首先我查询数据库以获取例如前 20k 用户的所有数据(这也需要时间 indexes 实现,但它并没有打扰我,因为我只做一次),然后我使用 userID 作为键将所有内容存储在无序映射中;然后对于这个 unordered_map,我使用另一个 unordered_map 作为存储桶,它存储用户给出的所有评分,这次使用 itemID 作为键。
然后,为了找到都已评分的项目集,我在评分较少的用户上循环,搜索另一个用户是否也对相同的东西评分。我所知道的最快的数据结构是哈希图,但是对于单个完整的列,我的算法需要 30 秒(仅针对 20k 条目),这在 WEEKS 中转换为完整的矩阵。
代码如下:
void similarity_matrix(sqlite3 *db, sqlite3 *db_avg, sqlite3 *similarity, long int tot_users, long int interval) {
long int n = 1;
double sim;
string temp_s;
vector<string> insert_query;
sqlite3_stmt *stmt;
std::cout << "Starting creating similarity matrix..." << std::endl;
string query_string = "SELECT * from usersratings where usersratings.user <= 20000;";
unordered_map<int, unordered_map<int, int>> users_map = db_query(query_string.c_str(), db);
std::cout << "Query time: " << duration_ << " s." << std::endl;
unordered_map<int, int> u1_map = users_map[1];
string select_avg = "SELECT * from averages;";
unordered_map<int, double> avg_map = avg_value(select_avg.c_str(), db_avg);
for (int i = 2; i <= tot_users; i++)
{
unordered_map<int, int> user;
int compare_id;
if (users_map[i].size() <= u1_map.size()) {
user = users_map[i];
compare_id = 1;
}
else {
user = u1_map;
compare_id = i;
}
int matches = 0;
double newnum = 0;
double newden1 = 0;
double newden2 = 0;
unordered_map<int, int> item_map = users_map[compare_id];
for (unordered_map<int, int>::iterator it = user.begin(); it != user.end(); ++it)
{
if (item_map.size() != 0) {
int rating = item_map[it->first];
if (rating != 0) {
double diff1 = (it->second - avg_map[1]);
double diff2 = (rating - avg_map[i]);
newnum += diff1 * diff2;
newden1 += pow(diff1, 2);
newden2 += pow(diff2, 2);
}
}
}
sim = newnum / (sqrt(newden1) * sqrt(newden2));
}
std::cout << "Execution time for first column: " << duration << " s." << std::endl;
std::cout << "First column finished..." << std::endl;
}
【问题讨论】:
-
你不能让数据库来做这件事吗?要求数据库做一些工作可能会更快(sql可以做非常聪明的事情,特别是如果你使用存储过程和类似的语言如plpgsql等),而不是返回所有行并最终完成工作..只是一个想法..
-
这在Code Review上会更好
标签: c++ performance sqlite time