2010-05-07

开发搜索引擎 – PHP中文分词

Views: 24502 | Add Comments

对于中文搜索引擎来说, 中文分词是整个系统最基础的部分之一, 因为目前基于单字的中文搜索算法并不是太好. 当然, 本文不是要对中文搜索引擎做研究, 而是分享如果用 PHP 做一个站内搜索引擎. 本文是这个系统中的一篇.

我使用的分词工具是中科院计算所的开源版本的 ICTCLAS. 另外还有开源的 Bamboo, 我随后也会对该工具进行调研.

从 ICTCLAS 出发是个不错的选择, 因为其算法传播比较广泛, 有公开的学术文档, 并且编译简单, 库依赖少. 但目前只提供了 C/C++, Java 和 C# 版本的代码, 并没有 PHP 版本的代码. 怎么办呢? 也许可以学习它的 C/C++ 源码和学术文档中, 然后再开发一个 PHP 版本出来. 不过, 我要使用进程间通信, 在 PHP 代码里调用 C/C++ 版本的可执行文件.

下载源码解压后, 在有 C++ 开发库和编译环境的机器上直接 make ictclas 即可. 它的 Makefile 脚本有个错误, 执行测试的代码没有加上'./', 当然不能像 Windows 下执行成功了. 但也不影响编译结果.

进行中文分词的 PHP 类就在下面了, 用 proc_open() 函数来执行分词程序, 并通过管道和其交互, 输入要进行分词的文本, 读取分词结果.

<?php
class NLP{
    private static $cmd_path;

    // 不以'/'结尾
    static function set_cmd_path($path){
        self::$cmd_path = $path;
    }

    private function cmd($str){
        $descriptorspec = array(
           0 => array("pipe", "r"),
           1 => array("pipe", "w"),
        );
        $cmd = self::$cmd_path . "/ictclas";
        $process = proc_open($cmd, $descriptorspec, $pipes);
        
        if (is_resource($process)) {
            $str = iconv('utf-8', 'gbk', $str);
            fwrite($pipes[0], $str);
            fclose($pipes[0]);
            $output = stream_get_contents($pipes[1]);
            fclose($pipes[1]);

            $return_value = proc_close($process);
        }

        /*
        $cmd = "printf '$input' | " . self::$cmd_path . "/ictclas";
        exec($cmd, $output, $ret);
        $output = join("\n", $output);
        */

        $output = trim($output);
        $output = iconv('gbk', 'utf-8', $output);

        return $output;
    }

    /**
     * 进行分词, 返回词语列表.
     */
    function tokenize($str){
        $tokens = array();

        $output = self::cmd($str);
        if($output){
            $ps = preg_split('/\s+/', $output);
            foreach($ps as $p){
                list($seg, $tag) = explode('/', $p);
                $item = array(
                    'seg' => $seg,
                    'tag' => $tag,
                    );
                $tokens[] = $item;
            }
        }

        return $tokens;
    }
}
NLP::set_cmd_path(dirname(__FILE__));
?>

使用起来很简单(确保 ICTCLAS 编译后的可执行文件和词典在当前目录):

<?php
require_once('NLP.php');
var_dump(NLP::tokenize('你好啊, 世界!'));
?>

下一步将结合 ZendFramework 的 Zend_Search_Lucene 模块来做一个可以运行的中文搜索系统了!

Related posts:

  1. iphp 框架增加 lazyload 特性
  2. 集成于 iphp 框架的 PHP 并发模型和工具
  3. 史上最强大的PHP MySQL操作类
  4. 如何让 PHP json_encode 函数不转义中文?
  5. Zend Framework 的缓存模块 Zend_Cache 使用
Posted by ideawu at 2010-05-07 08:30:07 Tags: ,

Leave a Comment