找回密码

碧海潮声大学生网

查看: 316|回复: 0
打印 上一主题 下一主题

简单全文索引实现

[复制链接]
跳转到指定楼层
1#
发表于 2014-9-24 00:34 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式



[color=rgb(51, 102, 153) !important]复制代码

1、sphinx的seekcore
不必说,mysql全文搜索的不二方案,为mysql所问索引而生的第三方软件。coreseeksphinx的衍生版本,为适应中国市场而生做了很多本土化的优化。之前在公司实习的时候有接触过sphinx,但是没有深入研究。拿到sphinx高兴啊,立即装上百度找一些配置文章。装好之后才想起来我用的是虚拟空间,虚拟空间装什么sphinx啊。
2、海曼大神pscws分词神器
首先我想说网上很多人都说highman的分词神器,但是不知道多少人用过了,highman个人现在应该是把大部分时间放在迅搜上边,关于分词的pscws已经很久没更新了。迅搜和seekcore一样都是建立在服务器端的,这种解决方案对只能虚拟空间的屌丝来说几乎不太可能实现。首先我想说highmanpswcs在高版本php下支持是不怎么好的,之前用的是5.01的没有报错,后来换了5.4+php版本结果上来直接一脸的错。能在虚拟机上运行的分词php文件有两个一个pswcs23还有一个pswcs4,官方说pswcs4速度较慢不推荐使用,剩下的只有23两个版本了。看了一下速度还不错。注意pswcs2pswcs3只支持gbk形式文件。
当初自己没看清楚文档,吃不少苦,整整调试了三天全是乱码,害得我一个项目全跟着乱码巴拉巴拉看源代码,看得稀里糊涂没发现什么错了,最后在一字一句的去读了文档才发现只支持gbk编码。还好我是随时备份的。我用的是nodepad++默认是utf-8编码,所以是没法分割,只有乱码。而且数据库也是utf-8的编码,后来一运行我整个项目全乱码,什么验证码无法显示啊,乱七八槽。所以我再次提醒就算你全都用gbk形式来编码,做用之前别直接放到项目里边去测试。海曼的pswcs我研究了好几天,也得到了解决方案。解决方案请耐心看完下边关于另个方法的介绍。待会一起提到。
3、下面介绍关于二元法全文索引解决方案。
研究海曼哥哥的东西最后无功而返,倍受打击本来打算放弃了的。后来去研究了discuzecshop的站内搜索引擎,没有惊喜,无例外的用like只是在提交的搜索做了简单的处理全文索引用不上。百无聊赖躺在床上的时候用百度百科看了一下全文索引的定义,看到二分法做分词的方法,想想这倒是解决方案。然后花了一天去百度啊,找啊,终于找到了一个分词算法,因为不知道到底谁是原创,就不引用作者了。同样的问题,乱码,又不支持utf8
后来转念一想php不是可以转码吗?既然php可以转码,那么编码的问题就不存在了。
Ok到这里基本上问题都可以解决了。虽然可以转码,但是因为弄错了gbkutf-8ASCii码,害得我折腾了两天。把源代码看了无数遍。下面是我做的修改,我想再啰嗦一遍,网上有的哪个二元分词法是不正确的,只能分gbk,而且会把字符里的英文全过滤掉,我在这里做了点修正。
先说一下二元法分词怎么做:
(1)、如果要对一张article的表建立全文索引,那么得借助另一张变index来存放分词后的文本字符。两张表外键相关(分词后再逆回去是不现实的,而且建立全文索引之后写操作是相当吃力的)。
(2)、让msyql支持中文分词,最起码在my.ini里边加上这句ft_min_word_len = 1
这里有一边官文全文索引很好的文章可以参考一下,接下来怎么做我就不多说了
http://www.cnblogs.com/macula7/archive/2011/05/18/2050525.html

  • /**
  • * 二元发分割中文字符,可以对不同编码的中文进行分词
  • * @param string $name 转入字符串
  • * @return string
  • */
  • function spl_zhstr($strings) {
  • $str=$strings;
  • $encode = mb_detect_encoding($str, array("ASCII","UTF-8","GB2312","GBK","BIG5"));
  • $str=iconv($encode,"GBK",$str);//更改编码,转为gbk,以一个汉字两个字节分词
  • preg_match_all('/[0-9a-z]+?/U',$str,$enlg);
  • $enword=implode(' ',$enlg[0]);//获得英文单词
  • $charset= "/[\x01-\x7f]|[\x81-\xfe][\x40-\xfe]/";
  • $str=preg_replace($charset,"\\0".chr(0x00),$str);//为了分词准确在每个单词后加'.'
  • $search = array(",", "/", "\\", ".", ";", ":", "\"", "!", "~", "`", "^", "(", ")", "?", "-", "\t", "\n", "'", "<", ">", "\r", "\r\n", "$", "&", "%", "#", "@", "+", "=", "{", "}", "[", "]", ":", ")", "(", ".", "。", ",", "!", ";", "“", "”", "‘", "’", "〔", "〕", "、", "—", " ", "《", "》", "-", "…", "【", "】",);
  • $str = str_replace($search,' ',$str);
  • preg_match_all("/[\x80-\xff].?/",$str,$ar);
  • $ar=$ar[0];
  • for ($i=0;$i<count($ar);$i++)
  • if($ar[$i]!=chr(0x00)) {
  • $ar_new[]=$ar[$i];//将单词压入数组
  • }
  • $ar=$ar_new;
  • $oldsw=0;
  • for ($ar_str='',$i=0;$i<count($ar);$i++) {
  • $sw=strlen($ar[$i]);
  • if ($i>0 and $sw!=$oldsw)
  • $ar_str.=' ';
  • if ($sw==1)
  • $ar_str.=$ar[$i];
  • else
  • if (@strlen($ar[$i+1])===2)
  • $ar_str.=$ar[$i].$ar[$i+1].' ';
  • elseif ($oldsw==1 or $oldsw==0)
  • $ar_str.=$ar[$i];
  • $oldsw=$sw;
  • }
  • $ar_str=trim(preg_replace("#\s{1,}#i"," ",$ar_str));
  • $word=$ar_str;//.' '.$enword;
  • $encode = mb_detect_encoding($word, array("ASCII","UTF-8","GB2312","GBK","BIG5"));
  • $word=iconv($encode,"utf-8",$word);//编码转回utf-8
  • return $word;
  • }
  • /**
  • * 二元发分割中文字符,可以对不同编码的中文进行分词
  • * @param string $name 转入字符串
  • * @return string
  • */
  • function spl_zhstr($strings) {
  • $str=$strings;
  • $encode = mb_detect_encoding($str, array("ASCII","UTF-8","GB2312","GBK","BIG5"));
  • $str=iconv($encode,"GBK",$str);//更改编码,转为gbk,以一个汉字两个字节分词
  • preg_match_all('/[0-9a-z]+?/U',$str,$enlg);
  • $enword=implode(' ',$enlg[0]);//获得英文单词
  • $charset= "/[\x01-\x7f]|[\x81-\xfe][\x40-\xfe]/";
  • $str=preg_replace($charset,"\\0".chr(0x00),$str);//为了分词准确在每个单词后加'.'
  • $search = array(",", "/", "\\", ".", ";", ":", "\"", "!", "~", "`", "^", "(", ")", "?", "-", "\t", "\n", "'", "<", ">", "\r", "\r\n", "$", "&", "%", "#", "@", "+", "=", "{", "}", "[", "]", ":", ")", "(", ".", "。", ",", "!", ";", "“", "”", "‘", "’", "〔", "〕", "、", "—", " ", "《", "》", "-", "…", "【", "】",);
  • $str = str_replace($search,' ',$str);
  • preg_match_all("/[\x80-\xff].?/",$str,$ar);
  • $ar=$ar[0];
  • for ($i=0;$i<count($ar);$i++)
  • if($ar[$i]!=chr(0x00)) {
  • $ar_new[]=$ar[$i];//将单词压入数组
  • }
  • $ar=$ar_new;
  • $oldsw=0;
  • for ($ar_str='',$i=0;$i<count($ar);$i++) {
  • $sw=strlen($ar[$i]);
  • if ($i>0 and $sw!=$oldsw)
  • $ar_str.=' ';
  • if ($sw==1)
  • $ar_str.=$ar[$i];
  • else
  • if (@strlen($ar[$i+1])===2)
  • $ar_str.=$ar[$i].$ar[$i+1].' ';
  • elseif ($oldsw==1 or $oldsw==0)
  • $ar_str.=$ar[$i];
  • $oldsw=$sw;
  • }
  • $ar_str=trim(preg_replace("#\s{1,}#i"," ",$ar_str));
  • $word=$ar_str;//.' '.$enword;
  • $encode = mb_detect_encoding($word, array("ASCII","UTF-8","GB2312","GBK","BIG5"));
  • $word=iconv($encode,"utf-8",$word);//编码转回utf-8
  • return $word;
  • }


