java分词框架_Java开源分词系统IKAnalyzer学习(五) 词库加载源代码——DictSegmenty类 | 学步园...

本文详细介绍了Java分词框架中的IKAnalyzer组件,特别是DictSegment类的实现,该类结合数组和HashMap实现词典存储和词语匹配。通过DictSegment的match方法进行词段匹配,fillSegment方法用于加载和填充词典片段,动态适应不同长度的词汇。
摘要由CSDN通过智能技术生成

/**

*

*/

package org.wltea.analyzer.dic;

import java.util.HashMap;

import java.util.Map;

/**

* IK Analyzer v3.2

* 字典子片断 字典匹配核心类

* 该类采用 数组 结合 HashMap,实现词典存储,词语匹配

*

* 当下属的页节点小等于3时,采用数组存储

* 当下属的页节点大于3时,采用HashMap存储

* @author 林良益

*

*/

public class DictSegment {

//公用字典表,存储汉字

private static final Map charMap = new HashMap(16 , 0.95f);

//数组大小上限

private static final int ARRAY_LENGTH_LIMIT = 3;

//当前节点上存储的字符

private Character nodeChar;

//Map存储结构

private Map childrenMap;

//数组方式存储结构

private DictSegment[] childrenArray;

//当前节点存储的Segment数目

//storeSize <=ARRAY_LENGTH_LIMIT ,使用数组存储, storeSize >ARRAY_LENGTH_LIMIT ,则使用Map存储

private int storeSize = 0;

//当前DictSegment状态 ,默认 0 , 1表示从根节点到当前节点的路径表示一个词

private int nodeState = 0;

public DictSegment(Character nodeChar){

if(nodeChar == null){

throw new IllegalArgumentException("参数为空异常,字符不能为空");

}

this.nodeChar = nodeChar;

}

public Character getNodeChar() {

return nodeChar;

}

/*

* 判断是否有下一个节点

*/

public boolean hasNextNode(){

return this.storeSize > 0;

}

/**

* 匹配词段

* @param charArray

* @return Hit

*/

public Hit match(char[] charArray){

return this.match(charArray , 0 , charArray.length , null);

}

/**

* 匹配词段

* @param charArray

* @param begin

* @param length

* @return Hit

*/

public Hit match(char[] charArray , int begin , int length){

return this.match(charArray , begin , length , null);

}

/**

* 匹配词段

* @param charArray

* @param begin

* @param length

* @param searchHit

* @return Hit

*/

public Hit match(char[] charArray , int begin , int length , Hit searchHit){

if(searchHit == null){

//如果hit为空,新建

searchHit= new Hit();

//设置hit的其实文本位置

searchHit.setBegin(begin);

}else{

//否则要将HIT状态重置

searchHit.setUnmatch();

}

//设置hit的当前处理位置

searchHit.setEnd(begin);

Character keyChar = new Character(charArray[begin]);

DictSegment ds = null;

//引用实例变量为本地变量,避免查询时遇到更新的同步问题

DictSegment[] segmentArray = this.childrenArray;

Map segmentMap = this.childrenMap;

//STEP1 在节点中查找keyChar对应的DictSegment

if(segmentArray != null){

//在数组中查找

for(DictSegment seg : segmentArray){

if(seg != null && seg.nodeChar.equals(keyChar)){

//找到匹配的段

ds = seg;

}

}

}else if(segmentMap != null){

//在map中查找

ds = (DictSegment)segmentMap.get(keyChar);

}

//STEP2 找到DictSegment,判断词的匹配状态,是否继续递归,还是返回结果

if(ds != null){

if(length > 1){

//词未匹配完,继续往下搜索

return ds.match(charArray, begin + 1 , length - 1 , searchHit);

}else if (length == 1){

//搜索最后一个char

if(ds.nodeState == 1){

//添加HIT状态为完全匹配

searchHit.setMatch();

}

if(ds.hasNextNode()){

//添加HIT状态为前缀匹配

searchHit.setPrefix();

//记录当前位置的DictSegment

searchHit.setMatchedDictSegment(ds);

}

return searchHit;

}

}

//STEP3 没有找到DictSegment, 将HIT设置为不匹配

return searchHit;

}

/**

* 加载填充词典片段

* @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 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 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;

}

/**

* 获取数组容器

* 线程同步方法

*/

private DictSegment[] getChildrenArray(){

if(this.childrenArray == null){

synchronized(this){

if(this.childrenArray == null){

this.childrenArray = new DictSegment[ARRAY_LENGTH_LIMIT];

}

}

}

return this.childrenArray;

}

/**

* 获取Map容器

* 线程同步方法

*/

private Map getChildrenMap(){

if(this.childrenMap == null){

synchronized(this){

if(this.childrenMap == null){

this.childrenMap = new HashMap(ARRAY_LENGTH_LIMIT * 2,0.8f);

}

}

}

return this.childrenMap;

}

/**

* 将数组中的segment迁移到Map中

* @param segmentArray

*/

private void migrate(DictSegment[] segmentArray , Map segmentMap){

for(DictSegment segment : segmentArray){

if(segment != null){

segmentMap.put(segment.nodeChar, segment);

}

}

}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值