首页 | PHP资讯 | 技术专栏 | 资源共享 | PHP培训 | PHP职场 | 图书 | PHP ON WIN | PHP圈子
返回列表 回复 发帖

[ZendFramework] [组件]Zend_Search_Lucene的,支持中文

[ZendFramework] [组件]Zend_Search_Lucene的,支持中文

本帖最后由 七月十五 于 2009-5-16 13:45 编辑

首先按照hightman的方法给Zend Framework打个补丁,具体请看:
http://bbs.chinaunix.net/archiver/?tid-746635.html

然后自己实现分词方法,我的分词方法是按照hightman的php简易分词程序改写的,比他的还简易,当然正确率低。
代码写的时候因为赶时间,看上去比较dirty

[PHP]
<?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);
    }
}
?>

[/PHP]

新建索引:
[PHP]
        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;
        }
[/PHP]


检索的时候:
[PHP]
/** 进行分词 **/
                $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);
[/PHP]
修改成高亮显示..好读一些
不错,支持!
楼上的老大,有没有实际的例子给个url看看 效果

顶一下

好东西
其实我就是改变社会风气,风靡万千少女,
刺激PHP市场,提高年轻人内涵,
玉树临风,风度翩翩的PHPer

Zend::loadClass("Faq_Model_Dict"); 词典谁提供一下啊

系统中好象没有这个文件
返回列表