像谷歌一样进行数据库搜索

7

我目前在我的PHP+MYSQL网站上有一个搜索选项。

目前的MYSQL查询类似于“SELECT pageurl WHERE name LIKE'%$query%'”。

我在这里发帖的原因是因为我注意到,如果我的产品之一的名称是“蓝色自行车”,而有人寻找“自行车蓝色”,则不会返回结果。

我正在寻找解决方案,因为我知道如果我在Google上输入相同的单词,就会出现结果。

我想创建一个PHP函数来混合查询中的所有单词,如果查询包含4个或更少的单词,则生成大约24个查询。

是否有更简单的解决方案?

谢谢您的时间。


4
按单词拆分怎么样?WHERE name LIKE '%$word1%' AND name LIKE '%$word2%'等等? - h2ooooooo
我认为你的建议可能已经解决了问题。 - NVG
6个回答

6
为了不让这个问题没有答案,请看以下解决方法:
<?php
    $search = 'this is my search';

    $searchSplit = explode(' ', $search);

    $searchQueryItems = array();
    foreach ($searchSplit as $searchTerm) {
        /*
         * NOTE: Check out the DB connections escaping part 
         * below for the one you should use.
         */
        $searchQueryItems[] = "name LIKE '%" . mysqli_real_escape_string($searchTerm) . "%'";
    }

    $query = 'SELECT pageurl FROM names' . (!empty($searchQueryItems) ? ' WHERE ' . implode(' AND ', $searchQueryItems) : '');
?>

数据库连接转义

mysqli_:

继续使用mysqli_real_escape_string或者使用$mysqli->real_escape_string($searchTerm)

mysql_:

如果您使用mysql_,应该使用mysql_real_escape_string($searchTerm)(并考虑更改,因为它已被弃用)。

PDO:

如果您使用PDO,则应该使用trim($pdo->quote($searchTerm), "'")


4

使用全文搜索代替LIKE语句

全文搜索基于索引文本,比使用LIKE语句更快、更好。

有关全文搜索的更多信息,请参见本文


4
您要寻找的是全文搜索功能。 尝试使用Sphinx,它非常快速并且与MySQL集成良好。 Sphinx网站

这个使用的是 PHP 吗?我已经下载了它,但看起来它是基于 C++ 的。如果它确实使用 PHP,那就点个赞吧。 - John Max
1
@JohnMax Sphinx是独立的服务器软件。它实现了MySQL协议以进行集成,因此您可以使用任何支持连接到MySQL服务器的客户端。 - Kacer

2

我写了一个函数,考虑到双引号作为整个块进行搜索的元素,接近谷歌的操作。它不考虑-或*指令。

表:要考虑的MySQL表

列:要解析的列数组

searchParams:要处理的搜索。例如:红色野马“佛罗里达90210”

function naturalQueryConstructor($table, $cols, $searchParams) {

    // Basic processing and controls
    $searchParams = strip_tags($searchParams);
    if( (!$table) or (!is_array($cols)) or (!$searchParams) ) {
        return NULL;
    }
    // Start query
    $query = "SELECT * FROM $table WHERE ";

   // Explode search criteria taking into account the double quotes
    $searchParams = str_getcsv($searchParams, ' ');

   // Query writing
    foreach($searchParams as $param) {
      if(strpos($param, ' ') or (strlen($param)<4)) {
        // Elements with space were between double quotes and must be processed with LIKE.
        // Also for the elements with less than 4 characters. (red and "Florida 90210")
        $query .= "(";
        // Add each column
        foreach($cols as $col) {
            if($col) {
                $query .= $col." LIKE '%".$param."%' OR ";
            }
        }
        // Remove last ' OR ' sequence
        $query = substr($query, 0, strlen($query)-4);
        // Following criteria will added with an AND
        $query .= ") AND ";
      } else {
        // Other criteria processed with MATCH AGAINST (mustang)
        $query .= "(MATCH (";
        foreach($cols as $col) {
            if($col) {
                $query .= $col.",";
            }
        }
        // Remove the last ,
        $query = substr($query, 0, strlen($query)-1);
        // Following criteria will added with an AND
        $query .= ") AGAINST ('".$param."' IN NATURAL LANGUAGE MODE)) AND ";
      }
  }
  // Remove last ' AND ' sequence
  $query = substr($query, 0, strlen($query)-5);
  return $query;
}

感谢stackoverflow社区,我在那里找到了这个函数的部分内容!


每个搜索的列都必须在“全文”中,并且“全文”中的每个列都必须被解析! - Prof Abronsius
另外一点:MATCH AGAINST 要求完整的单词匹配,这意味着 'musta' 不能帮助找到 'mustang'。因此,我删除了查询构建的第二部分... - Prof Abronsius

0
要实现类似谷歌的搜索,您需要许多数据库和索引节点,疯狂的算法...现在你可以使用SELECT LIKE...哈哈:D
MySQL在搜索方面很慢,您需要正确设置全文索引和索引集(MyISAM或Aria Engine)。几乎不可能正确且快速地搜索不同实体的组合。
我建议设置一个基于Apache Lucene的Elasticsearch服务器。这个搜索非常快,易于维护。而且您不必担心SQL注入,仍然可以快速使用mysql服务器。
Elasticsearch(或其他基于Lucene的搜索引擎,如SolR)可以轻松安装在任何服务器上,因为它们是用Java编写的。
良好的文档:

http://www.elasticsearch.org/guide/en/elasticsearch/client/php-api/current/


2
嘲笑别人的请求或知识缺乏,并不能让你变得更聪明或更优秀。 - NVG
@NVG,他们从未这样做过... - user13944038

-1

我会先用explode函数进行分割:

$queryArray = explode(" ", $query);

然后生成类似以下的SQL查询:

for ($i=0; $i< count($queryArray); $i++) {
    $filter += " LIKE '%" + $queryArray[$i] + "%' AND" ;
}
$filter = rtrim ($filter, " AND");

$sql = "SELECT pageurl FROM ... WHERE name " + $filter

(注意:尚未测试/运行此代码)


2
请记得对输入进行消毒,如果您没有使用预处理语句。 - Sami Korhonen
是的,你说得没错,但我只是想大致表达这个想法。无论如何,这与@h2ooooooo在评论中提到的基本相同。 - benka

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接