Main

April 18, 2007

基于字符串匹配的中文分词

分词算法一般有三类:基于字符串匹配、基于语义分析、基于统计。复杂的分词程序会将各种算法结合起来以便提高准确率。

Lucene被很多公司用来提供站内搜索,但是Lucene本身并没有支持中文分词的组件,只是在Sandbox里面有两个组件支持中文分词:ChineseAnalyzer和CJKAnalyzer。
ChineseAnalyzer采取一个字符一个字符切分的方法,例如“我想去北京天安门广场”用ChineseAnalyzer分词后结果为: 我#想#去#北#京#天#安#门#广#场。
CJKAnalyzer则是二元分词法,即将相邻的两个字当成一个词,同样前面那句用CJKAnalyzer分词之后结果为:我想#想去#去北#北京#京天#天安#安门#门广#广场。
这两种分词方法都不支持中文和英文及数字混合的文本分词,例如:IBM T60HKU现在只要11000元就可以买到。用上述两种分词方法建立索引,不管是搜索IBM还是11000都是没办法搜索到的。另外,假如我们使用“服务器”作为关键字进行搜索时,只要文档包含“服务”和“器”就会出现在搜索结果中,但这显然是错误的。因此,ChineseAnalyzer和CJKAnalyzer虽然能够简单实现中文的分词,但是在应用中仍然会感觉到诸多不便。

基于字符串匹配的分词算法用得很多的是正向最大匹配和逆向最大匹配。其实这两种算法是大同小异的,只不过扫描的方向不同而已,但是逆向匹配的准确率会稍微高一些。"我想去北京天安门广场"这句使用最大正向分词匹配分词结果:我#想去#北京#天安门广场。这样分显然比ChineseAnalyzer和CJKAnalyzer来得准确,但是正向最大匹配是基于词典的,因此不同的词典对分词结果影响很大,比如有的词典里面会认为“北京天安门”是一个词,那么上面那句的分词结果则是:我#想去#北京天安门#广场。如果用“广场”作为关键字进行检索,那么使用后一个词典分出来的便可检索到,而使用前一个的则不行,而事实上应该是不管搜索北京天安门、天安门广场、天安门、广场都能检索到这篇文档。使用全切分可以实现这个想法,同样是那句使用正向全切分分词结果为:我#想去#北京天安门#北京#天安门#天安门广场#广场,这样不管用”北京天安门“、”天安门广场“、”天安门“、”广场“中的哪一个作为关键字搜索都可以搜索到。采取这种分法会在一定程度上提高分词的准确率,但也会出现问题,例如“我要在上海南站上车”这句采用正向全切分结果为:我#要在#上海#海南#南站,分出海南这个词显然是错误的,这属于交叉歧义。这有一篇声称可以检测所有交叉歧义的分词算法论文,我没去实现过,所以不知道真正的效果到底如何。

正如前面所说,基于字符串匹配的分词算法都是依赖于词典的,但是不管再怎么大的词典也未必能完全收录所有词汇,况且不断的有新词出现,还有就是人名的识别,因此分词程序如果能够识别出一些词典中所没有的新词的话,有助于提高分词的准确率。最简单的识别新词的方法可以基于统计,一般来说如果两个字不断重复的出现在一起那么他们组成一个词的频率就比较大。基于单字共现的统计方法计算两个汉字A和B(也可能是三个或更多)的相邻共现概率,当这种概率值大于一定的阀值时,我们就认为这两个字可以组词。经常被用来做新词识别的统计理论有:N - 元模型、后缀数组等。

February 03, 2007

memcached+squid+apache deflate解决网站大访问量问题

不许联想的RSS之前停了两天,据说是因为服务器负荷不了技术人员建议给关了,不输出RSS能减轻多少负载呢?所以月光博客不干了,出来给支了几招,但对于个人博客可能管用,对于流量更大的专业网站显然需要进一步的优化。途牛最近的访问量增长得比较快,所以很多页面load比较慢。之前我们就一直使用memcached进行了缓存以减轻数据库的压力,近期又对sql查询进行了优化,数据库的性能得到了明显的改善。途牛有很大一部分资源是图片,针对这个我们使用squid进行了缓存,这部分还包括js、css等一些静态文件。由于我们又有社区,用户的反馈比较多,所以页面并没有使用缓存,而是使用Apache的deflate模块进行压缩。技术实现都比较简单但非常实用,通过这几步优化,途牛在响应速度上有了不小的提高。

squid 2.6缓存多个虚拟机配置及常用命令

安装笔记中的大多配置是默认的,作为测试用,如果要用到生产环境中还需更详细的配置,然后根据服务器运行状况不断调整,一般服务器可能会有多个虚拟主机,通过配置squid可以轻松为同一服务器上的多个虚拟主机进行缓存
cache_peer www.example.org.cn parent 80 0 no-query originserver
cache_peer www.example.net.cn parent 80 0 no-query originserver
acl exampleorg dstdomain .example.org.cn
acl examplenet dstdomain .example.net.cn

