| // Licensed to the Apache Software Foundation (ASF) under one |
| // or more contributor license agreements. See the NOTICE file |
| // distributed with this work for additional information |
| // regarding copyright ownership. The ASF licenses this file |
| // to you under the Apache License, Version 2.0 (the |
| // "License"); you may not use this file except in compliance |
| // with the License. You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, |
| // software distributed under the License is distributed on an |
| // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| // KIND, either express or implied. See the License for the |
| // specific language governing permissions and limitations |
| // under the License. |
| |
| import org.roaringbitmap.RoaringBitmap; |
| import org.roaringbitmap.longlong.Roaring64NavigableMap; |
| |
| import java.io.ByteArrayInputStream; |
| import java.io.ByteArrayOutputStream; |
| import java.io.DataInputStream; |
| import java.io.DataOutputStream; |
| import java.nio.ByteBuffer; |
| import java.nio.ByteOrder; |
| import java.sql.Connection; |
| import java.sql.DriverManager; |
| import java.sql.ResultSet; |
| import java.sql.Statement; |
| |
| /** |
| * Prepare the table and data in Doris: |
| * |
| * <pre> |
| * {@code |
| * CREATE TABLE `t_bitmap` ( |
| * `rn` int(11) NULL, |
| * `uids` bitmap BITMAP_UNION NULL |
| * ) AGGREGATE KEY(`rn`) |
| * DISTRIBUTED BY HASH(`rn`) BUCKETS 1 |
| * PROPERTIES ( |
| * "replication_num" = "1" |
| * ); |
| * |
| * INSERT INTO t_bitmap VALUES |
| * (0, bitmap_empty()), |
| * (1, to_bitmap(243)), |
| * (2, bitmap_from_array([1,2,3,4,5,434543])), |
| * (3, to_bitmap(287667876573)), |
| * (4, bitmap_from_array([487667876573, 387627876573, 987567876573, 187667876573])); |
| * } |
| * </pre> |
| * |
| * The pom.xml dependency: |
| * <pre> |
| * {@code |
| * <dependency> |
| * <groupId>mysql</groupId> |
| * <artifactId>mysql-connector-java</artifactId> |
| * <version>8.0.28</version> |
| * </dependency> |
| * <dependency> |
| * <groupId>org.roaringbitmap</groupId> |
| * <artifactId>RoaringBitmap</artifactId> |
| * <version>0.9.39</version> |
| * </dependency> |
| * } |
| * </pre> |
| */ |
| public class ReadBitmap { |
| public static void main(String[] args) throws Exception { |
| |
| try (Connection conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:9030/test?user=root"); |
| Statement stmt = conn.createStatement() |
| ) { |
| stmt.execute("set return_object_data_as_binary=true"); // IMPORTANT!!! |
| ResultSet rs = stmt.executeQuery("select uids from t_bitmap"); |
| while (rs.next()) { |
| byte[] bytes = rs.getBytes(1); |
| |
| RoaringBitmap bitmap32 = new RoaringBitmap(); |
| // Only Roaring64NavigableMap can work, Roaring64Bitmap can't work!!! |
| Roaring64NavigableMap bitmap64 = new Roaring64NavigableMap(); |
| switch (bytes[0]) { |
| case 0: // for empty bitmap |
| break; |
| case 1: // for only 1 element in bitmap32 |
| bitmap32.add(ByteBuffer.wrap(bytes, 1, bytes.length - 1) |
| .order(ByteOrder.LITTLE_ENDIAN) |
| .getInt()); |
| break; |
| case 2: // for more than 1 elements in bitmap32 |
| bitmap32.deserialize(ByteBuffer.wrap(bytes, 1, bytes.length - 1)); |
| break; |
| case 3: // for only 1 element in bitmap64 |
| bitmap64.add(ByteBuffer.wrap(bytes, 1, bytes.length - 1) |
| .order(ByteOrder.LITTLE_ENDIAN) |
| .getLong()); |
| break; |
| case 4: // for more than 1 elements in bitmap64 |
| Object[] tuple2 = decodeVarint64(bytes); |
| int offset = (int) tuple2[1]; |
| int newLen = 8 + bytes.length - offset; |
| |
| try (ByteArrayOutputStream baos = new ByteArrayOutputStream(newLen); |
| DataOutputStream dos = new DataOutputStream(baos)) { |
| dos.write((byte[]) tuple2[0]); |
| dos.write(bytes, offset, bytes.length - offset); |
| dos.flush(); |
| try (DataInputStream dis = new DataInputStream( |
| new ByteArrayInputStream(baos.toByteArray()))) { |
| bitmap64.deserializePortable(dis); |
| } |
| } |
| break; |
| } |
| System.out.println(bytes[0] <= 2 ? bitmap32 : bitmap64); |
| } |
| } |
| } |
| |
| static Object[] decodeVarint64(byte[] bt) { // nolint |
| long result = 0; |
| int shift = 0; |
| short B = 128; |
| int idx = 1; |
| for (; ; ) { |
| short readByte = bt[idx]; |
| idx++; |
| boolean isEnd = (readByte & B) == 0; |
| result |= (long) (readByte & (B - 1)) << (shift * 7); |
| if (isEnd) { |
| break; |
| } |
| shift++; |
| } |
| byte[] bytes = new byte[8]; |
| for (int i = 0; i < bytes.length; i++) { |
| // LITTLE_ENDIAN |
| bytes[i] = (byte) (result >> 8 * i); |
| } |
| return new Object[]{bytes, idx}; |
| } |
| } |