thinkphp利用中文分词和全文索引技术实现搜索

前瞻

以前搜索功能一直使用的是like模糊查询,这种虽然操作简便,但是效果不好,需要搜索整个库,不如使用全文索引便捷,本文档是利用中文分词加上mysql的全文索引实现搜索功能。使用的框架是thinkphp3.2

思路

  1. 当在插入和修改文章的成功时,将文章用于客户搜索的字段利用中文分词插件进行分割,分割成用空格间隔词语的格式插入到索引表(我这里只是将title分割了),删除后也要把对应的索引表数据删除
  2. 当用户输入查询内容时再用中文分词分割成词语,利用mysql的全文索引去查询出数据
  3. 使用字符串替换函数,将存在的词语高亮显示

实现

  • 数据库表


  • 插入文章时代码(修改和删除不写了,一个道理)
public function add(){
...
...
//文章插入成功是走,$data为插入文章的id,这块需要注意,对应search表的art_id字段
                if($data)
                {
                    $title = $_POST['atitle'];//文章标题
                    $cont=isWhat($title);//自己封装的函数,判断是纯英文还是包含中文,下面有展示
                    //vendor("Fenci.segment");//引入词典
                    require_once "/Fenci/segment.php";//文件放在根目录
                    $se= new \Fenci\Segment();//实例化词典
                    if($cont==1){
                        $res['title']=$title;
                    }elseif($cont==2){
                        //调用方法
                        $res['title'] = $se->get_keyword($title);
                    }else{
                        //调用方法
                        $res['title'] = $se->get_keyword($title);
                        $words=split_en_str($title,false);
                        $res['title'].=" ".implode(' ',$words);
                    }
                    $res['tables'] = 'article';
                    $res['art_id'] = $data;
                    $search = M('Search');
                    $search->create( $res );
                    if( $search->add() ){
                        $this->success('添加成功!',U('Admin/Article/index'));
                    }else{
                        $this->error('文章插入成功,索引表插入失败!');
                    }
                }
...
...
}
  • 当用户输入搜索关键词提交时的demo
public function searchnews ()
    {
        $title = $_POST['title'];
        $cont=isWhat($title);//自己封装的函数,判断是纯英文还是包含中文,下面有展示  
        require_once "/Fenci/segment.php";//文件放在根目录
        $se= new \Fenci\Segment();//实例化词典
        if($cont==1){
            $seach_cont=$title;
        }elseif($cont==2){
            //调用方法
            $seach_cont = $se->get_keyword($title);
        }else{
            //调用方法
            $seach_cont = $se->get_keyword($title);
            $words=split_en_str($title,false);
            $seach_cont.=" ".implode(' ',$words);
        }
        $search = M('Search');
        //利用全文索引的语句查询
        $sql="select art_id,tables from search where MATCH(title) AGAINST('".$seach_cont."' IN BOOLEAN MODE)";
        $res = $search->query($sql);
        //获取所有匹配的文章,并且高亮显示
        $data = array();//查询的数据
        $seach_arr = explode(' ',$seach_cont);//将字符串转换成数组
        foreach( $res as $v ){
            //这里我是查询所有符合的内容,没有锁定单个表,所有表的主键最好是id,否则需要在索引表再加个字段判断
            $vs = M( $v['tables'] )->find($v['art_id']);
            //高亮显示查询内容
            foreach($seach_arr as $v1){
                //将数据中的关键词高亮显示
                $vs['atitle']=str_replace($v1,"<font color='red'><b>{$v1}</b></font>",$vs['atitle']);
            }
            $data[] = $vs;
        }
        $this->field=$data;
        $this->display($this->tpl.'news_lists1.html');//这块自己改
    }
  • 最后效果



  • 使用到的函数(放在/app/Common/function.php里)

/**
 *
 *判断字符串时全英文,全中文,或者都有
 *@param string $str1 需要检查的字符串
 *@return int 英文->1 中文->2 混合->3
 */
function isWhat($str1){
    $strA= trim($str1);
    $lenA= strlen($strA); //检测字符串实际长度
    $lenB= mb_strlen($strA, "utf-8"); //文件的编码方式要是UTF8
    if($lenA=== $lenB) {
        return"1";//全英文
    }else {
        if($lenA% $lenB== 0) {
            return"2";//全中文
        }else {
            return"3";//中英混合
        }
    }
}
/**
 *
 *匹配英文单词
 *@param string $str 需要匹配的字符
 *@param bool $distinct 是否去除重复值
 *@return array 返回所有单词的索引数组
 */
function split_en_str($str,$distinct=true) {
    preg_match_all('/([a-zA-Z]+)/',$str,$match);
    if ($distinct == true) {
        $match[1] = array_unique($match[1]);
    }
    sort($match[1]);
    return $match[1];
}
  • 小注
    • 分词用到的插件在我网盘,网盘地址:链接:http://pan.baidu.com/s/1gf7LZG3 密码:amqh;拿到之后直接解压到项目根目录,不放在根目录那就自己放,但是需要修改两处第一处是引入分词的路径(所有的引入路径都要改),见图1,第二是Segment.php类里面的引入词库的路径见图2;
      图1

      图2
    • 这个分词的词典词语还是比较少,没有找到更多的词库,谁有更好的词库也可以告诉一下,谢谢!我的代码需要优化的,或者有问题的留言!
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,636评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,890评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,680评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,766评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,665评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,045评论 1 276
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,515评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,182评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,334评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,274评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,319评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,002评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,599评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,675评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,917评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,309评论 2 345
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,885评论 2 341

推荐阅读更多精彩内容