[color=rgb(51, 102, 153) !important]复制代码





关于pscws的的解决方案:
既然编码不是问题,那么就很容易了。如果appserv集成环境的我建议你该到wamp下来,因为appserv2.59太老了,2.6版本有太新了,php6都没正式发行就参合进去了。相对而言wamp的版本会多一点。但是我用的版本下一屏幕都是这个错Strict standards: Redefining already defined constructor for class PSCWS2,我想是highman大神太久没有更新了,文坛都是2008年的,我才上高中。我现在没有时间去研究为什么他会报错了,指导老师天天催着做设计(我的专业和计算机不搭嘎)。但是把php.inidisplay erros屏蔽掉时候还是能看到结果的。
下面是一个测试demo,我测过可以分词,不管是gbk/gb2312 还是utf-8,都可以成功分词。关于pscws请到官方自行下载http://www.xunsearch.com/scws/

  • require 'pscws2.class.php';

  • $str="你好吗天气好吗";
  • $encode = mb_detect_encoding($str, array("ASCII","UTF-8","GB2312","GBK","BIG5")); //获得编码
  • echo $encode;
  • $str=iconv($encode,"GBK",$str);//转码
  • $pscws = new PSCWS2('./dict/dict.xdb');//实例化对象,参数为路径,部分省略详见官网
  • $res = $pscws->segment($str);//返回的是数组哦
  • $res=implode(" ",$res);
  • $encode = mb_detect_encoding($res, array("ASCII","UTF-8","GB2312","GBK","BIG5"));
  • $res=iconv($encode,"UTF-8",$res);
  • echo $encode;
  • print_r($res

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 顶 踩
您需要登录后才可以回帖 登录 | 注册

本版积分规则

Archiver|小黑屋| 碧海潮声大学生网  

Copyright © 2001-2013 Comsenz Inc.   All Rights Reserved.

Powered by Discuz! X3.2( 浙ICP备11026473号 )

快速回复 返回顶部 返回列表