2006/06/21

CMS, AMP Stack, Windows Service

开始为新网站做准备,域名已经想好了,只有cn的没被注册了,暂时保密。

CMS系统的选择有点头疼,我一直不喜欢Nuke系列,包括phpNuke, postNuke和Xoops;以前一直用Drupal,但是Drupal的论坛很弱,虽然有个vB Drupal,但是这样以后的升级成了问题;Xaraya没用过,ezpublish有些杀鸡用牛刀,最终决定先尝试Joomla!,这是大名鼎鼎的Mambo的一个分支,只是我没搞明白为什么会有这么一个分支出来。

Drupal的Collaborative Book功能会让我怀念的;但是Mambo/Joomla的简洁和它的社区支持更让人放心。

Apache/Mysql/Php的安装一直是个不大不小的麻烦,每次安装都是看文档,还好没遇到过问题;这次偷懒找了一些做好的东东,有三个选择,XAMPP,EasyPHP和apache2triad,最后一个不知道为什么下载有问题,sourceforge上所有的镜像都是下载到30%就挂了。于是下了一个XAMPP,也许这个更适合我,除了AMP之外,只装了PHPMYADMIN,够用了。

上次本机安装Ezpublish,反安装之后在Windows Service里留了两个空的apache和mysql服务,开动GooGle找了一下,发现手工删除服务也很简单.

停止服务是:

net stop

删除服务是

sc delete

2006/06/09

巨硬,J2ME,Symbian...

今天Blogger竟然挂了,只好打开Writely写Blog.

巨硬还在胶着状态,改来改去,当然越改越简单。事实上,代码很早就接近30K了,然后就不停的合并修改删除,现在还保持在28K的标准,估计最终也不会超过35K。

前 面提到过一个键盘模型的问题,在巨硬的构架中,键盘模型仅仅影响零级序列,即传统意义上的词库。为了提高搜索速度,不会把所有词都存在一张表中,通常都会 按照首字母分开以提高检索速度。如果要兼顾数字键盘和qwerty键盘,最简单的办法就是按照手机键盘的分组方法把首字母相同的词合并在一个表中,也是传 统的处理声母模糊音的办法,粗略估算了一下,这个办法应该可行,副作用主要是降低了词库的最大容量,不过巨硬二本来就不是为大词库设计的,这样做也算是一 个不错的办法。方便用户迁移数据库。

这段时间还抽空看了看Symbian系统和J2ME系统的开发。Symbian是很彻底的C++,在 流存储上考虑的极为周密,而且也把C++的继承特性,或者说代码重用特性,发挥到了极致。Java实际上是我学编程的入门语言,比C++更简洁优雅,只是 效率差了些。J2ME中设计了一个Record Management System,我不知道PC程序员或者数据库开发人员会怎么看这个玩意,但是作为PalmOS开发者,我特别喜欢它。它的实现几乎和PalmOS数据库如 出一辙,在简单的数据库驱动的应用中,这种存储又灵活又高效;在Symbian系统中有个嵌入式存储,也是这类的“单表”“非严格字段”数据库。之所以关 心这个问题,是因为巨硬二仍然没有改掉巨硬一的记录数庞大的问题,不过这次不是基础词库庞大,而且词序库庞大,如果系统级不支持这种数据库存储的话,就得 自己些个小型的文件数据库了,虽然不是不可行,但是效率就差多了,而且光是表头就要Cache掉不少的内存,因为这个原因,巨硬二应该不会有 Windows Mobile版本了,Windows Mobile提供的数据库太肿了,又浪费空间速度又慢,只适合做标准的数据库应用程序。

上 周把娘子的Moto E398刷了E1,为的是有iTunes。感觉非常不错--我是iTunes/iPod的狂热拥护者。但是Moto的输入法烂到极点了。因此萌生了一个在 Moto手机上开发输入法的想法,于是引出了J2ME的话题,再然后想到可以开发一个把中文输入和短信结合在一起的程序,这个东西市场应该不错。巨硬+ Threaded模式+狂多的J2ME手机,蛮有趣的吧。其实我还有很多关于手机和internet结合的应用构思,先用一个程序打出一片用户群体,然后 就可以逐步实施这些想法了。能跨出Treo用户群体,对巨硬来说也是很重要的一步吧。巨硬II的PalmOS版完工之后应该很快就会投入J2ME版本的开 发,至于Symbian版,要看移植的工作量了,但是我现在还没想好是先把Symbian的做了再说,还是先写J2ME的。

