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