001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package org.apache.hadoop.hbase.filter; 019 020import java.io.IOException; 021import java.util.ArrayList; 022import java.util.Iterator; 023import java.util.List; 024import org.apache.hadoop.hbase.Cell; 025import org.apache.hadoop.hbase.CellUtil; 026import org.apache.hadoop.hbase.CompareOperator; 027import org.apache.hadoop.hbase.exceptions.DeserializationException; 028import org.apache.yetus.audience.InterfaceAudience; 029 030import org.apache.hbase.thirdparty.com.google.protobuf.InvalidProtocolBufferException; 031 032import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil; 033import org.apache.hadoop.hbase.shaded.protobuf.generated.FilterProtos; 034 035/** 036 * A {@link Filter} that checks a single column value, but does not emit the tested column. This 037 * will enable a performance boost over {@link SingleColumnValueFilter}, if the tested column value 038 * is not actually needed as input (besides for the filtering itself). 039 */ 040@InterfaceAudience.Public 041public class SingleColumnValueExcludeFilter extends SingleColumnValueFilter { 042 /** 043 * Constructor for binary compare of the value of a single column. If the column is found and the 044 * condition passes, all columns of the row will be emitted; except for the tested column value. 045 * If the column is not found or the condition fails, the row will not be emitted. 046 * @param family name of column family 047 * @param qualifier name of column qualifier 048 * @param op operator 049 * @param value value to compare column values against 050 */ 051 public SingleColumnValueExcludeFilter(byte[] family, byte[] qualifier, CompareOperator op, 052 byte[] value) { 053 super(family, qualifier, op, value); 054 } 055 056 /** 057 * Constructor for binary compare of the value of a single column. If the column is found and the 058 * condition passes, all columns of the row will be emitted; except for the tested column value. 059 * If the condition fails, the row will not be emitted. 060 * <p> 061 * Use the filterIfColumnMissing flag to set whether the rest of the columns in a row will be 062 * emitted if the specified column to check is not found in the row. 063 * @param family name of column family 064 * @param qualifier name of column qualifier 065 * @param op operator 066 * @param comparator Comparator to use. 067 */ 068 public SingleColumnValueExcludeFilter(byte[] family, byte[] qualifier, CompareOperator op, 069 ByteArrayComparable comparator) { 070 super(family, qualifier, op, comparator); 071 } 072 073 /** 074 * Constructor for protobuf deserialization only. 075 */ 076 protected SingleColumnValueExcludeFilter(final byte[] family, final byte[] qualifier, 077 final CompareOperator op, ByteArrayComparable comparator, final boolean filterIfMissing, 078 final boolean latestVersionOnly) { 079 super(family, qualifier, op, comparator, filterIfMissing, latestVersionOnly); 080 } 081 082 // We cleaned result row in FilterRow to be consistent with scanning process. 083 @Override 084 public boolean hasFilterRow() { 085 return true; 086 } 087 088 // Here we remove from row all key values from testing column 089 @Override 090 public void filterRowCells(List<Cell> kvs) { 091 Iterator<? extends Cell> it = kvs.iterator(); 092 while (it.hasNext()) { 093 // If the current column is actually the tested column, 094 // we will skip it instead. 095 if (CellUtil.matchingColumn(it.next(), this.columnFamily, this.columnQualifier)) { 096 it.remove(); 097 } 098 } 099 } 100 101 public static Filter createFilterFromArguments(ArrayList<byte[]> filterArguments) { 102 SingleColumnValueFilter tempFilter = 103 (SingleColumnValueFilter) SingleColumnValueFilter.createFilterFromArguments(filterArguments); 104 SingleColumnValueExcludeFilter filter = 105 new SingleColumnValueExcludeFilter(tempFilter.getFamily(), tempFilter.getQualifier(), 106 tempFilter.getCompareOperator(), tempFilter.getComparator()); 107 108 if (filterArguments.size() == 6) { 109 filter.setFilterIfMissing(tempFilter.getFilterIfMissing()); 110 filter.setLatestVersionOnly(tempFilter.getLatestVersionOnly()); 111 } 112 return filter; 113 } 114 115 /** Returns The filter serialized using pb */ 116 @Override 117 public byte[] toByteArray() { 118 FilterProtos.SingleColumnValueExcludeFilter.Builder builder = 119 FilterProtos.SingleColumnValueExcludeFilter.newBuilder(); 120 builder.setSingleColumnValueFilter(super.convert()); 121 return builder.build().toByteArray(); 122 } 123 124 /** 125 * Parse a serialized representation of {@link SingleColumnValueExcludeFilter} 126 * @param pbBytes A pb serialized {@link SingleColumnValueExcludeFilter} instance 127 * @return An instance of {@link SingleColumnValueExcludeFilter} made from <code>bytes</code> 128 * @throws DeserializationException if an error occurred 129 * @see #toByteArray 130 */ 131 public static SingleColumnValueExcludeFilter parseFrom(final byte[] pbBytes) 132 throws DeserializationException { 133 FilterProtos.SingleColumnValueExcludeFilter proto; 134 try { 135 proto = FilterProtos.SingleColumnValueExcludeFilter.parseFrom(pbBytes); 136 } catch (InvalidProtocolBufferException e) { 137 throw new DeserializationException(e); 138 } 139 140 FilterProtos.SingleColumnValueFilter parentProto = proto.getSingleColumnValueFilter(); 141 final CompareOperator compareOp = CompareOperator.valueOf(parentProto.getCompareOp().name()); 142 final ByteArrayComparable comparator; 143 try { 144 comparator = ProtobufUtil.toComparator(parentProto.getComparator()); 145 } catch (IOException ioe) { 146 throw new DeserializationException(ioe); 147 } 148 149 return new SingleColumnValueExcludeFilter( 150 parentProto.hasColumnFamily() ? parentProto.getColumnFamily().toByteArray() : null, 151 parentProto.hasColumnQualifier() ? parentProto.getColumnQualifier().toByteArray() : null, 152 compareOp, comparator, parentProto.getFilterIfMissing(), parentProto.getLatestVersionOnly()); 153 } 154 155 /** 156 * Returns true if and only if the fields of the filter that are serialized are equal to the 157 * corresponding fields in other. Used for testing. 158 */ 159 @Override 160 boolean areSerializedFieldsEqual(Filter o) { 161 if (o == this) { 162 return true; 163 } 164 if (!(o instanceof SingleColumnValueExcludeFilter)) { 165 return false; 166 } 167 return super.areSerializedFieldsEqual(o); 168 } 169 170 @Override 171 public boolean equals(Object obj) { 172 return obj instanceof Filter && areSerializedFieldsEqual((Filter) obj); 173 } 174 175 @Override 176 public int hashCode() { 177 return super.hashCode(); 178 } 179}