0

在我下面的脚本中,用户输入一个表单,如果行与用户输入的行相似,则从 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'];
4

1 回答 1

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 中,您将需要求助于一个非常丑陋的 hack:

(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)   . ')';
于 2012-09-26T22:32:32.250 回答