|
18 | 18 | package com.alipay.oceanbase.hbase.filter;
|
19 | 19 |
|
20 | 20 | import org.apache.hadoop.hbase.filter.*;
|
21 |
| -import org.apache.hadoop.hbase.util.Bytes; |
22 | 21 |
|
| 22 | +import java.io.ByteArrayOutputStream; |
| 23 | +import java.io.IOException; |
23 | 24 | import java.util.List;
|
24 | 25 |
|
25 | 26 | public class HBaseFilterUtils {
|
26 | 27 |
|
27 |
| - public static String toParseableString(Filter filter) { |
| 28 | + public static byte[] toParseableByteArray(Filter filter) throws IOException { |
| 29 | + ByteArrayOutputStream byteStream = new ByteArrayOutputStream(); |
| 30 | + toParseableByteArray(byteStream, filter); |
| 31 | + return byteStream.toByteArray(); |
| 32 | + } |
| 33 | + |
| 34 | + private static void toParseableByteArray(ByteArrayOutputStream byteStream, Filter filter) throws IOException { |
28 | 35 | if (filter == null) {
|
29 | 36 | throw new IllegalArgumentException("Filter is null");
|
30 | 37 | } else if (filter instanceof CompareFilter) {
|
31 | 38 | // RowFilter, ValueFilter, QualifierFilter
|
32 |
| - return toParseableString((CompareFilter) filter); |
| 39 | + toParseableByteArray(byteStream, (CompareFilter) filter); |
33 | 40 | } else if (filter instanceof SingleColumnValueFilter) {
|
34 |
| - return toParseableString((SingleColumnValueFilter) filter); |
| 41 | + toParseableByteArray(byteStream, (SingleColumnValueFilter) filter); |
35 | 42 | } else if (filter instanceof PageFilter) {
|
36 |
| - return toParseableString((PageFilter) filter); |
| 43 | + toParseableByteArray(byteStream, (PageFilter) filter); |
37 | 44 | } else if (filter instanceof ColumnCountGetFilter) {
|
38 |
| - return toParseableString((ColumnCountGetFilter) filter); |
| 45 | + toParseableByteArray(byteStream, (ColumnCountGetFilter) filter); |
39 | 46 | } else if (filter instanceof PrefixFilter) {
|
40 |
| - return toParseableString((PrefixFilter) filter); |
| 47 | + toParseableByteArray(byteStream, (PrefixFilter) filter); |
41 | 48 | } else if (filter instanceof FilterList) {
|
42 |
| - return toParseableString((FilterList) filter); |
| 49 | + toParseableByteArray(byteStream, (FilterList) filter); |
43 | 50 | } else if (filter instanceof ColumnPaginationFilter) {
|
44 |
| - return toParseableString((ColumnPaginationFilter) filter); |
| 51 | + toParseableByteArray(byteStream, (ColumnPaginationFilter) filter); |
45 | 52 | } else if (filter instanceof SkipFilter) {
|
46 |
| - return toParseableString((SkipFilter) filter); |
| 53 | + toParseableByteArray(byteStream, (SkipFilter) filter); |
47 | 54 | } else if (filter instanceof WhileMatchFilter) {
|
48 |
| - return toParseableString((WhileMatchFilter) filter); |
| 55 | + toParseableByteArray(byteStream, (WhileMatchFilter) filter); |
49 | 56 | } else {
|
50 | 57 | throw new IllegalArgumentException("Invalid filter: " + filter);
|
51 | 58 | }
|
52 | 59 | }
|
53 | 60 |
|
54 |
| - private static String toParseableString(CompareFilter.CompareOp op) { |
| 61 | + private static byte[] toParseableByteArray(CompareFilter.CompareOp op) { |
55 | 62 | if (op == null) {
|
56 | 63 | throw new IllegalArgumentException("Compare operator is null");
|
57 | 64 | }
|
58 | 65 | switch (op) {
|
59 | 66 | case LESS:
|
60 |
| - return Bytes.toString(ParseConstants.LESS_THAN_ARRAY); |
| 67 | + return ParseConstants.LESS_THAN_ARRAY; |
61 | 68 | case LESS_OR_EQUAL:
|
62 |
| - return Bytes.toString(ParseConstants.LESS_THAN_OR_EQUAL_TO_ARRAY); |
| 69 | + return ParseConstants.LESS_THAN_OR_EQUAL_TO_ARRAY; |
63 | 70 | case EQUAL:
|
64 |
| - return Bytes.toString(ParseConstants.EQUAL_TO_ARRAY); |
| 71 | + return ParseConstants.EQUAL_TO_ARRAY; |
65 | 72 | case NOT_EQUAL:
|
66 |
| - return Bytes.toString(ParseConstants.NOT_EQUAL_TO_ARRAY); |
| 73 | + return ParseConstants.NOT_EQUAL_TO_ARRAY; |
67 | 74 | case GREATER_OR_EQUAL:
|
68 |
| - return Bytes.toString(ParseConstants.GREATER_THAN_OR_EQUAL_TO_ARRAY); |
| 75 | + return ParseConstants.GREATER_THAN_OR_EQUAL_TO_ARRAY; |
69 | 76 | case GREATER:
|
70 |
| - return Bytes.toString(ParseConstants.GREATER_THAN_ARRAY); |
| 77 | + return ParseConstants.GREATER_THAN_ARRAY; |
71 | 78 | default:
|
72 | 79 | throw new IllegalArgumentException("Invalid compare operator: " + op);
|
73 | 80 | }
|
74 | 81 | }
|
75 | 82 |
|
76 |
| - private static String toParseableString(ByteArrayComparable comparator) { |
| 83 | + private static void toParseableByteArray(ByteArrayOutputStream byteStream, ByteArrayComparable comparator) throws IOException { |
77 | 84 | if (comparator == null) {
|
78 | 85 | throw new IllegalArgumentException("Comparator is null");
|
79 | 86 | }
|
80 |
| - StringBuilder sb = new StringBuilder(); |
| 87 | + byteStream.write('\''); |
81 | 88 | if (comparator instanceof BinaryComparator) {
|
82 |
| - sb.append('\'').append(Bytes.toString(ParseConstants.binaryType)).append(':') |
83 |
| - .append(Bytes.toString(comparator.getValue())).append('\''); |
| 89 | + byteStream.write(ParseConstants.binaryType); |
84 | 90 | } else if (comparator instanceof BinaryPrefixComparator) {
|
85 |
| - sb.append('\'').append(Bytes.toString(ParseConstants.binaryPrefixType)).append(':') |
86 |
| - .append(Bytes.toString(comparator.getValue())).append('\''); |
| 91 | + byteStream.write(ParseConstants.binaryPrefixType); |
87 | 92 | } else if (comparator instanceof RegexStringComparator) {
|
88 |
| - sb.append('\'').append(Bytes.toString(ParseConstants.regexStringType)).append(':') |
89 |
| - .append(Bytes.toString(comparator.getValue())).append('\''); |
| 93 | + byteStream.write(ParseConstants.regexStringType); |
90 | 94 | } else if (comparator instanceof SubstringComparator) {
|
91 |
| - sb.append('\'').append(Bytes.toString(ParseConstants.substringType)).append(':') |
92 |
| - .append(Bytes.toString(comparator.getValue())).append('\''); |
| 95 | + byteStream.write(ParseConstants.substringType); |
93 | 96 | } else {
|
94 | 97 | throw new IllegalArgumentException("This comparator has not been implemented "
|
95 | 98 | + comparator);
|
96 | 99 | }
|
97 |
| - return sb.toString(); |
| 100 | + byteStream.write(':'); |
| 101 | + writeBytesWithEscape(byteStream, comparator.getValue()); |
| 102 | + byteStream.write('\''); |
98 | 103 | }
|
99 | 104 |
|
100 |
| - private static String toParseableString(CompareFilter filter) { |
101 |
| - return filter.getClass().getSimpleName() + '(' + toParseableString(filter.getOperator()) |
102 |
| - + ',' + toParseableString(filter.getComparator()) + ')'; |
| 105 | + // CompareFilter(=,'binary:123') |
| 106 | + private static void toParseableByteArray(ByteArrayOutputStream byteStream, CompareFilter filter) throws IOException { |
| 107 | + byteStream.write(filter.getClass().getSimpleName().getBytes()); |
| 108 | + byteStream.write('('); |
| 109 | + byteStream.write(toParseableByteArray(filter.getOperator())); |
| 110 | + byteStream.write(','); |
| 111 | + toParseableByteArray(byteStream, filter.getComparator()); |
| 112 | + byteStream.write(')'); |
103 | 113 | }
|
104 | 114 |
|
105 |
| - private static String toParseableString(SingleColumnValueFilter filter) { |
106 |
| - return filter.getClass().getSimpleName() + "('" + Bytes.toString(filter.getFamily()) |
107 |
| - + "','" + Bytes.toString(filter.getQualifier()) + "'," |
108 |
| - + toParseableString(filter.getOperator()) + ',' |
109 |
| - + toParseableString(filter.getComparator()) + ',' + filter.getFilterIfMissing() |
110 |
| - + ',' + filter.getLatestVersionOnly() + ')'; |
| 115 | + // SingleColumnValueFilter('cf1','col1',=,'binary:123',true,true) |
| 116 | + private static void toParseableByteArray(ByteArrayOutputStream byteStream, SingleColumnValueFilter filter) throws IOException { |
| 117 | + byteStream.write(filter.getClass().getSimpleName().getBytes()); |
| 118 | + byteStream.write("('".getBytes()); |
| 119 | + writeBytesWithEscape(byteStream, filter.getFamily()); |
| 120 | + byteStream.write("','".getBytes()); |
| 121 | + writeBytesWithEscape(byteStream, filter.getQualifier()); |
| 122 | + byteStream.write("',".getBytes()); |
| 123 | + byteStream.write(toParseableByteArray(filter.getOperator())); |
| 124 | + byteStream.write(','); |
| 125 | + toParseableByteArray(byteStream, filter.getComparator()); |
| 126 | + byteStream.write(','); |
| 127 | + byteStream.write(Boolean.toString(filter.getFilterIfMissing()).getBytes()); |
| 128 | + byteStream.write(','); |
| 129 | + byteStream.write(Boolean.toString(filter.getLatestVersionOnly()).getBytes()); |
| 130 | + byteStream.write(')'); |
111 | 131 | }
|
112 | 132 |
|
113 |
| - private static String toParseableString(PageFilter filter) { |
114 |
| - return filter.getClass().getSimpleName() + '(' + filter.getPageSize() + ')'; |
| 133 | + // PageFilter(100); |
| 134 | + private static void toParseableByteArray(ByteArrayOutputStream byteStream, PageFilter filter) throws IOException { |
| 135 | + byteStream.write(filter.getClass().getSimpleName().getBytes()); |
| 136 | + byteStream.write('('); |
| 137 | + byteStream.write(Long.toString(filter.getPageSize()).getBytes()); |
| 138 | + byteStream.write(')'); |
115 | 139 | }
|
116 | 140 |
|
117 |
| - private static String toParseableString(ColumnPaginationFilter filter) { |
118 |
| - return filter.getClass().getSimpleName() + '(' + filter.getLimit() + ',' |
119 |
| - + filter.getOffset() + ')'; |
| 141 | + // ColumnPaginationFilter(ColumnPaginationFilter(10,2) |
| 142 | + private static void toParseableByteArray(ByteArrayOutputStream byteStream, ColumnPaginationFilter filter) throws IOException { |
| 143 | + byteStream.write(filter.getClass().getSimpleName().getBytes()); |
| 144 | + byteStream.write('('); |
| 145 | + byteStream.write(Long.toString(filter.getLimit()).getBytes()); |
| 146 | + byteStream.write(','); |
| 147 | + byteStream.write(Long.toString(filter.getOffset()).getBytes()); |
| 148 | + byteStream .write(')'); |
120 | 149 | }
|
121 | 150 |
|
122 |
| - private static String toParseableString(ColumnCountGetFilter filter) { |
123 |
| - return filter.getClass().getSimpleName() + '(' + filter.getLimit() + ')'; |
| 151 | + // ColumnCountGetFilter(100) |
| 152 | + private static void toParseableByteArray(ByteArrayOutputStream byteStream, ColumnCountGetFilter filter) throws IOException { |
| 153 | + byteStream.write(filter.getClass().getSimpleName().getBytes()); |
| 154 | + byteStream.write('('); |
| 155 | + byteStream.write(Long.toString(filter.getLimit()).getBytes()); |
| 156 | + byteStream .write(')'); |
124 | 157 | }
|
125 | 158 |
|
126 |
| - private static String toParseableString(PrefixFilter filter) { |
127 |
| - return filter.getClass().getSimpleName() + "('" + Bytes.toString(filter.getPrefix()) + "')"; |
| 159 | + // PrefixFilter('prefix'); |
| 160 | + private static void toParseableByteArray(ByteArrayOutputStream byteStream, PrefixFilter filter) throws IOException { |
| 161 | + byteStream.write(filter.getClass().getSimpleName().getBytes()); |
| 162 | + byteStream.write("('".getBytes()); |
| 163 | + writeBytesWithEscape(byteStream, filter.getPrefix()); |
| 164 | + byteStream .write("')".getBytes()); |
128 | 165 | }
|
129 | 166 |
|
130 |
| - private static String toParseableString(SkipFilter filter) { |
131 |
| - return "(" + Bytes.toString(ParseConstants.SKIP_ARRAY) + " " |
132 |
| - + toParseableString(filter.getFilter()) + ")"; |
| 167 | + // (SKIP filter) |
| 168 | + private static void toParseableByteArray(ByteArrayOutputStream byteStream, SkipFilter filter) throws IOException { |
| 169 | + byteStream.write('('); |
| 170 | + byteStream.write(ParseConstants.SKIP_ARRAY); |
| 171 | + byteStream.write(' '); |
| 172 | + toParseableByteArray(byteStream, filter.getFilter()); |
| 173 | + byteStream.write(')'); |
133 | 174 | }
|
134 | 175 |
|
135 |
| - private static String toParseableString(WhileMatchFilter filter) { |
136 |
| - return "(" + Bytes.toString(ParseConstants.WHILE_ARRAY) + " " |
137 |
| - + toParseableString(filter.getFilter()) + ")"; |
| 176 | + // (WHILE filter) |
| 177 | + private static void toParseableByteArray(ByteArrayOutputStream byteStream, WhileMatchFilter filter) throws IOException { |
| 178 | + byteStream.write('('); |
| 179 | + byteStream.write(ParseConstants.WHILE_ARRAY); |
| 180 | + byteStream.write(' '); |
| 181 | + toParseableByteArray(byteStream, filter.getFilter()); |
| 182 | + byteStream.write(')'); |
138 | 183 | }
|
139 | 184 |
|
140 |
| - private static String toParseableString(FilterList filterList) { |
141 |
| - StringBuilder sb = new StringBuilder(); |
| 185 | + // (filter and filter ...) or (filter or filter ...) |
| 186 | + // when filter list is empty, "" is generated, and empty filter list member is removed |
| 187 | + // in result parseable byteArray |
| 188 | + private static void toParseableByteArray(ByteArrayOutputStream byteStream, FilterList filterList) throws IOException { |
142 | 189 | List<Filter> filters = filterList.getFilters();
|
143 | 190 | boolean isEmpty = true;
|
| 191 | + ByteArrayOutputStream oneFilterBytes = new ByteArrayOutputStream(); |
144 | 192 | for (int i = 0; i < filters.size(); i++) {
|
145 |
| - String filterString = toParseableString(filters.get(i)); |
146 |
| - if (filterString.isEmpty()) |
147 |
| - continue; |
| 193 | + toParseableByteArray(oneFilterBytes, filters.get(i)); |
| 194 | + if (oneFilterBytes.size() == 0) { continue; } |
148 | 195 | if (isEmpty) {
|
149 |
| - sb.append("(").append(filterString); |
| 196 | + byteStream.write('('); |
150 | 197 | isEmpty = false;
|
151 | 198 | } else {
|
152 |
| - sb.append(" "); |
| 199 | + byteStream.write(' '); |
153 | 200 | if (filterList.getOperator().equals(FilterList.Operator.MUST_PASS_ALL)) {
|
154 |
| - sb.append(Bytes.toString(ParseConstants.AND)); |
| 201 | + byteStream.write(ParseConstants.AND); |
155 | 202 | } else if (filterList.getOperator().equals(FilterList.Operator.MUST_PASS_ONE)) {
|
156 |
| - sb.append(Bytes.toString(ParseConstants.OR)); |
| 203 | + byteStream.write(ParseConstants.OR); |
157 | 204 | } else {
|
158 | 205 | throw new IllegalArgumentException("Invalid FilterList: " + filterList);
|
159 | 206 | }
|
160 |
| - sb.append(" ").append(filterString); |
| 207 | + byteStream.write(' '); |
161 | 208 | }
|
| 209 | + oneFilterBytes.writeTo(byteStream); |
| 210 | + oneFilterBytes.reset(); |
162 | 211 | }
|
163 | 212 | if (!isEmpty) {
|
164 |
| - sb.append(")"); |
| 213 | + byteStream.write(')'); |
165 | 214 | }
|
166 |
| - return sb.toString(); |
167 | 215 | }
|
168 | 216 |
|
| 217 | + // when write family/qualifier/value/row into hbase filter, need add escape for |
| 218 | + // special character to prevent parse error in server |
| 219 | + public static void writeBytesWithEscape(ByteArrayOutputStream byteStream, byte[] bytes) throws IOException { |
| 220 | + if (bytes == null) { |
| 221 | + return; |
| 222 | + } |
| 223 | + for (int i = 0; i < bytes.length; i++) { |
| 224 | + if (bytes[i] == '\'') { |
| 225 | + byteStream.write('\''); |
| 226 | + } |
| 227 | + byteStream.write(bytes[i]); |
| 228 | + } |
| 229 | + } |
169 | 230 | }
|
0 commit comments