免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12
最近访问板块 发新帖
楼主: hightman
打印 上一主题 下一主题

[下载] php版简易中文分词代码及词典(新加cscwsd) [复制链接]

论坛徽章:
0
11 [报告]
发表于 2005-12-03 21:09 |显示全部楼层
回 38楼,请使用 php4 , 在 php5下经多位网友测试读取 cdb库时均有问题.

论坛徽章:
0
12 [报告]
发表于 2005-12-08 10:41 |显示全部楼层
原帖由 wildlily980 于 2005-12-7 23:21 发表
                        if (($p = strpos($this->_mb_num2_chars, $zh)) === false
                                || ($p & 0x01))
                                break;

                        if ($ret === 0)
                        {
                                // 严格起始: 第/一二三 ...
                                if ($p >= 66)
                                        break;
                        }


因为 p 是前面 strpos() 的值, 而 _mb_num2_chars 是一长串字符, 偏移 66 即第 33字起是一些修饰词, 如: 点, 年, 分 ...

智能识别数字时间时要求完全从 第,一,二,三 开始, 所以这样判断一下

论坛徽章:
0
13 [报告]
发表于 2006-05-28 13:06 |显示全部楼层

回复 1楼 hightman 的帖子

再顶一下, 楼贴已更新, 增加 cscwsd 0.0.1

详情在 C 版, 这里作部分拷复
http://bbs.chinaunix.net/viewthr ... &extra=page%3D1
  http://scws.tguanlim.com/_csource/  是用doxygen生成的源码查看页

cscwsd 是英文全称 C-Simpled Chinese Word Segment Daemon 的首字缩写, 这是用标准纯 C 编写, 并配合使用 autoconf GNU软件工具包, 基本上可以很方便在的各类 Unix-Like OS 系统下顺利编译执行. 目前测试过的有 RedHat Linux (as3,as4)  FreeBSD 4.10, 5.4 ..目前只支持  GBK 编码

BTW: 用 autoconf 开发包编译出来的可执行文件约为 60~80K 视操作系统而定, 比较大, 我在 Linux 底下自己编制了一个小的 makefile 在 src/makefile.test  util/makefile.test , 编译结果是 20KB 左右, 有兴趣的可以试试
(无需 configure, 进入 util/ 目录 make -f makefile.test; 进行 src 目录 make -f makefiel.test ,然后使用 src/cscwsd 即可)

这个小程序的基本工作方式如下, 运行后在本地绑定一个端口 (缺省是 4700) 监听处理分词服务, 基本上无别的功能, 只针对输入的文字原样进行分词后然后原样输出, 注意每次输入均以 "\n" 作为处理标记, 即一行处理一次并返回.

这样作的目的在于提高分词的效率, 由专门的一支程序来处理, 别的程序只需通过 socket 与其对话即可, 客户端用什么语言都方便的实现,发布包中附带了一个 misc/CWS_test.web.php , 可以在 web 上测试分词..  速度比原 PHP直接分词要提高数十倍

而词典采用的是 .txt 格式, 解决了编辑困扰问题, 格式非常简单, 一行一条目, 词与频率之间用(TAB制表符或空格)分开

具体的程序运行说明, 请参看发布包中的 README

下载地址:  http://scws.tguanlim.com/cscwsd-0.0.1.tar.gz   在线测试: http://scws.tguanlim.com/by_server.php

安装方法:

tar xvzf cscwsd-0.0.1.tar.gz
cd cscwsd-0.0.1
./configure --prefix=/usr/local
make
make install

这样缺省就会把 cscwsd 安装到 /usr/local/sbin/ 中, 而词典 dict.txt 会安装到 /usr/local/etc 中, 请运行:

cscwsd -h  查看帮助说明

快速测试

./cscwsd -D -L /tmp/test.log

服务程序会切入后台服务, 所有的日志记录在 test.log 中, 你可以在本机 telnet localhost 4700

