
com.aspire.nm.component.common.keyword.KeyWordUtil Maven / Gradle / Ivy
/*
* @(#)KeywordCharFinder.java
*
* Create Version: 1.0.0
* Author: James Liu
* Create Date: 2014-03-03
*
* Copyright (c) 2014 Aspire Information Technologies Ltd. All Right Reserved.
*/
package com.aspire.nm.component.common.keyword;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import com.aspire.nm.component.common.keyword.Strategy.LoadKeyWordStrategy;
import com.aspire.nm.component.common.keyword.Strategy.Impl.db.UpdateTimes;
import com.aspire.nm.component.commonUtil.log.ReleaseLogger;
/**
* 关键字查找器。
* 将所有关键字单词组装成单字树,遍历待查字符串的每个字,发现关键字树根有这个字开始检查。
* 使用字符实现.
*
* @version 1.0.0 2014-03-03
* @author James Liu
*/
public class KeyWordUtil extends Thread{
private static Logger logger = Logger.getLogger(KeyWordUtil.class);
private static Logger releaselogger = Logger.getLogger(ReleaseLogger.class);
private static final int REFRESH_SEC = 60;
private static String updateKeyWordTime;
private static boolean stop = false;
private LoadKeyWordStrategy loadKeyWordStrategy;
public KeyWordUtil(LoadKeyWordStrategy loadKeyWordStrategy){
this(loadKeyWordStrategy,true);
}
public KeyWordUtil(LoadKeyWordStrategy loadKeyWordStrategy,boolean availability){
this.loadKeyWordStrategy = loadKeyWordStrategy;
if(availability){
init();
}
}
private void init(){
doRun();
start();
}
public void run(){
while(true){
try {
Thread.sleep(REFRESH_SEC * 1000);
} catch (InterruptedException e) {}
if(stop){
break;
}
doRun();
}
}
private void doRun(){
UpdateTimes updateTimes = loadKeyWordStrategy.getUpdateTimes();
if(updateTimes == null) return;
if(updateKeyWordTime == null || !updateTimes.getUpdateKeyWordTime().equals(updateKeyWordTime)){
updateKeyWordTime = updateTimes.getUpdateKeyWordTime();
logger.debug("reLoadKeyWords...");
WriteLock writeLock = lock.writeLock();
try {
writeLock.lock();
root = new HashMap();
for(String keyword : loadKeyWordStrategy.loadKeyWords()){
parseWord(keyword);
}
} catch(Exception e) {
logger.error("[更新关键字失败]" + root.size(), e);
e.printStackTrace();
} finally {
writeLock.unlock();
}
logger.debug("reLoadKeyWords Done , size = " + root.size());
}
}
private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
private Map root = new HashMap();
private void parseWord(String word) {
if ((word == null) || (word.length() == 0)) return;
this.parseWord(this.getCharArray(word));
}
private void parseWord(Character[] word) {
if ((word == null) || (word.length == 0)) return;
Character parentChar = null;
Map parentNode = null;
for (int i = 0; i < word.length; i++) {
parentNode = this.parseChar(parentChar, parentNode, word[i], (i == (word.length - 1)) ? true : false);
parentChar = word[i];
if (parentNode == null) break;
}
}
/*
* 解析每个字符.
* 当碰到字符树的分支结束符时,提前结束单词解析。分支结束符的节点是Object,不是Map。
* 比如:“ab”和“abcd”,当解析“abcd”的“c”时,发现已经有“ab”了,则“abcd”将剔除,不作为关键字。
* 同样:“abcd”和“ab”,当解析“ab”完成时,会清除掉所有“ab”后面的分支,则“abcd”将剔除,不作为关键字。
*
* @param prevChar 前一个字符
* @param prevNode 前一个节点
* @param curChar 当前解析的字符
* @param isEndChar 当前解析字符是否是单词最后一个字符
*
* @return 当前字符节点,null为结束单词解析。
*/
@SuppressWarnings("unchecked")
private Map parseChar(Character prevChar, Map prevNode,
Character curChar, boolean isEndChar) {
Map curNode = this.root;
if (prevChar != null) {
Object current = prevNode.get(prevChar);
if (current == null) {
curNode = null;
} else if (current instanceof Map) {
curNode = (Map) current;
} else {
return null;
}
}
if (curNode == null) {
curNode = new HashMap();
if (isEndChar) {
curNode.put(curChar, new Object());
} else {
curNode.put(curChar, null);
}
prevNode.put(prevChar, curNode);
} else {
Object nextNode = curNode.get(curChar);
if ((nextNode != null) && !(nextNode instanceof Map)) return null;
if (nextNode == null) {
if (isEndChar) {
curNode.put(curChar, new Object());
} else {
curNode.put(curChar, null);
}
} else if (isEndChar) {
curNode.put(curChar, new Object());
}
}
return (isEndChar) ? null : curNode;
}
/*
* 获得字符串字符数组。
*
* @param s 要转换的字符串
*
* @return 字符串字符数组。如果s是null,则返回null;如果s是空字符串,则返回长度为零的数组。
*/
private Character[] getCharArray(String s) {
if (s == null) return null;
if (s.length() == 0) return new Character[0];
Character[] result = new Character[s.length()];
for (int i = 0; i < s.length(); i++) result[i] = s.charAt(i);
return result;
}
/*
* 匹配关键字。
*
* @param node 要匹配查找的节点
* @param chars 字符串字符数组
* @param pos 当前要匹配的字符
*
* @return 匹配上的关键字,没有匹配上返回null。
*/
@SuppressWarnings("unchecked")
private String match(Map node, Character[] chars, int pos) {
if (pos == chars.length) return null;
Object findResult = node.get(chars[pos]);
if (findResult == null) {
return null;
} else if (findResult instanceof Map) {
String keyword = this.match((Map) findResult, chars, pos + 1);
return (keyword == null) ? null : chars[pos].toString() + keyword;
} else {
return chars[pos].toString();
}
}
/**
* 检查字符串是否包含关键字。
*
* @param s 要检查的字符串
*
* @return 查找结果对象。对象中index是第一个找到的关键字的字符位置,-1为没有找到;keyword是找到的关键字。
*/
public Result check(String s) {
if (StringUtils.isEmpty(s)) return new Result(-1, null);
int index = -1;
String keyword = null;
Character[] chars = this.getCharArray(s);
ReadLock readLock = lock.readLock();
try {
readLock.lock();
for (int i = 0; i < chars.length; i++) {
keyword = this.match(this.root, chars, i);
if (keyword != null) {
index = i;
break;
}
}
} finally {
if(readLock != null) readLock.unlock();
}
return (index == -1) ? new Result(-1, null) : new Result(index, keyword);
}
/**
* 释放资源(停止线程)
*/
public void release(){
stop = true;
interrupt();
releaselogger.debug("release KeyWordUtil SUCESS");
}
/**
* 关键字查找器返回的结果类。
* 类中包含两个字段:index和keyword。
* index是被查找字符串中第一个和关键字匹配的字符的位置,从0开始。
* keyword是被查找字符串匹配上的关键字。
*
* @version 1.0.0 2014-03-03
* @author James Liu
*/
public static class Result {
private int index;
private String keyword;
private Result(int index, String keyword) {
this.index = index;
this.keyword = keyword;
}
public int getIndex() {
return index;
}
public String getKeyword() {
return keyword;
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("Result [index=").append(this.index).append(", keyword=").append(this.keyword).append("]");
return builder.toString();
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy