| 1 | {{{ |
| 2 | #!html |
| 3 | <div style="text-align: center; color:#151B8D"><big style="font-weight: bold;"><big><big> |
| 4 | HBase Indexed Table |
| 5 | </big></big></big></div> <div style="text-align: center; color:#7E2217"><big style="font-weight: bold;"><big> |
| 6 | Using HBase TableIndexed from Thrift with unique keys |
| 7 | </big></big></div> |
| 8 | }}} |
| 9 | [[PageOutline]] |
| 10 | |
| 11 | [http://kdpeterson.net/blog/2009/09/using-hbase-tableindexed-from-thrift-with-unique-keys.html] |
| 12 | |
| 13 | HBase is primarily a sorted distributed hash map, but it does support secondary keys through a contrib package called Transactional HBase. The secondary keys are provided by a component called TableIndexed. |
| 14 | |
| 15 | |
| 16 | |
| 17 | |
| 18 | = Secondary indexes in HBase = |
| 19 | [http://rajeev1982.blogspot.com/2009/06/secondary-indexes-in-hbase.html] |
| 20 | |
| 21 | {{{ |
| 22 | #!java |
| 23 | import java.io.IOException; |
| 24 | import java.util.Date; |
| 25 | import org.apache.hadoop.fs.Path; |
| 26 | import org.apache.hadoop.hbase.HBaseConfiguration; |
| 27 | import org.apache.hadoop.hbase.HColumnDescriptor; |
| 28 | import org.apache.hadoop.hbase.HConstants; |
| 29 | import org.apache.hadoop.hbase.HTableDescriptor; |
| 30 | import org.apache.hadoop.hbase.client.Scanner; |
| 31 | import org.apache.hadoop.hbase.client.tableindexed.IndexSpecification; |
| 32 | import org.apache.hadoop.hbase.client.tableindexed.IndexedTable; |
| 33 | import org.apache.hadoop.hbase.client.tableindexed.IndexedTableAdmin; |
| 34 | import org.apache.hadoop.hbase.filter.ColumnValueFilter; |
| 35 | import org.apache.hadoop.hbase.filter.ColumnValueFilter.CompareOp; |
| 36 | import org.apache.hadoop.hbase.io.BatchUpdate; |
| 37 | import org.apache.hadoop.hbase.io.RowResult; |
| 38 | import org.apache.hadoop.hbase.util.Bytes; |
| 39 | |
| 40 | public class SecondaryIndexTest { |
| 41 | public void writeToTable() throws IOException { |
| 42 | HBaseConfiguration conf = new HBaseConfiguration(); |
| 43 | conf.addResource(new Path("/opt/hbase-0.19.3/conf/hbase-site.xml")); |
| 44 | |
| 45 | IndexedTable table = new IndexedTable(conf, Bytes.toBytes("test_table")); |
| 46 | |
| 47 | String row = "test_row"; |
| 48 | BatchUpdate update = null; |
| 49 | |
| 50 | for (int i = 0; i < 100; i++) { |
| 51 | update = new BatchUpdate(row + i); |
| 52 | update.put("columnfamily1:column1", Bytes.toBytes("value1-" + i)); |
| 53 | update.put("columnfamily1:column2", Bytes.toBytes("value2-" + i)); |
| 54 | table.commit(update); |
| 55 | } |
| 56 | |
| 57 | table.close(); |
| 58 | } |
| 59 | |
| 60 | public void readAllRowsFromSecondaryIndex() throws IOException { |
| 61 | HBaseConfiguration conf = new HBaseConfiguration(); |
| 62 | conf.addResource(new Path("/opt/hbase-0.19.3/conf/hbase-site.xml")); |
| 63 | |
| 64 | IndexedTable table = new IndexedTable(conf, Bytes.toBytes("test_table")); |
| 65 | |
| 66 | Scanner scanner = table.getIndexedScanner("column1", |
| 67 | HConstants.EMPTY_START_ROW, null, null, new byte[][] { |
| 68 | Bytes.toBytes("columnfamily1:column1"), |
| 69 | Bytes.toBytes("columnfamily1:column2") }); |
| 70 | |
| 71 | for (RowResult rowResult : scanner) { |
| 72 | System.out.println(Bytes.toString( |
| 73 | rowResult.get(Bytes.toBytes("columnfamily1:column1")).getValue()) |
| 74 | + ", " + Bytes.toString(rowResult.get( |
| 75 | Bytes.toBytes("columnfamily1:column2")).getValue() |
| 76 | )); |
| 77 | } |
| 78 | |
| 79 | table.close(); |
| 80 | } |
| 81 | |
| 82 | public void readFilteredRowsFromSecondaryIndex() throws IOException { |
| 83 | HBaseConfiguration conf = new HBaseConfiguration(); |
| 84 | conf.addResource(new Path("/opt/hbase-0.19.3/conf/hbase-site.xml")); |
| 85 | |
| 86 | IndexedTable table = new IndexedTable(conf, Bytes.toBytes("test_table")); |
| 87 | |
| 88 | ColumnValueFilter filter = |
| 89 | new ColumnValueFilter(Bytes.toBytes("columnfamily1:column1"), |
| 90 | CompareOp.LESS, Bytes.toBytes("value1-40")); |
| 91 | |
| 92 | Scanner scanner = table.getIndexedScanner("column1", |
| 93 | HConstants.EMPTY_START_ROW, null, filter, |
| 94 | new byte[][] { Bytes.toBytes("columnfamily1:column1"), |
| 95 | Bytes.toBytes("columnfamily1:column2") |
| 96 | }); |
| 97 | |
| 98 | for (RowResult rowResult : scanner) { |
| 99 | System.out.println(Bytes.toString( |
| 100 | rowResult.get(Bytes.toBytes("columnfamily1:column1")).getValue()) |
| 101 | + ", " + Bytes.toString(rowResult.get( |
| 102 | Bytes.toBytes("columnfamily1:column2")).getValue() |
| 103 | )); |
| 104 | } |
| 105 | |
| 106 | table.close(); |
| 107 | } |
| 108 | |
| 109 | public void createTableWithSecondaryIndexes() throws IOException { |
| 110 | HBaseConfiguration conf = new HBaseConfiguration(); |
| 111 | conf.addResource(new Path("/opt/hbase-0.19.3/conf/hbase-site.xml")); |
| 112 | |
| 113 | HTableDescriptor desc = new HTableDescriptor("test_table"); |
| 114 | |
| 115 | desc.addFamily(new HColumnDescriptor("columnfamily1:column1")); |
| 116 | desc.addFamily(new HColumnDescriptor("columnfamily1:column2")); |
| 117 | |
| 118 | desc.addIndex(new IndexSpecification("column1", |
| 119 | Bytes.toBytes("columnfamily1:column1"))); |
| 120 | desc.addIndex(new IndexSpecification("column2", |
| 121 | Bytes.toBytes("columnfamily1:column2"))); |
| 122 | |
| 123 | IndexedTableAdmin admin = null; |
| 124 | admin = new IndexedTableAdmin(conf); |
| 125 | |
| 126 | if (admin.tableExists(Bytes.toBytes("test_table"))) { |
| 127 | if (admin.isTableEnabled("test_table")) { |
| 128 | admin.disableTable(Bytes.toBytes("test_table")); |
| 129 | } |
| 130 | |
| 131 | admin.deleteTable(Bytes.toBytes("test_table")); |
| 132 | } |
| 133 | |
| 134 | if (admin.tableExists(Bytes.toBytes("test_table-column1"))) { |
| 135 | if (admin.isTableEnabled("test_table-column1")) { |
| 136 | admin.disableTable(Bytes.toBytes("test_table-column1")); |
| 137 | } |
| 138 | |
| 139 | admin.deleteTable(Bytes.toBytes("test_table-column1")); |
| 140 | } |
| 141 | |
| 142 | admin.createTable(desc); |
| 143 | } |
| 144 | |
| 145 | public void addSecondaryIndexToExistingTable() throws IOException { |
| 146 | HBaseConfiguration conf = new HBaseConfiguration(); |
| 147 | conf.addResource(new Path("/opt/hbase-0.19.3/conf/hbase-site.xml")); |
| 148 | |
| 149 | IndexedTableAdmin admin = null; |
| 150 | admin = new IndexedTableAdmin(conf); |
| 151 | |
| 152 | admin.addIndex(Bytes.toBytes("test_table"), |
| 153 | new IndexSpecification("column2", |
| 154 | Bytes.toBytes("columnfamily1:column2"))); |
| 155 | } |
| 156 | |
| 157 | public void removeSecondaryIndexToExistingTable() throws IOException { |
| 158 | HBaseConfiguration conf = new HBaseConfiguration(); |
| 159 | conf.addResource(new Path("/opt/hbase-0.19.3/conf/hbase-site.xml")); |
| 160 | |
| 161 | IndexedTableAdmin admin = null; |
| 162 | admin = new IndexedTableAdmin(conf); |
| 163 | |
| 164 | admin.removeIndex(Bytes.toBytes("test_table"), "column2"); |
| 165 | } |
| 166 | |
| 167 | public static void main(String[] args) throws IOException { |
| 168 | SecondaryIndexTest test = new SecondaryIndexTest(); |
| 169 | |
| 170 | test.createTableWithSecondaryIndexes(); |
| 171 | test.writeToTable(); |
| 172 | test.addSecondaryIndexToExistingTable(); |
| 173 | test.removeSecondaryIndexToExistingTable(); |
| 174 | test.readAllRowsFromSecondaryIndex(); |
| 175 | test.readFilteredRowsFromSecondaryIndex(); |
| 176 | |
| 177 | System.out.println("Done!"); |
| 178 | } |
| 179 | } |
| 180 | }}} |