Evan一直 在鼓动我把输入法卖给手机厂商,不过我的想法是越来越相反。输入法就像GPS导航地图一样,只是一个技术,不是一套完善的应用;基于这个东西积累用户群 体,然后融入周边应用,譬如短信,IM,Email等等,才是输入法的出路。我喜欢能够接触终端用户并且持续挖掘用户需求的商业模式,而不是专注于技术产 品,当然,我不是说技术不重要,但是从商业角度或者从发展的角度来说,技术应该最大限度的转化为应用。

2006/06/06

巨硬II进展

巨硬II的进展依旧缓慢。

周末偷懒休息了两天,看prison break到天昏地暗,没写代码,罪过罪过。

今天挤出了点儿时间修改了Filter类的设计,原来的Filter类是Attach到数据库的一张表上,其结果是在查询过程中不能改动表,在目前的假设中这不构成问题,但是以后就不好说了。当前的假设是在用户部分选定了候选词之后,预测词库自动失效,检索被设定为精确匹配状态,但是我发现在实际的输入过程中,有时会有把一些本不该划为一个词组的内容一起输入的情况,在这种情况下,能启用预测词库对减少选字还是有帮助的。

另外一个小小的改进是把多级预测词库并为一个数据库,其好处是,在遗忘的时候可以体现出不同级别的预测序列之间的频率比较;否则分开存储的话,那些本该属于短期记忆的序列会大量挤占存储空间,不上算。虽然还没有实际输入过,我估计1,2级预测序列肯定是最多的,3级应该比较少才对。

总的来说,目前已经完成了大部分框架类,包括所有的数据库存储,文件存储,字库词库Alpha库,统一的dataStore界面,0级和n级序列库,查询填充队列,过滤器,以及composition/candidate/nominee/history工具类,剩下的主要类就只有popup类和window类,对巨硬来说,这都是比较简单的UI和事件处理了,就是要花些时间上去。理论上说,这些类都完成之后就可以工作了,但实际上还有不短的路要走,因为巨硬II的算法和传统输入法改动很大,需要准备一个非常好的初始化序列数据库,才能比较理想的工作。另外我还在犹豫是不是在第一个版本中就加入支持键盘对象和被动匹配的代码,这样做的好处是在training过程中可以直接得到一个词频排序良好的0级词库。ANYWAY,离进入调试阶段不会很远了。

2006/06/02

Filter,友元函数,MindManager

今天没有任何功能性的进展,仅仅解决了一个很小但是异常复杂的问题。

在一次搜索中会遇到多种情况,包括联想状态(用户尚未输入任何字母),首次选字,以及已经选字;巨硬允许用户选择是否混合匹配中英文(比如输入br的时候匹配brighthand.com);允许用户选择使用和不使用预测词库;是否允许longer匹配(输入s的时候匹配“上海”,这是词频高于字数的匹配方式),以及自动切换longer设置(比如在用户已经输入超过一个音节的情况下自动关闭longer匹配);是否允许尾码渐进匹配(比如输入了kun ji的时候匹配“困窘”);还要照顾到自动分隔匹配(几乎所有的拼音输入法都这样匹配)和被动匹配(适用于数字键盘或者有按键合并的half qwerty);在输入的不同阶段,这些匹配设置可能会动态打开或关闭,还会遇到一些冲突情况(比如用户已经选了一个字,然后继续输入导致编码不再符合拼音规则)。

在MingManager的帮助下,这个问题最终通过一个简单模型实现了。我设计了一个Filter类,该类是可以attach到数据库上去的,从Filter类派生了很多行为不同的类,比如只匹配英文词汇,只匹配单字,词频优先或者字数优先等等,用于匹配的不同阶段和不同环境,这样就不用把所有的配置和环境变量放到一个由if语句堆积而成的函数中折腾,使得代码更容易实现,更容易理解,同时大大减少犯错误的机会,需要改动的时候也很方便。

