分类: Java
2013-02-16 17:05:25
很多场景下,对于某些元数据,经常会出现按多种条件查询的情况
举个简单的例子
public class ServiceMeta { private int serviceId; private int serviceType; private int serviceLevel; private int parentId; private int status; /**getters and setters**/ }
这个元数据类中,在实际应用中可能会根据ID/TYPE/LEVEL/STATUS单独或组合条件进行查询。
元数据的特点一般是:固定,数据量不是非常大,数据使用密度高。
在计算密度非常大的应用中,利用数据库的sql语句来做查询显然是不明智的,更多地是将元数据加载到内存中,通过集合存储,在使用的时候遍历查询获取数据。
public class MetaManager { priavet SetmetaSet; public ServiceMeta getServiceById (int id) { for (ServiceMeta meta : metaSet) { if (meta.getServiceId() == id) return meta; } return null; } /**other get methods**/ }
当然,这种方式的一个明显的缺点在于,过多的循环会严重影响系统的性能。因此,明智的选择是根据最常用的KEY建立映射关系,这样能有效地增加查询效率
public class MetaManager{ praivet MapmetaMap; pulic ServiceMeta getServiceMetaById (int id) { return metaMap.get(new Integer(id)); } public ServiceMeta getServiceMetaByType(int type){ for (ServiceMeta meta : metaMap.values()){ if(meta.getType()==type) return meta; } return null; } /**other get methods**/ }
好吧,在绝大部分查询都是使用单一类型的索引的情况下,上述代码可以很好得完成工作。
但是问题在于,当存在多个索引的时候呢?
在没有很好的解决方案的时候,通常会考虑使用两个map来实现,如上例中,同时建立
private MapidMap;
private MaptypeMap;
也可以避免频繁地查询,但是随之而来的问题,开发者需要同时维护多个map,当索引多到一定程度时,所有map的维护就会需要相当大的代价
因此一种更好的做法就是建立一个这样的关联关系
private Map
通过对KEY类型建立映射关系来解决问题。
这似乎看起来很美好,代码可以节省很多,但是由于某些细节,使用者还是需要关心KeyMeta与Key(例子中的Integer)的关系
如果调用者不想关心KeyMeta与Key的关心,那就只能将这个关系交给操作这个复合Map的相关类了,于是就会对这个Map封装在某个类中,使之成为单独的一个工具。
本文作者由于喜欢偷懒,因此这里使用guava的table来代替Map
其实HashBasedTable
于是就有了以下的工具类:
/** * 多维度KEY对同一个value的映射关系表 * * @author KOsteve * @version 1.0.0, 6/2/13 * @since 1.0.0 * */ public class WiMap{ /** * 维度信息 */ private final Set > metaSet; /** * 数据存储 */ private Table , K, V> table; public WiMap(Set > metaSet) { super(); this.metaSet = metaSet; table = HashBasedTable.create(); } public V get (K key) { WiKeyMeta meta = this.getMetaByKey(key); if (meta != null) { return table.get(meta, key); } return null; } public V put (K key, V value) { WiKeyMeta meta = this.getMetaByKey(key); if (meta != null) { return table.put(meta, key, value); } return null; } public int size() { return table.size(); } public boolean isEmpty() { return table.isEmpty(); } public boolean containsKey(K key) { WiKeyMeta meta = this.getMetaByKey(key); if (meta != null) { return table.containsColumn(key); } return false; } public boolean containsValue(Object value) { return table.containsValue(value); } public V remove(K key) { WiKeyMeta meta = this.getMetaByKey(key); if (meta != null) { return table.remove(meta, key); } return null; } public void clear() { table.clear(); } public Set keySet() { return table.columnKeySet(); } public Collection values() { return table.values(); } public Set > getMetaSet() { return metaSet; } private WiKeyMeta getMetaByKey (K key) { for (WiKeyMeta meta : metaSet) { if (meta.getKeyClazz().isInstance(key)) { return meta; } } return null; } }
/** * WiMap维度信息定义 * @author KOsteve * @version 1.0.0, 6/2/13 * @since 1.0.0 * */ public class WiKeyMeta{ /** * 维度名称 */ private final String meta; /** * 键值类 */ private final Class extends T> keyClazz; public WiKeyMeta(String meta, Class extends T> keyClazz) { this.meta = meta; this.keyClazz = keyClazz; } public String getMeta() { return meta; } public Class extends T> getKeyClazz() { return keyClazz; } @Override public int hashCode() { return HashCodeBuilder.reflectionHashCode(this); } @Override public boolean equals(Object obj) { return EqualsBuilder.reflectionEquals(this, obj); } }