输入一句话试试分词效果, 类似的如下:

[hightman@sata cscwsd]$ telnet localhost 4700
Trying 127.0.0.1...
Connected to sata.sunbo.com (127.0.0.1).
Escape character is '^]'.
我是中国人
我是 中国人
/bye

论坛徽章:
0
14 [报告]
发表于 2006-05-28 17:49 |显示全部楼层
顺便发布刚刚作好的 PHP 访问 cscwsd 的操作类, 最后附了一个小例子.
这样搭配用起来的话,效率相当可观,  粗估了一下1秒可以处理100万字符以上, 这样作甚至可能比作成PHP扩展还要好.

关于分词准确度方面还请大家共同继续改进, 不希望太复杂的算法, 马马虎虎过得去就可以了


  1. <?php
  2. /**
  3.   cscwsd-0.0.1 (PHP版查询交互程序示例版)
  4.   由于服务器互无法显性判断数据读取的始终, 故目前 socket 设为无阻塞模式
  5.   
  6.   尝试读取一定次数后仍没数据就假设已经读完, 在 close() 前调用 recv() 会比较浪费资源.
  7.   这一点请注意, 务必一个 send() 对应一次 recv()

  8.   send 时程序自动在 string 的最后插了一个 '\x01'

  9.   PHP 版本要求 >= 4.3.0

  10.   类用法:

  11.   建立操作句柄: server,port 开启  
  12.   $cws = new CSCWS('localhost', 4700);
  13.   $cws->open('localhost', 4700);        // 若已打开且port/host不对就先关闭旧的  
  14.   $cws = CSCWS::open('localhost', 4700);

  15.   查询分词(自动侦测连接?):
  16.   $cws->send("我是中国人");

  17.   获取结果
  18.   echo $cws->recv();

  19.   设定参数: key=>value
  20.   binary        => (on)
  21.   autodis        => (on|off)
  22.   ignore_mark => (yes|no)
  23.   delim => '_|/'...

  24.   $cws->set("autodis", "yes")

  25.   关闭
  26.   $cws->close();

  27.   变量: dirty (多余的 read次数), rbuf (close之后续读的数据)

  28.   对于大量的输入输出, 处理上可能会有问题, 请务必再 ->close() 之后调用 $cws->rbuf 来查看

  29.   $Id: CWS_query.class.php,v 1.2 2006/05/28 09:19:42 hightman Exp $

  30. */

  31. // 纯英文或纯字母组成或纯数字
  32. define ('_SPECIAL_TAG_',        'abcdefgHgfedcba');
  33. define ('_SPECIAL_LEN_',        strlen(_SPECIAL_TAG_));
  34. define ('_SPECIAL_OFF_',        (-2 - _SPECIAL_LEN_));

  35. class CSCWS
  36. {
  37.         var $host        = 'localhost';
  38.         var $port        = 4700;
  39.         var $sock        = false;
  40.         var $rbuf        = '';
  41.         var $dirty        = 0;
  42.         var $clean        = 0;

  43.         /** construct function */
  44.         function CSCWS($host = '', $port = 0)
  45.         {
  46.                 if ($host !== '')
  47.                         $this->host = $host;
  48.                 if ($port !== 0)
  49.                         $this->port = $port;

  50.                 if ($host !== '')
  51.                         $this->open($this->host, $this->port);
  52.         }

  53.         /** return true on success or false on failed */
  54.         function &open($host, $port = 4700)
  55.         {
  56.                 if (!isset($this))
  57.                 {
  58.                         $cws = new CSCWS;
  59.                         $cws->open($host, $port);

  60.                         return $cws;
  61.                 }

  62.                 /** sock opened? */
  63.                 if ($this->sock !== false)
  64.                 {
  65.                         if ($host === $this->host && $port == $this->port)
  66.                                 return true;

  67.                         $this->close();
  68.                 }

  69.                 /** connect to the server */
  70.                 $this->host = $host;
  71.                 $this->port = $port;
  72.                 $this->sock = fsockopen($host, $port, $errno, $errstr, 10);
  73.                 if (!$this->sock)
  74.                 {
  75.                         trigger_error("fsockopen(): $errstr ($errno)", E_USER_WARNING);
  76.                         trigger_error("Failed to open cscwsd server by '$host:$port'.", E_USER_ERROR);

  77.                         return false;
  78.                 }
  79.                
  80.                 /** set to nonblock mode */
  81.                 stream_set_blocking($this->sock, 0);
  82.                 return true;
  83.         }

  84.         /** set the parameters */
  85.         function set($key, $value = 'on')
  86.         {
  87.                 if (!in_array($key, array('autodis', 'binary', 'delim', 'ignore_mark')))
  88.                         return;

  89.                 $str = "/set $key=$value\n";
  90.                 fwrite($this->sock, $str);
  91.         }

  92.         /** send the original string */
  93.         function send($str)
  94.         {
  95.                 $str = trim($str);
  96.                 if (empty($str))
  97.                         return false;

  98.                 if (!$this->sock)
  99.                         $this->open($this->host, $this->port);

  100.                 if (!$this->sock)
  101.                         return false;

  102.                 fwrite($this->sock, $str . _SPECIAL_TAG_ . "\n");
  103.         }

  104.         /** recv the segmented string, param: try times for end? */
  105.         function recv($maxtry = 1000)
  106.         {
  107.                 $try = 0;
  108.                 $frag = '';

  109.                 if (!$this->sock)
  110.                         return $this->rbuf;

  111.                 while (true)
  112.                 {                       
  113.                         $frag = fread($this->sock, 2048);

  114.                         if ($frag === '')
  115.                                 $try++;
  116.                         else
  117.                         {
  118.                                 $this->dirty += $try;
  119.                                 $this->clean++;
  120.                                 $try = 0;

  121.                                 if (substr($frag, _SPECIAL_OFF_, _SPECIAL_LEN_) == _SPECIAL_TAG_)
  122.                                 {
  123.                                         $str .= substr($frag, 0, _SPECIAL_OFF_);
  124.                                         break;
  125.                                 }
  126.                                 $str .= $frag;                       
  127.                         }

  128.                         if ($try > $maxtry)
  129.                                 break;

  130.                         if (feof($this->sock))       
  131.                                 break;                       
  132.                 }

  133.                 $this->dirty += $try;
  134.                 return $str;
  135.         }

  136.         /** close the connection */
  137.         function close()
  138.         {
  139.                 $this->send('/bye');
  140.                 $this->rbuf = '';

  141.                 while (!feof($this->sock))               
  142.                         $this->rbuf .= $this->recv();               

  143.                 fclose($this->sock);
  144.                 $this->sock = false;
  145.         }
  146. }

  147. // Sample01:
  148. /*
  149. $cws = &CSCWS::open('localhost');
  150. $cws->set("ignore_mark", "yes");
  151. $cws->set("delim", "_");
  152. $cws->send("我是中国人,你应该也是吧?\n哈哈by hightman2006");
  153. echo $cws->recv();
  154. $cws->close();
  155. echo $cws->recv();
  156. */
  157. ?>
复制代码

[ 本帖最后由 hightman 于 2006-5-28 22:23 编辑 ]

论坛徽章:
0
15 [报告]
发表于 2007-04-14 10:46 |显示全部楼层
原帖由 lonestone 于 2007-4-13 23:42 发表
我已经将这个组件用在了项目中,房产网站,搜索房屋信息,19万条记录,将地址分词后,将mysql5的全文索引修改为最短1个字(因为要较高的准确度),然后用match。。。against。。。布尔搜索,效果很不错。具体可以 ...


很好,能对大家有帮助也是发布这些东西的初衷.

呵呵,百万条数据也还蛮快的呢
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP