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では本当に醜いハックに頼る必要があります:

(LENGTH(
    REPLACE(CONCAT(title,'|',link,'|',keywords),'{$term}','')
) - LENGTH(CONCAT(title,'|',link,'|',keywords)))/LENGTH('{$term}');

上記は、検索が行われるテキストの全長と、検索文字列を削除した同じテキストの全長との差を計算します。違いはもちろん、検索文字列が存在する回数に比例します。文字列の長さが8文字の場合、32の違いは、検索文字列が4回存在することを意味します。長さの差を項の長さで割ると、ヒット数が得られます。

問題は、いくつかの用語について、クエリを非常に複雑にする必要があり、実行するのに非常に費用がかかる可能性があることです。

$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 に答える