设计Filter类的另外一个原因是为了提高检索速度,巨硬II使用了保留搜索断点的方式来获得候选字词,而不是一次性完成所有搜索填入buffer,事实上按照巨硬的数据结构设计,一次性填充Buffer几乎是不可行的,用户输入单一字符时,如果打开longer匹配和中英文混合匹配的选项,符合的选择可能多达上万个。我试了一下拼音加加,它不允许longer匹配也没有英文匹配,输入y的时候候选字有729x3个,而且要考虑到这是PC上的结果,手持设备上一次遍历匹配2000多个字很吃不消了。

这个断点状态的保留也是个很麻烦的问题,所以Filter类不仅仅是处理各种不同的匹配设置,它还负责维护搜索状态,最早的代码把这个工作交给了数据库自己来完成,但是后来发现很难处理那么多种情况,还是分到不同的Filter派生类中处理更清晰。最终在MindManager中得到了一个四级的二分树来表示不同的输入过程,再混合4个排列组合的设置(longer, longer auto off, progressive, alpha match),这回让我庆幸自己是用C++来写巨硬II的,可以利用virtual特性为所有的Filter类提供一个统一的Read函数供填充队列使用;如果是C,我真不知道怎么处理才好了。

以前一直鄙视C++的友元函数设计。但是今天派上了用场。

通常在程序中,有很多类提供了类似API一样的基础功能,而另外一些类封装了几乎所有核心数据结构,一些核心算法要同时访问这些东西。就比如前面说到的Filter类,它要访问字词库符号库以获取字词的音标并判断是否匹配,要访问输入过程的当前数据,包括Composition(用户输入),Candidates(候选词),和Nominee(用户已经选择的字词,但是还没有完成输入过程),还要访问当前的队列填充状况(比如这样的设置,在用户翻页两次之后关闭所有词频优先选项,改为精确匹配优先),在这种情况下有两个办法来处理。一种是C++中的Composition方式,即类套着类层层封装,以前我很喜欢这个方式,它使程序看起来很优雅,结构清晰,尤其是写UI程序时,把数据和UI层层绑定,是非常方便的做法;但是这种封装会牺牲灵活性和效率,就像MFC那样,而且对于错误处理也很麻烦(很不幸我没能在巨硬中使用C++的异常处理,这个Metrowerks提供的特性让我担心在弹出程序中会带来一些难以预料的问题,我还没能力在Debug窗口中看那些汇编代码并从中找出错误)。

除了层层封装之外的一个做法是,用一个容器类把这些东西统统丢进去,然后把所有需要用到这些数据或API的类都声明成友元类,这样可以大大减少参数传递和数据成员,让类简化很多,函数参数少了,代码也好看很多(不然要传递一长串参数进去);而且更重要的是,我觉得这样做在开发阶段是方便的,很多想法往往在调试时发现效果不佳,要采用另外的逻辑,如果是这样设计的类结构,那改起来也很方便,真的功能定型了之后,在refactoring阶段再考虑如何更优雅的封装也来得及。

另外这几周来,我对MindManager是越来越崇拜。以前看过一些Mind Map方法的介绍,不以为然。不就是拿张白纸从中心向四周画圈圈吗?我从来没想过用这类工具作为程序开发的辅助工具。

我想和我遇到一样问题的个人开发者应该有很多,为了解决程序结构和代码控制问题,我学了也试了很多工具,包括Case Tool,UML工具,大量撰写注释,大量撰写文档(包括需求和设计)。但是最终没有适合的。

从这次借助MindManger开发,我明白了这里面的问题所在。Case Tool,UML工具,注释,文档这些东西,都是维护需求、设计或者代码用的;个人开发者和那种大型商业软件开发的很大区别在于,前者并没有特别明确的用户需求,往往是靠算法、数据结构或特殊功能设计来取胜,软件开发过程的实验性很强,这时候最需要的并不是很高级的维护代码的工具,而是有效的分析和辅助思考的工具,MindManger正是这样的东西。在功能最终趋于大而全的时候,那些需求和代码维护工具才派得上用场。