1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.hadoop.hbase.spark;
19
20 import com.google.protobuf.ByteString;
21 import com.google.protobuf.InvalidProtocolBufferException;
22 import org.apache.commons.logging.Log;
23 import org.apache.commons.logging.LogFactory;
24 import org.apache.hadoop.hbase.Cell;
25 import org.apache.hadoop.hbase.exceptions.DeserializationException;
26 import org.apache.hadoop.hbase.filter.FilterBase;
27 import org.apache.hadoop.hbase.spark.protobuf.generated.FilterProtos;
28 import org.apache.hadoop.hbase.util.ByteStringer;
29 import org.apache.hadoop.hbase.util.Bytes;
30 import scala.collection.mutable.MutableList;
31
32 import java.io.IOException;
33 import java.util.HashMap;
34 import java.util.List;
35 import java.util.Map;
36
37
38
39
40
41
42 public class SparkSQLPushDownFilter extends FilterBase{
43 protected static final Log log = LogFactory.getLog(SparkSQLPushDownFilter.class);
44
45
46 DynamicLogicExpression dynamicLogicExpression;
47 byte[][] valueFromQueryArray;
48 HashMap<ByteArrayComparable, HashMap<ByteArrayComparable, String>>
49 currentCellToColumnIndexMap;
50
51
52 HashMap<String, ByteArrayComparable> columnToCurrentRowValueMap = null;
53
54 static final byte[] rowKeyFamily = new byte[0];
55 static final byte[] rowKeyQualifier = Bytes.toBytes("key");
56
57 public SparkSQLPushDownFilter(DynamicLogicExpression dynamicLogicExpression,
58 byte[][] valueFromQueryArray,
59 HashMap<ByteArrayComparable,
60 HashMap<ByteArrayComparable, String>>
61 currentCellToColumnIndexMap) {
62 this.dynamicLogicExpression = dynamicLogicExpression;
63 this.valueFromQueryArray = valueFromQueryArray;
64 this.currentCellToColumnIndexMap = currentCellToColumnIndexMap;
65 }
66
67 public SparkSQLPushDownFilter(DynamicLogicExpression dynamicLogicExpression,
68 byte[][] valueFromQueryArray,
69 MutableList<SchemaQualifierDefinition> columnDefinitions) {
70 this.dynamicLogicExpression = dynamicLogicExpression;
71 this.valueFromQueryArray = valueFromQueryArray;
72
73
74 this.currentCellToColumnIndexMap =
75 new HashMap<>();
76
77 for (int i = 0; i < columnDefinitions.size(); i++) {
78 SchemaQualifierDefinition definition = columnDefinitions.get(i).get();
79
80 ByteArrayComparable familyByteComparable =
81 new ByteArrayComparable(definition.columnFamilyBytes(),
82 0, definition.columnFamilyBytes().length);
83
84 HashMap<ByteArrayComparable, String> qualifierIndexMap =
85 currentCellToColumnIndexMap.get(familyByteComparable);
86
87 if (qualifierIndexMap == null) {
88 qualifierIndexMap = new HashMap<>();
89 currentCellToColumnIndexMap.put(familyByteComparable, qualifierIndexMap);
90 }
91 ByteArrayComparable qualifierByteComparable =
92 new ByteArrayComparable(definition.qualifierBytes(), 0,
93 definition.qualifierBytes().length);
94
95 qualifierIndexMap.put(qualifierByteComparable, definition.columnName());
96 }
97 }
98
99 @Override
100 public ReturnCode filterKeyValue(Cell c) throws IOException {
101
102
103
104 if (columnToCurrentRowValueMap == null) {
105 columnToCurrentRowValueMap = new HashMap<>();
106 HashMap<ByteArrayComparable, String> qualifierColumnMap =
107 currentCellToColumnIndexMap.get(
108 new ByteArrayComparable(rowKeyFamily, 0, rowKeyFamily.length));
109
110 if (qualifierColumnMap != null) {
111 String rowKeyColumnName =
112 qualifierColumnMap.get(
113 new ByteArrayComparable(rowKeyQualifier, 0,
114 rowKeyQualifier.length));
115
116 if (rowKeyColumnName != null) {
117 columnToCurrentRowValueMap.put(rowKeyColumnName,
118 new ByteArrayComparable(c.getRowArray(),
119 c.getRowOffset(), c.getRowLength()));
120 }
121 }
122 }
123
124
125 ByteArrayComparable currentFamilyByteComparable =
126 new ByteArrayComparable(c.getFamilyArray(),
127 c.getFamilyOffset(),
128 c.getFamilyLength());
129
130 HashMap<ByteArrayComparable, String> qualifierColumnMap =
131 currentCellToColumnIndexMap.get(
132 currentFamilyByteComparable);
133
134 if (qualifierColumnMap != null) {
135
136 String columnName =
137 qualifierColumnMap.get(
138 new ByteArrayComparable(c.getQualifierArray(),
139 c.getQualifierOffset(),
140 c.getQualifierLength()));
141
142 if (columnName != null) {
143 columnToCurrentRowValueMap.put(columnName,
144 new ByteArrayComparable(c.getValueArray(),
145 c.getValueOffset(), c.getValueLength()));
146 }
147 }
148
149 return ReturnCode.INCLUDE;
150 }
151
152
153 @Override
154 public boolean filterRow() throws IOException {
155
156 try {
157 boolean result =
158 dynamicLogicExpression.execute(columnToCurrentRowValueMap,
159 valueFromQueryArray);
160 columnToCurrentRowValueMap = null;
161 return !result;
162 } catch (Throwable e) {
163 log.error("Error running dynamic logic on row", e);
164 }
165 return false;
166 }
167
168
169
170
171
172
173
174 @SuppressWarnings("unused")
175 public static SparkSQLPushDownFilter parseFrom(final byte[] pbBytes)
176 throws DeserializationException {
177
178 FilterProtos.SQLPredicatePushDownFilter proto;
179 try {
180 proto = FilterProtos.SQLPredicatePushDownFilter.parseFrom(pbBytes);
181 } catch (InvalidProtocolBufferException e) {
182 throw new DeserializationException(e);
183 }
184
185
186 DynamicLogicExpression dynamicLogicExpression =
187 DynamicLogicExpressionBuilder.build(proto.getDynamicLogicExpression());
188
189
190 final List<ByteString> valueFromQueryArrayList = proto.getValueFromQueryArrayList();
191 byte[][] valueFromQueryArray = new byte[valueFromQueryArrayList.size()][];
192 for (int i = 0; i < valueFromQueryArrayList.size(); i++) {
193 valueFromQueryArray[i] = valueFromQueryArrayList.get(i).toByteArray();
194 }
195
196
197 HashMap<ByteArrayComparable, HashMap<ByteArrayComparable, String>>
198 currentCellToColumnIndexMap = new HashMap<>();
199
200 for (FilterProtos.SQLPredicatePushDownCellToColumnMapping
201 sqlPredicatePushDownCellToColumnMapping :
202 proto.getCellToColumnMappingList()) {
203
204 byte[] familyArray =
205 sqlPredicatePushDownCellToColumnMapping.getColumnFamily().toByteArray();
206 ByteArrayComparable familyByteComparable =
207 new ByteArrayComparable(familyArray, 0, familyArray.length);
208 HashMap<ByteArrayComparable, String> qualifierMap =
209 currentCellToColumnIndexMap.get(familyByteComparable);
210
211 if (qualifierMap == null) {
212 qualifierMap = new HashMap<>();
213 currentCellToColumnIndexMap.put(familyByteComparable, qualifierMap);
214 }
215 byte[] qualifierArray =
216 sqlPredicatePushDownCellToColumnMapping.getQualifier().toByteArray();
217
218 ByteArrayComparable qualifierByteComparable =
219 new ByteArrayComparable(qualifierArray, 0 ,qualifierArray.length);
220
221 qualifierMap.put(qualifierByteComparable,
222 sqlPredicatePushDownCellToColumnMapping.getColumnName());
223 }
224
225 return new SparkSQLPushDownFilter(dynamicLogicExpression,
226 valueFromQueryArray, currentCellToColumnIndexMap);
227 }
228
229
230
231
232 public byte[] toByteArray() {
233
234 FilterProtos.SQLPredicatePushDownFilter.Builder builder =
235 FilterProtos.SQLPredicatePushDownFilter.newBuilder();
236
237 FilterProtos.SQLPredicatePushDownCellToColumnMapping.Builder columnMappingBuilder =
238 FilterProtos.SQLPredicatePushDownCellToColumnMapping.newBuilder();
239
240 builder.setDynamicLogicExpression(dynamicLogicExpression.toExpressionString());
241 for (byte[] valueFromQuery: valueFromQueryArray) {
242 builder.addValueFromQueryArray(ByteStringer.wrap(valueFromQuery));
243 }
244
245 for (Map.Entry<ByteArrayComparable, HashMap<ByteArrayComparable, String>>
246 familyEntry : currentCellToColumnIndexMap.entrySet()) {
247 for (Map.Entry<ByteArrayComparable, String> qualifierEntry :
248 familyEntry.getValue().entrySet()) {
249 columnMappingBuilder.setColumnFamily(
250 ByteStringer.wrap(familyEntry.getKey().bytes()));
251 columnMappingBuilder.setQualifier(
252 ByteStringer.wrap(qualifierEntry.getKey().bytes()));
253 columnMappingBuilder.setColumnName(qualifierEntry.getValue());
254 builder.addCellToColumnMapping(columnMappingBuilder.build());
255 }
256 }
257
258 return builder.build().toByteArray();
259 }
260 }