ICTCLAS的源码分析

来源:百度文库 编辑:神马文学网 时间:2024/05/02 17:33:31
10月15日
Faint~全都不在南京
男子篮球
解放军—山东
15:30
泰州体育馆
江苏—上海
19:00
泰州体育馆
浙江—北京
20:45
泰州体育馆
湖北—辽宁
15:30
盐城体育馆
吉林—黑龙江
19:00
盐城体育馆
河南—广东
20:45
盐城体育馆
18:34|固定链接 |评论 (2) |引用通告 (0)
固定链接关闭
10月10日
Lucene,Nutch‘sChineseAnalyzer的实现--ICTCLAS的源码分析(二)
分析*.dic 文件的具体结构和内容。
从上面我具体知道了DIC文件的结构,下一步我做的就是把*.DIC文件的内容提取出来,一来确认结构的正确性(是不是还含有别的信息在里面),二来了解一下整个字典的结构。
本来我想用完全标准的C++来完成分析,可惜用OFSTREAM的时候,怎么也读不出来数据(sample file却能读出来)。所以,为了节省时间,用MFC的Cfile类完成了字典的分析。其实分析很简单,只是一个函数而已:
#define CC_NUM 6768
int WriteDicToFile(char* dicFile,char* resultFile)
{
if(!dicFile||!resultFile)return 0;
CFile dic(dicFile,CFile::modeRead);
CFile res(resultFile,CFile::modeCreate|CFile::modeWrite);
int bytenum=0;
for(int i = 0 ; i< CC_NUM ; i++)
{
int SaIn;
dic.Read(&SaIn,4);
bytenum = bytenum +4;
CString s;
s.Format("IndexTable\nnCount:%d\n",SaIn);
res.Write(s,strlen(s));
if(SaIn==0)
{
res.Write("****************************\n",32);
continue;
}
int j=0;
while(j
{
int Buffer[3];
dic.Read(Buffer,12);
bytenum = bytenum +12;
int nFrenquency = Buffer[0];
int nLen = Buffer[1];
int nHanle = Buffer[2];
s.Format(" WordItem\n nFrenquency:%d\n nLen:%d\n nHandle:%d\n",nFrenquency,nLen,nHanle);
res.Write(s,strlen(s));
if(nLen!=0)
{
char* word = new char[nLen];
dic.Read(word,nLen);
bytenum = bytenum+nLen;
s.Format(" Word:%s\n",word);
res.Write(s,strlen(s));
}
res.Write("====================\n",21);
j++;
}
}
dic.Close();
res.Close();
return bytenum;
}
下面是对coreDict.dct的内容分析(太多了,只能截取,分析下来的是一个9M多的文件)
IndexTable
nCount:137
WordItem
nFrenquency:0
nLen:0
nHandle:26624
====================
WordItem
nFrenquency:256
nLen:0
nHandle:27136
====================
WordItem
nFrenquency:8
nLen:4
nHandle:28160
Word:巴鸟1
====================
WordItem
nFrenquency:2
nLen:2
nHandle:28275
Word:坝葺1
====================
WordItem
nFrenquency:12
nLen:2
nHandle:28160
Word:爸
====================
WordItem
nFrenquency:46
nLen:4
nHandle:28275
Word:比让1
====================
WordItem
nFrenquency:4
nLen:6
nHandle:28275
Word:比让市
====================
WordItem
nFrenquency:4
nLen:4
nHandle:28275
Word:比托1
====================
WordItem
nFrenquency:7
nLen:4
nHandle:28274
Word:波罗1
====================
WordItem
nFrenquency:6
nLen:4
nHandle:28282
Word:波罗1
====================
WordItem
nFrenquency:0
nLen:4
nHandle:28160
Word:伯丁1
====================
WordItem
nFrenquency:4
nLen:6
nHandle:28275
Word:布迪斯
====================
WordItem
nFrenquency:26
nLen:6
nHandle:28275
Word:布哈兹
========================================
从上面可以了解,这个是“阿”字的INDEX_TABLE。从我读取的字节数我也了解到这个DIC文件中再没别的信息。
我同时还分析BigramDict.dct文件,产生的是一个28M的文件(打开真是很辛苦),同样截取一段:
IndexTable
nCount:8
WordItem
nFrenquency:4
nLen:3
nHandle:3
Word:@、?
====================
WordItem
nFrenquency:38
nLen:3
nHandle:3
Word:@。?
====================
WordItem
nFrenquency:6
nLen:5
nHandle:3
Word:@……
====================
WordItem
nFrenquency:214
nLen:3
nHandle:3
Word:@!
====================
前面的是一个包含标点符号的INDEX_TABLE,奇怪的是都还有’@’符号,可能后面分词的时候会用到。
后面的INDEX_TABLE也是‘阿’字的。看来这个文件是coreDict.dct的补充,匆匆看了一下,里面含有了很多不是很常用的词汇。
16:45|固定链接 |评论 (0) |引用通告 (0)
固定链接关闭
Lucene,Nutch‘sChineseAnalyzer的实现--ICTCLAS的源码分析(一)
好,现在开始对ICTCLAS的源码分析,下面给出的是整个ICTCLAS的工程结构,可见这个工程不算大,我要分析的是和分析有关的类的结构以及实现(粗体字已经标出)。
Codes
│ ICTCLAS_WIN.cpp Windows界面的程序
│ ICTCLAS_Win.dsp
│ ICTCLAS_WIN.dsw
│ ICTCLAS_WIN.h
│ ICTCLAS_Win.exe 可执行程序
│ ICTCLAS_WinDlg.cpp
│ ICTCLAS_WinDlg.h
│ resource.h
│ StdAfx.cpp
│ StdAfx.h
│ log.txt 日志
│ ICTCLAS_Win.rc Windows界面的资源

├—Utility 共用函数模块
│ ContextStat.cpp
│ ContextStat.h
│ Dictionary.cpp
│ Dictionary.h
│ Utility.h
│ Utility.cpp

├—Unknown 未登录词识别模块
│ UnknowWord.cpp
│ UnknowWord.h

├—Tag HMM标注模块
│ Span.cpp
│ Span.h

├—Segment 词语切分模块
│ DynamicArray.h
│ NShortPath.cpp
│ NShortPath.h
│ Queue.cpp
│ Queue.h
│ SegGraph.cpp
│ Segment.cpp
│ Segment.h
│ DynamicArray.cpp
│ SegGraph.h

├—Result 结果生成模块
│ Result.cpp
│ Result.h

├—Data 概率数据文件
│ lexical.ctx
│ BigramDict.dct
│ coreDict.dct
│ nr.dct
│ nr.ctx
│ ns.ctx
│ ns.dct
│ tr.dct
│ tr.ctx

└—res Windows界面的资源

分析Cdictionary
Cdictionary类可以说是包在最外面的分词类,负责对汉语词句的处理,可以说这是一个汉语词句的加工工厂,输进去的是毫无分析信息的汉语句子,输出的是具有分词信息和词性标注的字符流。
分析Cdictionary之前,我们必须熟悉相关类的结构。下面是我对ICTCLAS中几个结构的图形表示(便于在看代码的时候查阅,我用WORD比较挫~~)
分词的第一步就是调用
/********************************************************************
* Func Name : Load
* Description: Load the dictionary from the file .dct
* Parameters : sFilename: the file name
* Returns : success or fail
* Author : Kevin Zhang
* History : 1.create 2002-1-9
*********************************************************************
bool CDictionary::Load(char *sFilename,bool bReset)
该函数用来读取DATA文件夹下面的*.dic文件(含有所有的语料信息),初始化自己的各个分词所用的结构,相当于把字典LOAD入内存,便于后面对于词语的查阅。分析他可以使我们得到*.dic的部分结构信息(该死的,要是有DIC结构的文档,还用得着这么费力的来推测他的结构吗?强烈建议以后开放源代码的项目,一定要开放内部的设计文档)
下面对函数内部的代码进行分析:
FILE *fp;//DIC文件
int i,j,nBuffer[3];//BUFFER中三个整数的意义到后面在具体讲述
if((fp=fopen(sFilename,"rb"))==NULL)
return false;//fail while opening the file
//如果原先的m_IndexTable是已经初始化的,需要把他所申请的内存全部归还
for( i=0;i
{//delete the memory of word item array in the dictionary,结构内部的内存释放
for( j=0;j
delete m_IndexTable[i].pWordItemHead[j].sWord;
delete [] m_IndexTable[i].pWordItemHead;
}
DelModified();//暂且不提
for(i=0;i具作者所说是所有汉字的个数,
//#define CC_NUM 6768
//The number of Chinese Char,including 5 empty //position between 3756-3761
{
fread(&(m_IndexTable[i].nCount),sizeof(int),1,fp);
//先读出单个IndexTable的nCount值,每个IndexTable记载了以某个单字开//头的所有WORD的信息,nCount就是那些WORD的个数,对于他所谓的//WORD的意义,暂不了解。
if(m_IndexTable[i].nCount>0)
m_IndexTable[i].pWordItemHead=new WORD_ITEM[m_IndexTable[i].nCount];
//如果nCount>0,就申请nCount个WORD_ITEM的内存空间,用来存放那些开头////都相同的WORD的WORD的信息
else
{
m_IndexTable[i].pWordItemHead=0;//如果nCount为0,就直接赋空
//转到下次循环(因为不需要初始化//IndexTable的各项信息)
continue;
}
j=0;
while(j
{
fread(nBuffer,sizeof(int),3,fp);//读三个整数,该整数和WORD_ITEM有直//接的关系,下面细说
m_IndexTable[i].pWordItemHead[j].sWord=new char[nBuffer[1]+1];
//可见nBuffer[1]存放的是单个//WORD_ITEM的Char* sWord的长度,
if(nBuffer[1])//String length is more than 0
{
fread(m_IndexTable[i].pWordItemHead[j].sWord,sizeof(char),nBuffer[1],fp);
//读出nCount为长度的字符串,如果nCount不为零的话。
//到这边我们就大概可以窥见*.dic文件的结构了。我会在
//后面做图形解释
}
m_IndexTable[i].pWordItemHead[j].sWord[nBuffer[1]]=0;
//他在这边做的就是把字符的最后一位赋为结
//束符号
if(bReset)//Reset the frequency
m_IndexTable[i].pWordItemHead[j].nFrequency=0;
else
m_IndexTable[i].pWordItemHead[j].nFrequency=nBuffer[0];
//到这边,我们就可以知道他前面读出的前//3个整数中的第一个就是这个//WORD_ITEM的nFrenquency.
m_IndexTable[i].pWordItemHead[j].nWordLen=nBuffer[1];
//哈哈,就是这个nWordLen
m_IndexTable[i].pWordItemHead[j].nHandle=nBuffer[2];
//Word_Item的nHandle值,具体的用途暂
//不可知
j+=1;//Get next item in the original table.
}
}
fclose(fp);
return true;
整理一下代码分析,我们大概已经窥视到了*.dic文件的内部结构
DIC结构 ( [ ]代表读取的是一个整形)
[Index Table’snCoun][nFrenquency][nLen][ nHandle] [ nFrenquency][nLen][ nHandle] [ nFrenquency][nLen][ nHandle]……………………………………………………….
[Index Table’snCoun][nFrenquency][nLen][ nHandle] [ nFrenquency][nLen][ nHandle] [ nFrenquency][nLen][ nHandle]………………………………………………………
即:

先分析到这吧,得去上课了,明天还得交算法作业,唉~~开夜车开夜车开夜车。
10:28|固定链接 |评论 (3) |引用通告 (0)
固定链接关闭
10月9日
Lucene,Nutch‘sChineseAnalyzer的实现--前述
Lucene是一个完全基于JAVA的全文检索搜索引擎。是个完全开放源码的项目。本来是隶属于Sourceforge的一个项目,现在已经被作者contribute到Jakarta.apache。所以你可以在以下两个链接访问到:http://sourceforge.net/projects/lucene,http://jakarta.apache.org/lucene。
Nutch是在Luncene下孵化的基于Lucene的Web search engine.Nutch比较年轻,所以运行的还不是很稳定,刚刚在10.1的时候刚刚发布他们的Nutch 0.7.1。在0.7的基础上修改了一点小BUG。虽然Nucth是个以Lucene为引擎的开放源码项目,但是由于没有详尽的文档(这方面Lucene做的比较好),而且在只给出了一般的公共包,关于那些运行的包好像没有公布(奇怪是不是?至少我没有找到。)这样导致了跟踪程序的困难。而且Nutch改动了些许Lucene的索引结构,所以阅读他的代码真的是很枯燥~没文档啊。
好,大概介绍完后就切入正题
Lucene的索引机制中定义了抽象类Analyzer,由Analyzer的派生对象完成对所要索引内容的分析,去除不必要的词(由StopFiler),连接不可分割的词(比如:chainone@gmail.com).然后再进行索引。下面给出了Analyzer的各个Lucene内置的派生对象:
WhitespaceAnalyzer Splits tokens at whitespace
SimpleAnalyzer Divides text at nonletter characters and lowercases
StopAnalyzer Divides text at nonletter characters, lowercases, and removes stop words
StandardAnalyzer Tokenizes based on a sophisticated grammar that recognizes e-mail
addresses, acronyms, Chinese-Japanese-Korean characters,
alphanumerics, and more; lowercases; and removes stop words。
StandardAnalyzer 对于英文的分词已经足够了,但是对于中文汉字却远远不够。比如:我是中国人。这句话,理想的分词结果是[我][是][中国人]或者[我][是][中国][人],但是StandardAnalyzer 对于这个却无能为力,只是标注了各个汉字的所属:[我(CJK)][是(CJK)][中(CJK)][国(CJK)][人(CJK)],可见他只是做了单字索引。网上也有人提供了比较简易的ChineseAnalyer,比如二元分词法,他的分词结果是[我是][是中][中国][国人],这样的分词太缺乏智能,也太浪费性能(非词的比例比较高)。
中科院对于自然语言理解一直进行着深入的研究,并且在网上发布了他们的ICTCLAS系统。他以人民日报2个月的资料作为自己的语料库,能对汉语句子进行划分,并进行词性标注。在这方面ICTCLAS做的非常的好。
据我了解,一开始ICTCLAS只是在网上发布了他们的几个简单的DEMO,有的也只是DLL类似的组件,对于源代码完全不可知。虽然对于对于JAVA,也可以用JINI达到对DLL的调用,但是ICTCLAS是个学术性质非常强的项目(发表了好多论文),但是同时也导致了ICTCLAS具有或大或小的BUG,所以在调用的时候经常会导致CRASH,由于异常来自DLL内,所以很是束手无策。
还好,现在ICTCLAS公布了他的DEMO版的代码,我大概跟踪了一下异常,发现了一个BUFFER溢出的BUG。但是对于他的分词原理还不理解。
所以,我接下来要做的,也是我写这篇文章的原因,就是分析ICTCLAS的源代码。由于自己导师那边还有项目赶着要转移平台,而且后面还有个无聊的考试,所以花在那上面的时间可能不会很多。我是把他当成一个兴趣来做的。我把他发在自己的BLOG上希望自己能有始有终,最终完成Lucene,Nutch‘sChineseAnalyzer。
11:52|固定链接 |评论 (0) |引用通告 (0)
固定链接关闭
9月29日
国庆放假从今天开始~
21:23|固定链接 |评论 (1) |引用通告 (0)
固定链接关闭
9月27日
我的Windows可能被ISP BS了
忽然之间
发现浏览GOOGLE居然也可以这么慢
杀毒,检查一遍系统后,发现没有什么问题
遂改用FIREFOX,问题继续,以前去SUN,APPACH下载都是100K+,现在只有5K-
faint!
是不是我被ISP限制了?仔细想想到现在也就用BT下过一部悬疑片和李敖来清华的演讲。
怎么可能同是一个路由器,为什么小宁的网速就这么快?
转用FEDORA CORE 3,发现网速正常。但是我的WINDOWS真的没什么问题啊!
这几天,为了下几个文件,天天LINUX,WINDOWS之间切换,真是够麻烦的。
忍。。。。。。。。。。。。。
13:32|固定链接 |评论 (7) |引用通告 (0)
固定链接关闭
9月26日
To be or not to be ?
13:28|固定链接 |评论 (0) |引用通告 (0)