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  import org.apache.hadoop.hbase.Cell;
25  import org.apache.hadoop.hbase.classification.InterfaceStability;
26  import org.apache.hadoop.hbase.protobuf.ProtobufUtil;
27  import org.apache.hadoop.hbase.protobuf.generated.FilterProtos;
28  import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos;
29  import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.CompareType;
30  import org.apache.hadoop.hbase.util.Bytes;
31  
32  import java.util.ArrayList;
33  /**
34   * This is a generic filter to be used to filter by comparison.  It takes an
35   * operator (equal, greater, not equal, etc) and a byte [] comparator.
36   * <p>
37   * To filter by row key, use {@link RowFilter}.
38   * <p>
39   * To filter by column qualifier, use {@link QualifierFilter}.
40   * <p>
41   * To filter by value, use {@link SingleColumnValueFilter}.
42   * <p>
43   * These filters can be wrapped with {@link SkipFilter} and {@link WhileMatchFilter}
44   * to add more control.
45   * <p>
46   * Multiple filters can be combined using {@link FilterList}.
47   */
48  @InterfaceAudience.Public
49  @InterfaceStability.Stable
50  public abstract class CompareFilter extends FilterBase {
51  
52    /** Comparison operators. */
53    @InterfaceAudience.Public
54    @InterfaceStability.Stable
55    public enum CompareOp {
56      /** less than */
57      LESS,
58      /** less than or equal to */
59      LESS_OR_EQUAL,
60      /** equals */
61      EQUAL,
62      /** not equal */
63      NOT_EQUAL,
64      /** greater than or equal to */
65      GREATER_OR_EQUAL,
66      /** greater than */
67      GREATER,
68      /** no operation */
69      NO_OP,
70    }
71  
72    protected CompareOp compareOp;
73    protected ByteArrayComparable comparator;
74  
75    /**
76     * Constructor.
77     * @param compareOp the compare op for row matching
78     * @param comparator the comparator for row matching
79     */
80    public CompareFilter(final CompareOp compareOp,
81        final ByteArrayComparable comparator) {
82      this.compareOp = compareOp;
83      this.comparator = comparator;
84    }
85  
86    /**
87     * @return operator
88     */
89    public CompareOp getOperator() {
90      return compareOp;
91    }
92  
93    /**
94     * @return the comparator
95     */
96    public ByteArrayComparable getComparator() {
97      return comparator;
98    }
99  
100   protected boolean doCompare(final CompareOp compareOp,
101       final ByteArrayComparable comparator, final byte [] data,
102       final int offset, final int length) {
103     if (compareOp == CompareOp.NO_OP) {
104       return true;
105     }
106     int compareResult = comparator.compareTo(data, offset, length);
107     switch (compareOp) {
108       case LESS:
109         return compareResult <= 0;
110       case LESS_OR_EQUAL:
111         return compareResult < 0;
112       case EQUAL:
113         return compareResult != 0;
114       case NOT_EQUAL:
115         return compareResult == 0;
116       case GREATER_OR_EQUAL:
117         return compareResult > 0;
118       case GREATER:
119         return compareResult >= 0;
120       default:
121         throw new RuntimeException("Unknown Compare op " +
122           compareOp.name());
123     }
124   }
125 
126   // Override here explicitly as the method in super class FilterBase might do a KeyValue recreate.
127   // See HBASE-12068
128   @Override
129   public Cell transformCell(Cell v) {
130     return v;
131   }
132 
133   // returns an array of heterogeneous objects
134   public static ArrayList<Object> extractArguments(ArrayList<byte []> filterArguments) {
135     Preconditions.checkArgument(filterArguments.size() == 2,
136                                 "Expected 2 but got: %s", filterArguments.size());
137     CompareOp compareOp = ParseFilter.createCompareOp(filterArguments.get(0));
138     ByteArrayComparable comparator = ParseFilter.createComparator(
139       ParseFilter.removeQuotesFromByteArray(filterArguments.get(1)));
140 
141     if (comparator instanceof RegexStringComparator ||
142         comparator instanceof SubstringComparator) {
143       if (compareOp != CompareOp.EQUAL &&
144           compareOp != CompareOp.NOT_EQUAL) {
145         throw new IllegalArgumentException ("A regexstring comparator and substring comparator" +
146                                             " can only be used with EQUAL and NOT_EQUAL");
147       }
148     }
149     ArrayList<Object> arguments = new ArrayList<Object>();
150     arguments.add(compareOp);
151     arguments.add(comparator);
152     return arguments;
153   }
154 
155   /**
156    * @return A pb instance to represent this instance.
157    */
158   FilterProtos.CompareFilter convert() {
159     FilterProtos.CompareFilter.Builder builder =
160       FilterProtos.CompareFilter.newBuilder();
161     HBaseProtos.CompareType compareOp = CompareType.valueOf(this.compareOp.name());
162     builder.setCompareOp(compareOp);
163     if (this.comparator != null) builder.setComparator(ProtobufUtil.toComparator(this.comparator));
164     return builder.build();
165   }
166 
167   /**
168    *
169    * @param o
170    * @return true if and only if the fields of the filter that are serialized
171    * are equal to the corresponding fields in other.  Used for testing.
172    */
173   boolean areSerializedFieldsEqual(Filter o) {
174     if (o == this) return true;
175     if (!(o instanceof CompareFilter)) return false;
176 
177     CompareFilter other = (CompareFilter)o;
178     return this.getOperator().equals(other.getOperator()) &&
179       (this.getComparator() == other.getComparator()
180         || this.getComparator().areSerializedFieldsEqual(other.getComparator()));
181   }
182 
183   @Override
184   public String toString() {
185     return String.format("%s (%s, %s)",
186         this.getClass().getSimpleName(),
187         this.compareOp.name(),
188         Bytes.toStringBinary(this.comparator.getValue()));
189   }
190 }