sphinx(九)根据关键词类似度排序

全文检索通过sphinx搜索出来的内容是没有问题的。

但是搜索结束之后,文章的排序还是多少有点小问题,是这样,我最开始是使用时间倒叙排序,这样就会有一个小问题就是,我想要的结果,或者说跟我搜索关键词最贴近的结果不会出目前前几条。这个体验很不好。

然后,我这里使用了PHP内置的similar_text函数对文章的描述以及标题进行类似度的计算,然后根据计算之后的类似度数值进行倒叙排序。

我这里封装了一个函数:仅作示例,具体还是需要根据你自己的需求来

function similar_arr($array, $keyword, $arr_key =  title )
{
    //数组类似度处理
    foreach ($array as $key => $value) 
    {
        similar_text($value[$arr_key], $keyword, $percent);
        $value[ percent ] = $percent;
        $data[] = $value;
         
    }
 
    //取出数组中percent的一列,返回一维数组
    $percent =  array_column($data,  percent );
 
    //排序,根据 percent 排序
    array_multisort($percent, SORT_DESC, $data);
    
    return $data;
}

// $data是一个二维数组
$res = similar_arr($data,  微信小程序 );
var_dump($res);

这个是没有问题的,但是其对中文的类似度计算不是很友善。有点瞎算的感觉。

这可怎么办呢?也不能用这玩意啊。

百度上还是大婶多,我这里找到了一个计算中文类似度的一个类,我这里稍加改动了一下:

整体如下所示:

Lcscontroller.php

<?php
 
namespace AppHttpControllersindex;
 
/**
 * @name: 文章类似度计算类
 * @author: camellia
 * @date: 2021-03-04 
 */
class LcsController extends BaseController
{
    private $str1;
    private $str2;
    private $c = array();
    /**
     * @name: 返回串一和串二的最长公共子序列
     * @author: camellia
     * @date: 2021-03-04 
     * @param:  data    type    description
     * @return: data    type    description
     */
    public function getLCS($str1, $str2, $len1 = 0, $len2 = 0)
    {
        $this->str1 = $str1;
        $this->str2 = $str2;
        if ($len1 == 0) $len1 = strlen($str1);
        if ($len2 == 0) $len2 = strlen($str2);
        $this->initC($len1, $len2);
        return $this->printLCS($this->c, $len1 - 1, $len2 - 1);
    }
    /**
     * @name: 返回两个串的类似度
     * @author: camellia
     * @date: 2021-03-04 
     * @param:  data    type    description
     * @return: data    type    description
     */
    public function getSimilar($str1, $str2)
    {
        $len1 = strlen($str1);
        $len2 = strlen($str2);
        $len = strlen($this->getLCS($str1, $str2, $len1, $len2));
        if(($len1 + $len2) > 0)
        {
            return $len * 2 / ($len1 + $len2);
        }
        else
        {
            return 0;
        }
        
    }
    /**
     * @name: 函数名
     * @author: camellia
     * @date: 2021-03-04 
     * @param:  data    type    description
     * @return: data    type    description
     */
    public function initC($len1, $len2)
    {
        for ($i = 0; $i < $len1; $i++) 
        {
            $this->c[$i][0] = 0;
        }
        for ($j = 0; $j < $len2; $j++) 
        {
            $this->c[0][$j] = 0;
        }
        for ($i = 1; $i < $len1; $i++) 
        {
            for ($j = 1; $j < $len2; $j++) 
            {
                if ($this->str1[$i] == $this->str2[$j]) 
                {
                    $this->c[$i][$j] = $this->c[$i - 1][$j - 1] + 1;
                } 
                else if ($this->c[$i - 1][$j] >= $this->c[$i][$j - 1]) 
                {
                    $this->c[$i][$j] = $this->c[$i - 1][$j];
                } 
                else 
                {
                    $this->c[$i][$j] = $this->c[$i][$j - 1];
                }
            }
        }
    }
    /**
     * @name: 函数名
     * @author: camellia
     * @date: 2021-03-04 
     * @param:  data    type    description
     * @return: data    type    description
     */
    public function printLCS($c, $i, $j)
    {
        if($i < 0 || $j < 0)
        {
            return "";
        }
        if ($i == 0 || $j == 0) 
        {
            if ($this->str1[$i] == $this->str2[$j]) 
            {
                return $this->str2[$j];
            }
            else 
            {
                return "";
            }
        }
        if ($this->str1[$i] == $this->str2[$j]) 
        {
            return $this->printLCS($this->c, $i - 1, $j - 1) . $this->str2[$j];
        }
        else if ($this->c[$i - 1][$j] >= $this->c[$i][$j - 1]) 
        {
            return $this->printLCS($this->c, $i - 1, $j);
        } 
        else 
        {
            return $this->printLCS($this->c, $i, $j - 1);
        }
    }
}

调用:

 /**
     * @name: 根据类似度对数组进行排序
     * @author: camellia
     * @date: 2021-03-04 
     * @param:  data    type    description
     * @return: data    type    description
     */
    public function similar_arr($array, $keyword, $arr_key_one =  arttitle , $arr_key_two= content , $arr_key_three=  artdesc )
    {
        $lcs = new LcsController();
 
        //数组类似度处理
        foreach ($array as $key => $value) {
            // similar_text函数对中文类似度处理的不是很友善
            // similar_text($value[$arr_key], $keyword, $percent);
            $title_percent = $lcs->getSimilar($value[$arr_key_one], $keyword);
            //返回最长公共子序列
            //echo $lcs->getLCS("hello word","hello china");
            $value[ title_percent ] = $title_percent;
            // $content_percent = $lcs->getSimilar($value[$arr_key_two], $keyword);
            // $value[ content_percent ] = $content_percent;
            $desc_percent = $lcs->getSimilar($value[$arr_key_three], $keyword);
            $value[ desc_percent ] = $desc_percent;
            $data[] = $value;
        }
 
        //取出数组中percent的一列,返回一维数组
        // $percent = array_column($data,  percent );
        //排序,根据 percent 排序
        // array_multisort($percent, SORT_DESC, $data);
        // $array = $this->sortArrByManyField($data,  title_percent , SORT_DESC,  content_percent , SORT_DESC,  desc_percent , SORT_DESC);
        $array = $this->sortArrByManyField($data,  title_percent ,SORT_DESC,  id , SORT_DESC,  desc_percent , SORT_DESC );
        return $array;
    }
    /**
     * @name: php二维数组根据多个字段排序
     * @author: camellia
     * @date: 2021-03-04 
     * @param:  data    type    description
     * @return: data    type    description
     */
    public function sortArrByManyField()
    {
        $args = func_get_args(); // 获取函数的参数的数组
        if(empty($args))
        {
            return null;
        }
        $arr = array_shift($args);
        if(!is_array($arr))
        {
            throw new Exception("第一个参数不为数组");
        }
        foreach($args as $key => $field)
        {
            if(is_string($field)){
            $temp = array();
            foreach($arr as $index=> $val){
                $temp[$index] = $val[$field];
            }
            $args[$key] = $temp;
            }
        }
        $args[] = &$arr;//引用值
        call_user_func_array( array_multisort ,$args);
        return array_pop($args);
    }

调用计算类似度方法

 $listShow = $this->similar_arr($list, $search,  arttitle );

这个最后的计算出来的类似度实则也不是特别的准确,但是,要比PHP内置的similar_text函数要好。

具体实现的效果,请访问我的个人博客:https://guanchao.site

有好的提议,请在下方输入你的评论。

欢迎访问个人博客
https://guanchao.site

© 版权声明

相关文章

暂无评论

none
暂无评论...