【问题标题】:How to order mysql search results by relevence of word priority [duplicate]如何通过单词优先级的相关性对mysql搜索结果进行排序[重复]
【发布时间】:2011-06-24 18:32:55
【问题描述】:

可能重复:
PHP MySQL Search And Order By Relevancy

嗨,

我有一个表格,其中有几列,其中包含姓名、地址、公司等字段。假设有人搜索“microsoft john”。我希望首先出现包含“microsoft”的结果,然后是包含 john.如果查询是“john microsoft”,反之亦然

我的php代码是:

$searchitems=explode(" ", $trimmed);
//print_r($searchitems);
$so = $_GET['so']=='2'?"2":"1";

$clause = $so=='2'?"AND":"OR";
include("dbconnect.php");
// Build SQL Query

$query = "select FirstName,LastName,course,Department,batch,City,companyjob,companylocation,
    companyposition,coursename,institutename,coursename2,institutename2,coursename3,
    institutename3 from alumni WHERE ";
for($i=0;$i<count($searchitems);$i++)
{
    $queryappend .= "(FirstName LIKE '".$searchitems[$i]."%' OR LastName LIKE '".$searchitems[$i]."%'
    OR City LIKE '".$searchitems[$i]."%' OR CountryorRegion LIKE '".$searchitems[$i]."%'
    OR companyjob LIKE '".$searchitems[$i]."%' OR companylocation LIKE '".$searchitems[$i]."%'
    OR coursename LIKE '".$searchitems[$i]."%' OR institutename LIKE '".$searchitems[$i]."%'
    OR coursename2 LIKE '".$searchitems[$i]."%' OR institutename2 LIKE '".$searchitems[$i]."%')";
    if($i<count($searchitems)-1) $queryappend .= $clause;

}
$query .=$queryappend;

问题是 MYSQL 是按 id 排序结果...这很有趣,因为一些更高价值的结果可能会卡在堆栈的深处。顺便说一句,phpmyadmin 搜索也有同样的缺陷。

请提出建议。

【问题讨论】:

  • 不确定这是 PHP 还是 phpmyadmin 的缺陷。我在您的语句中根本没有看到 任何 ORDER BY 子句,因此返回的订单将始终是纯粹任意的(甚至不保证是通过 id)
  • 感谢马克的回复。我需要按搜索查询中的单词序列排序。正如我在示例中所说,如果第一个 $searchitems 是 microsoft,则应首先显示所有包含 microsoft 的结果。 (微软结果可能会进一步按下一个 $searchitems 排序,依此类推)。我不能添加任何任意顺序,因为这会破坏目的。
  • 您提到的页面stackoverflow.com/questions/344199/… 只是要求从查询字符串中搜索单个单词。我通过使用 explode() 函数实现了这个效果
  • 哇,这就是我所说的穷人的全文搜索......好吧,在支付了你的专用搜索服务器场的每月账单之后,你肯定会很穷:)
  • @sfussenegger 你的意思是我应该跳到全文搜索和这些复杂的东西?就时间和空间复杂性而言,这是否会降低成本?

标签: php mysql search relevance


【解决方案1】:

举个例子:

SELECT
  FirstName,
  LastName,
  IF (FirstName LIKE '%Microsoft%' || LastName LIKE '%Microsoft%', 1, 0) AS One,
  IF (FirstName LIKE '%John%' || LastName LIKE '%John%', 1, 0) AS Two
FROM alumni
ORDER BY One DESC, Two DESC

在您的代码中,这会使查询变得相当复杂。这样做的好处是,具有两个搜索词的项目出现在仅匹配单个搜索词的项目之前。

另一种方法是在使用 PHP 检索记录时将记录分类到存储桶中。假设您在数组$search 中有搜索词(按优先级降序排列):

while ($record = mysql_fetch_array($result))
{
  $total = join(' ', $record);
  $found = false;
  foreach ($search as $term)
  {
    if (strpos($total, $term) !== false)
    {
      $buckets[$term][] = $record;
      $found = true;
      break;
    }
  }
  if (!$found)
  {
    $results[] = $record;
  }
}
foreach (array_reverse($search) as $term)
{
  if (isset($buckets[$term]))
  {
    $result = array_merge($buckets[$term], $result);
  }
}

现在您在数组$results 中获得了结果。请注意,这演示了算法,它没有针对性能进行调整。

【讨论】:

  • 谢谢@oswald!!那行得通!非常感谢您花费宝贵的时间来编写代码……但也许我也会留意@sfussenegger 并将转向全文搜索。全文搜索会比您的第一种和第二种(存储桶)方法更有效吗?
  • 可能。否则全文搜索将不会包含在 mysql 中。
  • 我终于改变了我的搜索系统。现在 WHERE 之后的查询是 MATCH (FirstName,LastName,Department,City,CountryorRegion,companyjob,companylocation, coursename,institutename,coursename2,institutename2,altemail,addcmets,Name,WebPage) AGAINST ('$trimmed' WITH QUERY EXPANSION) 我是仍在对全文的分数部分进行更多试验,以使其更加健壮。感谢所有帮助我的人!特别感谢@symcbean 提出了关于levenshtein 的好主意……读起来很不错……这个练习将帮助我完成本科学位后的面试!
【解决方案2】:

我认为解决它的最简单方法是按levenstein distance 对结果进行排序。

类似......

$queryappend="ORDER BY
   length(firstname) - levenshtein(FirstName, '".$searchitems[$i]."') +
   length(lastname)  - levenstein(LastName, '".$searchitems[$i]."')   +
   length(City)      - levenstein(City, '".$searchitems[$i]."')       +
   ...

虽然使用更适合这种搜索的模式可能是个好主意

【讨论】:

    猜你喜欢
    • 2011-11-26
    • 2017-03-09
    • 2010-11-04
    • 2012-01-28
    • 1970-01-01
    • 1970-01-01
    • 2014-05-24
    • 2011-10-09
    • 1970-01-01
    相关资源
    最近更新 更多