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
178
179 int compareResult =
180 this.comparator.compareTo(Arrays.copyOfRange(data, offset, offset + length));
181 switch (this.compareOp) {
182 case LESS:
183 return compareResult <= 0;
184 case LESS_OR_EQUAL:
185 return compareResult < 0;
186 case EQUAL:
187 return compareResult != 0;
188 case NOT_EQUAL:
189 return compareResult == 0;
190 case GREATER_OR_EQUAL:
191 return compareResult > 0;
192 case GREATER:
193 return compareResult >= 0;
194 default:
195 throw new RuntimeException("Unknown Compare op " + compareOp.name());
196 }
197 }
198
199 public boolean filterRow() {
200
201
202 return this.foundColumn? !this.matchedColumn: this.filterIfMissing;
203 }
204
205 public void reset() {
206 foundColumn = false;
207 matchedColumn = false;
208 }
209
210
211
212
213
214
215 public boolean getFilterIfMissing() {
216 return filterIfMissing;
217 }
218
219
220
221
222
223
224
225
226
227 public void setFilterIfMissing(boolean filterIfMissing) {
228 this.filterIfMissing = filterIfMissing;
229 }
230
231
232
233
234
235
236
237
238 public boolean getLatestVersionOnly() {
239 return latestVersionOnly;
240 }
241
242
243
244
245
246
247
248
249 public void setLatestVersionOnly(boolean latestVersionOnly) {
250 this.latestVersionOnly = latestVersionOnly;
251 }
252
253 public static Filter createFilterFromArguments(ArrayList<byte []> filterArguments) {
254 Preconditions.checkArgument(filterArguments.size() == 4 || filterArguments.size() == 6,
255 "Expected 4 or 6 but got: %s", filterArguments.size());
256 byte [] family = ParseFilter.removeQuotesFromByteArray(filterArguments.get(0));
257 byte [] qualifier = ParseFilter.removeQuotesFromByteArray(filterArguments.get(1));
258 CompareOp compareOp = ParseFilter.createCompareOp(filterArguments.get(2));
259 WritableByteArrayComparable comparator = ParseFilter.createComparator(
260 ParseFilter.removeQuotesFromByteArray(filterArguments.get(3)));
261
262 if (comparator instanceof RegexStringComparator ||
263 comparator instanceof SubstringComparator) {
264 if (compareOp != CompareOp.EQUAL &&
265 compareOp != CompareOp.NOT_EQUAL) {
266 throw new IllegalArgumentException ("A regexstring comparator and substring comparator " +
267 "can only be used with EQUAL and NOT_EQUAL");
268 }
269 }
270
271 SingleColumnValueFilter filter = new SingleColumnValueFilter(family, qualifier,
272 compareOp, comparator);
273
274 if (filterArguments.size() == 6) {
275 boolean filterIfMissing = ParseFilter.convertByteArrayToBoolean(filterArguments.get(4));
276 boolean latestVersionOnly = ParseFilter.convertByteArrayToBoolean(filterArguments.get(5));
277 filter.setFilterIfMissing(filterIfMissing);
278 filter.setLatestVersionOnly(latestVersionOnly);
279 }
280 return filter;
281 }
282
283 public void readFields(final DataInput in) throws IOException {
284 this.columnFamily = Bytes.readByteArray(in);
285 if(this.columnFamily.length == 0) {
286 this.columnFamily = null;
287 }
288 this.columnQualifier = Bytes.readByteArray(in);
289 if(this.columnQualifier.length == 0) {
290 this.columnQualifier = null;
291 }
292 this.compareOp = CompareOp.valueOf(in.readUTF());
293 this.comparator =
294 (WritableByteArrayComparable)HbaseObjectWritable.readObject(in, null);
295 this.foundColumn = in.readBoolean();
296 this.matchedColumn = in.readBoolean();
297 this.filterIfMissing = in.readBoolean();
298 this.latestVersionOnly = in.readBoolean();
299 }
300
301 public void write(final DataOutput out) throws IOException {
302 Bytes.writeByteArray(out, this.columnFamily);
303 Bytes.writeByteArray(out, this.columnQualifier);
304 out.writeUTF(compareOp.name());
305 HbaseObjectWritable.writeObject(out, comparator,
306 WritableByteArrayComparable.class, null);
307 out.writeBoolean(foundColumn);
308 out.writeBoolean(matchedColumn);
309 out.writeBoolean(filterIfMissing);
310 out.writeBoolean(latestVersionOnly);
311 }
312 }