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 App\Http\Controllers\index;
/**
* @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函数要好。
具体实现的效果,请访问我的个人博客:guanchao.site
相关文章