【问题标题】:How can I use wildcard in the most efficient way?如何以最有效的方式使用通配符?
【发布时间】:2013-08-29 14:45:00
【问题描述】:

我正在处理一个快速搜索条形码,它看起来像这样:

搜索栏.php:

<form method="post" action="search.php">
<input type="text" name="search" />
<input type="submit" />
</form>

搜索.php:

<?php
include("config.php");
$search = mysql_real_escape_string($_POST['search']);
$data = mysql_query("SELECT * FROM shop WHERE name LIKE '%$search%' OR id LIKE '%$search%' OR description LIKE '%$search%' OR keywords LIKE '%$search%' ORDER BY id DESC ") or die(mysql_error());
while ($info = mysql_fetch_array($data)) {
    $name = stripslashes($info['name']);
    $desc = stripslashes($info['description']);
    Print "<h3><a href=\"result.php?product=".$name."\">".$name."</a>: <font color=\"#cd0000\">".$desc."</font></h3><br>";
}
echo $name;
?>

结果.php:

<?php
$result = $_GET['product'];
echo $result;
?>

现在我的问题是我的搜索中的通配符。假设有人搜索两个词“foo bar”。按照我的说法,这些词必须完全按照这个顺序排列,它们之间要有一个空格才能出现。有没有办法在我的搜索参数中,如果“foo”和“bar”这两个词在任何地方(甚至不是彼此相邻),结果就会显示出来?如果单词的顺序按顺序颠倒,我也希望它能够工作,“bar foo”(再次甚至不是彼此相邻)。

【问题讨论】:

  • 您可以在空格上拆分搜索词并为每个词添加一个新的like 子句,但我怀疑这是人们所期望的。如果我搜索“给我”,我不会期望得到“美国立法者”的结果
  • 我强烈建议您先对该主题进行一些小搜索,因为正如您可能想象的那样,您不是第一个关心这个问题的人。顺便说一句,现场搜索并不是那么糟糕。我记得有一个或其他问答材料很好地处理了这个主题,并且在不同的角度和不同的细节层次上。

标签: php mysql search wildcard


【解决方案1】:

由于您正在执行LIKE '%...%' 匹配,您应该意识到 MySQL 不能使用索引来执行此类搜索,并且您每次都将强制进行全表扫描。正如您所提到的,如果用户输入 foo bar,您将搜索完整的短语。

您有几个选择,使用 foo bar 作为搜索词组:

1) 对搜索词进行预处理,使搜索词组中的每个“词”成为自己的匹配集,例如

WHERE (
        field1 LIKE '%foo%' OR field2 LIKE '%foo%' OR ...
     OR field1 LIKE '%bar%' OR field2 LIKE '%bar%' OR ...
)

2) 切换到使用全文索引,将查询减少到

WHERE MATCH(field1, field2, ...) AGAINST ('foo bar')

【讨论】:

  • 好的,所以我使用了 FULLTEXT,它几乎可以工作了。我创建了一个 FULLTEXT INDEX 并在其中创建了名称、描述和关键字的列。我还在布尔模式下运行了查询,因为这个例子只有两行,所以它总是违反 50% 规则。我的问题是,当我在“名称”列而不是“描述”或“关键字”列中搜索内容时,当它们同时在全文索引和搜索查询中时,它会返回结果。有什么想法是什么原因造成的吗?
【解决方案2】:

你可以使用这个来消除查询中的空格

str_replace('  ' , '' , $string );

这里我们在第一个参数中寻找空格,在第二个参数中用空替换它,然后在第三个参数中加载我们想要处理的字符串..

希望这会有所帮助。

【讨论】:

  • 好吧,这行得通,所以如果出现“foo blah blah blah bar”,它就会出现。你知道有一种方法可以让它也以相反的顺序显示吗?
  • 我假设您要求反转字符串,例如:Hello -> olleH 在这种情况下您可以使用 strrev() 函数。
【解决方案3】:

如果您想搜索每个单独的项目,您必须单独搜索它们。 这段代码(未经测试)应该这样做

$search = explode(' ',$_POST['search']);
$query = "SELECT * FROM shop WHERE (";
foeach($search as $value){
    $value = mysql_real_escape_string($value);
    $whereClauses[] = "name LIKE '%$value%' OR id LIKE '%$value%' OR description LIKE '%$value%' OR keywords LIKE '%value%'";
}
$query.= implode(' OR ',$whereClauses) .') ORDER BY id DESC ';

$data = mysql_query($query) or die(mysql_error());
while ($info = mysql_fetch_array($data)) {
    $name = stripslashes($info['name']);
    $desc = stripslashes($info['description']);
    Print "<h3><a href=\"result.php?product=".$name."\">".$name."</a>: <font color=\"#cd0000\">".$desc."</font></h3><br>";
}

请注意,这是一种非常糟糕的方法,因为由于要找到的项目前后存在通配符,MySQL 无法使用索引,因此需要进行全表扫描。

【讨论】:

  • 这段代码似乎可以显示所有带有“foo bar”、“bar foo”、“foo”和“bar”的结果。有没有办法让它只显示同时具有“foo”和“bar”的结果?不只是一个或另一个
  • 这只是 php 部分的更多编码,结果如下子句: WHERE (name LIKE '%foo%bar%' OR name LIKE '%bar%foo%') OR (id LIKE '%foo%bar%' OR id LIKE '%bar%foo%') OR ....
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-01-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-12-17
相关资源
最近更新 更多