【发布时间】:2014-06-26 16:00:47
【问题描述】:
我有两张桌子。在表 1 中,我有大约 400K 行,其中每行包含一段文本,最多可包含 50 个句子。在表 2 中,我有一个包含 80k 单词的词典,其中包含我对每个段落的每个单词进行编码所需的分数。
我的 php 脚本的重点是将每段文本分解为所需的多个单词,然后在词典中查找每个单词的分数,最后计算所有单词的总分每一行。
到目前为止,我的策略是编写一个执行以下操作的脚本:
- 连接数据库,表 1
- While Loop,一排接一排
- 对于当前行,展开段落。
- 对于每个单词,如果该单词存在,请查阅表 2 并返回分数。
- 以当前行的总分结束。
- 用当前段落的总分更新表 1。
- 回到第 2 点。
我的代码有效,但效率不高。问题是脚本太慢了,让它运行一个小时只计算前 500 行。这是一个问题,因为我有 400K 行。我将需要此脚本用于其他项目。
你会建议我做些什么来减少这个过程的紧张?
<?php
//Include functions
include "functions.php";
ini_set('max_execution_time', 9000000);
echo 'Time Limit = ' . ini_get('max_execution_time');
$db='senate';
//Function to search into the array lexicon
function searchForId($id, $array) {
foreach ($array as $key2 => $val) {
if ($val['word'] === $id) {
return $key2;
}
}
return null;
}
// tags to remove
$remove = array('{J}','{/J}','{N}','{/N}','{V}','{/V}','{RB}','{/RB}');
$x=1;
//Conecting the database
if (!$conn) {
die('Not connected : ' . mysql_error());}
// Choose the current db
mysql_select_db($db);
//Slurps the lexicon into an array
$sql = "SELECT word, score FROM concreteness";
$resultconcreteness = mysql_query($sql) or die(mysql_error());
$array = array();
while($row = mysql_fetch_assoc($resultconcreteness)) {
$array[] = $row;
}
//loop
while($x<=500000) {
$data = mysql_query("SELECT `key`, `tagged` FROM speechesLCMcoded WHERE `key`='$x'") or die(mysql_error());
// puts the "data" info into the $info array
$info = mysql_fetch_array( $data);
$tagged=$info['tagged'];
unset($weight);
unset($count);
$weight=0;
$count=0;
// Print out the contents of the entry
Print "<b>Key:</b> ".$info['key'] . " <br>";
// Explodes the sentence
$speech = explode(" ", $tagged);
// Loop every word
foreach($speech as $word) {
//Check if string contains our tag
if(!preg_match('/({V}|{J}|{N}|{RB})/', $word, $matches)) {} else{
//Removes our tags
$word = str_replace($remove, "", $word);
$id = searchForId($word, $array);
// print "ID: " . $id . "<br>";
// print "Word: " . $array[$id]['word'] . "<br>";
// print "Score: " . $array[$id]['score'] . "<br>";
$weight=$weight+$array[$id]['score'];
$count=$count +1;
// print "Weight: " . $weight . "<br>";
// print "Count: " . $count . "<br>";
}
}
$sql = "UPDATE speechesLCMcoded SET weight='$weight', count='$count' WHERE `key`='$x';" ;
$retval = mysql_query( $sql, $conn );
if(! $retval )
{die('Could not update data: ' . mysql_error());}
echo "Updated data successfully\n";
ob_flush();
flush();
//Increase the loop by one
$x=$x+1;
}?>
这是索引:
CREATE TABLE `speechesLCMcoded` (
`key` int(11) NOT NULL AUTO_INCREMENT,
`speaker_state` varchar(100) NOT NULL,
`speaker_first` varchar(100) NOT NULL,
`congress` varchar(100) NOT NULL,
`title` varchar(100) NOT NULL,
`origin_url` varchar(100) NOT NULL,
`number` varchar(100) NOT NULL,
`order` varchar(100) NOT NULL,
`volume` varchar(100) NOT NULL,
`chamber` varchar(100) NOT NULL,
`session` varchar(100) NOT NULL,
`id` varchar(100) NOT NULL,
`raw` mediumtext NOT NULL,
`capitolwords_url` varchar(100) NOT NULL,
`speaker_party` varchar(100) NOT NULL,
`date` varchar(100) NOT NULL,
`bills` varchar(100) NOT NULL,
`bioguide_id` varchar(100) NOT NULL,
`pages` varchar(100) NOT NULL,
`speaker_last` varchar(100) NOT NULL,
`speaker_raw` varchar(100) NOT NULL,
`tagged` mediumtext NOT NULL,
`adjectives` varchar(10) NOT NULL,
`verbs` varchar(10) NOT NULL,
`nouns` varchar(10) NOT NULL,
`weight` varchar(50) NOT NULL,
`count` varchar(50) NOT NULL,
PRIMARY KEY (`key`)
) ENGINE=InnoDB AUTO_INCREMENT=408344 DEFAULT CHARSET=latin1
【问题讨论】:
-
老实说,我认为 MySQL 是错误的技术。如果您想在数据分析期间进行高分,不妨看看 Lucene 或 Elasticsearch 之类的东西。
-
感谢您的建议,但我现在无法承受更改技术的费用。我真的在寻找优化当前系统的方法。
-
慢是一回事,但一个小时处理 500 行似乎真的非常慢。即每段大约 12 秒。我建议将 php 代码移动到存储过程中。在数据库中完成单个段落的工作应该会显示出相当大的性能改进。
-
也许可以尝试记录您的查询,然后使用 MySQL EXPLAIN 命令分析它们。这将告诉您索引的任何问题以及如何优化它们。 dev.mysql.com/doc/refman/5.0/en/explain.html
-
我添加了我的代码,如果它有助于理解什么是这么慢的话。
标签: php mysql sql lookup words