##1th
cache_peer_domain www.example.org.cn .example.org.cn
cache_peer_domain www.example.net.cn .example.net.cn
http_access allow exampleorg
http_access allow examplenet
http_access deny all
##2nd
cache_peer_access www.example.org.cn allow exampleorg
cache_peer_access www.example.net.cn allow examplenet
cache_peer_access www.example.org.cn deny all
cache_peer_access www.example.net.cn deny all
以上两种方式都可以达到为同一服务器上的多个虚拟主机进行缓存的目的,2.6改进之后配置相当灵活,包括Log配置、缓存规则配置、支持虚拟主机配置

另外需要注意一点的是经过apache的deflate模块压缩的文件可能不会被缓存,只要配置一下就可以
cache_vary on

squid常用命令:
/usr/local/squid/sbin/squid -z 初始化缓存空间
/usr/local/squid/sbin/squid 启动
/usr/local/squid/sbin/squid -k shutdown 停止
/usr/local/squid/sbin/squid -k reconfigure 重新载入配置文件
/usr/local/squid/sbin/squid -k rotate 轮循日志

February 02, 2007

squid 2.6 安装配置笔记

使用当前最新的稳定版本squid-2.6.STABLE9

配置选项
./configure --prefix=/usr/local/squid \
--enable-poll \
--enable-snmp \
--enable-removal-policies="heap,lru" \
--enable-storeio="aufs,coss,diskd,null,ufs" \
--enable-ssl \
--enable-delay-pools \
--enable-linux-netfilter \
--enable-useragent-log \
--enable-referer-log \
--enable-truncate \
--enable-underscores \
--enable-basic-auth-helpers="NCSA" \
--enable-err-language="Simplify_Chinese" \
--enable-default-err-language="Simplify_Chinese" \
--enable-stacktrace \
--enable-auth="basic" \
--disable-dependency-tracking \
--disable-internal-dns \
--with-openssl=/usr/kerberos \
--with-pthreads \
--with-winbind-auth-challenge

配置文件
# NETWORK OPTIONS
# -----------------------------------------------------------------------------
http_port 192.168.0.1:80 vhost vport
icp_port 0
cache_peer 192.168.0.1 parent 81 0 no-query originserver

# OPTIONS WHICH AFFECT THE NEIGHBOR SELECTION ALGORITHM
# -----------------------------------------------------------------------------
hierarchy_stoplist cgi-bin ?
acl QUERY urlpath_regex cgi-bin \?
cache deny QUERY
acl IMAGE urlpath_regex images
cache deny !IMAGE
acl apache rep_header Server ^Apache
broken_vary_encoding allow apache


# OPTIONS WHICH AFFECT THE CACHE SIZE
# -----------------------------------------------------------------------------
cache_mem 512 MB
cache_swap_low 90
cache_swap_high 95
maximum_object_size 4096 KB
minimum_object_size 0 KB
maximum_object_size_in_memory 80 KB

# LOGFILE PATHNAMES AND CACHE DIRECTORIES
# -----------------------------------------------------------------------------
cache_dir ufs /usr/local/squid/var/cache 1024 56 256
access_log /usr/local/squid/var/logs/access.log squid
cache_log /usr/local/squid/var/logs/cache.log
#cache_store_log /usr/local/squid/var/logs/store.log
emulate_httpd_log on
pid_filename /usr/local/squid/var/logs/squid.pid

# ACCESS CONTROLS
# -----------------------------------------------------------------------------
acl all src 0.0.0.0/0.0.0.0
acl example dstdomain .example.org.cn
acl Safe_ports port 80 # http
acl Safe_ports port 81 # http
http_access allow example
http_access deny !Safe_ports
http_access deny all
http_reply_access allow all
icp_access deny all

# ADMINISTRATIVE PARAMETERS
# -----------------------------------------------------------------------------
cache_mgr david.chenfuwei@gmail.com
cache_effective_user squid
cache_effective_group squid
visible_hostname www.example.org.cn

# MISCELLANEOUS
# -----------------------------------------------------------------------------
logfile_rotate 0
tcp_recv_bufsize 65535 bytes
error_directory /usr/local/squid/share/errors/Simplify_Chinese

# DELAY POOL PARAMETERS (all require DELAY_POOLS compilation option)
# -----------------------------------------------------------------------------
coredump_dir /usr/local/squid/var/cache
client_persistent_connections off
server_persistent_connections on

January 28, 2007

mysql查询性能优化

mysql的优化可以从硬件设备的选择、操作系统、数据库结构设计、SQL查询、应用程序各个方面进行y优化,这里只从数据库的设计及查询语句方面进行优化。

1,创建索引
对于查询占主要的应用来说,索引显得尤为重要。很多时候性能问题很简单的就是因为我们忘了添加索引而造成的,或者说没有添加更为有效的索引导致。如果不加索引的话,那么查找任何哪怕只是一条特定的数据都会进行一次全表扫描,如果一张表的数据量很大而符合条件的结果又很少,那么不加索引会引起致命的性能下降。但是也不是什么情况都非得建索引不可,比如性别可能就只有两个值,建索引不仅没什么优势,还会影响到更新速度,这被称为过度索引。

