`
单眼皮大娘
  • 浏览: 112783 次
  • 性别: Icon_minigender_2
  • 来自: 上海
社区版块
存档分类
最新评论

paoding分词工具的字典如何构建

阅读更多
    分词工具不管如何变,其肯定会包含字典管理模块(当然,这是针对按字符串匹配分词),就算是基于语义分词也得有语义字典,基于统计需要词频字典等等。

    在调研了mmseg4j,ictclas4j(imdict和ictclas4j属于一类,只不过其为了效率去掉了ictclas4j的命名实体识别部分),IKAnalyzer,paoding 等分词器后,发现他们的字典管理基本大同小异。一下以paoding为例,解释下分词工具的字典管理模块。

    先说下paoding的字典数据结构。下面代码是字典接口,BinaryDictionary 和 HashBinaryDictionary 都实现该接口。其采用面向接口编程思想,其好处就是主要逻辑不用修改,易扩展。
public interface Dictionary {
	public int size();
	public Word get(int index);
	public Hit search(CharSequence input, int offset, int count);
}

HashBinaryDictionary的数据结构
public class HashBinaryDictionary implements Dictionary {

	/**
	 * 字典中所有词语,用于方便{@link #get(int)}方法
	 */
	private Word[] ascWords;

	/**
	 * 首字符到分词典的映射
	 */
	private Map/* <Object, SubDictionaryWrap> */subs;
	private final int hashIndex;

	private final int start;
	private final int end;
	private final int count;
}
    

BinaryDictionary 的数据结构
public class BinaryDictionary implements Dictionary {

	// -------------------------------------------------

	private Word[] ascWords;

	private final int start;
	private final int end;
	private final int count;
}


   字典文件首先是加载到一个HashSet中,这样的好处是可以去掉冗余的词,然后倒入到一个数组中,接着用
Arrays.sort(array);
这个方法对数组中的字典按升序排序,这样方便后续的二叉查找。

    下面就看一下其如何把一个array变成 BinaryDictionary的(注:HashBinaryDictionary最后也是以BinaryDictionary结构存储的)。
  
     首先通过FileDictionaries类中的
public synchronized Dictionary getVocabularyDictionary()
这个方法,加载字典文件中的词条到数组中,然后通过HashBinaryDictionary的构造方法开始构建字典的Hash数据结构,以key=词汇的首字母为分词典的索引键值(这个是BinaryDictionary的最终方式,HashBinaryDictionary如果词条的个数大于一定值,就按照词条的第二个字建立BinaryDictionary结构,这个过程是一个递归的过程)。看一下paoding中的这段代码:

public HashBinaryDictionary(Word[] ascWords, int hashIndex, int start,
			int end, int initialCapacity, float loadFactor) {
		this.ascWords = ascWords;
		this.start = start;
		this.end = end;
		this.count = end - start;
		this.hashIndex = hashIndex;
		subs = new HashMap(initialCapacity , loadFactor);
		createSubDictionaries();
	}



start记录的是分词典的开始偏移量,end记录的是分词典的末偏移量,initialCapacity 和 loadFactor两个值确定分词典的容积(目的估计是为了节省空间,因为构建这样的数据结构时确实是以空间换取时间来提升性能的)。
看一下createSubDictionaries()这个函数:
protected void createSubDictionaries() {
		if (this.start >= ascWords.length) {
			return;
		}
		
		// 定位相同头字符词语的开头和结束位置以确认分字典
		int beginIndex = this.start;
		int endIndex = this.start + 1;
		
		char beginHashChar = getChar(ascWords[start], hashIndex);
		char endHashChar;
		for (; endIndex < this.end; endIndex++) {
			endHashChar = getChar(ascWords[endIndex], hashIndex);
			if (endHashChar != beginHashChar) {
				addSubDictionary(beginHashChar, beginIndex, endIndex);
				beginIndex = endIndex;
				beginHashChar = endHashChar;
			}
		}
		addSubDictionary(beginHashChar, beginIndex, this.end);
	}


其大致流程就是以词典的首个字惊醒对比,目的是分块。即把每个首个字一样的词划分为一个子词典,hashIndex开始的时候是0,表示从第一个字开始,什么时候hashIndex的值变呢?
看一下addSubDictionary(beginHashChar, beginIndex, this.end)会有些眉目。

protected void addSubDictionary(char hashChar, int beginIndex, int endIndex) {
		Dictionary subDic = createSubDictionary(ascWords, beginIndex, endIndex);
		SubDictionaryWrap subDicWrap = new SubDictionaryWrap(hashChar,
				subDic, beginIndex);
		subs.put(keyOf(hashChar), subDicWrap);
	}


貌似没看到啥,在来看一下createSubDictionary函数:
protected Dictionary createSubDictionary(Word[] ascWords, int beginIndex,
			int endIndex) {
		int count = endIndex - beginIndex;
		if (count < 16) {
			return new BinaryDictionary(ascWords, beginIndex, endIndex);
		} else {
			return new HashBinaryDictionary(ascWords, hashIndex + 1,
					beginIndex, endIndex, getCapacity(count), 0.75f);
		}
	}


这下可以看的很清楚,当子字典的词条数大于一定值的时候就会使hashIndex 加 1,这里庖丁的作者把这个值设置为15。从createSubDictionary函数可以很清楚的看到构建字典结构是一个递归的过程,当词条数大于一定值时,就会把该子词典接着切分成更小的词典,因为hash是直接映射过去的,要比二叉查找快的多,但是统一构建成hash查找的方式取代二叉查找,其内存开销会很大,当字典达到一定规模后绝对会抛出 OOM错误,这是很头疼的问题,我估计作者考虑这一点,选择了个这种的办法。

     这样构建字典数据结构基本完成。

     后续:个人认为构建这样的数据结构不是很好,因为这样开销太大。中科院的ictclas4j采用的是二分查找的方法,其主要依靠的是他的字典,一次人工处理,终生受益,虽然ictclas4j采用的是ArrayList的存储方式,但由于字典经过人工整理,本身的字典就按照汉字的值进行排序,因而数组也就先天的具有了一定的序列,不需要在捣腾。这样的数据结构内存开销不大,但是有一个缺陷,那就是可扩展性几乎为0。
       
分享到:
评论

相关推荐

    Java调用paoding分词器对抓取的xml里面的新闻按照出现的词频进行分类

    Paoding分词器是一款高效的中文分词工具,它为Java开发者提供了方便的接口,用于实现对中文文本的智能分析,特别适合于海量文本的分词任务。下面将详细阐述这一过程中的关键知识点。 首先,我们要了解Paoding分词器...

    paoding中文分词

    Paoding中文分词是一款高效的开源分词工具,主要由Java编写,具备良好的性能和准确性。Paoding的设计目标是提供快速、准确且易用的分词服务,适用于各种应用场景,包括搜索引擎、推荐系统和大数据分析等。它采用了...

    庖丁分词jar包和dic目录

    标题中的“庖丁分词jar包和dic目录”指的是一个用于中文分词处理的软件工具,其中包含了必要的jar包和字典文件。庖丁分词是基于Java开发的一个高效、可扩展的中文分词库,它借鉴了Lucene的分词技术,并在此基础上...

    lucene简单教程poading中文分词.pdf

    在使用 Paoding 分词器时,需要配置相应的字典文件路径和分词参数,以确保分词的效果。例如,需要设置 `paoding.dic.home` 属性来指定字典文件存放的目录。同时,分词器还提供了词典修改检测间隔的配置,可以设置...

    庖丁分词jar包

    庖丁分词是一款高效、灵活且易用的中文分词工具,主要针对Java平台设计。在中文信息处理领域,分词是基础性的工作,它将连续的汉字序列切分成具有语义的词汇,为后续的文本分析、信息检索、情感分析等任务提供支持。...

    paoding-analysis-2.0.4-alpha2.rar_2.0.4-alpha2_paoding-analysis-

    《PaoDing Analysis 2.0.4-alpha2:高效中文分词工具解析》 在信息技术领域,中文处理是一项重要的挑战,特别是在自然语言处理、搜索引擎优化和文本挖掘等方面。PaoDing Analysis是一个针对这一问题的专业解决方案...

    solr安装设置资料

    - 在系统环境变量中添加`PAODING_DIC_HOME`,其值指向Paoding分词器的字典文件夹。 - 修改Solr的配置文件,确保Solr能够正确加载Paoding分词器的字典文件。 ##### 2. 配置Solr分词器 - 在Solr的`schema.xml`文件...

    几个搜索相关的pdf(lucene, 分词等)

    疱丁解牛分词器是一款专门针对中文分词的工具,其特点在于使用了灵活的词典和多种切分方法。本知识点将详细解析疱丁分词器中的关键概念、词典的组成、词典加载策略、编译过程、编码方式以及刀的种类和切分方法等。 ...

    最新庖丁分词源代码(for lucene3.0)

    通过阅读源代码,你可以了解其内部工作原理,如分词算法、字典构建、动态策略等,这对于理解中文分词技术,以及自定义和优化分词规则非常有帮助。 5. **学习与应用**: 对于开发者来说,学习庖丁分词的源代码可以...

    lucene3庖丁解牛中文分词器

    “庖丁解牛”中文分词器是一款专为中文文本处理设计的工具,其名字来源于古代寓言故事,寓意对复杂问题的深入理解和熟练掌握。它在Lucene的基础上,针对中文特有的语法结构和词汇习惯,提供了更加符合中文语境的分词...

    paoding-analysis3.0

    庖丁解牛中文分词器,只要配置好字典的路径,就可以使用庖丁解牛,可以有效针对中文进行分词,而且可以自定义词典。适用于lucene-core-3.3.0.jar,包内已经包含lucene-core-3.3.0.jar,已测试,包好用!

    solr的安装与使用

    我们使用的是paoding分词器。 首先,我们需要下载paoding分词器,下载地址为http://code.google.com/p/paoding/downloads/list。然后,我们需要在系统环境变量中加入PAODING_DIC_HOME变量,值为字典的位置。 在...

    庖丁解牛jarbao

    庖丁解牛中文分词器通过高效的算法和精心构建的字典,能够准确、快速地将连续的汉字序列分割成有意义的词语。在信息检索、文本分析、情感分析等众多领域,分词效果的好坏直接影响到后续处理的精度。 庖丁解牛的特点...

    Solrj and Solr and LDAP and SearchEngine

    4. 解决中文问题:对于中文分词,可以使用第三方库如Paoding,下载并设置PAODING_DIC_HOME环境变量指向字典文件位置,以便正确处理中文文本。 5. 示例代码:在给定的代码中,展示了一个基于Paoding的...

Global site tag (gtag.js) - Google Analytics