一个给javabean列表建立倒排索引的通用类,主要可用于给缓存中的一类对象添加索引便于搜索,对于缓存中的对象实现模糊搜索是一种非常合适的方案
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class InvertedIndexGeneric<T> {
/**
* 索引
*/
private Map<String, List<T>> invertedIndex = new HashMap<String, List<T>>();
/**
* 缓存的待索引项
*/
private Map<String, T> invertedIndexItemsMap = new HashMap<String, T>();
/**
* 主键属性的get方法
*/
private Method prekeyMethod;
/**
* 被索引属性的get方法
*/
private Method indexedAttrMethod;
private Class<T> beanClass;
/**
*
* @param beanList
* 待索引javabean列表
* @param targetBeanClass
* 待索引javabean类型
* @param preKeyAttr
* 待索引项唯一标识(主键)的javabean属性名
* @param indexedAttr
* 待索引项的附加索引的javabean属性名
*/
public InvertedIndexGeneric(List<T> beanList, Class<T> targetBeanClass,
String preKeyAttr, String indexedAttr) {
if (beanList == null || beanList.size() == 0) {
throw new RuntimeException("待索引项为空!");
}
this.beanClass = targetBeanClass;
this.prekeyMethod = this.buildAttrGetMethod(preKeyAttr);
this.indexedAttrMethod = this.buildAttrGetMethod(indexedAttr);
for (T invertedIndexAble : beanList) {
invertedIndexItemsMap
.put(this.getIndexedBeanPrekey(invertedIndexAble),
invertedIndexAble);
}
this.buildInverteIndex();
}
/**
* 查询键值相关的索引项
*
* @param key
* 关键字
* @return 键值相关的索引项
*/
public synchronized List<T> find(String key) {
return invertedIndex.get(key);
}
/**
* 增加待索引项
*
* @param item
* 待索引项
*/
public synchronized void addInvertItem(T item) {
List<String> keys = getAllKeys(this.getIndexedAttrValue(item));
for (int i = 0; i < keys.size(); i++) {
String key = keys.get(i);
List<T> linkedIndexAbles = invertedIndex.get(key);
if (linkedIndexAbles != null) {
for (T varIndexAble : linkedIndexAbles) {
if (varIndexAble.equals(item)) {
continue;
}
}
linkedIndexAbles.add(item);
} else {
List<T> indexAbles = new ArrayList<T>();
indexAbles.add(item);
invertedIndex.put(key, indexAbles);
}
}
}
/**
* 删除待索引项
*
* @param beanPreKey
* 可索引项的主键
*/
public synchronized void deleteInvertedItem(String beanPreKey) {
T invertedIndexAble = invertedIndexItemsMap.get(beanPreKey);
List<String> keys = getAllKeys(this
.getIndexedAttrValue(invertedIndexAble));
for (int i = 0; i < keys.size(); i++) {
String key = keys.get(i);
List<T> linkedIndexAbles = invertedIndex.get(key);
if (linkedIndexAbles != null && linkedIndexAbles.size() > 0) {
for (T varTItem : linkedIndexAbles) {
if (this.getIndexedBeanPrekey(varTItem).equals(beanPreKey)) {
linkedIndexAbles.remove(varTItem);
break;
}
}
}
if (linkedIndexAbles.size() <= 0) {
invertedIndex.remove(key);
}
}
}
/**
* 更新可索引项
*
* @param bean
* 可索引项
*/
public synchronized void updateInvertedItem(T bean) {
T oldItem = invertedIndexItemsMap.get(this.getIndexedBeanPrekey(bean));
if (oldItem != null) {
this.deleteInvertedItem(this.getIndexedBeanPrekey(oldItem));
this.addInvertItem(bean);
}
}
/**
* 构建索引
*/
private synchronized void buildInverteIndex() {
for (T bean : invertedIndexItemsMap.values()) {
this.addInvertItem(bean);
}
}
/**
* 找出一个字符串所有的可能的倒排索引的键列表
*
* @param str
* 字符串
* @return 一个字符串所有的可能的倒排索引的键列表
*/
private List<String> getAllKeys(String str) {
List<String> result = new ArrayList<String>();
char[] chars = str.toCharArray();
for (int i = 0; i < chars.length; i++) {
String key = "";
for (int j = i; j < chars.length; j++) {
key = key + chars[j];
result.add(key);
}
}
return result;
}
private String getIndexedBeanPrekey(T bean) {
try {
return this.prekeyMethod.invoke(bean).toString();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private String getIndexedAttrValue(T bean) {
try {
return this.indexedAttrMethod.invoke(bean).toString();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private Method buildAttrGetMethod(String attrName) {
String firstLetter = attrName.substring(0, 1);
firstLetter = firstLetter.toUpperCase();
String methodName = "get" + firstLetter + attrName.substring(1);
Method method = null;
try {
method = this.beanClass.getMethod(methodName);
} catch (Exception e) {
throw new RuntimeException(e);
}
return method;
}
}