2,复合索引
比如有一条语句是这样的:select * from users where area='beijing' and age=22;
如果我们是在area和age上分别创建单个索引的话,由于mysql查询每次只能使用一个索引,所以虽然这样已经相对不做索引时全表扫描提高了很多效率,但是如果在area、age两列上创建复合索引的话将带来更高的效率。如果我们创建了(area, age, salary)的复合索引,那么其实相当于创建了(area,age,salary)、(area,age)、(area)三个索引,这被称为最佳左前缀特性。因此我们在创建复合索引时应该将最常用作限制条件的列放在最左边,依次递减。

3,索引不会包含有NULL值的列
只要列中包含有NULL值都将不会被包含在索引中,复合索引中只要有一列含有NULL值,那么这一列对于此复合索引就是无效的。所以我们在数据库设计时不要让字段的默认值为NULL。

4,使用短索引
对串列进行索引,如果可能应该指定一个前缀长度。例如,如果有一个CHAR(255)的 列,如果在前10 个或20 个字符内,多数值是惟一的,那么就不要对整个列进行索引。短索引不仅可以提高查询速度而且可以节省磁盘空间和I/O操作。

5,排序的索引问题
mysql查询只使用一个索引,因此如果where子句中已经使用了索引的话,那么order by中的列是不会使用索引的。因此数据库默认排序可以符合要求的情况下不要使用排序操作;尽量不要包含多个列的排序,如果需要最好给这些列创建复合索引。

6,like语句操作
一般情况下不鼓励使用like操作,如果非使用不可,如何使用也是一个问题。like "%aaa%" 不会使用索引而like "aaa%"可以使用索引。

7,不要在列上进行运算
select * from users where YEAR(adddate)<2007;将在每个行上进行运算,这将导致索引失效而进行全表扫描,因此我们可以改成select * from users where adddate<‘2007-01-01’;

8,不使用NOT IN和<>操作
NOT IN和<>操作都不会使用索引将进行全表扫描。NOT IN可以NOT EXISTS代替,id<>3则可使用id>3 or id<3来代替。

January 21, 2007

从REST看WEB全面Servcice

ROR两天前正式发布了 1.2版本,David H. Hansson在blog上详细的描述了1.2增加的新特性和改进。其中最吸引人的特性当然是对REST的全面支持,web service再一次站到了前排。鼓吹web service已经有好几年的时间了,然而SOAP等重型装备虽然在一些企业应用中占有一席之地,却始终无法得到web开发社区的认可。现在有人将已经占据统治地位六年之久的SOAP描述为死星不可避免的灭亡,再联想到Google抛弃了SOAP API改而使用AJAX提供搜索服务,以及AmazondeliciousFlickr对于REST的支持,很容易让人相信WEB社区激动的变革即将产生。
REST(Representational State Transfer)翻为中文是具象状态传输,其最核心的观念转变便是面向资源的web service而不是传统的面向行为。每个资源都有一个唯一的URI来定位,对于此资源的操作则通过HTTP协议的四个主要命令GET、POST、PUT、DELETE来控制。换句话说REST暴露的URI只是用来定位资源用的,而我们要操作的动作则用HTTP中的四个主要命令来表示。试想在以前,我们要增加、更新、浏览、删除一篇文章我们可能都会用POST的方式去请求,而事实上HTTP的四个命令天生就是用来代表这四个动作的,就象在数据库中我们使用CRUD一样。ROR在一开始引入active recode已经掀起了一股热潮,其他社区的framework纷纷模仿这一模式,这一次ROR又率先将人们在开发WEB时对于请求方式固化为POST和GET方式进行了颠覆。
人们对于web的service化已经讨论和期待了很久之后,netvibes之类的网站越来越被看好,google也将自己的很多应用开放了API,ROR的持续升温和大胆变革,以AJAX为代表的RIA开发方式,web服务整合的年代已经到来。将来web开发有人专门提供基础服务,以API的方式开放,有人专做整合,将各种底层服务整合成一个独特的应用,就像IBM广告炫耀的:我们的优势就是整合。

参考资料:
SIP/IMS网络中的Representational State Transfer (REST)和数据分布
http://dev2dev.bea.com.cn/bbsdoc/20060529259.html
面向资源与面向活动的 Web 服务
http://www-128.ibm.com/developerworks/cn/webservices/ws-restvsoap/
REST:Rails 1.2的意义,以及一个翻译接力的发起
http://blog.csdn.net/myan/archive/2006/11/25/1413937.aspx

January 14, 2007

awk学习笔记

awk用于处理结构化的数据比如数据报表,一种文本处理功能强大的编程语言。

Linux下的/etc/passwd文件拿来当试手的例子非常合适。
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
这是我取我机器上这个文件的前5行,用来做测试

$ awk -F ":" '{ print }' passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin

$ awk -F ":" '{ print $0 }' passwd 得到的结果和上面一摸一样

$ awk -F ":" '{print $1,$2}' passwd
root x
bin x
daemon x
adm x
lp x
-F ":"表示以:为分割符号,默认以空格分割。$0表示当前的整个行,而$1,$2...则相应代表分割后的列

逗号则让列与列之间插入空格
$ awk -F ":" '{print $1 $2}' passwd
rootx
binx
daemonx
admx
lpx
也可以使用插入字符来到达格式化的效果,$ awk -F ":" '{print $1 ” “ $2}' passwd和$ awk -F ":" '{print $1,$2}' passwd得到的结果是一样的

$ awk -F ":" '/root/{print "uid:" $3}' passwd
uid:0
这里使用了正则匹配,含有root的行输出第三列,这里就是uid

$ awk -F ":" '/^(root|bin)/{print $1}' passwd
root
bin
匹配以root或bin开头的行

$ awk -F ":" '$3==0 {print $0}' passwd
root:x:0:0:root:/root:/bin/bash
可以使用表达式,当uid等于0时输出这一行

还可以做数值运算
$ awk -F ":" '$3==0 {print $3+10}' passwd
10

$ awk -F ":" '{print ($3 > 1 ? "yes":"no")}' passwd
no
no
yes
yes
yes

$ awk -F ":" '/^root/,/^daemon/{print $0}' passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
匹配以root开头的行到以daemon开头的行,如果没有以daemon开头的行则将打印到文件末尾

$ awk -F ":" '$1~/bin/{i=$3+$4; print "i=" i}' passwd
i=2
既然awk是一种编程语言,我们就能够使用变量,上面就是匹配第一列以bin开头的行,取出第三和第四列相加赋值给i然后打印
我们还可以将在命令行中赋值的变量带到awk脚本中
$ awk -F ":" -f script i=1 j=2 passwd
这样在脚本script中可以使用i和j,它们分别被赋值1和2,这和在脚本中定义变量是一样的

$ awk 'BEGIN{FS=":"; OFS=" "; ORS="\n"} {print $1} END{print NR}' passwd
root
bin
daemon
adm
lp
5
BEGIN和END中的代码快分别在匹配文件之前和之后执行,FS,OFS,ORS,NR都是awk的内建变量
上例的意思是将分割符设为:,输出分割符为空格,换行符为行之间的分隔符,NR代表匹配的行数

$ awk -F ":" '$3==0 {print $0 > "root.txt" }' passwd
使用重定向将结果输出到root.txt中

$ awk -F ":" '{if($3==0){print "yes"} else {print "no"}}' passwd
yes
no
no
no
no
awk中的条件判断语句
if(expr){
statment;
}else{
statment;
}

$ awk -F ":" '$1~/root/{for (i=1; i < NF; i++) print i,$i}' passwd
1 root
2 x
3 0
4 0
5 root
6 /root
for循环语句
awk -F ":" '$1~/root/{i=1;while(i < NF){print i,$i;i++}}' passwd
使用while打印出与上面的for语句一样的结果

$ awk -F ":" '{gsub(/root/, "david"); print}' passwd
david:x:0:0:david:/david:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
使用awk的内建函数,将root替换为david


参考文档:
IBM的awk实例
http://www-128.ibm.com/developerworks/cn/linux/shell/awk/awk-1/
http://www-128.ibm.com/developerworks/cn/linux/shell/awk/awk-2/
http://www-128.ibm.com/developerworks/cn/linux/shell/awk/awk-3/

January 13, 2007

sed学习笔记

sed是一种在线编辑器,它一次处理一行内容。

一般sed有两种调用方式:
sed [options] 'command' {filenames}
sed [options] -f scriptfile {filenames}

删除操作,命令d
$ sed '3d' test 删除test文件的第三行
$ sed '1,3d' test 删除test文件的第一行到的三行
$ sed '3,$d' test 删除的第三行后的所有行
$ sed '/^A/d' test 删除以A开头的行
$ sed '/david/d' test 删除包含有david的所有行

打印操作,命令p
$ sed -n '/david/p' test 只输出含有david的行
$ sed -n '/david/,/wade/p' test 匹配从包含有david的行到包含有wade的行之前所有行,如果匹配不到wade则匹配从含有david的行开始的所有行
$ sed -n -e '=' -e 'p' test 打印行号和每一行,-e使得=和p先后作用于一行

替换操作,命令s
$ sed 's/david/wade/g' test 将每一行的david替换为wade,g代表全局替换,否则将只替换每行第一个
$ sed '1,3s/david/wade/g' test 将第一行到第三行的david替换成wade
$ sed 's:/home/david:/home/wade:g' test 将/home/david替换为/home/wade,这里用:取代/为分割符
$ sed -n 's/^david/wade/p' test 将以david开头的行替换成wade开头并打印
$ sed -n 's/\(log\)in/\1out/p' test 将login以logout替换并打印
$ sed 's/.*/david: &/' test 在每行前面加上加上david:,&代表匹配到的本身

插入操作,命令i,a,c
$ sed '/david/i\hello world!' test 在含有david的行之前加入内容为'hello world!'的行
$ sed '/david/a\hello world!' test 在含有david的行之后加入内容为'hello world!'的行
$ sed '/david/c\hello world!' test 把含有david的行替换为内容为he'llo world!'的行

文件操作,命令r,w
$ sed '/david/r test1' test 将test1的内容读入显示在与david匹配的行后面
$ sed -n '/david/w test' test1 将test1中包含david的行写入test中

保持并替换,命令h,x
$ sed -e '/wade/h' -e '/david/x' test 用含有wade的行替换含有david的行替换

保持并获取,命令h,G
$ sed -e '/david/h' -e '/wade/G' test 把含有david的行保存并插入含有wade的行的后面

处理下一行,命令n
$ sed '/david/{ n; s/hello/wade/; }' test 匹配到david后移到下一行并将这一行的hello替换为wade

January 10, 2007

在Linux上运行IE7

做WEB开发当然希望尽可能兼容各种浏览器,但通过分析途牛的访问者可以发现,有大概95%以上的中国用户使用IE浏览器,因此如果说我们首先满足IE用户的话也算是“相信数据”的一种体现了吧。我用的是IEs4Linux,在Ubuntu6.06下IE6模式看起来效果不是很好,但是用来测试兼容性还是足够的,反正平时自己还是用firefox。今天发现一篇介绍在linux上运行IE7的文章,现在用IE7的并不多,途牛的后台数据显示只有大概不到2%的人使用。

January 06, 2007

网站备份

曾经有一个机会摆在我面前,我没有好好珍惜,如果上天再给我一次机会,我会说:我一定要备份,如果一定要给这个备份加一个保险,那就是多备一个。

丢失数据的经验很多人都有,可能是因为操作错误、硬盘损坏或者黑客光顾,总之,当你丢失了重要数据的那一刻,你或许会庆幸自己买了保险--备份。如果没有,那么你只能默哀了。找出多少理由来说明需要备份都是不为过的,如果你还是一个网站维护人员的话,那么备份就显得尤为重要。那么什么东西是需要备份的,用什么工具备份,备份在哪里,什么时候备份?这大概就是我们需要关注的关于备份的事项。
对于网站来说,硬件设备、数据、应用程序基本上是我们需要有后备的元素。首先是硬件,也就是硬件服务器,我们一般希望当一台服务器宕掉的时候,有另一台服务器可以顶上而不会影响网站的营运和服务,也就是所谓的主机备份。一般就是做集群,然后又分什么双机热备、双机互备、双机双工(哪来这么多概念呀?),方法有很多,唯一的目的就是希望即使有部分服务器不能提供服务了也不会影响整个网站的运行,直到坏掉的服务器重新投入工作。而服务器一般又会分为应用服务器和数据库服务器,所以相应的有应用服务器集群和数据库服务器集群,这方面一个藏袍在分析LiveJournal网站架构时有比较深入的阐述,其他的实现集群的方法也有很多。
数据备份简单理解就是在别的地方再放一份数据。在服务器上需要备份的数据可能是网站的一些资源文件、数据库、应用程序、email,数据库如果是mysql可以直接使用musqldump备份成文件,然后跟其他文件一起做备份。即使有版本管理系统并且进行了night build,我们也需要备份一份能正常运行的完善的系统,因为除了代码之外应用程序可能还包含了许多和生产环境相关的配置。从备份手段方面讲,最简单就是使用诸如tar这样的程序,打包压缩之后转存到其他的存储介质上,还可以使用ssh/scp进行跨服务器备份,将数据定期从一台机器搬到另一台机器。第三种方法是将数据备份到其他介质,比如使用磁带机进行备份。还有就是使用RAID进行镜像备份,RAID功能强大也比较复杂。当然,备份手段非常多,但是还有其他方面需要考虑,比如性能,备份很多时候是非常消耗系统资源的,因此我们尽量在系统负载较低的时候备份,并且应该确定整个备份过程不要持续的过长。

January 05, 2007

bayes,简单就是美

