【问题标题】:PHP/MySQL: Simple search enginePHP/MySQL:简单的搜索引擎
【发布时间】:2012-04-04 03:09:53
【问题描述】:

我正在为一个小型网站构建一个简单的搜索引擎。用户将能够通过email addressname 搜索他们的朋友。我希望使用 FULLTEXT 搜索,但我使用的是 InnoDB 表,所以这让我回到了LIKE %keyword%

我的问题是用户的名字和姓氏存储在两个单独的列中。我怎么能去搜索“大卫规则”是这样的情况?

这是我目前拥有的:

    if(filter_var($query,FILTER_VALIDATE_EMAIL)) {
        $STH = $this->_db->prepare("SELECT UserID
            FROM UserCredTable
            WHERE EmailAddress = :query;");
    } else {
        $STH = $this->_db->prepare("SELECT UserID
            FROM UserInfoTable
            WHERE FirstName LIKE :query
            OR LastName LIKE :query;");
    }

它有点工作,但我猜相关性几乎不存在:(

如何按最相关的结果排序?


更新:

这看起来是一个不错的解决方案吗?

    if(filter_var($query,FILTER_VALIDATE_EMAIL)) {
        $params["query"] = $query;
        $STH = $this->_db->prepare("SELECT UserID
            FROM UserCredentials
            WHERE EmailAddress = :query;");
    } else {
        $params["query"] = "%".$query."%";
        $STH = $this->_db->prepare("SELECT UserID
            FROM UserDetails
            WHERE CONCAT(FirstName,' ',LastName) 
            LIKE :query;");
    }

【问题讨论】:

  • 这不是从性能的角度来看。此查询将无法使用索引,因此,对于大型表和/或大量使用,它会使服务器变慢。不过对于小桌子来说还可以。
  • @YourCommonSense 搜索的行数不会超过六千行。而且很少见。这可以接受吗?
  • “很少”表示每天最多 50 次。
  • 是的,总的来说应该没问题。
  • 我知道这已经过时了,但对于未来的读者来说,值得一提的是,从 MySQL 5.6 开始,InnoDB 也支持 FULLTEXT 索引。

标签: php mysql search full-text-search pdo


【解决方案1】:

搜索显然是一个很大的话题,有很多不同的处理方式。

也就是说,对于最基本的可能解决方案,您应该能够搜索这两个字段的连接:

SELECT UserID
        FROM UserInfoTable
        WHERE CONCAT(FirstName, ' ', LastName) LIKE '%Dave Smith%';

CONCAT() MySQL 函数将与您连接的字符串一样多的字符串作为参数。在上述情况下,我们只是在 FirstNameLastName 之间添加了一个空格。

【讨论】:

    【解决方案2】:

    如果全文搜索不是一个选项,那么您可能不得不考虑拆分搜索词并查询如下内容:

    SELECT UserID
    FROM UserInfoTable
    WHERE (FirstName LIKE '%David%'
    OR LastName LIKE '%David%') OR
    (FirstName LIKE '%:Rule%'
    OR LastName LIKE '%:Rule%')
    

    不理想,我不确定这是否是最佳解决方案,但它可能会为您返回最佳结果集。特别是如果人们开始使用三重名称(例如“John Taylor Smith”),这似乎变得越来越普遍

    【讨论】:

      【解决方案3】:

      您可以在 MySQL 中使用 CONCAT() 函数

      } else {
           $STH = $this->_db->prepare("SELECT UserID
               FROM UserInfoTable
               WHERE CONCAT(FirstName,LastName) LIKE '%:query%';");
       } 
      

      【讨论】:

        【解决方案4】:

        看看Sphinx,它直接从 MySQL 索引数据,并有一个用于搜索的 PHP API。

        除此之外,您可以拆分搜索文本中的空格并尝试一些 OR,但就像您所说的 InnoDB 中不存在相关性。

        MySQL 并不是真正为搜索而设计的,因此从长远来看,使用另一种更加灵活和可扩展的产品。

        【讨论】:

          【解决方案5】:

          您应该考虑使用内置于 MySQL 和许多其他数据库引擎中的全文搜索支持。

          它为您的搜索增加了排名,这非常棒。

          以下示例来自 MySQL 手册,http://dev.mysql.com/doc/refman/5.0/en/fulltext-natural-language.html

          mysql> CREATE TABLE articles (
              ->   id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY,
              ->   title VARCHAR(200),
              ->   body TEXT,
              ->   FULLTEXT (title,body)
              -> ) ENGINE=MyISAM;
          Query OK, 0 rows affected (0.00 sec)
          
          mysql> INSERT INTO articles (title,body) VALUES
              -> ('MySQL Tutorial','DBMS stands for DataBase ...'),
              -> ('How To Use MySQL Well','After you went through a ...'),
              -> ('Optimizing MySQL','In this tutorial we will show ...'),
              -> ('1001 MySQL Tricks','1. Never run mysqld as root. 2. ...'),
              -> ('MySQL vs. YourSQL','In the following database comparison ...'),
              -> ('MySQL Security','When configured properly, MySQL ...');
          Query OK, 6 rows affected (0.00 sec)
          Records: 6  Duplicates: 0  Warnings: 0
          
          mysql> SELECT * FROM articles
              -> WHERE MATCH (title,body) AGAINST ('database');
          +----+-------------------+------------------------------------------+
          | id | title             | body                                     |
          +----+-------------------+------------------------------------------+
          |  5 | MySQL vs. YourSQL | In the following database comparison ... |
          |  1 | MySQL Tutorial    | DBMS stands for DataBase ...             |
          +----+-------------------+------------------------------------------+
          2 rows in set (0.00 sec)
          

          【讨论】:

          • “我希望使用 FULLTEXT 搜索,但我使用的是 InnoDB 表”
          • 从 MySQL 5.6 和 MariaDB 10.0 开始,InnoDB 支持 FULLTEXT 索引