终于突破CLuence中文分词的效率问题(转载)
传统的全文检索都是基于数据库的,Sql Server Oracle mysql 都提供全文检索,但这些比较大,不适合单机或小应用程序(Mysql4.0以上可以作为整合开发),Mysql也不支持中文。
后来得知Apache有一个开源的全文检索引擎,而且应用比较广,Lucene是Apache旗下的JAVA版的全文检索引擎,性能相当出色,可惜是java版的,我一直在想有没有C或C++版的,终于有一天在http://sourceforge.net 淘到一个好东东,Clucene!CLucene是C++版的全文检索引擎,完全移植于Lucene,不过对中文支持不好,而且有很多的内存泄露,:P
Cluene不支持中文的分词,我就写了一个简单的中文分词,大概思路就是传统的二分词法,因为中文的分词不像英文这类的语言,一遇到空格或标点就认为是一个词的结束,所以就采用二分词法,二分词法就是例如:北京市,就切成 北京 , 京市。这样一来词库就会很大,不过是一种简单的分词方法(过段时间我再介绍我对中文分词的一些思路) ,当然了,在检索时就不能输入“北京市”了,这样就检索不到,只要输入:“+北京 +京市”,就可以检索到北京市了,虽然精度不是很高,但适合简单的分词,而且不怕会漏掉某些单词。
我照着Clucene的分词模块,做了一个ChineseTokenizer,这个模块就负责分词工作了,我把主要的函数写出来
ChineseTokenizer.cpp:
Token* ChineseTokenizer::next() {
while(!rd.Eos())
{
char_t ch = rd.GetNext();
if( isSpace((char_t)ch)!=0 )
{
continue;
}
// Read for Alpha-Nums and Chinese
if( isAlNum((char_t)ch)!=0 )
{
start = rd.Column();
return ReadChinese(ch);
}
}
return NULL;
}
Token* ChineseTokenizer::ReadChinese(const char_t prev)
{
bool isChinese = false;
StringBuffer str;
str.append(prev);
char_t ch = prev;
if(((char_t)ch>>8)&&(char_t)ch>=0xa0)
isChinese = true;
while(!rd.Eos() && isSpace((char_t)ch)==0 )
{
ch = rd.GetNext();
if(isAlNum((char_t)ch)!=0)
{
//是数学或英语就读到下一个空格.或下一个汉字
//是汉字.就读下一个汉字组成词组,或读到空格或英文结束
if(isChinese)
{
//汉字,并且ch是汉字
if(((char_t)ch>>8)&&(char_t)ch>=0xa0)
{
// 返回上一个汉字
str.append(ch);
rd.UnGet();
// wprintf(_T("[%s]"),str);
return new Token(str.getBuffer(), start, rd.Column(), tokenImage[lucene::analysis::chinese::CHINESE] );
}
else
{
//是字母或数字或空格
rd.UnGet();
// wprintf(_T("[%s]"),str);
return new Token(str.getBuffer(), start, rd.Column(), tokenImage[lucene::analysis::chinese::CHINESE] );
}
}
else
{
//非汉字
// ch是汉字
if(((char_t)ch>>8)&&(char_t)ch>=0xa0)
{
// wprintf(_T("[%s]"),str);
rd.UnGet();
return new Token(str.getBuffer(), start, rd.Column(), tokenImage[lucene::analysis::chinese::CHINESE] );
}
str.append( ch );
}
}
}
// wprintf(_T("[%s]"),str);
return new Token(str.getBuffer(), start, rd.Column(), tokenImage[lucene::analysis::chinese::ALPHANUM] );
}
同时,这个中文分词不支持文件,只能支持内存流的形式,因为我用到了rd.UnGet();如果是文件的话,嘿嘿,只能回退半个字节哦
嗯。先写到这里了,今天太急了,等我有空了我就把我对CLucene的改进发到上面来。
后来得知Apache有一个开源的全文检索引擎,而且应用比较广,Lucene是Apache旗下的JAVA版的全文检索引擎,性能相当出色,可惜是java版的,我一直在想有没有C或C++版的,终于有一天在http://sourceforge.net 淘到一个好东东,Clucene!CLucene是C++版的全文检索引擎,完全移植于Lucene,不过对中文支持不好,而且有很多的内存泄露,:P
Cluene不支持中文的分词,我就写了一个简单的中文分词,大概思路就是传统的二分词法,因为中文的分词不像英文这类的语言,一遇到空格或标点就认为是一个词的结束,所以就采用二分词法,二分词法就是例如:北京市,就切成 北京 , 京市。这样一来词库就会很大,不过是一种简单的分词方法(过段时间我再介绍我对中文分词的一些思路) ,当然了,在检索时就不能输入“北京市”了,这样就检索不到,只要输入:“+北京 +京市”,就可以检索到北京市了,虽然精度不是很高,但适合简单的分词,而且不怕会漏掉某些单词。
我照着Clucene的分词模块,做了一个ChineseTokenizer,这个模块就负责分词工作了,我把主要的函数写出来
ChineseTokenizer.cpp:
Token* ChineseTokenizer::next() {
while(!rd.Eos())
{
char_t ch = rd.GetNext();
if( isSpace((char_t)ch)!=0 )
{
continue;
}
// Read for Alpha-Nums and Chinese
if( isAlNum((char_t)ch)!=0 )
{
start = rd.Column();
return ReadChinese(ch);
}
}
return NULL;
}
Token* ChineseTokenizer::ReadChinese(const char_t prev)
{
bool isChinese = false;
StringBuffer str;
str.append(prev);
char_t ch = prev;
if(((char_t)ch>>8)&&(char_t)ch>=0xa0)
isChinese = true;
while(!rd.Eos() && isSpace((char_t)ch)==0 )
{
ch = rd.GetNext();
if(isAlNum((char_t)ch)!=0)
{
//是数学或英语就读到下一个空格.或下一个汉字
//是汉字.就读下一个汉字组成词组,或读到空格或英文结束
if(isChinese)
{
//汉字,并且ch是汉字
if(((char_t)ch>>8)&&(char_t)ch>=0xa0)
{
// 返回上一个汉字
str.append(ch);
rd.UnGet();
// wprintf(_T("[%s]"),str);
return new Token(str.getBuffer(), start, rd.Column(), tokenImage[lucene::analysis::chinese::CHINESE] );
}
else
{
//是字母或数字或空格
rd.UnGet();
// wprintf(_T("[%s]"),str);
return new Token(str.getBuffer(), start, rd.Column(), tokenImage[lucene::analysis::chinese::CHINESE] );
}
}
else
{
//非汉字
// ch是汉字
if(((char_t)ch>>8)&&(char_t)ch>=0xa0)
{
// wprintf(_T("[%s]"),str);
rd.UnGet();
return new Token(str.getBuffer(), start, rd.Column(), tokenImage[lucene::analysis::chinese::CHINESE] );
}
str.append( ch );
}
}
}
// wprintf(_T("[%s]"),str);
return new Token(str.getBuffer(), start, rd.Column(), tokenImage[lucene::analysis::chinese::ALPHANUM] );
}
同时,这个中文分词不支持文件,只能支持内存流的形式,因为我用到了rd.UnGet();如果是文件的话,嘿嘿,只能回退半个字节哦
![Razz :P](http://joinbbs.myjoin.cn/images/smilies/icon_razz.gif)
嗯。先写到这里了,今天太急了,等我有空了我就把我对CLucene的改进发到上面来。