【问题标题】:PHP Search for keywordsPHP 搜索关键字
【发布时间】:2011-12-08 14:29:28
【问题描述】:

我一直在为网站上某些类型的帖子构建一个 PHP 搜索工具(为此,请接受 mySQL 是不可能的)。

经过一系列的过程,我们得到了每个帖子的标题和标签,并将它们存储在一个名为$full的变量中。

搜索词位于一个名为$terms的变量中

$full = $title . ' ' . $tago[$result->ID];

两者都转换为小写。

然后我们想使用$terms$full中寻找相似的词

我试过了。

$final = strpos($full,$terms);

它有效,但不如我需要的那么好。

  • 这将匹配标题和标签中的相似词,但根本不处理空格。我尝试从标题和标签中删除空格和逗号,但无济于事。
  • 如果用户输入的某人的名字由两个标签而不是一个标签组成,它将找不到任何结果。
  • 它不能处理一个以上的单词,更不用说一个以上的术语了,我希望它能够做到这两点。

如果有帮助,这里是完整的脚本

$proto = $_GET['p'];
$terms = $_GET['s'];

$terms = strtolower($terms);
$terms = str_replace(' ', '', $terms);

$ids = array();

if($proto == 'inline') {

    $search = get_posts('post_type=post&post_status=publish');

    foreach($search as $result) {

        $title = get_the_title($result);

        $tags = wp_get_post_tags( $result->ID);

        foreach($tags as $tag){ $tago[$result->ID].= $tag->name;}

        $full = $title . ' ' . $tago[$result->ID];
        $full = strtolower($full);
        $final = strpos($full,$terms);


        if($final != false){ 

            $ids[] = $result->ID;

         }

    }
    if ($ids[0] == '') { 
        echo '<div align="center" style="text-align:center; color:#FFF;">No Results Found</div>';
    return false; } else {
    $args = array( 'post__in' => $ids );

    $srs = get_posts($args);

    foreach($srs as $sr) { 

    echo '<a href="'.$sr->post_slug.'"><img src=""/><b>'.$sr->post_title.'</b>'. $tago[$result->ID].'<span>'.date('dS M Y', strtotime($sr->post_date)).'</span></a>';

     }
    }


}

价值观

$terms 可能包含用户输入的一些值以进行搜索,例如“红色汽车”;

$full 包含帖子标题和标签,所以它可能会说。 '红色的vaxhaul不是很好,车,车,可怕,丑陋'

所以在这种情况下应该可以找到。

【问题讨论】:

  • 您能否举个例子说明您希望它找到什么,显示 $full 和 $terms 的值可能会更容易为您创建解决方案

标签: php search strpos


【解决方案1】:

有几种方法可以实现,我会尝试提供一些:

STRPOS

这将匹配红色然后停止,但它也会匹配非精确的单词,例如 car 也会匹配卡片等。

$words = explode(' ', $terms);

foreach ($words as $word) 
{
    if (false !== strpos()) {
        $ids[] = $result->ID;
    }
}

使用数组交集

//create an array of searched terms
$words = explode(' ', $terms);

//remove non letter numbers
$fullClean = preg_replace('/[^a-z\d\s]/', '', $full);

//Create an array of words
$criteria = explode(' ', $fullClean);

//find if any elements of $words exist in $criteria
if (count(array_intersect($words, $criteria))) {
    $ids[] = $result->ID;
}

第三种方法可能是使用正则表达式和 preg_quote,但它很可能会遇到与 strpos 相同的问题

希望有帮助

【讨论】:

    【解决方案2】:

    真正的搜索引擎会这样做的方式是建立一个倒排索引,即最简单的形式是一个查找表,从每个单词到包含该单词的文档集以及包含多少次。 (这里的文档仅仅意味着被搜索的文本)在 php 中很简单:

    foreach($documents as $docIndex => $documentText) {
        //remove all types of punctuation and other characters here
        $documentText = str_replace(array(',','.','?','!'),"",$documentText);
        $words = explode(" ",$documentText);
        foreach($words as $word) $invertedIndex[$word][$docIndex]++;
    }
    

    运行后我们已经建立了倒排索引。现在要在您的示例中使用它,传入的查询是“红色汽车”。将其拆分并查找 $invertedIndex['red'] 和 $invertedIndex['car'] 每一个都将返回数组,其中包含所有包含这些单词的文档以及次数。要同时使用 array_intersect 来获取文档,在这些数组的键上使用 array_merge 来获取文档:

    foreach($keywords as $count => $keyword) {
        if($count == 0) $validDocs = keys($invertedIndex[$keyword]);
        $validDocs = array_intersect(keys($invertedIndex[$keyword]),$validDocs);
    }
    

    现在每个包含所有关键字的文档的文档索引都将在 $validDocs 中,如果您想根据单词在文本中出现的次数对它们进行排名,您在 $invertedIndex 中也有该信息。这种方法速度非常快,但您必须提前构建倒排索引,但它会比实际搜索快得多。

    【讨论】:

      猜你喜欢
      • 2012-02-22
      • 1970-01-01
      • 2013-04-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-02-18
      相关资源
      最近更新 更多