View Javadoc

1   /**
2    *
3    * Licensed to the Apache Software Foundation (ASF) under one
4    * or more contributor license agreements.  See the NOTICE file
5    * distributed with this work for additional information
6    * regarding copyright ownership.  The ASF licenses this file
7    * to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance
9    * with the License.  You may obtain a copy of the License at
10   *
11   *     http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing, software
14   * distributed under the License is distributed on an "AS IS" BASIS,
15   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   * See the License for the specific language governing permissions and
17   * limitations under the License.
18   */
19  
20  package org.apache.hadoop.hbase.filter;
21  
22  import java.io.IOException;
23  import java.util.ArrayList;
24  
25  import org.apache.hadoop.hbase.Cell;
26  import org.apache.hadoop.hbase.CellComparator;
27  import org.apache.hadoop.hbase.classification.InterfaceAudience;
28  import org.apache.hadoop.hbase.classification.InterfaceStability;
29  import org.apache.hadoop.hbase.protobuf.ProtobufUtil;
30  import org.apache.hadoop.hbase.protobuf.generated.FilterProtos;
31  import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos;
32  import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.CompareType;
33  import org.apache.hadoop.hbase.util.Bytes;
34  
35  import com.google.common.base.Preconditions;
36  /**
37   * This is a generic filter to be used to filter by comparison.  It takes an
38   * operator (equal, greater, not equal, etc) and a byte [] comparator.
39   * <p>
40   * To filter by row key, use {@link RowFilter}.
41   * <p>
42   * To filter by column qualifier, use {@link QualifierFilter}.
43   * <p>
44   * To filter by value, use {@link SingleColumnValueFilter}.
45   * <p>
46   * These filters can be wrapped with {@link SkipFilter} and {@link WhileMatchFilter}
47   * to add more control.
48   * <p>
49   * Multiple filters can be combined using {@link FilterList}.
50   */
51  @InterfaceAudience.Public
52  @InterfaceStability.Stable
53  public abstract class CompareFilter extends FilterBase {
54  
55    /** Comparison operators. */
56    @InterfaceAudience.Public
57    @InterfaceStability.Stable
58    public enum CompareOp {
59      /** less than */
60      LESS,
61      /** less than or equal to */
62      LESS_OR_EQUAL,
63      /** equals */
64      EQUAL,
65      /** not equal */
66      NOT_EQUAL,
67      /** greater than or equal to */
68      GREATER_OR_EQUAL,
69      /** greater than */
70      GREATER,
71      /** no operation */
72      NO_OP,
73    }
74  
75    protected CompareOp compareOp;
76    protected ByteArrayComparable comparator;
77  
78    /**
79     * Constructor.
80     * @param compareOp the compare op for row matching
81     * @param comparator the comparator for row matching
82     */
83    public CompareFilter(final CompareOp compareOp,
84        final ByteArrayComparable comparator) {
85      this.compareOp = compareOp;
86      this.comparator = comparator;
87    }
88  
89    /**
90     * @return operator
91     */
92    public CompareOp getOperator() {
93      return compareOp;
94    }
95  
96    /**
97     * @return the comparator
98     */
99    public ByteArrayComparable getComparator() {
100     return comparator;
101   }
102 
103   @Override
104   public boolean filterRowKey(Cell cell) throws IOException {
105     // Impl in FilterBase might do unnecessary copy for Off heap backed Cells.
106     return false;
107   }
108 
109   protected boolean compareRow(final CompareOp compareOp, final ByteArrayComparable comparator,
110       final Cell cell) {
111     if (compareOp == CompareOp.NO_OP) {
112       return true;
113     }
114     int compareResult = CellComparator.compareRow(cell, comparator);
115     return compare(compareOp, compareResult);
116   }
117 
118   protected boolean compareFamily(final CompareOp compareOp, final ByteArrayComparable comparator,
119       final Cell cell) {
120     if (compareOp == CompareOp.NO_OP) {
121       return true;
122     }
123     int compareResult = CellComparator.compareFamily(cell, comparator);
124     return compare(compareOp, compareResult);
125   }
126 
127   protected boolean compareQualifier(final CompareOp compareOp,
128       final ByteArrayComparable comparator, final Cell cell) {
129     if (compareOp == CompareOp.NO_OP) {
130       return true;
131     }
132     int compareResult = CellComparator.compareQualifier(cell, comparator);
133     return compare(compareOp, compareResult);
134   }
135 
136   protected boolean compareValue(final CompareOp compareOp, final ByteArrayComparable comparator,
137       final Cell cell) {
138     if (compareOp == CompareOp.NO_OP) {
139       return true;
140     }
141     int compareResult = CellComparator.compareValue(cell, comparator);
142     return compare(compareOp, compareResult);
143   }
144 
145   private boolean compare(final CompareOp compareOp, int compareResult) {
146     switch (compareOp) {
147     case LESS:
148       return compareResult <= 0;
149     case LESS_OR_EQUAL:
150       return compareResult < 0;
151     case EQUAL:
152       return compareResult != 0;
153     case NOT_EQUAL:
154       return compareResult == 0;
155     case GREATER_OR_EQUAL:
156       return compareResult > 0;
157     case GREATER:
158       return compareResult >= 0;
159     default:
160       throw new RuntimeException("Unknown Compare op " + compareOp.name());
161     }
162   }
163 
164   // returns an array of heterogeneous objects
165   public static ArrayList<Object> extractArguments(ArrayList<byte []> filterArguments) {
166     Preconditions.checkArgument(filterArguments.size() == 2,
167                                 "Expected 2 but got: %s", filterArguments.size());
168     CompareOp compareOp = ParseFilter.createCompareOp(filterArguments.get(0));
169     ByteArrayComparable comparator = ParseFilter.createComparator(
170       ParseFilter.removeQuotesFromByteArray(filterArguments.get(1)));
171 
172     if (comparator instanceof RegexStringComparator ||
173         comparator instanceof SubstringComparator) {
174       if (compareOp != CompareOp.EQUAL &&
175           compareOp != CompareOp.NOT_EQUAL) {
176         throw new IllegalArgumentException ("A regexstring comparator and substring comparator" +
177                                             " can only be used with EQUAL and NOT_EQUAL");
178       }
179     }
180     ArrayList<Object> arguments = new ArrayList<Object>();
181     arguments.add(compareOp);
182     arguments.add(comparator);
183     return arguments;
184   }
185 
186   /**
187    * @return A pb instance to represent this instance.
188    */
189   FilterProtos.CompareFilter convert() {
190     FilterProtos.CompareFilter.Builder builder =
191       FilterProtos.CompareFilter.newBuilder();
192     HBaseProtos.CompareType compareOp = CompareType.valueOf(this.compareOp.name());
193     builder.setCompareOp(compareOp);
194     if (this.comparator != null) builder.setComparator(ProtobufUtil.toComparator(this.comparator));
195     return builder.build();
196   }
197 
198   /**
199    *
200    * @param o
201    * @return true if and only if the fields of the filter that are serialized
202    * are equal to the corresponding fields in other.  Used for testing.
203    */
204   boolean areSerializedFieldsEqual(Filter o) {
205     if (o == this) return true;
206     if (!(o instanceof CompareFilter)) return false;
207 
208     CompareFilter other = (CompareFilter)o;
209     return this.getOperator().equals(other.getOperator()) &&
210       (this.getComparator() == other.getComparator()
211         || this.getComparator().areSerializedFieldsEqual(other.getComparator()));
212   }
213 
214   @Override
215   public String toString() {
216     return String.format("%s (%s, %s)",
217         this.getClass().getSimpleName(),
218         this.compareOp.name(),
219         Bytes.toStringBinary(this.comparator.getValue()));
220   }
221 }