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