机器学习大体可以分为分类学习、聚类、关联学习、数值预测。分类学习通过对一个已知分类的学习集的学习获得可以将未知数据集进行分类的能力,聚类则使数据自然的落在几个小组里,关联学习是希望能获得每个特性之间的相关性,数值预测则预测出一个离散类。在上海的时候由于公司的需要做过一段时间的机器学习的工作,主要就是文本自动分类,尝试过naive bayes、knn、svm等方法。google黑板报上的数学之美系列文章,除了让人了解到各种关于搜索和数据挖掘的知识之外,更大的作用还在于让你发现其实很多东西即使是最简单的手段也可以做到不错的效果。google的工程师说在中学学习余弦定理时,很难想象它可以用来对新闻进行分类,事实上在大学上概率统计的课程时我都没想到说bayes会对我将来的工作有任何的帮助。机器学习的一个重要的应用领域就是文本分类,而bayes算法在这一领域的使用有很长的历史了。bayes算法是非常简单的,但是在实际的应用领域,bayes算法的效果并不比那些复杂的算法差,有时甚至更有优势。SpamAssassin是apache基金的一个反垃圾邮件软件项目,获得了2006 Linux New Media Awards上的Best Linux-based Anti-spam Solution award。SpamAssassin是用perl写的,算法便是基于bayes。SpamAssassin采用概率统计的方法来为邮件打分,通过分数的高低来猜测哪些有可能是垃圾邮件。SpamAssassin官方网站表示只有大概0.9%的垃圾邮件会被漏过和0.1%的有效邮件被当成垃圾邮件过滤掉。当然除了基于bayes算法之外,SpamAssassin还做了很多工作才能到达这个效果。另外,由于bayes基于属性独立的假设之上,而事实上这是很难的,因此如果在数据中加入一个新的属性,则很有可能破坏了原有的整个机器学习的过程。我自己在做英文文本自动分类时发现,在分词、停词处理、词根处理、同义词转换都相同的情况下,bayes得到的效果稍好于knn和svm,当然这并不是说bayes这个算法绝对的好于其他算法,因为除了算法之外还有很多其他方面以及应用领域的影响。而在效率上由于nayes不用进行参数选择,所以bayes的训练强度几乎就是和他的训练集的增长以及测试集的增场成线性关系。而采用knn和svm时,由于需要找到最有效的参数才能使结果优化所以在训练方面需要有很大的投入,比如使用交叉训练的方式来获取最优参数就是一见非常消耗时间和资源的事情。由此可见流传甚广的一句格言:简单就是美,在bayes身上有非常好的体现。当然,除了算法之外,机器学习还跟前期训练数据的准备和处理有很大关系,6e关于相关度计算的介绍,google黑板报上关于统计语言模型数据处理的系列文章都是很好的参考资料。

参考资料:
International Society for Bayesian Analysis
http://www.bayesian.org/
SpamAssassin
http://spamassassin.apache.org/

January 03, 2007

clustering

clustering(聚类)对文本挖掘、图像切割、数据检索等方面来说是一项非常重要的技术。聚类就是将一组实例进行自然分组。表示聚类的结果可以有多种方法,排他的(每个实例只能属于一个组)、重叠的(一个实例可以属于多个组)、概率表示的(表示为属于每个组的概率为多少)、分层次(多级分类)的等。在聚类研究中最常用的一种技术是K-means,首先指定要聚类的个数K,也就是我们要将一组实例归为几组,然后随机选出k个点作为聚类中心,接下来计算出实例所在的每个聚类的质心,这些质心成为各个聚类的新的中心值,不断的重复这个过程直到每个聚类所拥有的实例与上一次相同,此时聚类的中心便确定下来。使用k-means时必须事先知道聚类数目,并且初始的聚类中心的选择对于结果可能有很大的影响,因此有时需要采用多次不同的初始值进行运算然后取最优的结果。当然,如果是一种固定分类的形式,则采用机器学习的方法自动分类也是可以达到效果,但是这种方法则需要大量已知分类的学习集,这一方面比较成熟的算法是bayes、knn、svm等。

在互联网中,clusty将聚类这一技术引入了搜索引擎中,这将给用户带来体验上的很大改进。象google这样的搜索引擎可以提供大量的搜索结果,但是如何提供最相关的内容似乎已经碰到了瓶颈。事实上google对于同一网站可能在一次搜索中只显示一条结果,而将同域名的相似文章组织在一起,这也算是聚类的一种。但必须通过标题和内容的更有效的聚类分析才能进一步提高用户体验。从clusty的结果来看,聚类本身似乎并不会有太大的问题,最大的问题可能出现在速度上(据6e介绍,clusty使用的是平移算法),因为clusty是在每次搜索结果返回之前进行聚类分析,这样每次搜索的速度受到了极大的限制,并且clusty是一个META搜索引擎,这就更加影响了它的速度。

google则在机器新闻中展示了聚类的研究成果。就像前面说的一样,在实时的搜索中,速度方面可能会是一个问题,但是在机器新闻的生产过程中,因为新闻可以是定期生成的,因此这个问题就自然解决了。

参考资料
A Tutorial on Clustering Algorithms
http://www.elet.polimi.it/upload/matteucc/Clustering/tutorial_html/index.html
信息的聚类
http://www.wespoke.com/archives/000844.html

January 02, 2007

使用cronolog和webalizer分割和分析apache日志

