本帖最后由 七月十五 于 2009-5-16 13:45 编辑
首先按照hightman的方法给Zend Framework打个补丁,具体请看:
http://bbs.chinaunix.net/archiver/?tid-746635.html
然后自己实现分词方法,我的分词方法是按照hightman的php简易分词程序改写的,比他的还简易,当然正确率低。
代码写的时候因为赶时间,看上去比较dirty
<?php
Zend::loadClass("Zend_Search_Lucene_Analysis_Analyzer_Common");
Zend::loadClass("Faq_Model_Dict");
class Faq_MySearch_MyAnalyzer extends Zend_Search_Lucene_Analysis_Analyzer_Common
{
/** 成词标记 **/
const _WORD_ALONE_ = 0x4000000;
/** 词根标记 **/
const _WORD_PART_ = 0x8000000;
/**
* 待分词的文字
*
* @var string
*/
protected $_strData;
/**
* 句子的长度(字符数)
*
* @var int
*/
protected $_intLen;
/**
* 词典
*
* @var Dict
*/
protected $_objDict;
/**
* 字母
*
* @var string
*/
protected $_strAlphaChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
/**
* 数字
*
* @var string
*/
protected $_strNumChars = "01234567890123456789";
/**
* 标点
*
* @var string
*/
protected $_strSignChars = "~`!@#\$%^&*()_-+=|\\{}[]:\";'<>,.?/~!@#$%︿&*()_-+=|、{}[]:;“”‘’《》,。?/`……¥";
/**
* 对一段文字分词,返回Token
*
* @param string $strData
* @return array
*/
public function tokenize($strData){
$arrRet = $this->scsw($strData);
//处理完毕,$arrRet即为分词结果
foreach($arrRet as $arrWord){
$objToken = new Zend_Search_Lucene_Analysis_Token($arrWord[0],$arrWord[1],$arrWord[1]+strlen($arrWord[0]));
$arrToken[] = $this->normalize($objToken);
}
//($arrToken);
return $arrToken;
}
/**
* 对一段文字分词,返回一个数组
*
* @param string $strData
* @return array
*/
public function scsw($strData){
$this->_objDict = new Faq_Model_Dict();
$this->_intLen = mb_strlen($strData);
$this->_strData = $strData;
$intLen = $this->_intLen;
$intOffset = 0;
$intSOffset = 0; //单字节位置
$strLastType = "space"; //当前状态为空白
$strWord = "";
$arrRet = array();
while($intOffset < $intLen){
//取得一个字符
$strChar = mb_substr($strData,$intOffset,1);
$intOffset++;
if($this->_isAlpha($strChar)){
//是一个字母
if($strLastType!="alpha"&&$strWord!=""){
//如果前一个字符不是字母不是空白,且词不为空,则记录这个词
$arrRet[] = array($strWord,$intSOffset);
$intSOffset += strlen($strWord);
$strWord = "";
}
//然后继续读取
$strWord .= $strChar;
$strLastType = "alpha";
continue;
}else if($this->_isNum($strChar)){
//是一个数字
if($strLastType!="num"&&$strWord!=""){
//如果前一个字符不是数字不是空白,且词不为空,则记录这个词
$arrRet[] = array($strWord,$intSOffset);
$intSOffset += strlen($strWord);
$strWord = "";
}
//然后继续读取
$strWord .= $strChar;
$strLastType = "num";
continue;
}else if($this->_isSpace($strChar)){
//是一个空白
if($strLastType!="space"&&$strWord!=""){
//如果前一个字符不是空白,且词不为空,则记录这个词
$arrRet[] = array($strWord,$intSOffset);
$intSOffset += strlen($strWord);
$strWord = "";
}
//不读取空白
$strLastType = "space";
$intSOffset += strlen($strChar);
continue;
}elseif(ord($strChar)>=176){
//其它字符
if($strLastType!="cword"&&$strWord!=""){
//如果前一个字符不是汉字,且词不为空,则记录这个词
$arrRet[] = array($strWord,$intSOffset);
$intSOffset += strlen($strWord);
$strWord = "";
}
$strLastType = "cword";
//继续读取
if($arrRow = $this->_objDict->find($strWord.$strChar)){
//是词
$intFreqE = $arrRow->info;
if($intFreqE & self::_WORD_PART_ ){
//是词根
$strWord .= $strChar;
continue;
}elseif ($intFreqE & self::_WORD_ALONE_){
//是成词
$arrRet[] = array($strWord.$strChar,$intSOffset);
$intSOffset += strlen($strWord.$strChar);
$strWord = "";
continue;
}
}
//不是词,记录旧词,开始一个新词
if($strWord!=""){
$arrRet[] = array($strWord,$intSOffset);
$intSOffset += strlen($strWord);
}
$strWord = $strChar;
continue;
}
}
if($strWord!=""){
$arrRet[] = array($strWord,$intSOffset);
}
return $arrRet;
}
/**
* 判断是否是字母
*
* @param string $strChar
* @return boolean
*/
protected function _isAlpha($strChar){
$intPos = mb_strpos($this->_strAlphaChars, $strChar);
return ($intPos !== false);
}
/**
* 判断是否为数字
*
* @param string $strChar
* @return boolean
*/
protected function _isNum($strChar){
$intPos = mb_strpos($this->_strNumChars, $strChar);
return ($intPos !== false);
}
/**
* 判断是否是空白或标点
*
* @param string $strChar
* @return boolean
*/
protected function _isSpace($strChar){
$intOrd = ord($strChar);
if ($intOrd === 0x0d || $intOrd === 0x20 || $intOrd === 0x09){
return true;
}
$intPos = mb_strpos($this->_strSignChars, $strChar);
return ($intPos !== false);
}
}
?>
复制代码 新建索引:function addIndex($content,$id,$cat_id){
$objLucene = new Zend_Search_Lucene(INDEX_PATH);
$objDoc = new Zend_Search_Lucene_Document();
$objDoc->addField(Zend_Search_Lucene_Field::UnStored('contents', $content));
$objDoc->addField(Zend_Search_Lucene_Field::Text('faqid', $id));
$objDoc->addField(Zend_Search_Lucene_Field::Text('catid', $cat_id));
$objLucene->addDocument($objDoc);
$objLucene->commit();
return true;
}
复制代码 检索的时候:/** 进行分词 **/
$arrRet = $objAnalyzer->scsw($res['question']);
/** 开始检索 **/
$query = new Zend_Search_Lucene_Search_Query_MultiTerm();
foreach ($arrRet as $arrWord) {
$query->addTerm(new Zend_Search_lucene_Index_term($arrWord[0]));
}
$query->addTerm(new Zend_Search_lucene_Index_term($res['cat_id'],"catid"));
$index = new Zend_Search_Lucene(INDEX_PATH);
$hits = $index->find($query);
复制代码 |