首先,我首先要说的是,我已就此主题进行了大量研究,并已将大量时间投入到可行的解决方案中。话虽如此,我遇到了一些我似乎无法克服的问题,因此正在朝着正确的方向寻求一些指导。
小背景故事:我为网站编写/维护php / mysql。我们基本上是一个发布文章,评论,视频等的游戏网站。
问题:我有一个存储所有网站内容的mysql数据库。这个数据库中基本上有4个字段,我从中拉出单词,然后我想匹配数据库中的所有其他文章,并确定前3个相关文章,以便它们可以显示。最有效和最好的方法来实现这一目标?
以下是我到目前为止所做的事情:
在我设计的CMS中,我基本上设计了一个“词袋”类型系统。该程序将浏览所有文章(大约有4,000篇)并将每个单词分解为一个单独的数据库。在这个单独的数据库中,存储了文章中的单词,字数,tf * idf(后面有更多内容)和文章ID(x-ref到内容数据库)。因此,一个单词可以在此数据库中不止一次,但对于一篇文章不能超过一次。处理完这个(大约需要4分钟)后,这个新数据库中有近700,000个条目。
然后,我有另一个程序通过这个新的单词数据库并解析它的tf*idf。通过整个700,000个条目的列表,这个程序大约需要15分钟。
现在,这是我坚持的部分。我正在研究这个的前端部分,以实际使系统可用。前端部分对正在查看的当前文章(article_id)进行数据库查询,并拉出按其tf * idf排序的前20个单词。然后,我拉出这些单词并将其与其他包含单词的文章进行查询,并使用一个数组来存储被比较的文章以及它们匹配的次数。然后,对数组进行排序,并使用最多的比较来拉出前3篇文章。
这最后一部分工作正常,花花公子,我实际上使用tf * idf和bag-of-words之间的混合进行了很好的比较。问题是,对于前端部分发生,它需要30-45秒。显然这是不可行的......它必须在几分之一秒内完成,这就是我遇到的问题。
我知道这真的很长,我为此道歉。我基本上正在寻找一些帮助清理这个想法,有些地方我错了,不同的方法。我对所有建议持开放态度,并乐意提供更多信息,如果它能使这些更清楚。谢谢你的时间!
每个请求,表架构和前端代码......
--
-- Table structure for table `bagofwords`
--
CREATE TABLE IF NOT EXISTS `bagofwords` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`article_id` int(11) NOT NULL,
`article_total_word_count` int(11) NOT NULL,
`word` text NOT NULL,
`count` int(11) NOT NULL,
`timestamp` int(11) NOT NULL,
`tfidf` float NOT NULL,
KEY `id` (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=660930 ;
public function related_articles($article_id, $count = 3) {
$query = "SELECT * FROM `bagofwords` WHERE `article_id` = '$article_id' ORDER BY `tfidf` DESC LIMIT 20";
$result = $this->db->query($query);
$num_rows = $this->db->num_rows($result);
$articles_list = array();
for ($i=0; $i<$num_rows; $i++) {
$word = $this->db->fetch_field($result, 'word', $i);
$query_word = "SELECT `article_id` FROM `bagofwords` WHERE `word` = '$word' AND `article_id` != '$article_id' ORDER BY `tfidf` DESC";
$result_word = $this->db->query($query_word);
$result_num_rows = $this->db->num_rows($result_word);
for ($x=0; $x<$result_num_rows; $x++) {
$article_id_word = $this->db->fetch_field($result_word, 'article_id', $x);
if (isset($articles_list["$article_id_word"])) $articles_list["$article_id_word"]++;
else $articles_list["$article_id_word"] = 1;
}
}
array_flip($articles_list);
asort($articles_list);
return $articles_list;
}
好吧,这几乎是前端代码部分,因为现在它返回整个数组和前端的var_dump只是为了看看我得到了什么样的数据。但是,你必须有一个更好的方法来使用嵌套的东西或临时表在单个mySQL语句中编写所有这些。我无法理解!
答案 0 :(得分:1)
显而易见的是将此查询作为自联接运行。我需要测试生产量以优化它,但是类似于:
select word, count(*) as article_count
from bagofwords article,
bagofwords relations
where article.article_id = '$article_id'
and article.word = relation.word
group by word
order by article.tfidf, article_count
limit 20
你还想要一个关于colum“word”的索引:
create index word on bagofwords(word)