package com.activequant.dao.hbase; import java.io.IOException; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Map.Entry; import java.util.NavigableMap; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.hbase.HBaseConfiguration; import org.apache.hadoop.hbase.HColumnDescriptor; import org.apache.hadoop.hbase.HTableDescriptor; import org.apache.hadoop.hbase.client.HBaseAdmin; import org.apache.hadoop.hbase.client.HTable; import org.apache.hadoop.hbase.client.Put; import org.apache.hadoop.hbase.client.Result; import org.apache.hadoop.hbase.client.ResultScanner; import org.apache.hadoop.hbase.client.Scan; import org.apache.hadoop.hbase.filter.CompareFilter.CompareOp; import org.apache.hadoop.hbase.filter.FilterList; import org.apache.hadoop.hbase.filter.SingleColumnValueFilter; import org.apache.hadoop.hbase.util.Bytes; import org.apache.log4j.Logger; import com.activequant.domainmodel.exceptions.DaoException; public class TagDao { private List<Put> puts = new ArrayList<Put>(); protected HTable htable; private final Logger log = Logger.getLogger(TagDao.class); public TagDao(final String zookeeperQuorumHost) throws IOException { this(zookeeperQuorumHost, 2181, "TAGS"); } public TagDao(final String zookeeperQuorumHost, final int zookeeperPort, final String tableName) throws IOException { Configuration config = HBaseConfiguration.create(); config.set("hbase.zookeeper.quorum", zookeeperQuorumHost + ":" + zookeeperPort); HBaseAdmin admin = new HBaseAdmin(config); if (!admin.tableExists(tableName.getBytes())) { log.info("HTable for Tags doesn't exist. Creating it."); // create the table. HTableDescriptor desc = new HTableDescriptor(tableName.getBytes()); HColumnDescriptor col1 = new HColumnDescriptor("tags".getBytes()); desc.addFamily(col1); admin.createTable(desc); boolean avail = admin.isTableAvailable(tableName.getBytes()); log.info("HTable for Tags is available: " + avail); } htable = new HTable(config, tableName.getBytes()); htable.setAutoFlush(false); htable.setScannerCaching(1000000); } /* * (non-Javadoc) * * @see com.activequant.archive.IArchiveWriter#commit() */ public void commit() throws IOException { synchronized (puts) { htable.put(puts); puts.clear(); htable.flushCommits(); } } public void tag(String objectType, String objectId, String tag) { String rowKey = objectType + "_" + objectId; Put p = new Put(rowKey.getBytes()); p.add("tags".getBytes(), tag.toUpperCase().getBytes(), Bytes.toBytes(1)); p.add("tags".getBytes(), "OBJECTID".getBytes(), Bytes.toBytes(objectId)); p.add("tags".getBytes(), "OBJECTTYPE".getBytes(), Bytes.toBytes(objectType)); // relatively expensive call. have to find a way around. // maybe by using a special class. synchronized (puts) { puts.add(p); } } public void untag(String objectType, String objectId, String tag) { String rowKey = objectType + "_" + objectId; Put p = new Put(rowKey.getBytes()); p.add("tags".getBytes(), tag.toUpperCase().getBytes(), Bytes.toBytes(0)); synchronized (puts) { puts.add(p); } } public String[] getAll() throws DaoException { try { List<String> ret = new ArrayList<String>(); Scan s = new Scan(); s.setMaxVersions(1); ResultScanner scanner = htable.getScanner(s); try { for (Result rr = scanner.next(); rr != null; rr = scanner.next()) { String localObjectId = new String(rr.getValue("tags".getBytes(), "OBJECTID".getBytes())); ret.add(localObjectId); } } finally { scanner.close(); } return ret.toArray(new String[] {}); } catch (IOException ex) { throw new DaoException(ex); } } public String[] getTags(String objectType, String objectId) throws IOException { List<String> ret = new ArrayList<String>(); String rowKey = objectType + "_" + objectId; Scan s = new Scan(rowKey.getBytes(), rowKey.getBytes()); s.setMaxVersions(1); ResultScanner scanner = htable.getScanner(s); try { for (Result rr = scanner.next(); rr != null; rr = scanner.next()) { String localObjectType = new String(rr.getValue("tags".getBytes(), "OBJECTTYPE".getBytes())); String localObjectId = new String(rr.getValue("tags".getBytes(), "OBJECTID".getBytes())); NavigableMap<byte[], byte[]> map = rr.getFamilyMap("tags".getBytes()); Iterator<Entry<byte[], byte[]>> it = map.entrySet().iterator(); while (it.hasNext()) { Entry<byte[], byte[]> entry = it.next(); String key = new String(entry.getKey()); if (!key.startsWith("OBJECT")) { int val = Bytes.toInt(entry.getValue()); if (val > 0) ret.add(key); } } } } finally { scanner.close(); } return ret.toArray(new String[] {}); } public String[] getObjectIDs(String objectType, String... tags) throws IOException { List<String> ret = new ArrayList<String>(); FilterList list = new FilterList(FilterList.Operator.MUST_PASS_ALL); SingleColumnValueFilter filter1 = new SingleColumnValueFilter("tags".getBytes(), "OBJECTTYPE".getBytes(), CompareOp.EQUAL, Bytes.toBytes(objectType)); list.addFilter(filter1); for (String tag : tags) { SingleColumnValueFilter filter2 = new SingleColumnValueFilter("tags".getBytes(), tag.toUpperCase() .getBytes(), CompareOp.EQUAL, Bytes.toBytes(1)); filter2.setFilterIfMissing(true); list.addFilter(filter2); } Scan s = new Scan(); s.setFilter(list); s.setMaxVersions(1); ResultScanner scanner = htable.getScanner(s); try { for (Result rr = scanner.next(); rr != null; rr = scanner.next()) { String localObjectType = new String(rr.getValue("tags".getBytes(), "OBJECTTYPE".getBytes())); String localObjectId = new String(rr.getValue("tags".getBytes(), "OBJECTID".getBytes())); ret.add(localObjectId); } } finally { scanner.close(); } return ret.toArray(new String[] {}); } }