显示PHP搜索结果


PHP Search Results display

我正在为我的框架创建一个基本的搜索功能,并寻求一些关于如何以最佳方式(谷歌风格)显示搜索结果的建议。我的MYSQL查询基于搜索查询返回不同的页面。MySQL返回的结果是完美的,我只需要做以下操作:

例如,有人搜索"Hello World"一词。我的搜索结果将返回所有包含"hello"answers"world"的行。

我正在努力实现的是:

  • 突出显示搜索查询中的单词,但仅显示结果的一部分。我只想返回200个字符,并突出显示(粗体)搜索词中任何单词的第一个出现
  • 显示的副本将在CMS中创建,并带有html标记。我可以在显示之前剥离html标签,但如果我以正确的方式进行操作,我希望得到反馈

我目前使用的代码是:

  // The query string:
  <?php $q = urldecode($_GET['qString']); ?>
  // Run a loop through the results:
  <?php foreach ($this->get("pageResults") AS $result): ?>
      // a clickable H3 to the actual page:
      <h3><?= $this->html->link($result['sub_heading'] . " " . $result['heading'], array("controller" => "pages", "action" => "viewer", "properties" => array($result['name']))) ?></h3>
      <?php
      // Strip all html characters as the content comes from an WYSIWYG editor:
      $value = preg_replace('/<[^>]*>/', '', $result['content']);
      // Find the position within the text:
      $position = stripos($value, $q);
      // If a positive position, display 200 characters and start -100 from the first occurance
      if ($position == true) {
           $string = substr($value, $position - 100, 200);
      } else {
           $string = " ... ";
      ?>
      <p><?= $string ?></p>
      <hr />
 <?php endforeach; ?>

我在这里遇到的主要问题是:

  1. 即使查询字符串不精确(因此如果列包含"你好"answers"世界",而stripos只会找到"你好世界"
  2. 我不知道在剥离的html中第一次出现单词或短语时包装<strong></strong>标签的最佳方法。我知道这可能是一件棘手的事情,尤其是由于发生问题。我可以在没有这个功能的情况下生活,但如果有一个很好的方法来做,那就太好了:)

任何想法都将不胜感激!

我建议您阅读自然语言全文搜索

这是做搜索功能时最优化的方式(基于我的观点)。

即使查询字符串不精确,搜索结果也会返回行(因此,如果列中包含"hello"answers"world",则会返回结果,而stripos只会找到"hello-world"。

这似乎是一个简单的答案,但鉴于您正在通过url传递查询字符串,我认为它看起来像这样:

?searchText=Hello%20World

因此,你可以在空格上分解单词(使用爆炸)并创建一个位置数组:

$positionArray = array();
$qs = explode($q, '%20');
$value = preg_replace('/<[^>]*>/', '', $result['content']);
foreach( $qs as $qword ){
    $position = stripos($value, $qword);
    array_push($positionArray, $position);
}

所以现在你会有一个你的单词出现在结果中的位置阵列:

positionArray = [4, 15, 32];

因此,您可以在这些位置启动相关的突出显示标记(strong或您正在使用的任何标记),然后在单词末尾关闭它们,或者您可以使用类似的东西找到单词的开始位置和结束位置:

foreach( $qs as $qword ){
    $start_position = stripos($value, $qword);
    $end_position = $start_position + strlen($qword);
    array_push($positionArray, {qword: $qword, start_position:$start_position, end_position:$end_position});
}

不幸的是,我现在没有时间考虑如何在这些位置插入标签,我相信你会明白的(但你可以使用substra_replace之类的东西)。无论如何,我希望这能给你一些想法。

这里有一个相当简单的方法来实现您的请求。

首先,你还没有说明你对搜索输入执行了什么转换,但我猜你是在把单词分解,进行不区分大小写的搜索。因此,我将创建一个数据结构,其中包含原始搜索字符串和一个解析版本,其中单词拆分并小写:

// $input is your sanitised query
$arr = explode(" ", strtolower($input));
$search_arr = [
    'original' => $input,
    'parsed' => $arr
];

现在,处理来自数据库的结果:让我们调用来自数据库的$text结果。

# strip the html tags
$stripped = strip_tags($text);
# first, see if the original search query is in the page
$pos = stripos($stripped, $search_arr['original']);
if ($pos !== false) {
    # if it is, take a 200 character snippet of the page (note that
    # if the search string occurs earlier than the first 50 characters,
    # we just take the first 200 characters of the page [I used 50 rather
    # than 100 as 100 seemed too many]):
    if ($pos < 50) {
        $stripped = substr($stripped, 0, 200);
    }
    else {
        $stripped = substr($stripped, $pos-50, 200);
    }
    # use a regular expression to enclose the search string in a <strong> tag
    $stripped = preg_replace("/{$search_arr['original']}/i","<strong>$1</strong>", $stripped);
}
else {
    # otherwise, for each word in the parsed version of the search query...
    foreach ($search_arr['parsed'] as $s) {
        # surround it with <> and </> (I'm doing this in case part of the query
        # matches within the <strong> tag - of course, if <> and </> appear in
        # the source text, this could be a problem!) 
        $stripped = preg_replace("/($s)/i", "<>$1</>", $stripped);
    }
    # now replace the <> and </> with strong tags
    $find = [ '<>', '</>'];
    $replace = ['<strong>', '</strong>'];
    $stripped = str_replace($find, $replace, $stripped);
    # find the first <strong> tag...
    $pos = strpos($stripped, "<strong>");
    if ($pos < 50) {
        $stripped = substr($stripped, 0, 200);
    }
    else {
        $stripped = substr($stripped, $pos-50, 200);
    }
}
echo $stripped; 

这是相当粗略的,你可能会想改进一些东西,但它应该让你知道如何进行。