词库加载模块的源码:
Java开源分词系统IKAnalyzer学习(四) 词库加载源代码——Dictionary类
Java开源分词系统IKAnalyzer学习(五) 词库加载源代码——DictSegmenty类
Java开源分词系统IKAnalyzer学习(六) 词库加载源代码——Hit类
首先这个词典管理类Dictionary类采用的设计模式是单立模式,实现的代码:
- /*
- * 词典单子实例
- */
- private static final Dictionary singleton;
- /*
- * 词典初始化
- */
- static{
- singleton = new Dictionary();
- }
- private Dictionary(){
- //初始化系统词典
- loadMainDict();
- loadSurnameDict();
- loadQuantifierDict();
- loadSuffixDict();
- loadPrepDict();
- loadStopWordDict();
- }
- /**
- * 词典初始化
- * 由于IK Analyzer的词典采用Dictionary类的静态方法进行词典初始化
- * 只有当Dictionary类被实际调用时,才会开始载入词典,
- * 这将延长首次分词操作的时间
- * 该方法提供了一个在应用加载阶段就初始化字典的手段
- * 用来缩短首次分词时的时延
- * @return Dictionary
- */
- public static Dictionary getInstance(){
- return Dictionary.singleton;
- }
词库加载的关键代码,这里以主词典为例,其他大同小异
- /**
- * 加载主词典及扩展词典
- */
- private void loadMainDict(){
- //建立一个主词典实例
- _MainDict = new DictSegment((char)0);
- //读取主词典文件
- InputStream is = Dictionary.class.getResourceAsStream(Dictionary.PATH_DIC_MAIN);
- if(is == null){
- throw new RuntimeException("Main Dictionary not found!!!");
- }
- try {
- BufferedReader br = new BufferedReader(new InputStreamReader(is , "UTF-8"), 512);
- String theWord = null;
- do {
- theWord = br.readLine();
- //假如还没有读到文件尾
- if (theWord != null && !"".equals(theWord.trim())) {
- _MainDict.fillSegment(theWord.trim().toCharArray());
- }
- } while (theWord != null);
- } catch (IOException ioe) {
- System.err.println("Main Dictionary loading exception.");
- ioe.printStackTrace();
- }finally{
- try {
- if(is != null){
- is.close();
- is = null;
- }
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
底层的字典存储代码
- /**
- * 加载填充词典片段
- * @param charArray
- */
- public void fillSegment(char[] charArray){
- this.fillSegment(charArray, 0 , charArray.length);
- }
- /**
- * 加载填充词典片段
- * @param charArray
- * @param begin
- * @param length
- */
- public synchronized void fillSegment(char[] charArray , int begin , int length){
- //获取字典表中的汉字对象
- Character beginChar = new Character(charArray[begin]);
- Character keyChar = charMap.get(beginChar);
- //字典中没有该字,则将其添加入字典
- if(keyChar == null){
- charMap.put(beginChar, beginChar);
- keyChar = beginChar;
- }
- //搜索当前节点的存储,查询对应keyChar的keyChar,如果没有则创建(这段代码没看明白)
- DictSegment ds = lookforSegment(keyChar);
- //处理keyChar对应的segment
- if(length > 1){
- //词元还没有完全加入词典树
- ds.fillSegment(charArray, begin + 1, length - 1);
- }else if (length == 1){
- //已经是词元的最后一个char,设置当前节点状态为1,表明一个完整的词
- ds.nodeState = 1;
- }
- }
- /**
- * 查找本节点下对应的keyChar的segment
- * 如果没有找到,则创建新的segment
- * @param keyChar
- * @return
- */
- private DictSegment lookforSegment(Character keyChar){
- DictSegment ds = null;
- if(this.storeSize <= ARRAY_LENGTH_LIMIT){
- //获取数组容器,如果数组未创建则创建数组
- DictSegment[] segmentArray = getChildrenArray();
- //搜寻数组
- for(DictSegment segment : segmentArray){
- if(segment != null && segment.nodeChar.equals(keyChar)){
- //在数组中找到与keyChar对应的segment
- ds = segment;
- break;
- }
- }
- //遍历数组后没有找到对应的segment
- if(ds == null){
- //构造新的segment
- ds = new DictSegment(keyChar);
- if(this.storeSize < ARRAY_LENGTH_LIMIT){
- //数组容量未满,使用数组存储
- segmentArray[this.storeSize] = ds;
- //segment数目+1
- this.storeSize++;
- }else{
- //数组容量已满,切换Map存储
- //获取Map容器,如果Map未创建,则创建Map
- Map<Character , DictSegment> segmentMap = getChildrenMap();
- //将数组中的segment迁移到Map中
- migrate(segmentArray , segmentMap);
- //存储新的segment
- segmentMap.put(keyChar, ds);
- //segment数目+1 , 必须在释放数组前执行storeSize++ , 确保极端情况下,不会取到空的数组
- this.storeSize++;
- //释放当前的数组引用
- this.childrenArray = null;
- }
- }
- }else{
- //获取Map容器,如果Map未创建,则创建Map
- Map<Character , DictSegment> segmentMap = getChildrenMap();
- //搜索Map
- ds = (DictSegment)segmentMap.get(keyChar);
- if(ds == null){
- //构造新的segment
- ds = new DictSegment(keyChar);
- segmentMap.put(keyChar , ds);
- //当前节点存储segment数目+1
- this.storeSize ++;
- }
- }
- return ds;
- }
http://blog.csdn.net/lengyuhong/article/details/6010123