1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 package org.apache.hadoop.hbase.filter;
22
23 import org.apache.commons.logging.Log;
24 import org.apache.commons.logging.LogFactory;
25 import org.apache.hadoop.hbase.KeyValue;
26 import org.apache.hadoop.hbase.client.Scan;
27 import org.apache.hadoop.hbase.filter.CompareFilter.CompareOp;
28 import org.apache.hadoop.hbase.io.HbaseObjectWritable;
29 import org.apache.hadoop.hbase.util.Bytes;
30
31 import java.io.DataInput;
32 import java.io.DataOutput;
33 import java.io.IOException;
34 import java.util.Arrays;
35 import java.util.List;
36 import java.util.ArrayList;
37
38 import com.google.common.base.Preconditions;
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67 public class SingleColumnValueFilter extends FilterBase {
68 static final Log LOG = LogFactory.getLog(SingleColumnValueFilter.class);
69
70 protected byte [] columnFamily;
71 protected byte [] columnQualifier;
72 private CompareOp compareOp;
73 private WritableByteArrayComparable comparator;
74 private boolean foundColumn = false;
75 private boolean matchedColumn = false;
76 private boolean filterIfMissing = false;
77 private boolean latestVersionOnly = true;
78
79
80
81
82 public SingleColumnValueFilter() {
83 }
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99 public SingleColumnValueFilter(final byte [] family, final byte [] qualifier,
100 final CompareOp compareOp, final byte[] value) {
101 this(family, qualifier, compareOp, new BinaryComparator(value));
102 }
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118 public SingleColumnValueFilter(final byte [] family, final byte [] qualifier,
119 final CompareOp compareOp, final WritableByteArrayComparable comparator) {
120 this.columnFamily = family;
121 this.columnQualifier = qualifier;
122 this.compareOp = compareOp;
123 this.comparator = comparator;
124 }
125
126
127
128
129 public CompareOp getOperator() {
130 return compareOp;
131 }
132
133
134
135
136 public WritableByteArrayComparable getComparator() {
137 return comparator;
138 }
139
140
141
142
143 public byte[] getFamily() {
144 return columnFamily;
145 }
146
147
148
149
150 public byte[] getQualifier() {
151 return columnQualifier;
152 }
153
154 public ReturnCode filterKeyValue(KeyValue keyValue) {
155
156 if (this.matchedColumn) {
157
158 return ReturnCode.INCLUDE;
159 } else if (this.latestVersionOnly && this.foundColumn) {
160
161 return ReturnCode.NEXT_ROW;
162 }
163 if (!keyValue.matchingColumn(this.columnFamily, this.columnQualifier)) {
164 return ReturnCode.INCLUDE;
165 }
166 foundColumn = true;
167 if (filterColumnValue(keyValue.getBuffer(),
168 keyValue.getValueOffset(), keyValue.getValueLength())) {
169 return this.latestVersionOnly? ReturnCode.NEXT_ROW: ReturnCode.INCLUDE;
170 }
171 this.matchedColumn = true;
172 return ReturnCode.INCLUDE;
173 }
174
175 private boolean filterColumnValue(final byte [] data, final int offset,
176 final int length) {
177 int compareResult = this.comparator.compareTo(data, offset, length);
178 switch (this.compareOp) {
179 case LESS:
180 return compareResult <= 0;
181 case LESS_OR_EQUAL:
182 return compareResult < 0;
183 case EQUAL:
184 return compareResult != 0;
185 case NOT_EQUAL:
186 return compareResult == 0;
187 case GREATER_OR_EQUAL:
188 return compareResult > 0;
189 case GREATER:
190 return compareResult >= 0;
191 default:
192 throw new RuntimeException("Unknown Compare op " + compareOp.name());
193 }
194 }
195
196 public boolean filterRow() {
197
198
199 return this.foundColumn? !this.matchedColumn: this.filterIfMissing;
200 }
201
202 public void reset() {
203 foundColumn = false;
204 matchedColumn = false;
205 }
206
207
208
209
210
211
212 public boolean getFilterIfMissing() {
213 return filterIfMissing;
214 }
215
216
217
218
219
220
221
222
223
224 public void setFilterIfMissing(boolean filterIfMissing) {
225 this.filterIfMissing = filterIfMissing;
226 }
227
228
229
230
231
232
233
234
235 public boolean getLatestVersionOnly() {
236 return latestVersionOnly;
237 }
238
239
240
241
242
243
244
245
246 public void setLatestVersionOnly(boolean latestVersionOnly) {
247 this.latestVersionOnly = latestVersionOnly;
248 }
249
250 public static Filter createFilterFromArguments(ArrayList<byte []> filterArguments) {
251 Preconditions.checkArgument(filterArguments.size() == 4 || filterArguments.size() == 6,
252 "Expected 4 or 6 but got: %s", filterArguments.size());
253 byte [] family = ParseFilter.removeQuotesFromByteArray(filterArguments.get(0));
254 byte [] qualifier = ParseFilter.removeQuotesFromByteArray(filterArguments.get(1));
255 CompareOp compareOp = ParseFilter.createCompareOp(filterArguments.get(2));
256 WritableByteArrayComparable comparator = ParseFilter.createComparator(
257 ParseFilter.removeQuotesFromByteArray(filterArguments.get(3)));
258
259 if (comparator instanceof RegexStringComparator ||
260 comparator instanceof SubstringComparator) {
261 if (compareOp != CompareOp.EQUAL &&
262 compareOp != CompareOp.NOT_EQUAL) {
263 throw new IllegalArgumentException ("A regexstring comparator and substring comparator " +
264 "can only be used with EQUAL and NOT_EQUAL");
265 }
266 }
267
268 SingleColumnValueFilter filter = new SingleColumnValueFilter(family, qualifier,
269 compareOp, comparator);
270
271 if (filterArguments.size() == 6) {
272 boolean filterIfMissing = ParseFilter.convertByteArrayToBoolean(filterArguments.get(4));
273 boolean latestVersionOnly = ParseFilter.convertByteArrayToBoolean(filterArguments.get(5));
274 filter.setFilterIfMissing(filterIfMissing);
275 filter.setLatestVersionOnly(latestVersionOnly);
276 }
277 return filter;
278 }
279
280 public void readFields(final DataInput in) throws IOException {
281 this.columnFamily = Bytes.readByteArray(in);
282 if(this.columnFamily.length == 0) {
283 this.columnFamily = null;
284 }
285 this.columnQualifier = Bytes.readByteArray(in);
286 if(this.columnQualifier.length == 0) {
287 this.columnQualifier = null;
288 }
289 this.compareOp = CompareOp.valueOf(in.readUTF());
290 this.comparator =
291 (WritableByteArrayComparable)HbaseObjectWritable.readObject(in, null);
292 this.foundColumn = in.readBoolean();
293 this.matchedColumn = in.readBoolean();
294 this.filterIfMissing = in.readBoolean();
295 this.latestVersionOnly = in.readBoolean();
296 }
297
298 public void write(final DataOutput out) throws IOException {
299 Bytes.writeByteArray(out, this.columnFamily);
300 Bytes.writeByteArray(out, this.columnQualifier);
301 out.writeUTF(compareOp.name());
302 HbaseObjectWritable.writeObject(out, comparator,
303 WritableByteArrayComparable.class, null);
304 out.writeBoolean(foundColumn);
305 out.writeBoolean(matchedColumn);
306 out.writeBoolean(filterIfMissing);
307 out.writeBoolean(latestVersionOnly);
308 }
309
310
311
312
313
314
315 public boolean isFamilyEssential(byte[] name) {
316 return !this.filterIfMissing || Bytes.equals(name, this.columnFamily);
317 }
318
319 @Override
320 public String toString() {
321 return String.format("%s (%s, %s, %s, %s)",
322 this.getClass().getSimpleName(), Bytes.toStringBinary(this.columnFamily),
323 Bytes.toStringBinary(this.columnQualifier), this.compareOp.name(),
324 Bytes.toStringBinary(this.comparator.getValue()));
325 }
326 }