1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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
101
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
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
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 }