实现Joomla!中文全文检索,有很多方式,其中之一是采用Mysql的全文检索,而且网络上有一个mysql支持中文全文检索的补丁,印象中是一位hightman写的,他的关于全文检索的东西还是很实用的。另外一种方式就是用lucene这样的全文检索系统,还可以选择xapian,但是由于这样的系统搭建起来稍有麻烦,比如lucene就需要安装关于java的东西,还要装php-javabridge。
最终采用ZendFramework的Zend_Lucene来解决这个问题,虽然评论这有点效率低,但是考虑到与php完美的融合,最终还是采用了,最终试验的效果也不错。反正要加入索引的文章也不多,估计对于Joomla!来说,只要Joomla!那些冗长的查询语句还允许服务器支撑,估计这个全文检索就没问题,呵呵!
我的解决过程如下:
1、安装,请参考这篇文章 ZendFramework安装配置指南 安装ZendFramework,如果你仅仅是用其中的Zend_Lucene,其实也可以不必安装pdo部分。
2、ZendFramework中文检索,请参考这篇文章 Zend_Search_Lucene 如何支持中文检索 ,实际工作中,这篇文章的代码存在一些错误,以后我会提到。
3、创建一个组件,如果你不熟悉组件的书写,还是要学习一下,也可以用一下这个试试 Joomla 组件自动生成器(Comgen)-测试版发布 。嘿嘿,不过还是要熟悉php啊。
4、增加索引建立,更新索引功能,你可以在组件的controller.php文件中,增加一个function,代码如下:
function createindex(){
$db = & JFactory::getDBO();
$categories = array();
$sections = array();
$query = 'select * from #__categories';
$db->setQuery( $query );
$items = $db->loadObjectList();
if($items){
foreach ( $items as $item ){
$categories[$item->id]=$item->alias;
}
}
$query = 'select * from #__sections';
$db->setQuery( $query );
$items = $db->loadObjectList();
if($items){
foreach ( $items as $item ){
$sections[$item->id]=$item->alias;
}
}
$query='select * from #__content limit 10';
$db->setQuery( $query );
$items = $db->loadObjectList();
if($items){
$maxid = 0;
$index = null;
Zend_Search_Lucene_Analysis_Analyzer::setDefault(new Phpbean_Lucene_Analyzer());
if(file_exists('/home/apache/www/maycode/search/read.lock.file')){
$index = new Zend_Search_Lucene('/tmp/search');
}
else{
$index = new Zend_Search_Lucene('/tmp/search',true);
}
foreach ( $items as $item ){
echo $item->title.'<br/>';
$content=htmlentities(strip_tags($item->introtext),ENT_NOQUOTES,'UTF-8');
if($item->alias){
$slug = $item->id.':'.$item->alias;
}
else{
$slug = $item->id;
}
if($categories[$item->catid]){
$catslug = $item->catid.':'.$categories[$item->catid];
}
else{
$catslug = $item->catid;
}
$sectionid= $item->sectionid;
$createdate = $item->created;
$title = $item->title;
$doc = new Zend_Search_Lucene_Document();
$doc->addField(Zend_Search_Lucene_Field::Text('title', $title,'utf-8'));
$doc->addField(Zend_Search_Lucene_Field::Text('content', $content,'utf-8'));
$doc->addField(Zend_Search_Lucene_Field::UnIndexed('slug', $slug,'utf-8'));
$doc->addField(Zend_Search_Lucene_Field::UnIndexed('catslug', $catslug,'utf-8'));
$doc->addField(Zend_Search_Lucene_Field::UnIndexed('sectionid', $sectionid,'utf-8'));
$doc->addField(Zend_Search_Lucene_Field::UnIndexed('createdate', $createdate,'utf-8'));
$index->addDocument($doc);
$maxid = $item->id;
}
$index->commit();
}
}程序的3-20行,建立了Joomla! 文章category和section的散列数组,以备以后需要。
程序21-23行,从数据库中查询出了前10篇文章,你具体应用的时候,应该修改,加上发布状态等条件。
程序24-65行,则是循环将每个文章添加到索引中。让我们来逐一来看看。
程序27-33行,根据目的目录是否存在建立的索引文件,来判断是更新索引,还是新建索引。
注意程序第37行的对于文件内容的处理,因为我的数据库是utf-8字符集,所以htmlentities与我们最常用的方式稍有区别,以支持utf-8,否则,内容就会成为乱码了。
程序52-62行,是添加几个字段,其中只有title和content是需要索引的,而slug,catslug,sectionid主要都是用来建立链接用的。之所以不是直接把连接写进去,主要是为以后连接可能发生的变化,留下一个接口。
$index->commit(); 将更新写如文件。注意,有多少个commit就会有多少segement,所以这个最好不要常作。这点因为不能优化索引也是zend_lucene被诟病的地方。
索引的保存路径是/tmp/search,这个路径你可以自己设置,但是如果你是通过浏览器调用http://www.yourdomain.com/index.php?option=com_***&view=***&task=createindex ,那么这样你就需要那个目录有写入权限。
当然我推荐是后台定期调用,生成索引文件。
注意:我的数据库默认字符集是UTF-8,程序页面也都是。
(未完待续,接下来,将描述如何利用索引查询)