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 com.google.common.base.Preconditions;
23  import org.apache.hadoop.hbase.classification.InterfaceAudience;
24  
25  import org.apache.hadoop.hbase.Cell;
26  import org.apache.hadoop.hbase.classification.InterfaceStability;
27  import org.apache.hadoop.hbase.protobuf.ProtobufUtil;
28  import org.apache.hadoop.hbase.protobuf.generated.FilterProtos;
29  import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos;
30  import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.CompareType;
31  import org.apache.hadoop.hbase.util.Bytes;
32  
33  import java.util.ArrayList;
34  import java.util.Objects;
35  
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   protected boolean doCompare(final CompareOp compareOp,
104       final ByteArrayComparable comparator, final byte [] data,
105       final int offset, final int length) {
106     if (compareOp == CompareOp.NO_OP) {
107       return true;
108     }
109     int compareResult = comparator.compareTo(data, offset, length);
110     switch (compareOp) {
111       case LESS:
112         return compareResult <= 0;
113       case LESS_OR_EQUAL:
114         return compareResult < 0;
115       case EQUAL:
116         return compareResult != 0;
117       case NOT_EQUAL:
118         return compareResult == 0;
119       case GREATER_OR_EQUAL:
120         return compareResult > 0;
121       case GREATER:
122         return compareResult >= 0;
123       default:
124         throw new RuntimeException("Unknown Compare op " +
125           compareOp.name());
126     }
127   }
128 
129   // Override here explicitly as the method in super class FilterBase might do a KeyValue recreate.
130   // See HBASE-12068
131   @Override
132   public Cell transformCell(Cell v) {
133     return v;
134   }
135 
136   // returns an array of heterogeneous objects
137   public static ArrayList<Object> extractArguments(ArrayList<byte []> filterArguments) {
138     Preconditions.checkArgument(filterArguments.size() == 2,
139                                 "Expected 2 but got: %s", filterArguments.size());
140     CompareOp compareOp = ParseFilter.createCompareOp(filterArguments.get(0));
141     ByteArrayComparable comparator = ParseFilter.createComparator(
142       ParseFilter.removeQuotesFromByteArray(filterArguments.get(1)));
143 
144     if (comparator instanceof RegexStringComparator ||
145         comparator instanceof SubstringComparator) {
146       if (compareOp != CompareOp.EQUAL &&
147           compareOp != CompareOp.NOT_EQUAL) {
148         throw new IllegalArgumentException ("A regexstring comparator and substring comparator" +
149                                             " can only be used with EQUAL and NOT_EQUAL");
150       }
151     }
152     ArrayList<Object> arguments = new ArrayList<Object>();
153     arguments.add(compareOp);
154     arguments.add(comparator);
155     return arguments;
156   }
157 
158   /**
159    * @return A pb instance to represent this instance.
160    */
161   FilterProtos.CompareFilter convert() {
162     FilterProtos.CompareFilter.Builder builder =
163       FilterProtos.CompareFilter.newBuilder();
164     HBaseProtos.CompareType compareOp = CompareType.valueOf(this.compareOp.name());
165     builder.setCompareOp(compareOp);
166     if (this.comparator != null) builder.setComparator(ProtobufUtil.toComparator(this.comparator));
167     return builder.build();
168   }
169 
170   /**
171    *
172    * @param o
173    * @return true if and only if the fields of the filter that are serialized
174    * are equal to the corresponding fields in other.  Used for testing.
175    */
176   @Override
177   boolean areSerializedFieldsEqual(Filter o) {
178     if (o == this) return true;
179     if (!(o instanceof CompareFilter)) return false;
180 
181     CompareFilter other = (CompareFilter)o;
182     return this.getOperator().equals(other.getOperator()) &&
183       (this.getComparator() == other.getComparator()
184         || this.getComparator().areSerializedFieldsEqual(other.getComparator()));
185   }
186 
187   @Override
188   public String toString() {
189     return String.format("%s (%s, %s)",
190         this.getClass().getSimpleName(),
191         this.compareOp.name(),
192         Bytes.toStringBinary(this.comparator.getValue()));
193   }
194 
195   @Override
196   public boolean equals(Object obj) {
197     return obj instanceof Filter && areSerializedFieldsEqual((Filter) obj);
198   }
199 
200   @Override
201   public int hashCode() {
202     return Objects.hash(this.getComparator(), this.getOperator());
203   }
204 }