View Javadoc

1   /**
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  package org.apache.hadoop.hbase.filter;
19  
20  import static org.junit.Assert.*;
21  
22  import java.util.ArrayList;
23  import java.util.HashMap;
24  import java.util.HashSet;
25  import java.util.List;
26  import java.util.Map;
27  import java.util.Set;
28  
29  import org.apache.commons.logging.Log;
30  import org.apache.commons.logging.LogFactory;
31  import org.apache.hadoop.hbase.*;
32  import org.apache.hadoop.hbase.client.HTable;
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.testclassification.MediumTests;
39  import org.apache.hadoop.hbase.util.Bytes;
40  import org.junit.Test;
41  import org.junit.After;
42  import org.junit.AfterClass;
43  import org.junit.Before;
44  import org.junit.BeforeClass;
45  import org.junit.experimental.categories.Category;
46  
47  
48  class StringRange {
49    private String start = null;
50    private String end = null;
51    private boolean startInclusive = true;
52    private boolean endInclusive = false;
53  
54    public StringRange(String start, boolean startInclusive, String end,
55        boolean endInclusive) {
56      this.start = start;
57      this.startInclusive = startInclusive;
58      this.end = end;
59      this.endInclusive = endInclusive;
60    }
61  
62    public String getStart() {
63      return this.start;
64    }
65  
66    public String getEnd() {
67      return this.end;
68    }
69  
70    public boolean isStartInclusive() {
71      return this.startInclusive;
72    }
73  
74    public boolean isEndInclusive() {
75      return this.endInclusive;
76    }
77  
78    @Override
79    public int hashCode() {
80      int hashCode = 0;
81      if (this.start != null) {
82        hashCode ^= this.start.hashCode();
83      }
84  
85      if (this.end != null) {
86        hashCode ^= this.end.hashCode();
87      }
88      return hashCode;
89    }
90  
91    @Override
92    public String toString() {
93      String result = (this.startInclusive ? "[" : "(")
94            + (this.start == null ? null : this.start) + ", "
95            + (this.end == null ? null : this.end)
96            + (this.endInclusive ? "]" : ")");
97      return result;
98    }
99  
100    public boolean inRange(String value) {
101     boolean afterStart = true;
102     if (this.start != null) {
103       int startCmp = value.compareTo(this.start);
104       afterStart = this.startInclusive ? startCmp >= 0 : startCmp > 0;
105     }
106 
107     boolean beforeEnd = true;
108     if (this.end != null) {
109       int endCmp = value.compareTo(this.end);
110       beforeEnd = this.endInclusive ? endCmp <= 0 : endCmp < 0;
111     }
112 
113     return afterStart && beforeEnd;
114   }
115 
116 }
117 
118 
119 @Category(MediumTests.class)
120 public class TestColumnRangeFilter {
121 
122   private final static HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
123 
124   private final Log LOG = LogFactory.getLog(this.getClass());
125 
126   /**
127    * @throws java.lang.Exception
128    */
129   @BeforeClass
130   public static void setUpBeforeClass() throws Exception {
131     TEST_UTIL.startMiniCluster();
132   }
133 
134   /**
135    * @throws java.lang.Exception
136    */
137   @AfterClass
138   public static void tearDownAfterClass() throws Exception {
139     TEST_UTIL.shutdownMiniCluster();
140   }
141 
142   /**
143    * @throws java.lang.Exception
144    */
145   @Before
146   public void setUp() throws Exception {
147     // Nothing to do.
148   }
149 
150   /**
151    * @throws java.lang.Exception
152    */
153   @After
154   public void tearDown() throws Exception {
155     // Nothing to do.
156   }
157 
158   @Test
159   public void TestColumnRangeFilterClient() throws Exception {
160     String family = "Family";
161     String table = "TestColumnRangeFilterClient";
162     HTable ht = TEST_UTIL.createTable(Bytes.toBytes(table),
163         Bytes.toBytes(family), Integer.MAX_VALUE);
164 
165     List<String> rows = generateRandomWords(10, 8);
166     long maxTimestamp = 2;
167     List<String> columns = generateRandomWords(20000, 8);
168 
169     List<KeyValue> kvList = new ArrayList<KeyValue>();
170 
171     Map<StringRange, List<KeyValue>> rangeMap = new HashMap<StringRange, List<KeyValue>>();
172 
173     rangeMap.put(new StringRange(null, true, "b", false),
174         new ArrayList<KeyValue>());
175     rangeMap.put(new StringRange("p", true, "q", false),
176         new ArrayList<KeyValue>());
177     rangeMap.put(new StringRange("r", false, "s", true),
178         new ArrayList<KeyValue>());
179     rangeMap.put(new StringRange("z", false, null, false),
180         new ArrayList<KeyValue>());
181     String valueString = "ValueString";
182 
183     for (String row : rows) {
184       Put p = new Put(Bytes.toBytes(row));
185       p.setDurability(Durability.SKIP_WAL);
186       for (String column : columns) {
187         for (long timestamp = 1; timestamp <= maxTimestamp; timestamp++) {
188           KeyValue kv = KeyValueTestUtil.create(row, family, column, timestamp,
189               valueString);
190           p.add(kv);
191           kvList.add(kv);
192           for (StringRange s : rangeMap.keySet()) {
193             if (s.inRange(column)) {
194               rangeMap.get(s).add(kv);
195             }
196           }
197         }
198       }
199       ht.put(p);
200     }
201 
202     TEST_UTIL.flush();
203 
204     ColumnRangeFilter filter;
205     Scan scan = new Scan();
206     scan.setMaxVersions();
207     for (StringRange s : rangeMap.keySet()) {
208       filter = new ColumnRangeFilter(s.getStart() == null ? null
209           : Bytes.toBytes(s.getStart()), s.isStartInclusive(),
210           s.getEnd() == null ? null : Bytes.toBytes(s.getEnd()),
211           s.isEndInclusive());
212       scan.setFilter(filter);
213       ResultScanner scanner = ht.getScanner(scan);
214       List<Cell> results = new ArrayList<Cell>();
215       LOG.info("scan column range: " + s.toString());
216       long timeBeforeScan = System.currentTimeMillis();
217 
218       Result result;
219       while ((result = scanner.next()) != null) {
220         for (Cell kv : result.listCells()) {
221           results.add(kv);
222         }
223       }
224       long scanTime = System.currentTimeMillis() - timeBeforeScan;
225       scanner.close();
226       LOG.info("scan time = " + scanTime + "ms");
227       LOG.info("found " + results.size() + " results");
228       LOG.info("Expecting " + rangeMap.get(s).size() + " results");
229 
230       /*
231       for (KeyValue kv : results) {
232         LOG.info("found row " + Bytes.toString(kv.getRow()) + ", column "
233             + Bytes.toString(kv.getQualifier()));
234       }
235       */
236 
237       assertEquals(rangeMap.get(s).size(), results.size());
238     }
239     ht.close();
240   }
241 
242   List<String> generateRandomWords(int numberOfWords, int maxLengthOfWords) {
243     Set<String> wordSet = new HashSet<String>();
244     for (int i = 0; i < numberOfWords; i++) {
245       int lengthOfWords = (int) (Math.random() * maxLengthOfWords) + 1;
246       char[] wordChar = new char[lengthOfWords];
247       for (int j = 0; j < wordChar.length; j++) {
248         wordChar[j] = (char) (Math.random() * 26 + 97);
249       }
250       String word = new String(wordChar);
251       wordSet.add(word);
252     }
253     List<String> wordList = new ArrayList<String>(wordSet);
254     return wordList;
255   }
256 
257 }
258