web服务器的日志对于网站管理者来说有非常重要的作用,对于分析网站的访问情况、搜索引擎的抓取、图片盗链、非法抓取等有很大的帮助。目前apache是最为广泛应用的web服务器,apache的日志功能能通过访问日志可以比较详细的记录网站服务器的被请求情况,但是要更好的根据日志来维护和管理网站则需要其他的工具来分析日志,以生成便于查看的报表。
默认安装的apache在运行时会产生两个日志文件,access_log用于存放访问记录,error则存放出错记录。日志的生成格式可以定制的,需要在配置文件中定义
LogFormat "%h %l %u %t \"%r\" %>s %b" common
CustomLog logs/access_log common
上面的配置是最常用的一种记录格式,产生的日志格式如下:
127.0.0.1 - - [02/Jan/2007:19:41:07 +0800] "GET /themes/original/img/s_error.png HTTP/1.1" 200 272

这是一条典型的apache访问记录,这条记录里面包含有远程访问IP( 127.0.0.1 )、访问者身份(现在一般缺省,以-代替)、访问者标识(缺省以-代替)、请求时间(02/Jan/2007:19:41:07 +0800)、请求方式(GET)、请求的协议(HTTP/1.1)、请求的资源(/themes/original/img/s_error.png)、响应情况(200,代表成功)、传输的字节数(272)。

还有一种比较常用的格式
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-agent}i\"" combined
CustomLog log/access_log combined

127.0.0.1 - - [02/Jan/2007:19:41:07 +0800] "GET /themes/original/img/s_error.png HTTP/1.1" 200 272"http://www.example.org.cn" "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.1) Gecko/20061208 Firefox/2.0.0.1"
Referer标示记录下来源,User-Agent则会记录客户端浏览器提供的一些识别信息,比如操作系统类别、浏览器类型和版本等,当然也可能是爬虫的信息。记录这些日志对于一个访问量比较大的网站来说是需要很多空间的,而且我们也没必要去保存三个月前的日志。apache提供了日志滚动和管道日志的功能来解决这个问题。
CustomLog "|/usr/local/apache/bin/rotatelogs /usr/local/apache/logs/access_log 86400" common
这条命令利用apache提供的rotatelogs每24小时滚动一次日志。当然,现在还有一个工具cronolog被广泛的应用
CustomLog "|/usr/local/sbin/cronolog /usr/local/apache/logs/access_log%m%d" combined
按天分割日志并且日志按照日期记录为access_log.0102的格式。然后可以写脚本定期使用gzip程序将日志压缩备份或者定期进行清理。


10 1 * * * /bin/rm -f /usr/local/apache/logs/`date --date "5 days ago" +access_log.\%m\%d`
加到crontab中,每天1点10分删除5天前的日志

apache帮我们记录一些重要的信息,现在就要对这些信息进行分析,这样日志才能对我们管理和维护网站有所帮助。webalizer是一个非常流行的日志分析工具。前面已经处理了apache的轮询,现在只要配置好webalizer就可以得到日志的分析结果。
0 1* * * /bin/cp -f /usr/local/apache/logs/`date -d yesterday +access_log.%m%d` usr/local/webalizer/logs/access.log
每天1点将日志拷贝一份供webzlizer分析使用

这还只是单机的日志分析,如果需要分析多台服务器的日志可以参考
http://www.chedong.com/tech/rotate_merge_log.html


参考文档:
apache日志文档
http://man.lupaworld.com/content/manage/Apache2.2_chinese_manual/logs.html
webalizer
http://www.mrunix.net/webalizer/
cronolog
http://cronolog.org/
Apache日志的cronolog轮循和webalizer合并统计
http://www.chedong.com/tech/rotate_merge_log.html

December 31, 2006

iptables学习笔记

Linux因为健壮、灵活、高效正在成为越来越多的WEB服务器的首选,Linux的内置功能非常多并且强大,但是很多功能可能需要用户根据自己的需求来定制。作为WEB服务器来说,安全性是需要考虑的一个非常重要的问题,因此在服务器上配置一个高效的防火强是非常必要的。防火墙可以有硬件防火墙和软件防火墙,还可以按防火墙对于数据包的获取方式分为代理和IP过滤。这篇文章关注的就是通过信息包过滤的方式来搭建防火墙的方式。IP过滤机制通过对访问服务器的TCP/IP包进行分析,从表头中取得IP、端口等资料,然后依据规则来判断访问者是否被授权访问。事实上除了IP、端口等资料外,因为取得的是底层的信息包,所以还可以用于取得MAC、TCP、UDP、ICMP等包的信息。netfilter/iptables 就是Linux中信息过滤的一个强大的组合。基于kernel2.6的Linux发行版安装好就支持iptables。首先判断一下系统是否已经支持了iptables,查看/proc/net/ip_tables_names文件,如果存在说明内核已经支持iptables,否则需要先安装iptables。
iptables是如何过滤信息的呢?首先我们需要制定一些规则,当iptables取得信息包的头信息后就会根据我们设定的规则来判断是否允许访问主机。我们定义的规则被存储在内核的信息包过滤表(filter,还有诸如nat等表)中,在信息过滤表中规则会被分组放在链中。缺省的一般有INPUT、OUTPUT和,FORWARD三种链,处理访问信息包的规则被放在INPUT链中,而处理服务器出去的信息包的规则则放在OUTPUT链中,FORWARD链中的规则是用来处理转发的信息包,另外还有其他一些类型的链可以根据需要配置。在我们设定一条规则之后,比如是放在INPUT链中的,那么当一个外部的请求到达时,信息包就会被传到INPUT链上根据规则进行处理,如果信息包不在设定的规则之内,则会根据预设的策略判断是否通过。

