对于初步接触分词的朋友们来说,分词词典的构造是一件不可小觑的事情。因为词典的好坏直接影响到算法的性能、运行时间。换句话说,分词词典构造的好,将会极大地改观分词的性能,而各种复杂的分词算法,直接依赖于分词词典的构造机制(是进行分词的根基)。下面将分几个部分进行词典构造机制几种方法的介绍。
在这片文章中,根据我所用过的最基础的方法进行词典的构造,即拼音的索引方法。(也是大家最能直接想到的方法)
下面结合我的应用,分享一下具体的做法。
1. hashMap.java 文件
文件用来将拼音生成一个 LinkedHashMap 表,并对应与相应的键值。如下所示:
hashMap.put("a", 0);
hashMap.put("ai", 1);
hashMap.put("an", 2);
hashMap.put("ang", 3);
hashMap.put("ao", 4);
hashMap.put("ba", 5);
hashMap.put("bai", 6);
hashMap.put("ban", 7);
…
将拼音“a”放在哈希散列图的第0个位置,依次类推。
2. CnToSpell.java 文件
此文件用于将汉字转化为读音。例如输入“你好”将返回“nihao”。其中用到的getCnAscii() 方法,是根据汉字的国标码将其对应于相应int型的数值。如下:
public static int getCnAscii(char cn) {
byte[] bytes = null;
try {
bytes = (String.valueOf(cn)).getBytes("gbk");
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (bytes == null || bytes.length > 2 || bytes.length <= 0) {
return 0;
}
if (bytes.length == 1) {
return bytes[0];
}
if (bytes.length == 2) {
int hightByte = 256 + bytes[0];
int lowByte = 256 + bytes[1];
int ascii = (256 * hightByte + lowByte) - 256 * 256;
// System.out.println("ASCII=" + ascii);
return ascii;
}
return 0;
}
而initialize()方法则将对应的数值和拼音的对应关系存入哈希散列图中。
(LinkedHashMap<String, Integer>spellMap = new LinkedHashMap<String, Integer>(400);)
spellPut("a", -20319);
spellPut("ai", -20317);
spellPut("an", -20304);
spellPut("ang", -20295);
spellPut("ao", -20292);
spellPut("ba", -20283);
spellPut("bai", -20265);
spellPut("ban", -20257);
spellPut("bang", -20242);
spellPut("bao", -20230);
spellPut("bei", -20051);
spellPut("ben", -20036);
spellPut("beng", -20032);
……
所以对于一个要转化为拼音的汉字而言,首先用getCnAscii() 方法获得int型数值,而后根据哈希散列图寻找相应的读音。
特别地,对于多音字的部分词汇将归为排在前面的第一个拼音。此外,其他情况,例如某些复杂汉字无法找到其对应的拼音,将要单独归为一类。(因为此种情况的汉字不算太多,所以对于性能而言,没有影响)
3. Dictionary.java文件
遍历一个txt 词典文件,根据第一个汉字的读音,将它们按照读音的不同归为不同的类中。
public void makeDictionary() throws IOException {// 打开一个到文件WordTable.txt的一个流
BufferedReader bf = new BufferedReader(new FileReader("stopword.txt"));
String dicItem = "";// 每一行的词语
int currentZiYinIndex = 0;// 当期字音的键值
while ((dicItem = bf.readLine()) != null) {
String firstCharacter = dicItem.substring(0, 1);// 获取第一个字
String ziYin = CnToSpell.getFullSpell(firstCharacter);// 获取第一个字的字音
if (hashMap.get(ziYin) != null) {
currentZiYinIndex = hashMap.get(ziYin).intValue(); // 获得第一个字音对应的键值
if (dicStr[currentZiYinIndex] == null) {
dicStr[currentZiYinIndex] = dicItem + " ";
} else {
dicStr[currentZiYinIndex] += dicItem + " ";
}
}// 否则存入未能识别的数组
else {// unknownWords 每次都叠加
if (dicStr[395] == null) {
dicStr[395] = dicItem + " ";
} else {
dicStr[395] += dicItem + " ";
}
}
}
}
同样的道理,查找某一个词条时,首先根据首字转化为拼音,然后,根据该拼音缩小查找范围,提高查询速率。程序如下:
public boolean lookDictionary(String words) {
boolean flag = false;// 定义布尔型变量用来标志是否找到
String firstWord = "";
if (words.length() > 1) {
firstWord = words.substring(0, 1);
} else if (words.length() == 1) {
firstWord = String.valueOf(words.charAt(0));
}
// System.out.println(firstWord);
String ziYin = CnToSpell.getFullSpell(firstWord);// 获取第一个字的字音
int index = 0;// 用来标记键值
if (hashMap.get(ziYin) != null) {
index = hashMap.get(ziYin).intValue();// 获得键值,找到相应的数组
} else {
index = 395;
}
if (dicStr[index] == null)
return false;
String singleWord[] = dicStr[index].split(" ");// 将一个长的字符串按照空格划分为多个单词
int numOfSpace = 0;// 定义一个变量来统计空格的个数,从而来确定划分完后的数组个数
for (int i = 0; i < dicStr[index].length(); i++) {// 统计有多少个空格,从而确定数组的个数
if (dicStr[index].charAt(i) == ' ') {
numOfSpace++;
}
}
// 在划分完的数组中查找该词,如果找到将flag设为true
for (int ind = 0; ind < (numOfSpace); ind++) {
if (singleWord[ind].equals(words)) {
flag = true;
break;
}
}
return flag;
}
当然,分词词典的构成机制还有其他的集中主流方法,在下面的文档中将会和大家一起交流。
分享到:
相关推荐
3、中文分词算法 之 词典机制性能优化与测试 4、中文分词算法 之 基于词典的正向最小匹配算法 5、中文分词算法 之 基于词典的逆向最小匹配算法 5、Java开源项目cws_evaluation:中文分词器分词效果评估
类中可能包含一个词典成员变量,用于存储词汇,以及一个或多个方法,如`Tokenize()`用于执行分词操作,`LoadDictionary()`用于加载词典文件,`AddCustomRule()`用于添加用户自定义的分词规则等。 7. **文件I/O操作*...
对于给定的字符串α1, α2, …, αn,在Trie树中搜索最多只需要经过n次匹配即可完成一次查找,这使得它成为中文匹配分词算法中词典的一种常见实现方式。然而,Trie树的空间利用率通常较低。 双数组Trie树是对Trie树...
"je-analysis"可能是一个早期的中文分析器,用于对中文文本进行预处理,包括词典匹配、分词、去除停用词等步骤,以便于Lucene理解并处理中文内容。这在处理大量中文文档时尤其关键,因为中文没有明显的词边界,传统...
例如,IK 分词器就是一种常用的基于词典的中文分词器,它支持动态加载词典,能较好地处理常见词汇。 - **统计语言模型分词**:这种方法利用概率统计模型,如隐马尔可夫模型(HMM)或条件随机场(CRF),根据词语...
3. **创建Analyzer实例**:通过`org.wltea.analyzer.lucene.IKAnalyzer`类的构造函数创建分词器实例。 4. **执行分词**:使用Analyzer的`TokenStream`方法对文本进行分词。 5. **处理分词结果**:遍历返回的`...
此外,为了优化性能和内存占用,盘古分词支持词典动态加载和缓存机制。当系统内存有限时,可以选择延迟加载词典,只在需要时才加载到内存,以减少启动时的资源消耗。 总结来说,盘古分词与Lucene.Net 3.0.3的集成...
开发者不仅对Alice的源码进行了深度定制,还充分利用了Maven的构建机制和IK分词器的特性,实现了对中文输入的高效处理和对话流程的灵活控制。这对于提升Alice与中文用户的交互体验具有重要意义。
然后,设计一个分词函数,该函数利用MFC的消息处理机制,接收输入文本,调用最大匹配算法进行分词,并将结果输出。 在MFC项目中,可以创建一个C++类,比如`CWordSeg`,来封装分词逻辑。类的成员变量可能包括词典、...
本文将深入探讨IKAnalyzer的源码,剖析其核心的词典处理、分词处理和歧义处理机制。 首先,我们来看IKAnalyzer的词典处理。词典是分词的基础,IKAnalyzer的词典主要分为两大部分:一是内置的主词典`main2012.dic`,...
- 附加分词词典是对主分词词典的补充,用于处理特定领域的专业词汇。 - 停用词典包含了一些常见但无意义的词汇,如“的”、“和”等,避免这些词汇干扰搜索结果。 - 附加停用词典同样是对主停用词典的扩展,针对特定...
在源码中,你可以看到分词器的实现细节,包括词典加载、动态扩展和词语切分策略。 接下来,我们关注TF-IDF(Term Frequency-Inverse Document Frequency)算法。TF-IDF是一种在信息检索和文本挖掘领域常用的评分...
2. **动态词典**:IKAnalyzer 支持动态加载词典,用户可以根据需要自行扩展或更新词典,增强了分词的灵活性。 3. **用户自定义分析**:除了内置的分词规则,IKAnalyzer 还允许用户自定义分析器,实现特定的分词逻辑...
作者基于该优化策略实现了一个词典管理程序,并将其与其他索引机制进行对比实验。实验结果显示,利用优化后的双数组Trie树算法的词典不仅在查询速度上优于使用其他索引机制的词典,而且在存储数据的空间占用方面也...
DotLucene提供了一个高效的索引机制,能够快速地对大量文本数据进行预处理,生成可以高效查询的索引。这个过程包括分析文本(分词)、建立倒排索引以及存储各种元数据。索引构建完成后,用户可以通过输入关键词进行...
这部分可能讲解了中文分词算法,如基于词典的分词、统计模型的分词等。同时,去重机制确保每个网页只被索引一次,防止重复信息。 4. **倒排索引**:倒排索引是搜索引擎的核心数据结构,使得快速查找包含特定关键词...
Lucene的查询解析过程包括了分词、语法分析、查询构造等多个步骤。用户输入的文本首先经过查询解析器(QueryParser)转化为一系列的查询条款(Query Terms),这些条款可以是单个词汇,也可以是复杂的布尔表达式。...
本文主要探讨了双数组Trie树(Double-Array Trie)算法的一种优化方法,并详细分析了其在实际应用中的表现,特别是在词典管理和自动分词领域。双数组Trie树作为一种高效的字符串搜索算法,在诸多场景下具有重要的应用...