终于将Lucene集成到中文WordPress中了,实现了中文博客的全文搜索。作为一个搞NLP的博主,如果还在用SQL的LIKE做搜索,那也太不上档次了。这次集成主要难点在于
①PHP平台上并没有一款成熟的分词套件。
②Lucene的PHP Port只有Zend_Search_Lucene一家,其对中文的支持非常糟糕,默认编码是ANSII;而且代码内部有不少错误,比如静态方法调用非静态成员。
③BAE对程序执行时间有限制,因此长文章必须忍痛割爱。
下面谈谈问题的解决以及整个实现过程。
一、Lucene的集成
wpsearch插件是WordPress上的Lucene集成插件,不过不要高兴得太早。wpsearch已经2年多没有更新,并且不支持中文。解决思路是去Zend的发行包里提取下列文件:
Zend │ Exception.php │ tree.txt │ Version.txt │ ├─Search │ │ Exception.php │ │ Lucene.php │ │ │ └─Lucene │ │ Document.php │ │ Exception.php │ │ Field.php │ │ FSM.php │ │ FSMAction.php │ │ Interface.php │ │ LockManager.php │ │ MultiSearcher.php │ │ PriorityQueue.php │ │ Proxy.php │ │ TermStreamsPriorityQueue.php │ │ │ ├─Analysis │ │ │ Analyzer.php │ │ │ Token.php │ │ │ TokenFilter.php │ │ │ │ │ ├─Analyzer │ │ │ │ Common.php │ │ │ │ │ │ │ └─Common │ │ │ │ Text.php │ │ │ │ TextNum.php │ │ │ │ Utf8.php │ │ │ │ Utf8Num.php │ │ │ │ │ │ │ ├─Text │ │ │ │ CaseInsensitive.php │ │ │ │ │ │ │ ├─TextNum │ │ │ │ CaseInsensitive.php │ │ │ │ │ │ │ ├─Utf8 │ │ │ │ CaseInsensitive.php │ │ │ │ │ │ │ └─Utf8Num │ │ │ CaseInsensitive.php │ │ │ │ │ └─TokenFilter │ │ LowerCase.php │ │ LowerCaseUtf8.php │ │ ShortWords.php │ │ StopWords.php │ │ │ ├─Document │ │ Docx.php │ │ Exception.php │ │ Html.php │ │ OpenXml.php │ │ Pptx.php │ │ Xlsx.php │ │ │ ├─Index │ │ │ DictionaryLoader.php │ │ │ DocsFilter.php │ │ │ FieldInfo.php │ │ │ SegmentInfo.php │ │ │ SegmentInfoPriorityQueue.php │ │ │ SegmentMerger.php │ │ │ SegmentWriter.php │ │ │ Term.php │ │ │ TermInfo.php │ │ │ TermsPriorityQueue.php │ │ │ Writer.php │ │ │ │ │ ├─SegmentWriter │ │ │ DocumentWriter.php │ │ │ StreamWriter.php │ │ │ │ │ └─TermsStream │ │ Interface.php │ │ │ ├─Interface │ │ MultiSearcher.php │ │ │ ├─Search │ │ │ BooleanExpressionRecognizer.php │ │ │ Query.php │ │ │ QueryEntry.php │ │ │ QueryHit.php │ │ │ QueryLexer.php │ │ │ QueryParser.php │ │ │ QueryParserContext.php │ │ │ QueryParserException.php │ │ │ QueryToken.php │ │ │ Similarity.php │ │ │ Weight.php │ │ │ │ │ ├─Highlighter │ │ │ Default.php │ │ │ Interface.php │ │ │ │ │ ├─Query │ │ │ │ Boolean.php │ │ │ │ Empty.php │ │ │ │ Fuzzy.php │ │ │ │ Insignificant.php │ │ │ │ MultiTerm.php │ │ │ │ Phrase.php │ │ │ │ Preprocessing.php │ │ │ │ Range.php │ │ │ │ Term.php │ │ │ │ Wildcard.php │ │ │ │ │ │ │ └─Preprocessing │ │ │ Fuzzy.php │ │ │ Phrase.php │ │ │ Term.php │ │ │ │ │ ├─QueryEntry │ │ │ Phrase.php │ │ │ Subquery.php │ │ │ Term.php │ │ │ │ │ ├─Similarity │ │ │ Default.php │ │ │ │ │ └─Weight │ │ Boolean.php │ │ Empty.php │ │ MultiTerm.php │ │ Phrase.php │ │ Term.php │ │ │ └─Storage │ │ Directory.php │ │ File.php │ │ │ ├─Directory │ │ Filesystem.php │ │ │ └─File │ Filesystem.php │ Memory.php │ └─Xml Exception.php Security.php
替换wpsearch的Zend文件夹,这还没完注意Zend的引用路径需要修改。这样我们就让一款2年前的插件获得了新的生命力。
二、PHP中文分词
PHP本来就不方便做高级算法,所以纯PHP的分词包极其难找,我只发现了一款PHPAnalysis分词系统。PHPAnalysis只支持词典分词,也就是说分词并不精准。不过我暂时也不能要求那么高,我倒是想用CRF分词,但问题是PHP的执行效率能满足要求吗?BAE的时间限制够用吗?如果是自己的主机的话,我当然可以选择Java Bridge或者其他的C接口。但是博客目前托管在BAE云平台上,没有那么高的自由度。
仿照StandardAnalyzer_Analyzer_Standard_English自己实现一个中文Analyzer,等以后有机会再用高级的分词吧。
(注:此分词实在无法胜任,码农场已经放弃全文索引。)
三、长文章截取
由于BAE开启了FastCGI,所以必须考虑时间耗费。对于长度过大的文章,只截取前10000个字做索引,总算在BAE上面跑了起来。
看看WordPress全文搜索的效果吧
我以“算法的文章”作为查询条件,很明显,任何文章里都没有直接写这句话,SQL的LIKE也就无能为力了,但是Lucene能够给出正确的答案:
效果还是蛮不错的,有时间加一点复杂的功能,比如同义词和指代消解,想想还是挺有趣的。
lucene的相关搜索怎么做的,求指教?
是改每个文件的require吧,工作量还是很大的。还有个问题,关于速度的。我在本地测试了一下速度,3Wpost的WP,使用自带搜索,耗时0.6S左右。如果使用wpsearch,生成index后测试,要1S左右,感觉效率上自带搜索还快些啊,按理应该是lucene快些的,不知道怎么回事
我觉得Lucene本来就应该慢一些,index储存在文件系统中,每次搜索都要加载进来;搜索语句每次都要分词,每个term每个document都要评分排序;以上都是用php完成的,而MySQL用C实现,有自己的缓存。
是改每个文件的require吧,工作量还是很大的。还有个问题,关于速度的。我在本地测试了一下速度,3Wpost的WP,使用自带搜索,耗时0.6S左右。如果使用wpsearch,生成index后测试,要1S左右,感觉效率上自带搜索还快些啊,按理应该是lucene快些的,不知道怎么回事
你好,博主,我想启用这个插件,我下wpsearch插件,但不知道怎么修改。我主要是用于英文搜索,没有中文,而且post量比较多,有好几万吧。文中说到的“Zend的发行包里提取下列文件”,是指Zend Framework2吗,怎么再出那么多文件?“注意Zend的引用路径需要修改”,这个又怎么改呢?希望不吝赐教,谢谢
只有旧版的Zend才集成Lucene,比如http://downloads.zend.com/framework/1.12.5/ZendFramework-1.12.5.zip 。解压到插件目录之后,参照插件里面的写法,一个文件一个文件地将Lucene的目录对上去。这个插件设计得并不怎么样,工作量可能会很大。