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函数要好。
作者:camellia
链接:https://juejin.cn/post/7026434799455698980