在我的下面的脚本中,如果行类似于用户输入的行,则用户输入表单并从MYSQL表返回行。我正在建立一个搜索引擎,一切都是基于排名。但我希望能够调整下面的代码,看看“iPad”这个词有多少次出现了行字段,即“标题”,“描述”,“关键字”和“链接”。如果是这样,我希望该行返回高于具有更高ID的行,但仅在所有字段组合中提及一次iPad。 我的代码如下: 条款一起查询: $ query =“SELECT * FROM scan WHERE”;
$terms = array_map('mysql_real_escape_string', $terms);
$i = 0;
foreach ($terms as $each) {
if ($i++ !== 0){
$query .= " AND ";
}
$query .= "title LIKE '%{$each}%' OR link LIKE '%{$each}%' OR keywords LIKE '%{$each}%' OR description LIKE '%{$each}%' ";
}
$query = mysql_query($query) or die('MySQL Query Error: ' . mysql_error( $connect ));
echo '<p class="time">Qlick showed your results in ' . number_format($secs,2) . ' seconds.</p>';
$numrows = mysql_num_rows($query);
if ($numrows > 0) {
while ($row = mysql_fetch_assoc($query)) {
$id = $row['id'];
$title = $row['title'];
$description = $row['description'];
$keywords = $row['keywords'];
$link = $row['link'];
$rank = $row['rank'];
Seperate Terms Query
$query = " SELECT * FROM scan WHERE ";
$terms = array_map('mysql_real_escape_string', $terms);
$i = 0;
foreach ($terms as $each) {
if ($i++ !== 0){
$query .= " OR ";
}
$query .= "title LIKE '%{$each}%' OR link LIKE '%{$each}%' OR keywords LIKE '%{$each}%' OR description LIKE '%{$each}%' ";
}
// Don't append the ORDER BY until after the loop
$query = mysql_query($query) or die('MySQL Query Error: ' . mysql_error( $connect ));
$numrows = mysql_num_rows($query);
if ($numrows > 0) {
while ($row = mysql_fetch_assoc($query)) {
$id = $row['id'];
$title = $row['title'];
$description = $row['description'];
$keywords = $row['keywords'];
$link = $row['link'];
$rank = $row['rank'];
答案 0 :(得分:0)
我尝试使用辅助字段来执行此操作,在该字段上运行FULLTEXT
查询,您将在其中保存所有文本数据:
http://dev.mysql.com/doc/refman/5.0/en/fulltext-search.html
另一种方法是在MySQL中运行过滤并在PHP中进行排名。您可以通过在连接字段上运行单个LIKE来挤压一些性能。
顺便说一下,上面的代码在LIKE中没有括号,因此结果不正确:你不能问WHERE field1 LIKE 'x' OR field2 LIKE 'x' AND field1 LIKE 'y' OR...
,你必须说明WHERE (field1 LIKE 'x' OR field2 LIKE 'x') AND (field1 LIKE 'y' OR...)
。
// Here we search for ALL terms (all must be present at least once)
// use ' OR ' to ask that at least one term must be present once.
$where = array();
foreach($terms as $term)
$where[] = "( CONCAT(title,'|',link,'|',keywords) LIKE '%{$term}%')";
$query .= ' WHERE ' . '('.implode(' AND ', $where).')';
现在在OR案例中,您可以对匹配的术语数量进行简单排名(使用AND,数字始终是术语总数):
$select_fields[] '(' . implode ('+', $where) . ') AS ranking';
否则在SQL中你需要求助于真的丑陋的黑客攻击:
(LENGTH(
REPLACE(CONCAT(title,'|',link,'|',keywords),'{$term}','')
) - LENGTH(CONCAT(title,'|',link,'|',keywords)))/LENGTH('{$term}');
以上计算要进行搜索的文本总长度与删除搜索字符串的相同文本的总长度之间的差异。差异当然与搜索字符串的数量成正比:如果字符串长度为8个字符,则32的差异意味着它存在四次。将长度差除以术语的长度,我们得到命中数。
问题在于,对于几个术语,您必须极大地复杂化查询,并且运行起来可能非常昂贵:
$select_fields = array('*');
$where = array();
$rank = array();
foreach($terms as $term)
{
// assume $term is NOT QUOTED
$search = mysql_real_escape_string($term);
$concat = "CONCAT(title,'|',link,'|',keywords)";
$where[] = "(${concat} LIKE '%{$search}%')";
$rank[] = "(LENGTH(REPLACE(${concat},'{$search}',''))
- LENGTH(${concat}))/LENGTH('{$search}')";
}
$select_fields[] = "(".implode(",", $rank).") AS ranking";
$query .= "SELECT " . implode(',', $select_fields)
. ' FROM scan WHERE (' . implode(' AND ', $where) . ')';