1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.hadoop.hbase.filter;
19
20 import static org.junit.Assert.*;
21
22 import java.io.IOException;
23 import java.util.ArrayList;
24 import java.util.HashMap;
25 import java.util.HashSet;
26 import java.util.List;
27 import java.util.Map;
28 import java.util.Set;
29
30 import org.apache.commons.logging.Log;
31 import org.apache.commons.logging.LogFactory;
32 import org.apache.hadoop.hbase.*;
33 import org.apache.hadoop.hbase.client.Put;
34 import org.apache.hadoop.hbase.client.Result;
35 import org.apache.hadoop.hbase.client.ResultScanner;
36 import org.apache.hadoop.hbase.client.Scan;
37 import org.apache.hadoop.hbase.client.Durability;
38 import org.apache.hadoop.hbase.client.Table;
39 import org.apache.hadoop.hbase.filter.FilterList.Operator;
40 import org.apache.hadoop.hbase.testclassification.MediumTests;
41 import org.apache.hadoop.hbase.util.Bytes;
42 import org.junit.Test;
43 import org.junit.After;
44 import org.junit.AfterClass;
45 import org.junit.Before;
46 import org.junit.BeforeClass;
47 import org.junit.experimental.categories.Category;
48
49
50 class StringRange {
51 private String start = null;
52 private String end = null;
53 private boolean startInclusive = true;
54 private boolean endInclusive = false;
55
56 public StringRange(String start, boolean startInclusive, String end,
57 boolean endInclusive) {
58 this.start = start;
59 this.startInclusive = startInclusive;
60 this.end = end;
61 this.endInclusive = endInclusive;
62 }
63
64 public String getStart() {
65 return this.start;
66 }
67
68 public String getEnd() {
69 return this.end;
70 }
71
72 public boolean isStartInclusive() {
73 return this.startInclusive;
74 }
75
76 public boolean isEndInclusive() {
77 return this.endInclusive;
78 }
79
80 @Override
81 public int hashCode() {
82 int hashCode = 0;
83 if (this.start != null) {
84 hashCode ^= this.start.hashCode();
85 }
86
87 if (this.end != null) {
88 hashCode ^= this.end.hashCode();
89 }
90 return hashCode;
91 }
92
93 @Override
94 public String toString() {
95 String result = (this.startInclusive ? "[" : "(")
96 + (this.start == null ? null : this.start) + ", "
97 + (this.end == null ? null : this.end)
98 + (this.endInclusive ? "]" : ")");
99 return result;
100 }
101
102 public boolean inRange(String value) {
103 boolean afterStart = true;
104 if (this.start != null) {
105 int startCmp = value.compareTo(this.start);
106 afterStart = this.startInclusive ? startCmp >= 0 : startCmp > 0;
107 }
108
109 boolean beforeEnd = true;
110 if (this.end != null) {
111 int endCmp = value.compareTo(this.end);
112 beforeEnd = this.endInclusive ? endCmp <= 0 : endCmp < 0;
113 }
114
115 return afterStart && beforeEnd;
116 }
117
118 }
119
120
121 @Category(MediumTests.class)
122 public class TestColumnRangeFilter {
123
124 private final static HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
125
126 private static final Log LOG = LogFactory.getLog(TestColumnRangeFilter.class);
127
128
129
130
131 @BeforeClass
132 public static void setUpBeforeClass() throws Exception {
133 TEST_UTIL.startMiniCluster();
134 }
135
136
137
138
139 @AfterClass
140 public static void tearDownAfterClass() throws Exception {
141 TEST_UTIL.shutdownMiniCluster();
142 }
143
144
145
146
147 @Before
148 public void setUp() throws Exception {
149
150 }
151
152
153
154
155 @After
156 public void tearDown() throws Exception {
157
158 }
159
160 @Test
161 public void TestColumnRangeFilterClient() throws Exception {
162 String family = "Family";
163 String table = "TestColumnRangeFilterClient";
164 Table ht =
165 TEST_UTIL.createTable(TableName.valueOf(table), Bytes.toBytes(family), Integer.MAX_VALUE);
166
167 List<String> rows = generateRandomWords(10, 8);
168 long maxTimestamp = 2;
169 List<String> columns = generateRandomWords(20000, 8);
170
171 List<KeyValue> kvList = new ArrayList<KeyValue>();
172
173 Map<StringRange, List<KeyValue>> rangeMap = new HashMap<StringRange, List<KeyValue>>();
174
175 rangeMap.put(new StringRange(null, true, "b", false), new ArrayList<KeyValue>());
176 rangeMap.put(new StringRange("p", true, "q", false), new ArrayList<KeyValue>());
177 rangeMap.put(new StringRange("r", false, "s", true), new ArrayList<KeyValue>());
178 rangeMap.put(new StringRange("z", false, null, false), new ArrayList<KeyValue>());
179 String valueString = "ValueString";
180
181 for (String row : rows) {
182 Put p = new Put(Bytes.toBytes(row));
183 p.setDurability(Durability.SKIP_WAL);
184 for (String column : columns) {
185 for (long timestamp = 1; timestamp <= maxTimestamp; timestamp++) {
186 KeyValue kv = KeyValueTestUtil.create(row, family, column, timestamp, valueString);
187 p.add(kv);
188 kvList.add(kv);
189 for (StringRange s : rangeMap.keySet()) {
190 if (s.inRange(column)) {
191 rangeMap.get(s).add(kv);
192 }
193 }
194 }
195 }
196 ht.put(p);
197 }
198
199 TEST_UTIL.flush();
200
201 ColumnRangeFilter filter;
202 Scan scan = new Scan();
203 scan.setMaxVersions();
204 for (StringRange s : rangeMap.keySet()) {
205 filter = new ColumnRangeFilter(s.getStart() == null ? null : Bytes.toBytes(s.getStart()),
206 s.isStartInclusive(), s.getEnd() == null ? null : Bytes.toBytes(s.getEnd()),
207 s.isEndInclusive());
208 scan.setFilter(filter);
209 assertEquals(rangeMap.get(s).size(), cellsCount(ht, filter));
210 }
211 ht.close();
212 }
213
214 @Test
215 public void TestColumnRangeFilterWithColumnPaginationFilter() throws Exception {
216 String family = "Family";
217 String table = "TestColumnRangeFilterWithColumnPaginationFilter";
218 try (Table ht =
219 TEST_UTIL.createTable(TableName.valueOf(table), Bytes.toBytes(family), Integer.MAX_VALUE)) {
220
221 String row = "row";
222
223 long timestamp = 100;
224
225 int[] columns = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
226 String valueString = "ValueString";
227
228 Put p = new Put(Bytes.toBytes(row));
229 p.setDurability(Durability.SKIP_WAL);
230 for (int column : columns) {
231 KeyValue kv =
232 KeyValueTestUtil.create(row, family, Integer.toString(column), timestamp, valueString);
233 p.add(kv);
234 }
235 ht.put(p);
236
237 TEST_UTIL.flush();
238
239
240 StringRange stringRange = new StringRange("1", true, "9", false);
241 ColumnRangeFilter filter1 = new ColumnRangeFilter(Bytes.toBytes(stringRange.getStart()),
242 stringRange.isStartInclusive(), Bytes.toBytes(stringRange.getEnd()),
243 stringRange.isEndInclusive());
244
245 ColumnPaginationFilter filter2 = new ColumnPaginationFilter(5, 0);
246 ColumnPaginationFilter filter3 = new ColumnPaginationFilter(5, 1);
247 ColumnPaginationFilter filter4 = new ColumnPaginationFilter(5, 2);
248 ColumnPaginationFilter filter5 = new ColumnPaginationFilter(5, 6);
249 ColumnPaginationFilter filter6 = new ColumnPaginationFilter(5, 9);
250 assertEquals(5, cellsCount(ht, new FilterList(Operator.MUST_PASS_ALL, filter1, filter2)));
251 assertEquals(5, cellsCount(ht, new FilterList(Operator.MUST_PASS_ALL, filter1, filter3)));
252 assertEquals(5, cellsCount(ht, new FilterList(Operator.MUST_PASS_ALL, filter1, filter4)));
253 assertEquals(2, cellsCount(ht, new FilterList(Operator.MUST_PASS_ALL, filter1, filter5)));
254 assertEquals(0, cellsCount(ht, new FilterList(Operator.MUST_PASS_ALL, filter1, filter6)));
255 }
256 }
257
258 private int cellsCount(Table table, Filter filter) throws IOException {
259 Scan scan = new Scan().setFilter(filter).setMaxVersions();
260 try (ResultScanner scanner = table.getScanner(scan)) {
261 List<Cell> results = new ArrayList<>();
262 Result result;
263 while ((result = scanner.next()) != null) {
264 results.addAll(result.listCells());
265 }
266 return results.size();
267 }
268 }
269
270 List<String> generateRandomWords(int numberOfWords, int maxLengthOfWords) {
271 Set<String> wordSet = new HashSet<String>();
272 for (int i = 0; i < numberOfWords; i++) {
273 int lengthOfWords = (int) (Math.random() * maxLengthOfWords) + 1;
274 char[] wordChar = new char[lengthOfWords];
275 for (int j = 0; j < wordChar.length; j++) {
276 wordChar[j] = (char) (Math.random() * 26 + 97);
277 }
278 String word = new String(wordChar);
279 wordSet.add(word);
280 }
281 List<String> wordList = new ArrayList<String>(wordSet);
282 return wordList;
283 }
284 }
285