使用iptables -L -n命令查看当前防火墙的规则,结果类似下面这样,其中(policy ACCEPT)指的就是预设的策略
Chain INPUT (policy ACCEPT)
target prot opt source destination
ACCEPT all -- 0.0.0.0/0 0.0.0.0/0

Chain FORWARD (policy ACCEPT)
target prot opt source destination

Chain OUTPUT (policy ACCEPT)
target prot opt source destination

iptables定义策略的语法:
iptables [-t tables] [-P] [INPUT, OUTPUT, FORWARD | PREROUTEING, OUTPUT, POSTROUTING] [ACCEPT, DROP]
-P 定义Policy
用于fliter表中的参数
INPUT 请求主机的信息包
OUTPUT 主机发出的信息包
FORWARD 转发的信息包

用于nat表的参数
PREROUTING 路由之前处理
OUTPUT 主机发出的信息包
POSTROUTING 路由之后处理


iptables查看规则的语法:
iptables [-t table] [-L] [-n]
-t 后面接 iptables 的 table,默认就是 -t filter。
-L 列出当前的 table 的规则
-n 不进行 IP 与 hostname 的转换

iptables清除规则的语法:
iptables [-t table] [-FXZ]
-F 清除所有规则;
-X 杀掉所有用户建立的链
-Z 将所有链的计数与流量统计都清零

iptables增加和定义规则的语法:
iptables [-t table] [-AI INPUT,OUTPUT,FORWARD] [-s IP/network] -j [ACCEPT,DROP]

-A:将一条规则添加到最后面
-I:插入一条规则,默认放在最前面
-s:来源数据包的IP地址或地址段
-j:要执行的动作(drop、accept、log)

iptables删除规则语法:
iptables -D INPUT 2,表示删除INPUT链中的第二条规则

调整Ubuntu Linux的分辨率

我现在用的是ubuntu6.06,安装完之后默认的分辨率是1024×768,而且选项里面也只有1024×768,800×600,640×480三种。一开始我其实也不是太在意,几个同事看了我的屏幕后都说看起来很不习惯,搞得我看起来感觉越来越不顺眼,所以一大早来首先查一下如何修改Ubuntu的分辨率。网上有人说用sudo dpkg-reconfigure xserver-xorg,我急急忙忙的就试了一下,进去之后经过N次选择之后重启,被告知X server错误无法启动。进入recover模式,在/etc/X11/下将xorg.conf用原来的备份还原。

又到Ubuntu的官方网站上找了一下,终于解决了,解决方法如下:
用编辑器打开/etc/X11/xorg.conf找到
Section "Monitor"
Identifier "Generic Monitor"
Option "DPMS"
HorizSync 28-78
VertRefresh 43-93
EndSection
其中数字代表显示器的水平和垂直刷新率,改成适合你的显示器的数值
再找到
Section "Screen"
Identifier "Default Screen"
Device "Intel Corporation 945G Integrated Graphics Controller"
Monitor "Generic Monitor"
DefaultDepth 24
SubSection "Display"
Depth 1
Modes "1024x768" "800x600" "640x480"
EndSubSection
SubSection "Display"
Depth 4
Modes "1024x768" "800x600" "640x480"
EndSubSection
SubSection "Display"
Depth 8
Modes "1024x768" "800x600" "640x480"
EndSubSection
SubSection "Display"
Depth 15
Modes "1024x768" "800x600" "640x480"
EndSubSection
SubSection "Display"
Depth 16
Modes "1280x1024" "1024x768" "800x600" "640x480"
EndSubSection
SubSection "Display"
Depth 24
Modes "1280x1024" "1024x768" "800x600" "640x480"
EndSubSection
EndSection

在Depth 16和Depth 24两段中,原来是没有"1280x1024" 的,需要自己加上
这样重启之后分辨率就会自动调整到1280x1024,如果没有的话可以将Depth 16和Depth 24中的"1024x768" 删除,这样就没问题了。

December 25, 2006

Apache Solr发布新版本

Apache Solr两天前发布了1.1版本。

Solr是apache的一个企业级的全文检索项目,基于Java5和Lucene,提供了基于XML协议的API接口,并对Lucene做了很多扩展,例如支持动态字段及唯一键,对查询结果进行动态分组和过滤,增强了文本分析功能等。Solr还提供了对JSON/Python/Ruby友好的数据格式。


Solr的主要特性有:
基于XML的配置提供了灵活性
关键字加亮显示
高效缓存
好的架构,可扩展性强并支持插件
强大的全文检索功能
良好的WEB管理界面
基于HTML和XML的API