BinaryRangeUtil.java 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  1. /*
  2. * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
  3. * or more contributor license agreements. Licensed under the Elastic License
  4. * 2.0 and the Server Side Public License, v 1; you may not use this file except
  5. * in compliance with, at your election, the Elastic License 2.0 or the Server
  6. * Side Public License, v 1.
  7. */
  8. package org.elasticsearch.index.mapper;
  9. import org.apache.lucene.document.InetAddressPoint;
  10. import org.apache.lucene.util.BytesRef;
  11. import org.apache.lucene.util.NumericUtils;
  12. import org.elasticsearch.common.TriFunction;
  13. import org.elasticsearch.common.io.stream.ByteArrayStreamInput;
  14. import org.elasticsearch.common.io.stream.BytesStreamOutput;
  15. import java.io.IOException;
  16. import java.net.InetAddress;
  17. import java.util.ArrayList;
  18. import java.util.Arrays;
  19. import java.util.Comparator;
  20. import java.util.List;
  21. import java.util.Set;
  22. enum BinaryRangeUtil {
  23. ;
  24. static BytesRef encodeIPRanges(Set<RangeFieldMapper.Range> ranges) throws IOException {
  25. BytesStreamOutput out = new BytesStreamOutput(5 + (16 * 2) * ranges.size());
  26. out.writeVInt(ranges.size());
  27. for (RangeFieldMapper.Range range : ranges) {
  28. InetAddress fromValue = (InetAddress) range.from;
  29. byte[] encodedFromValue = InetAddressPoint.encode(fromValue);
  30. out.writeBytes(encodedFromValue, 0, encodedFromValue.length);
  31. InetAddress toValue = (InetAddress) range.to;
  32. byte[] encodedToValue = InetAddressPoint.encode(toValue);
  33. out.writeBytes(encodedToValue, 0, encodedToValue.length);
  34. }
  35. return out.bytes().toBytesRef();
  36. }
  37. static List<RangeFieldMapper.Range> decodeIPRanges(BytesRef encodedRanges) throws IOException {
  38. return decodeRanges(encodedRanges, RangeType.IP, BinaryRangeUtil::decodeIP);
  39. }
  40. private static InetAddress decodeIP(byte[] bytes, int offset, int length) {
  41. // offset + length because copyOfRange wants a from and a to, not an offset & length
  42. byte[] slice = Arrays.copyOfRange(bytes, offset, offset + length);
  43. return InetAddressPoint.decode(slice);
  44. }
  45. static BytesRef encodeLongRanges(Set<RangeFieldMapper.Range> ranges) throws IOException {
  46. List<RangeFieldMapper.Range> sortedRanges = new ArrayList<>(ranges);
  47. Comparator<RangeFieldMapper.Range> fromComparator = Comparator.comparingLong(range -> ((Number) range.from).longValue());
  48. Comparator<RangeFieldMapper.Range> toComparator = Comparator.comparingLong(range -> ((Number) range.to).longValue());
  49. sortedRanges.sort(fromComparator.thenComparing(toComparator));
  50. BytesStreamOutput out = new BytesStreamOutput(5 + (9 * 2) * sortedRanges.size());
  51. out.writeVInt(sortedRanges.size());
  52. for (RangeFieldMapper.Range range : sortedRanges) {
  53. byte[] encodedFrom = encodeLong(((Number) range.from).longValue());
  54. out.writeBytes(encodedFrom, encodedFrom.length);
  55. byte[] encodedTo = encodeLong(((Number) range.to).longValue());
  56. out.writeBytes(encodedTo, encodedTo.length);
  57. }
  58. return out.bytes().toBytesRef();
  59. }
  60. static List<RangeFieldMapper.Range> decodeLongRanges(BytesRef encodedRanges) throws IOException {
  61. return decodeRanges(encodedRanges, RangeType.LONG, BinaryRangeUtil::decodeLong);
  62. }
  63. static BytesRef encodeDoubleRanges(Set<RangeFieldMapper.Range> ranges) throws IOException {
  64. List<RangeFieldMapper.Range> sortedRanges = new ArrayList<>(ranges);
  65. Comparator<RangeFieldMapper.Range> fromComparator = Comparator.comparingDouble(range -> ((Number) range.from).doubleValue());
  66. Comparator<RangeFieldMapper.Range> toComparator = Comparator.comparingDouble(range -> ((Number) range.to).doubleValue());
  67. sortedRanges.sort(fromComparator.thenComparing(toComparator));
  68. BytesStreamOutput out = new BytesStreamOutput(5 + (8 * 2) * sortedRanges.size());
  69. out.writeVInt(sortedRanges.size());
  70. for (RangeFieldMapper.Range range : sortedRanges) {
  71. byte[] encodedFrom = encodeDouble(((Number) range.from).doubleValue());
  72. out.writeBytes(encodedFrom, encodedFrom.length);
  73. byte[] encodedTo = encodeDouble(((Number) range.to).doubleValue());
  74. out.writeBytes(encodedTo, encodedTo.length);
  75. }
  76. return out.bytes().toBytesRef();
  77. }
  78. static List<RangeFieldMapper.Range> decodeDoubleRanges(BytesRef encodedRanges) throws IOException {
  79. return decodeRanges(encodedRanges, RangeType.DOUBLE, BinaryRangeUtil::decodeDouble);
  80. }
  81. static List<RangeFieldMapper.Range> decodeFloatRanges(BytesRef encodedRanges) throws IOException {
  82. return decodeRanges(encodedRanges, RangeType.FLOAT, BinaryRangeUtil::decodeFloat);
  83. }
  84. static List<RangeFieldMapper.Range> decodeDateRanges(BytesRef encodedRanges) throws IOException {
  85. return decodeRanges(encodedRanges, RangeType.DATE, BinaryRangeUtil::decodeLong);
  86. }
  87. static List<RangeFieldMapper.Range> decodeRanges(
  88. BytesRef encodedRanges,
  89. RangeType rangeType,
  90. TriFunction<byte[], Integer, Integer, Object> decodeBytes
  91. ) throws IOException {
  92. RangeType.LengthType lengthType = rangeType.lengthType;
  93. ByteArrayStreamInput in = new ByteArrayStreamInput();
  94. in.reset(encodedRanges.bytes, encodedRanges.offset, encodedRanges.length);
  95. int numRanges = in.readVInt();
  96. List<RangeFieldMapper.Range> ranges = new ArrayList<>(numRanges);
  97. final byte[] bytes = encodedRanges.bytes;
  98. int offset = in.getPosition();
  99. for (int i = 0; i < numRanges; i++) {
  100. int length = lengthType.readLength(bytes, offset);
  101. Object from = decodeBytes.apply(bytes, offset, length);
  102. offset += length;
  103. length = lengthType.readLength(bytes, offset);
  104. Object to = decodeBytes.apply(bytes, offset, length);
  105. offset += length;
  106. // TODO: Support for exclusive ranges, pending resolution of #40601
  107. RangeFieldMapper.Range decodedRange = new RangeFieldMapper.Range(rangeType, from, to, true, true);
  108. ranges.add(decodedRange);
  109. }
  110. return ranges;
  111. }
  112. static BytesRef encodeFloatRanges(Set<RangeFieldMapper.Range> ranges) throws IOException {
  113. List<RangeFieldMapper.Range> sortedRanges = new ArrayList<>(ranges);
  114. Comparator<RangeFieldMapper.Range> fromComparator = Comparator.comparingDouble(range -> ((Number) range.from).floatValue());
  115. Comparator<RangeFieldMapper.Range> toComparator = Comparator.comparingDouble(range -> ((Number) range.to).floatValue());
  116. sortedRanges.sort(fromComparator.thenComparing(toComparator));
  117. BytesStreamOutput out = new BytesStreamOutput(5 + (4 * 2) * sortedRanges.size());
  118. out.writeVInt(sortedRanges.size());
  119. for (RangeFieldMapper.Range range : sortedRanges) {
  120. byte[] encodedFrom = encodeFloat(((Number) range.from).floatValue());
  121. out.writeBytes(encodedFrom, encodedFrom.length);
  122. byte[] encodedTo = encodeFloat(((Number) range.to).floatValue());
  123. out.writeBytes(encodedTo, encodedTo.length);
  124. }
  125. return out.bytes().toBytesRef();
  126. }
  127. static byte[] encodeDouble(double number) {
  128. byte[] encoded = new byte[8];
  129. NumericUtils.longToSortableBytes(NumericUtils.doubleToSortableLong(number), encoded, 0);
  130. return encoded;
  131. }
  132. static double decodeDouble(byte[] bytes, int offset, int length) {
  133. return NumericUtils.sortableLongToDouble(NumericUtils.sortableBytesToLong(bytes, offset));
  134. }
  135. static byte[] encodeFloat(float number) {
  136. byte[] encoded = new byte[4];
  137. NumericUtils.intToSortableBytes(NumericUtils.floatToSortableInt(number), encoded, 0);
  138. return encoded;
  139. }
  140. static float decodeFloat(byte[] bytes, int offset, int length) {
  141. return NumericUtils.sortableIntToFloat(NumericUtils.sortableBytesToInt(bytes, offset));
  142. }
  143. /**
  144. * Encodes the specified number of type long in a variable-length byte format.
  145. * The byte format preserves ordering, which means the returned byte array can be used for comparing as is.
  146. * The first bit stores the sign and the 4 subsequent bits encode the number of bytes that are used to
  147. * represent the long value, in addition to the first one.
  148. */
  149. static byte[] encodeLong(long number) {
  150. int sign = 1; // means positive
  151. if (number < 0) {
  152. number = -1 - number;
  153. sign = 0;
  154. }
  155. return encode(number, sign);
  156. }
  157. static long decodeLong(byte[] bytes, int offset, int length) {
  158. boolean isNegative = (bytes[offset] & 128) == 0;
  159. // Start by masking off the last three bits of the first byte - that's the start of our number
  160. long decoded;
  161. if (isNegative) {
  162. decoded = -8 | bytes[offset];
  163. } else {
  164. decoded = bytes[offset] & 7;
  165. }
  166. for (int i = 1; i < length; i++) {
  167. decoded <<= 8;
  168. decoded += Byte.toUnsignedInt(bytes[offset + i]);
  169. }
  170. return decoded;
  171. }
  172. private static byte[] encode(long l, int sign) {
  173. assert l >= 0;
  174. // the header is formed of:
  175. // - 1 bit for the sign
  176. // - 4 bits for the number of additional bytes
  177. // - up to 3 bits of the value
  178. // additional bytes are data bytes
  179. int numBits = 64 - Long.numberOfLeadingZeros(l);
  180. int numAdditionalBytes = (numBits + 7 - 3) / 8;
  181. byte[] encoded = new byte[1 + numAdditionalBytes];
  182. // write data bytes
  183. int i = encoded.length;
  184. while (numBits > 0) {
  185. int index = --i;
  186. assert index > 0 || numBits <= 3; // byte 0 can't encode more than 3 bits
  187. encoded[index] = (byte) l;
  188. l >>>= 8;
  189. numBits -= 8;
  190. }
  191. assert Byte.toUnsignedInt(encoded[0]) <= 0x07;
  192. assert encoded.length == 1 || encoded[0] != 0 || Byte.toUnsignedInt(encoded[1]) > 0x07;
  193. if (sign == 0) {
  194. // reverse the order
  195. for (int j = 0; j < encoded.length; ++j) {
  196. encoded[j] = (byte) ~Byte.toUnsignedInt(encoded[j]);
  197. }
  198. // the first byte only uses 3 bits, we need the 5 upper bits for the header
  199. encoded[0] &= 0x07;
  200. }
  201. // write the header
  202. encoded[0] |= (byte) (sign << 7);
  203. if (sign > 0) {
  204. encoded[0] |= (byte) (numAdditionalBytes << 3);
  205. } else {
  206. encoded[0] |= (byte) ((15 - numAdditionalBytes) << 3);
  207. }
  208. return encoded;
  209. }
  210. }