View Javadoc

1   /*
2    * Copyright (c) 2010.  The Apache Software Foundation
3    *
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *     http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing, software
15   * distributed under the License is distributed on an "AS IS" BASIS,
16   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17   * See the License for the specific language governing permissions and
18   * limitations under the License.
19   */
20  
21  package org.apache.hadoop.hbase.hbql.filter;
22  
23  import org.apache.commons.logging.Log;
24  import org.apache.commons.logging.LogFactory;
25  import org.apache.expreval.client.NullColumnValueException;
26  import org.apache.expreval.client.ResultMissingColumnException;
27  import org.apache.expreval.expr.ExpressionTree;
28  import org.apache.hadoop.hbase.KeyValue;
29  import org.apache.hadoop.hbase.hbql.client.HBqlException;
30  import org.apache.hadoop.hbase.hbql.impl.HRecordImpl;
31  import org.apache.hadoop.hbase.hbql.impl.Utils;
32  import org.apache.hadoop.hbase.hbql.io.IO;
33  import org.apache.hadoop.hbase.hbql.mapping.ColumnAttrib;
34  import org.apache.hadoop.hbase.hbql.mapping.FieldType;
35  import org.apache.hadoop.hbase.hbql.mapping.MappingContext;
36  import org.apache.hadoop.hbase.hbql.mapping.TableMapping;
37  import org.apache.hadoop.hbase.util.Bytes;
38  
39  import java.io.ByteArrayInputStream;
40  import java.io.ByteArrayOutputStream;
41  import java.io.DataInput;
42  import java.io.DataOutput;
43  import java.io.IOException;
44  import java.io.ObjectInputStream;
45  import java.io.ObjectOutputStream;
46  import java.util.Arrays;
47  
48  public class RecordFilter implements InstrumentedFilter {
49  
50      private static final Log LOG = LogFactory.getLog(RecordFilter.class);
51  
52      private boolean verbose = false;
53      private ExpressionTree expressionTree = null;
54  
55      public HRecordImpl record = new HRecordImpl((MappingContext)null);
56  
57      public RecordFilter() {
58      }
59  
60      private RecordFilter(final ExpressionTree expressionTree) {
61          this.expressionTree = expressionTree;
62          this.getHRecord().setMappingContext(this.getExpressionTree().getMappingContext());
63      }
64  
65      public static RecordFilter newRecordFilter(final ExpressionTree expressionTree) {
66          return (expressionTree == null) ? null : new RecordFilter(expressionTree);
67      }
68  
69      private HRecordImpl getHRecord() {
70          return this.record;
71      }
72  
73      private TableMapping getMapping() {
74          return this.getExpressionTree().getTableMapping();
75      }
76  
77      private ExpressionTree getExpressionTree() {
78          return this.expressionTree;
79      }
80  
81      private boolean hasValidExpressionTree() {
82          return this.getExpressionTree() != null;
83      }
84  
85      public void setVerbose(final boolean verbose) {
86          this.verbose = verbose;
87      }
88  
89      public boolean getVerbose() {
90          return this.verbose;
91      }
92  
93      public void reset() {
94          if (this.getVerbose())
95              LOG.debug("In reset()");
96          this.getHRecord().clearValues();
97      }
98  
99      public boolean filterRowKey(byte[] buffer, int offset, int length) {
100         // LOG.debug("In filterRowKey()");
101         //final String rowKey = new String(buffer, offset, length);
102         final byte[] rowKey = Arrays.copyOfRange(buffer, offset, length);
103         try {
104             this.getMapping().getKeyAttrib().setCurrentValue(record, 0, rowKey);
105         }
106         catch (HBqlException e) {
107             Utils.logException(LOG, e);
108         }
109         return false;
110     }
111 
112     public boolean filterAllRemaining() {
113         return false;
114     }
115 
116     public ReturnCode filterKeyValue(KeyValue v) {
117 
118         if (this.getVerbose())
119             LOG.debug("In filterKeyValue()");
120 
121         if (this.hasValidExpressionTree()) {
122 
123             try {
124                 final String familyName = Bytes.toString(v.getFamily());
125                 final String columnName = Bytes.toString(v.getQualifier());
126                 final TableMapping tableMapping = this.getMapping();
127                 final ColumnAttrib attrib = tableMapping.getAttribFromFamilyQualifiedName(familyName, columnName);
128 
129                 // Do not bother setting value if it is not used in expression
130                 if (this.getExpressionTree().getAttribsUsedInExpr().contains(attrib)) {
131                     if (this.getVerbose())
132                         LOG.debug("In filterKeyValue() setting value for: " + familyName + ":" + columnName);
133                     final Object val = attrib.getValueFromBytes(null, v.getValue());
134                     this.getHRecord().setCurrentValue(familyName, columnName, v.getTimestamp(), val);
135                     this.getHRecord().setVersionValue(familyName, columnName, v.getTimestamp(), val, true);
136                 }
137             }
138             catch (Exception e) {
139                 Utils.logException(LOG, e);
140                 LOG.debug("Exception in filterKeyValue(): " + e.getClass().getName() + " - " + e.getMessage());
141             }
142         }
143 
144         return ReturnCode.INCLUDE;
145     }
146 
147     public boolean filterRow() {
148 
149         if (this.getVerbose())
150             LOG.debug("In filterRow()");
151 
152         boolean filterRow;
153         if (!this.hasValidExpressionTree()) {
154             if (this.getVerbose())
155                 LOG.debug("In filterRow() had invalid hasValidExpressionTree(): ");
156             filterRow = false;
157         }
158         else {
159             try {
160                 filterRow = !this.getExpressionTree().evaluate(null, this.getHRecord());
161                 if (this.getVerbose())
162                     LOG.debug("In filterRow() filtering record: " + filterRow);
163             }
164             catch (ResultMissingColumnException e) {
165                 if (this.getVerbose())
166                     LOG.debug("In filterRow() had ResultMissingColumnException exception: " + e.getMessage());
167                 filterRow = true;
168             }
169             catch (NullColumnValueException e) {
170                 if (this.getVerbose())
171                     LOG.debug("In filterRow() had NullColumnValueException exception: " + e.getMessage());
172                 filterRow = true;
173             }
174             catch (HBqlException e) {
175                 e.printStackTrace();
176                 Utils.logException(LOG, e);
177                 LOG.debug("In filterRow() had HBqlException: " + e.getMessage());
178                 filterRow = true;
179             }
180         }
181 
182         //LOG.debug("In filterRow() returning: " + filterRow);
183         return filterRow;
184     }
185 
186     public void write(DataOutput out) throws IOException {
187         try {
188             out.writeBoolean(this.getVerbose());
189             final byte[] b = IO.getSerialization().getObjectAsBytes(this.getExpressionTree());
190             Bytes.writeByteArray(out, b);
191         }
192         catch (HBqlException e) {
193             e.printStackTrace();
194             Utils.logException(LOG, e);
195             throw new IOException(e.getCause());
196         }
197     }
198 
199     public void readFields(DataInput in) throws IOException {
200 
201         try {
202             this.verbose = in.readBoolean();
203             final byte[] b = Bytes.readByteArray(in);
204             this.expressionTree = (ExpressionTree)IO.getSerialization().getScalarFromBytes(FieldType.ObjectType, b);
205 
206             this.getHRecord().setMappingContext(this.getExpressionTree().getMappingContext());
207             this.getMapping().resetDefaultValues();
208         }
209         catch (HBqlException e) {
210             e.printStackTrace();
211             Utils.logException(LOG, e);
212             throw new IOException(e.getCause());
213         }
214     }
215 
216     public static void testFilter(final RecordFilter origFilter) throws HBqlException, IOException {
217 
218         final ByteArrayOutputStream baos = new ByteArrayOutputStream();
219         final ObjectOutputStream oos = new ObjectOutputStream(baos);
220         origFilter.write(oos);
221         oos.flush();
222         oos.close();
223         final byte[] b = baos.toByteArray();
224 
225         final ByteArrayInputStream bais = new ByteArrayInputStream(b);
226         final ObjectInputStream ois = new ObjectInputStream(bais);
227 
228         RecordFilter filter = new RecordFilter();
229         filter.readFields(ois);
230 
231         filter.reset();
232 
233         final String family = "family1";
234         final String column = "author";
235         final String[] vals = {"An author value-81252702162528282000",
236                                "An author value-812527021593753270002009",
237                                "An author value-81252702156610125000",
238                                "An author value-812527021520532270002009",
239                                "An author value-81252702147337884000"
240         };
241 
242         for (String val : vals) {
243             filter.getHRecord().setCurrentValue(family, column, 100, val);
244             filter.getHRecord().setVersionValue(family, column, 100, val, true);
245         }
246 
247         boolean v = filter.filterRow();
248     }
249 }