Cardinality aggregation.
This aggregation computes unique term counts using the hyperloglog++ algorithm which uses linear counting to estimate low cardinalities and hyperloglog on higher cardinalities. Since this algorithm works on hashes, it is useful for high-cardinality fields to store the hash of values directly in the index, which is the purpose of the new `murmur3` field type. This is less necessary on low-cardinality string fields because the aggregator is smart enough to only compute the hash once per unique value per segment thanks to ordinals, or on numeric fields since hashing them is very fast. Close #5426
This commit is contained in:
parent
4e5714b31f
commit
5821fa042c
Binary file not shown.
After Width: | Height: | Size: 16 KiB |
|
@ -14,4 +14,6 @@ include::metrics/extendedstats-aggregation.asciidoc[]
|
|||
|
||||
include::metrics/valuecount-aggregation.asciidoc[]
|
||||
|
||||
include::metrics/percentile-aggregation.asciidoc[]
|
||||
include::metrics/percentile-aggregation.asciidoc[]
|
||||
|
||||
include::metrics/cardinality-aggregation.asciidoc[]
|
||||
|
|
|
@ -0,0 +1,159 @@
|
|||
[[search-aggregations-metrics-cardinality-aggregation]]
|
||||
=== Cardinality
|
||||
|
||||
coming[1.1.0]
|
||||
|
||||
A `single-value` metrics aggregation that calculates an approximate count of
|
||||
distinct values. Values can be extracted either from specific fields in the
|
||||
document or generated by a script.
|
||||
|
||||
.Experimental!
|
||||
[IMPORTANT]
|
||||
=====
|
||||
This feature is marked as experimental, and may be subject to change in the
|
||||
future. If you use this feature, please let us know your experience with it!
|
||||
=====
|
||||
|
||||
Assume you are indexing books and would like to count the unique authors that
|
||||
match a query:
|
||||
|
||||
[source,js]
|
||||
--------------------------------------------------
|
||||
{
|
||||
"aggs" : {
|
||||
"author_count" : {
|
||||
"cardinality" : {
|
||||
"field" : "author"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
--------------------------------------------------
|
||||
|
||||
This aggregation also supports the `precision_threshold` and `rehash` options:
|
||||
|
||||
[source,js]
|
||||
--------------------------------------------------
|
||||
{
|
||||
"aggs" : {
|
||||
"author_count" : {
|
||||
"cardinality" : {
|
||||
"field" : "author_hash",
|
||||
"precision_threshold": 100, <1>
|
||||
"rehash": false <2>
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
--------------------------------------------------
|
||||
|
||||
<1> The `precision_threshold` options allows to trade memory for accuracy, and
|
||||
defines a unique count below which counts are expected to be close to
|
||||
accurate. Above this value, counts might become a bit more fuzzy. The maximum
|
||||
supported value is 40000, thresholds above this number will have the same
|
||||
effect as a threshold of 40000.
|
||||
Default value depends on the number of parent aggregations that multiple
|
||||
create buckets (such as terms or histograms).
|
||||
<2> If you computed a hash on client-side, stored it into your documents and want
|
||||
Elasticsearch to use them to compute counts using this hash function without
|
||||
rehashing values, it is possible to specify `rehash: false`. Default value is
|
||||
`true`. Please note that the hash must be indexed as a long when `rehash` is
|
||||
false.
|
||||
|
||||
==== Counts are approximate
|
||||
|
||||
Computing exact counts requires loading values into a hash set and returning its
|
||||
size. This doesn't scale when working on high-cardinality sets and/or large
|
||||
values as the required memory usage and the need to communicate those
|
||||
per-shard sets between nodes would utilize too many resources of the cluster.
|
||||
|
||||
This `cardinality` aggregation is based on the
|
||||
http://static.googleusercontent.com/media/research.google.com/fr//pubs/archive/40671.pdf[HyperLogLog++]
|
||||
algorithm, which counts based on the hashes of the values with some interesting
|
||||
properties:
|
||||
|
||||
* configurable precision, which decides on how to trade memory for accuracy,
|
||||
* excellent accuracy on low-cardinality sets,
|
||||
* fixed memory usage: no matter if there are tens or billions of unique values,
|
||||
memory usage only depends on the configured precision.
|
||||
|
||||
For a precision threshold of `c`, the implementation that we are using requires
|
||||
about `c * 8` bytes.
|
||||
|
||||
The following chart shows how the error varies before and after the threshold:
|
||||
|
||||
image:images/cardinality_error.png[]
|
||||
|
||||
For all 3 thresholds, counts have been accurate up to the configured threshold
|
||||
(although not guaranteed, this is likely to be the case). Please also note that
|
||||
even with a threshold as low as 100, the error remains under under 5%, even when
|
||||
counting millions of items.
|
||||
|
||||
==== Pre-computed hashes
|
||||
|
||||
If you don't want Elasticsearch to re-compute hashes on every run of this
|
||||
aggregation, it is possible to use pre-computed hashes, either by computing a
|
||||
hash on client-side, indexing it and specifying `rehash: false`, or by using
|
||||
the special `murmur3` field mapper, typically in the context of a `multi-field`
|
||||
in the mapping:
|
||||
|
||||
[source,js]
|
||||
--------------------------------------------------
|
||||
{
|
||||
"author": {
|
||||
"type": "string",
|
||||
"fields": {
|
||||
"hash": {
|
||||
"type": "murmur3"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
--------------------------------------------------
|
||||
|
||||
With such a mapping, Elasticsearch is going to compute hashes of the `author`
|
||||
field at indexing time and store them in the `author.hash` field. This
|
||||
way, unique counts can be computed using the cardinality aggregation by only
|
||||
loading the hashes into memory, not the values of the `author` field, and
|
||||
without computing hashes on the fly:
|
||||
|
||||
[source,js]
|
||||
--------------------------------------------------
|
||||
{
|
||||
"aggs" : {
|
||||
"author_count" : {
|
||||
"cardinality" : {
|
||||
"field" : "author.hash"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
--------------------------------------------------
|
||||
|
||||
NOTE: `rehash` is automatically set to `false` when computing unique counts on
|
||||
a `murmur3` field.
|
||||
|
||||
NOTE: Pre-computing hashes is usually only useful on very large and/or
|
||||
high-cardinality fields as it saves CPU and memory. However, on numeric
|
||||
fields, hashing is very fast and storing the original values requires as much
|
||||
or less memory than storing the hashes. This is also true on low-cardinality
|
||||
string fields, especially given that those have an optimization in order to
|
||||
make sure that hashes are computed at most once per unique value per segment.
|
||||
|
||||
==== Script
|
||||
|
||||
The `cardinality` metric supports scripting, with a noticeable performance hit
|
||||
however since hashes need to be computed on the fly.
|
||||
|
||||
[source,js]
|
||||
--------------------------------------------------
|
||||
{
|
||||
"aggs" : {
|
||||
"author_count" : {
|
||||
"cardinality" : {
|
||||
"script": "doc['author.first_name'].value + ' ' + doc['author.last_name'].value"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
--------------------------------------------------
|
|
@ -0,0 +1,156 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch 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.
|
||||
*/
|
||||
|
||||
package org.elasticsearch.common.hash;
|
||||
|
||||
import org.elasticsearch.common.util.UnsafeUtils;
|
||||
|
||||
|
||||
/**
|
||||
* MurmurHash3 hashing functions.
|
||||
*/
|
||||
public enum MurmurHash3 {
|
||||
;
|
||||
|
||||
/**
|
||||
* A 128-bits hash.
|
||||
*/
|
||||
public static class Hash128 {
|
||||
public long h1, h2;
|
||||
}
|
||||
|
||||
private static long C1 = 0x87c37b91114253d5L;
|
||||
private static long C2 = 0x4cf5ad432745937fL;
|
||||
|
||||
protected static long getblock(byte[] key, int offset, int index) {
|
||||
int i_8 = index << 3;
|
||||
int blockOffset = offset + i_8;
|
||||
return UnsafeUtils.readLongLE(key, blockOffset);
|
||||
}
|
||||
|
||||
protected static long fmix(long k) {
|
||||
k ^= k >>> 33;
|
||||
k *= 0xff51afd7ed558ccdL;
|
||||
k ^= k >>> 33;
|
||||
k *= 0xc4ceb9fe1a85ec53L;
|
||||
k ^= k >>> 33;
|
||||
return k;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the hash of the MurmurHash3_x64_128 hashing function.
|
||||
*/
|
||||
public static Hash128 hash128(byte[] key, int offset, int length, long seed, Hash128 hash) {
|
||||
long h1 = seed;
|
||||
long h2 = seed;
|
||||
|
||||
if (length >= 16) {
|
||||
|
||||
final int len16 = length & 0xFFFFFFF0; // higher multiple of 16 that is lower than or equal to length
|
||||
final int end = offset + len16;
|
||||
for (int i = offset; i < end; i += 16) {
|
||||
long k1 = UnsafeUtils.readLongLE(key, i);
|
||||
long k2 = UnsafeUtils.readLongLE(key, i + 8);
|
||||
|
||||
k1 *= C1;
|
||||
k1 = Long.rotateLeft(k1, 31);
|
||||
k1 *= C2;
|
||||
h1 ^= k1;
|
||||
|
||||
h1 = Long.rotateLeft(h1, 27);
|
||||
h1 += h2;
|
||||
h1 = h1 * 5 + 0x52dce729;
|
||||
|
||||
k2 *= C2;
|
||||
k2 = Long.rotateLeft(k2, 33);
|
||||
k2 *= C1;
|
||||
h2 ^= k2;
|
||||
|
||||
h2 = Long.rotateLeft(h2, 31);
|
||||
h2 += h1;
|
||||
h2 = h2 * 5 + 0x38495ab5;
|
||||
}
|
||||
|
||||
// Advance offset to the unprocessed tail of the data.
|
||||
offset = end;
|
||||
}
|
||||
|
||||
long k1 = 0;
|
||||
long k2 = 0;
|
||||
|
||||
switch (length & 15) {
|
||||
case 15:
|
||||
k2 ^= (key[offset + 14] & 0xFFL) << 48;
|
||||
case 14:
|
||||
k2 ^= (key[offset + 13] & 0xFFL) << 40;
|
||||
case 13:
|
||||
k2 ^= (key[offset + 12] & 0xFFL) << 32;
|
||||
case 12:
|
||||
k2 ^= (key[offset + 11] & 0xFFL) << 24;
|
||||
case 11:
|
||||
k2 ^= (key[offset + 10] & 0xFFL) << 16;
|
||||
case 10:
|
||||
k2 ^= (key[offset + 9] & 0xFFL) << 8;
|
||||
case 9:
|
||||
k2 ^= (key[offset + 8] & 0xFFL) << 0;
|
||||
k2 *= C2;
|
||||
k2 = Long.rotateLeft(k2, 33);
|
||||
k2 *= C1;
|
||||
h2 ^= k2;
|
||||
|
||||
case 8:
|
||||
k1 ^= (key[offset + 7] & 0xFFL) << 56;
|
||||
case 7:
|
||||
k1 ^= (key[offset + 6] & 0xFFL) << 48;
|
||||
case 6:
|
||||
k1 ^= (key[offset + 5] & 0xFFL) << 40;
|
||||
case 5:
|
||||
k1 ^= (key[offset + 4] & 0xFFL) << 32;
|
||||
case 4:
|
||||
k1 ^= (key[offset + 3] & 0xFFL) << 24;
|
||||
case 3:
|
||||
k1 ^= (key[offset + 2] & 0xFFL) << 16;
|
||||
case 2:
|
||||
k1 ^= (key[offset + 1] & 0xFFL) << 8;
|
||||
case 1:
|
||||
k1 ^= (key[offset] & 0xFFL);
|
||||
k1 *= C1;
|
||||
k1 = Long.rotateLeft(k1, 31);
|
||||
k1 *= C2;
|
||||
h1 ^= k1;
|
||||
}
|
||||
|
||||
h1 ^= length;
|
||||
h2 ^= length;
|
||||
|
||||
h1 += h2;
|
||||
h2 += h1;
|
||||
|
||||
h1 = fmix(h1);
|
||||
h2 = fmix(h2);
|
||||
|
||||
h1 += h2;
|
||||
h2 += h1;
|
||||
|
||||
hash.h1 = h1;
|
||||
hash.h2 = h2;
|
||||
return hash;
|
||||
}
|
||||
|
||||
}
|
|
@ -140,6 +140,12 @@ public class BigArrays extends AbstractComponent {
|
|||
System.arraycopy(buf, offset, array, (int) index, len);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fill(long fromIndex, long toIndex, byte value) {
|
||||
assert indexIsInt(fromIndex);
|
||||
assert indexIsInt(toIndex);
|
||||
Arrays.fill(array, (int) fromIndex, (int) toIndex, value);
|
||||
}
|
||||
}
|
||||
|
||||
private static class IntArrayWrapper extends AbstractArrayWrapper implements IntArray {
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
package org.elasticsearch.common.util;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import org.apache.lucene.util.ArrayUtil;
|
||||
import org.apache.lucene.util.BytesRef;
|
||||
import org.apache.lucene.util.RamUsageEstimator;
|
||||
|
@ -106,6 +107,22 @@ final class BigByteArray extends AbstractBigArray implements ByteArray {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fill(long fromIndex, long toIndex, byte value) {
|
||||
Preconditions.checkArgument(fromIndex <= toIndex);
|
||||
final int fromPage = pageIndex(fromIndex);
|
||||
final int toPage = pageIndex(toIndex - 1);
|
||||
if (fromPage == toPage) {
|
||||
Arrays.fill(pages[fromPage], indexInPage(fromIndex), indexInPage(toIndex - 1) + 1, value);
|
||||
} else {
|
||||
Arrays.fill(pages[fromPage], indexInPage(fromIndex), pages[fromPage].length, value);
|
||||
for (int i = fromPage + 1; i < toPage; ++i) {
|
||||
Arrays.fill(pages[i], value);
|
||||
}
|
||||
Arrays.fill(pages[toPage], 0, indexInPage(toIndex - 1) + 1, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int numBytesPerElement() {
|
||||
return RamUsageEstimator.NUM_BYTES_BYTE;
|
||||
|
|
|
@ -355,6 +355,7 @@ public class BloomFilter {
|
|||
}
|
||||
|
||||
// START : MURMUR 3_128
|
||||
// NOTE: don't replace this code with the o.e.common.hashing.MurmurHash3 method which returns a different hash
|
||||
|
||||
protected static long getblock(byte[] key, int offset, int index) {
|
||||
int i_8 = index << 3;
|
||||
|
|
|
@ -46,4 +46,9 @@ public interface ByteArray extends BigArray {
|
|||
*/
|
||||
public abstract void set(long index, byte[] buf, int offset, int len);
|
||||
|
||||
/**
|
||||
* Fill slots between <code>fromIndex</code> inclusive to <code>toIndex</code> exclusive with <code>value</code>.
|
||||
*/
|
||||
public abstract void fill(long fromIndex, long toIndex, byte value);
|
||||
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ import org.apache.lucene.util.BytesRef;
|
|||
import sun.misc.Unsafe;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
/** Utility methods that use {@link Unsafe}. */
|
||||
public enum UnsafeUtils {
|
||||
|
@ -111,4 +112,26 @@ public enum UnsafeUtils {
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a long using little endian byte order.
|
||||
*/
|
||||
public static long readLongLE(byte[] src, int offset) {
|
||||
long value = readLong(src, offset);
|
||||
if (ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN) {
|
||||
value = Long.reverseBytes(value);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read an int using little endian byte order.
|
||||
*/
|
||||
public static int readIntLE(byte[] src, int offset) {
|
||||
int value = readInt(src, offset);
|
||||
if (ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN) {
|
||||
value = Integer.reverseBytes(value);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,120 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch 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.
|
||||
*/
|
||||
|
||||
package org.elasticsearch.index.fielddata;
|
||||
|
||||
import com.carrotsearch.hppc.hash.MurmurHash3;
|
||||
import org.apache.lucene.util.BytesRef;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class MurmurHash3Values {
|
||||
|
||||
public static LongValues wrap(DoubleValues values) {
|
||||
return new Double(values);
|
||||
}
|
||||
|
||||
public static LongValues wrap(LongValues values) {
|
||||
return new Long(values);
|
||||
}
|
||||
|
||||
public static LongValues wrap(BytesValues values) {
|
||||
return new Bytes(values);
|
||||
}
|
||||
|
||||
private static class Long extends LongValues {
|
||||
|
||||
private final LongValues values;
|
||||
|
||||
public Long(LongValues values) {
|
||||
super(values.isMultiValued());
|
||||
this.values = values;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int setDocument(int docId) {
|
||||
return values.setDocument(docId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long nextValue() {
|
||||
return MurmurHash3.hash(values.nextValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public AtomicFieldData.Order getOrder() {
|
||||
return AtomicFieldData.Order.NONE;
|
||||
}
|
||||
}
|
||||
|
||||
private static class Double extends LongValues {
|
||||
|
||||
private final DoubleValues values;
|
||||
|
||||
public Double(DoubleValues values) {
|
||||
super(values.isMultiValued());
|
||||
this.values = values;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int setDocument(int docId) {
|
||||
return values.setDocument(docId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long nextValue() {
|
||||
return MurmurHash3.hash(java.lang.Double.doubleToLongBits(values.nextValue()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public AtomicFieldData.Order getOrder() {
|
||||
return AtomicFieldData.Order.NONE;
|
||||
}
|
||||
}
|
||||
|
||||
private static class Bytes extends LongValues {
|
||||
|
||||
private final org.elasticsearch.common.hash.MurmurHash3.Hash128 hash = new org.elasticsearch.common.hash.MurmurHash3.Hash128();
|
||||
|
||||
private final BytesValues values;
|
||||
|
||||
public Bytes(BytesValues values) {
|
||||
super(values.isMultiValued());
|
||||
this.values = values;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int setDocument(int docId) {
|
||||
return values.setDocument(docId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long nextValue() {
|
||||
final BytesRef next = values.nextValue();
|
||||
org.elasticsearch.common.hash.MurmurHash3.hash128(next.bytes, next.offset, next.length, 0, hash);
|
||||
return hash.h1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AtomicFieldData.Order getOrder() {
|
||||
return AtomicFieldData.Order.NONE;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -95,7 +95,8 @@ public class DocumentMapperParser extends AbstractIndexComponent {
|
|||
.put(ObjectMapper.NESTED_CONTENT_TYPE, new ObjectMapper.TypeParser())
|
||||
.put(TypeParsers.MULTI_FIELD_CONTENT_TYPE, TypeParsers.multiFieldConverterTypeParser)
|
||||
.put(CompletionFieldMapper.CONTENT_TYPE, new CompletionFieldMapper.TypeParser())
|
||||
.put(GeoPointFieldMapper.CONTENT_TYPE, new GeoPointFieldMapper.TypeParser());
|
||||
.put(GeoPointFieldMapper.CONTENT_TYPE, new GeoPointFieldMapper.TypeParser())
|
||||
.put(Murmur3FieldMapper.CONTENT_TYPE, new Murmur3FieldMapper.TypeParser());
|
||||
|
||||
if (ShapesAvailability.JTS_AVAILABLE) {
|
||||
typeParsersBuilder.put(GeoShapeFieldMapper.CONTENT_TYPE, new GeoShapeFieldMapper.TypeParser());
|
||||
|
|
|
@ -150,6 +150,10 @@ public final class MapperBuilders {
|
|||
return new LongFieldMapper.Builder(name);
|
||||
}
|
||||
|
||||
public static Murmur3FieldMapper.Builder murmur3Field(String name) {
|
||||
return new Murmur3FieldMapper.Builder(name);
|
||||
}
|
||||
|
||||
public static FloatFieldMapper.Builder floatField(String name) {
|
||||
return new FloatFieldMapper.Builder(name);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,111 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch 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.
|
||||
*/
|
||||
|
||||
package org.elasticsearch.index.mapper.core;
|
||||
|
||||
import org.apache.lucene.document.Field;
|
||||
import org.apache.lucene.document.FieldType;
|
||||
import org.apache.lucene.util.BytesRef;
|
||||
import org.elasticsearch.common.Explicit;
|
||||
import org.elasticsearch.common.Nullable;
|
||||
import org.elasticsearch.common.hash.MurmurHash3;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.index.codec.docvaluesformat.DocValuesFormatProvider;
|
||||
import org.elasticsearch.index.codec.postingsformat.PostingsFormatProvider;
|
||||
import org.elasticsearch.index.mapper.Mapper;
|
||||
import org.elasticsearch.index.mapper.MapperParsingException;
|
||||
import org.elasticsearch.index.mapper.ParseContext;
|
||||
import org.elasticsearch.index.similarity.SimilarityProvider;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.elasticsearch.index.mapper.MapperBuilders.murmur3Field;
|
||||
import static org.elasticsearch.index.mapper.core.TypeParsers.parseNumberField;
|
||||
|
||||
public class Murmur3FieldMapper extends LongFieldMapper {
|
||||
|
||||
public static final String CONTENT_TYPE = "murmur3";
|
||||
|
||||
public static class Defaults extends LongFieldMapper.Defaults {
|
||||
}
|
||||
|
||||
public static class Builder extends NumberFieldMapper.Builder<Builder, Murmur3FieldMapper> {
|
||||
|
||||
public Builder(String name) {
|
||||
super(name, new FieldType(Defaults.FIELD_TYPE));
|
||||
builder = this;
|
||||
builder.precisionStep(Integer.MAX_VALUE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Murmur3FieldMapper build(BuilderContext context) {
|
||||
fieldType.setOmitNorms(fieldType.omitNorms() && boost == 1.0f);
|
||||
Murmur3FieldMapper fieldMapper = new Murmur3FieldMapper(buildNames(context), precisionStep, boost, fieldType, docValues, ~0L,
|
||||
ignoreMalformed(context), coerce(context), postingsProvider, docValuesProvider, similarity, normsLoading,
|
||||
fieldDataSettings, context.indexSettings(), multiFieldsBuilder.build(this, context), copyTo);
|
||||
fieldMapper.includeInAll(includeInAll);
|
||||
return fieldMapper;
|
||||
}
|
||||
}
|
||||
|
||||
public static class TypeParser implements Mapper.TypeParser {
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public Mapper.Builder parse(String name, Map<String, Object> node, ParserContext parserContext) throws MapperParsingException {
|
||||
Builder builder = murmur3Field(name);
|
||||
parseNumberField(builder, name, node, parserContext);
|
||||
return builder;
|
||||
}
|
||||
}
|
||||
|
||||
protected Murmur3FieldMapper(Names names, int precisionStep, float boost, FieldType fieldType, Boolean docValues,
|
||||
Long nullValue, Explicit<Boolean> ignoreMalformed, Explicit<Boolean> coerce,
|
||||
PostingsFormatProvider postingsProvider, DocValuesFormatProvider docValuesProvider,
|
||||
SimilarityProvider similarity, Loading normsLoading, @Nullable Settings fieldDataSettings,
|
||||
Settings indexSettings, MultiFields multiFields, CopyTo copyTo) {
|
||||
super(names, precisionStep, boost, fieldType, docValues, nullValue, ignoreMalformed, coerce,
|
||||
postingsProvider, docValuesProvider, similarity, normsLoading, fieldDataSettings,
|
||||
indexSettings, multiFields, copyTo);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String contentType() {
|
||||
return CONTENT_TYPE;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void innerParseCreateField(ParseContext context, List<Field> fields) throws IOException {
|
||||
final Object value;
|
||||
if (context.externalValueSet()) {
|
||||
value = context.externalValue();
|
||||
} else {
|
||||
value = context.parser().textOrNull();
|
||||
}
|
||||
if (value != null) {
|
||||
final BytesRef bytes = new BytesRef(value.toString());
|
||||
final long hash = MurmurHash3.hash128(bytes.bytes, bytes.offset, bytes.length, 0, new MurmurHash3.Hash128()).h1;
|
||||
context.externalValue(hash);
|
||||
super.innerParseCreateField(context, fields);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -31,6 +31,7 @@ import org.elasticsearch.search.aggregations.bucket.range.geodistance.GeoDistanc
|
|||
import org.elasticsearch.search.aggregations.bucket.range.ipv4.IPv4RangeBuilder;
|
||||
import org.elasticsearch.search.aggregations.bucket.terms.TermsBuilder;
|
||||
import org.elasticsearch.search.aggregations.metrics.avg.AvgBuilder;
|
||||
import org.elasticsearch.search.aggregations.metrics.cardinality.CardinalityBuilder;
|
||||
import org.elasticsearch.search.aggregations.metrics.max.MaxBuilder;
|
||||
import org.elasticsearch.search.aggregations.metrics.min.MinBuilder;
|
||||
import org.elasticsearch.search.aggregations.metrics.percentiles.PercentilesBuilder;
|
||||
|
@ -126,4 +127,8 @@ public class AggregationBuilders {
|
|||
public static PercentilesBuilder percentiles(String name) {
|
||||
return new PercentilesBuilder(name);
|
||||
}
|
||||
|
||||
public static CardinalityBuilder cardinality(String name) {
|
||||
return new CardinalityBuilder(name);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,6 +34,7 @@ import org.elasticsearch.search.aggregations.bucket.range.geodistance.GeoDistanc
|
|||
import org.elasticsearch.search.aggregations.bucket.range.ipv4.IpRangeParser;
|
||||
import org.elasticsearch.search.aggregations.bucket.terms.TermsParser;
|
||||
import org.elasticsearch.search.aggregations.metrics.avg.AvgParser;
|
||||
import org.elasticsearch.search.aggregations.metrics.cardinality.CardinalityParser;
|
||||
import org.elasticsearch.search.aggregations.metrics.max.MaxParser;
|
||||
import org.elasticsearch.search.aggregations.metrics.min.MinParser;
|
||||
import org.elasticsearch.search.aggregations.metrics.percentiles.PercentilesParser;
|
||||
|
@ -60,6 +61,7 @@ public class AggregationModule extends AbstractModule {
|
|||
parsers.add(ExtendedStatsParser.class);
|
||||
parsers.add(ValueCountParser.class);
|
||||
parsers.add(PercentilesParser.class);
|
||||
parsers.add(CardinalityParser.class);
|
||||
|
||||
parsers.add(GlobalParser.class);
|
||||
parsers.add(MissingParser.class);
|
||||
|
|
|
@ -35,6 +35,7 @@ import org.elasticsearch.search.aggregations.bucket.terms.LongTerms;
|
|||
import org.elasticsearch.search.aggregations.bucket.terms.StringTerms;
|
||||
import org.elasticsearch.search.aggregations.bucket.terms.UnmappedTerms;
|
||||
import org.elasticsearch.search.aggregations.metrics.avg.InternalAvg;
|
||||
import org.elasticsearch.search.aggregations.metrics.cardinality.InternalCardinality;
|
||||
import org.elasticsearch.search.aggregations.metrics.max.InternalMax;
|
||||
import org.elasticsearch.search.aggregations.metrics.min.InternalMin;
|
||||
import org.elasticsearch.search.aggregations.metrics.percentiles.InternalPercentiles;
|
||||
|
@ -60,6 +61,7 @@ public class TransportAggregationModule extends AbstractModule {
|
|||
InternalExtendedStats.registerStreams();
|
||||
InternalValueCount.registerStreams();
|
||||
InternalPercentiles.registerStreams();
|
||||
InternalCardinality.registerStreams();
|
||||
|
||||
// buckets
|
||||
InternalGlobal.registerStreams();
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch 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.
|
||||
*/
|
||||
|
||||
package org.elasticsearch.search.aggregations.metrics.cardinality;
|
||||
|
||||
import org.elasticsearch.search.aggregations.Aggregation;
|
||||
|
||||
/**
|
||||
* A number of unique terms.
|
||||
*/
|
||||
public interface Cardinality extends Aggregation {
|
||||
|
||||
public long getValue();
|
||||
|
||||
}
|
|
@ -0,0 +1,271 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch 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.
|
||||
*/
|
||||
|
||||
package org.elasticsearch.search.aggregations.metrics.cardinality;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import org.apache.lucene.index.AtomicReaderContext;
|
||||
import org.apache.lucene.util.BytesRef;
|
||||
import org.apache.lucene.util.FixedBitSet;
|
||||
import org.elasticsearch.ElasticsearchException;
|
||||
import org.elasticsearch.common.Nullable;
|
||||
import org.elasticsearch.common.lease.Releasable;
|
||||
import org.elasticsearch.common.lease.Releasables;
|
||||
import org.elasticsearch.common.util.BigArrays;
|
||||
import org.elasticsearch.common.util.LongArray;
|
||||
import org.elasticsearch.common.util.ObjectArray;
|
||||
import org.elasticsearch.index.fielddata.BytesValues;
|
||||
import org.elasticsearch.index.fielddata.LongValues;
|
||||
import org.elasticsearch.index.fielddata.MurmurHash3Values;
|
||||
import org.elasticsearch.index.fielddata.ordinals.Ordinals;
|
||||
import org.elasticsearch.search.aggregations.Aggregator;
|
||||
import org.elasticsearch.search.aggregations.InternalAggregation;
|
||||
import org.elasticsearch.search.aggregations.metrics.MetricsAggregator;
|
||||
import org.elasticsearch.search.aggregations.support.AggregationContext;
|
||||
import org.elasticsearch.search.aggregations.support.ValuesSource;
|
||||
import org.elasticsearch.search.aggregations.support.numeric.NumericValuesSource;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* An aggregator that computes approximate counts of unique values.
|
||||
*/
|
||||
public class CardinalityAggregator extends MetricsAggregator.SingleValue {
|
||||
|
||||
private final int precision;
|
||||
private final boolean rehash;
|
||||
private final ValuesSource valuesSource;
|
||||
|
||||
// Expensive to initialize, so we only initialize it when we have an actual value source
|
||||
@Nullable
|
||||
private HyperLogLogPlusPlus counts;
|
||||
|
||||
private Collector collector;
|
||||
|
||||
public CardinalityAggregator(String name, long estimatedBucketsCount, ValuesSource valuesSource, boolean rehash,
|
||||
int precision, AggregationContext context, Aggregator parent) {
|
||||
super(name, estimatedBucketsCount, context, parent);
|
||||
this.valuesSource = valuesSource;
|
||||
this.rehash = rehash;
|
||||
this.precision = precision;
|
||||
this.counts = valuesSource == null ? null : new HyperLogLogPlusPlus(precision, bigArrays, estimatedBucketsCount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNextReader(AtomicReaderContext reader) {
|
||||
postCollectLastCollector();
|
||||
collector = createCollector(reader);
|
||||
}
|
||||
|
||||
private Collector createCollector(AtomicReaderContext reader) {
|
||||
|
||||
// if rehash is false then the value source is either already hashed, or the user explicitly
|
||||
// requested not to hash the values (perhaps they already hashed the values themselves before indexing the doc)
|
||||
// so we can just work with the original value source as is
|
||||
if (!rehash) {
|
||||
LongValues hashValues = ((NumericValuesSource) valuesSource).longValues();
|
||||
return new DirectCollector(counts, hashValues);
|
||||
}
|
||||
|
||||
if (valuesSource instanceof NumericValuesSource) {
|
||||
NumericValuesSource source = (NumericValuesSource) valuesSource;
|
||||
LongValues hashValues = source.isFloatingPoint() ? MurmurHash3Values.wrap(source.doubleValues()) : MurmurHash3Values.wrap(source.longValues());
|
||||
return new DirectCollector(counts, hashValues);
|
||||
}
|
||||
|
||||
final BytesValues bytesValues = valuesSource.bytesValues();
|
||||
if (bytesValues instanceof BytesValues.WithOrdinals) {
|
||||
BytesValues.WithOrdinals values = (BytesValues.WithOrdinals) bytesValues;
|
||||
final long maxOrd = values.ordinals().getMaxOrd();
|
||||
if (maxOrd <= reader.reader().maxDoc()) {
|
||||
return new OrdinalsCollector(counts, values, bigArrays);
|
||||
}
|
||||
}
|
||||
|
||||
return new DirectCollector(counts, MurmurHash3Values.wrap(bytesValues));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean shouldCollect() {
|
||||
return valuesSource != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void collect(int doc, long owningBucketOrdinal) throws IOException {
|
||||
collector.collect(doc, owningBucketOrdinal);
|
||||
}
|
||||
|
||||
private void postCollectLastCollector() {
|
||||
if (collector != null) {
|
||||
try {
|
||||
collector.postCollect();
|
||||
collector.release();
|
||||
} finally {
|
||||
collector = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doPostCollection() {
|
||||
postCollectLastCollector();
|
||||
}
|
||||
|
||||
@Override
|
||||
public double metric(long owningBucketOrd) {
|
||||
return counts == null ? 0 : counts.cardinality(owningBucketOrd);
|
||||
}
|
||||
|
||||
@Override
|
||||
public InternalAggregation buildAggregation(long owningBucketOrdinal) {
|
||||
if (counts == null || owningBucketOrdinal >= counts.maxBucket() || counts.cardinality(owningBucketOrdinal) == 0) {
|
||||
return buildEmptyAggregation();
|
||||
}
|
||||
// We need to build a copy because the returned Aggregation needs remain usable after
|
||||
// this Aggregator (and its HLL++ counters) is released.
|
||||
HyperLogLogPlusPlus copy = new HyperLogLogPlusPlus(precision, BigArrays.NON_RECYCLING_INSTANCE, 1);
|
||||
copy.merge(0, counts, owningBucketOrdinal);
|
||||
return new InternalCardinality(name, copy);
|
||||
}
|
||||
|
||||
@Override
|
||||
public InternalAggregation buildEmptyAggregation() {
|
||||
return new InternalCardinality(name, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doRelease() {
|
||||
Releasables.release(counts, collector);
|
||||
}
|
||||
|
||||
private static interface Collector extends Releasable {
|
||||
|
||||
void collect(int doc, long bucketOrd);
|
||||
|
||||
void postCollect();
|
||||
|
||||
}
|
||||
|
||||
private static class DirectCollector implements Collector {
|
||||
|
||||
private final LongValues hashes;
|
||||
private final HyperLogLogPlusPlus counts;
|
||||
|
||||
DirectCollector(HyperLogLogPlusPlus counts, LongValues values) {
|
||||
this.counts = counts;
|
||||
this.hashes = values;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void collect(int doc, long bucketOrd) {
|
||||
final int valueCount = hashes.setDocument(doc);
|
||||
for (int i = 0; i < valueCount; ++i) {
|
||||
counts.collect(bucketOrd, hashes.nextValue());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postCollect() {
|
||||
// no-op
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean release() throws ElasticsearchException {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class OrdinalsCollector implements Collector {
|
||||
|
||||
private final BigArrays bigArrays;
|
||||
private final BytesValues.WithOrdinals values;
|
||||
private final Ordinals.Docs ordinals;
|
||||
private final int maxOrd;
|
||||
private final HyperLogLogPlusPlus counts;
|
||||
private ObjectArray<FixedBitSet> visitedOrds;
|
||||
|
||||
OrdinalsCollector(HyperLogLogPlusPlus counts, BytesValues.WithOrdinals values, BigArrays bigArrays) {
|
||||
ordinals = values.ordinals();
|
||||
Preconditions.checkArgument(ordinals.getMaxOrd() <= Integer.MAX_VALUE);
|
||||
maxOrd = (int) ordinals.getMaxOrd();
|
||||
this.bigArrays = bigArrays;
|
||||
this.counts = counts;
|
||||
this.values = values;
|
||||
visitedOrds = bigArrays.newObjectArray(1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void collect(int doc, long bucketOrd) {
|
||||
visitedOrds = bigArrays.grow(visitedOrds, bucketOrd + 1);
|
||||
FixedBitSet bits = visitedOrds.get(bucketOrd);
|
||||
if (bits == null) {
|
||||
bits = new FixedBitSet(maxOrd);
|
||||
visitedOrds.set(bucketOrd, bits);
|
||||
}
|
||||
final int valueCount = ordinals.setDocument(doc);
|
||||
for (int i = 0; i < valueCount; ++i) {
|
||||
bits.set((int) ordinals.nextOrd());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postCollect() {
|
||||
final FixedBitSet allVisitedOrds = new FixedBitSet(maxOrd);
|
||||
for (long bucket = visitedOrds.size() - 1; bucket >= 0; --bucket) {
|
||||
final FixedBitSet bits = visitedOrds.get(bucket);
|
||||
if (bits != null) {
|
||||
allVisitedOrds.or(bits);
|
||||
}
|
||||
}
|
||||
|
||||
final org.elasticsearch.common.hash.MurmurHash3.Hash128 hash = new org.elasticsearch.common.hash.MurmurHash3.Hash128();
|
||||
final LongArray hashes = bigArrays.newLongArray(maxOrd, false);
|
||||
boolean success = false;
|
||||
try {
|
||||
for (int ord = allVisitedOrds.nextSetBit(0); ord != -1; ord = ord + 1 < maxOrd ? allVisitedOrds.nextSetBit(ord + 1) : -1) {
|
||||
final BytesRef value = values.getValueByOrd(ord);
|
||||
org.elasticsearch.common.hash.MurmurHash3.hash128(value.bytes, value.offset, value.length, 0, hash);
|
||||
hashes.set(ord, hash.h1);
|
||||
}
|
||||
|
||||
for (long bucket = visitedOrds.size() - 1; bucket >= 0; --bucket) {
|
||||
final FixedBitSet bits = visitedOrds.get(bucket);
|
||||
if (bits != null) {
|
||||
for (int ord = bits.nextSetBit(0); ord != -1; ord = ord + 1 < maxOrd ? bits.nextSetBit(ord + 1) : -1) {
|
||||
counts.collect(bucket, hashes.get(ord));
|
||||
}
|
||||
}
|
||||
}
|
||||
success = true;
|
||||
} finally {
|
||||
Releasables.release(success, hashes);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean release() throws ElasticsearchException {
|
||||
Releasables.release(visitedOrds);
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch 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.
|
||||
*/
|
||||
|
||||
package org.elasticsearch.search.aggregations.metrics.cardinality;
|
||||
|
||||
import org.elasticsearch.search.aggregations.AggregationExecutionException;
|
||||
import org.elasticsearch.search.aggregations.Aggregator;
|
||||
import org.elasticsearch.search.aggregations.Aggregator.BucketAggregationMode;
|
||||
import org.elasticsearch.search.aggregations.support.AggregationContext;
|
||||
import org.elasticsearch.search.aggregations.support.ValueSourceAggregatorFactory;
|
||||
import org.elasticsearch.search.aggregations.support.ValuesSource;
|
||||
import org.elasticsearch.search.aggregations.support.ValuesSourceConfig;
|
||||
import org.elasticsearch.search.aggregations.support.numeric.NumericValuesSource;
|
||||
|
||||
final class CardinalityAggregatorFactory extends ValueSourceAggregatorFactory<ValuesSource> {
|
||||
|
||||
private final long precisionThreshold;
|
||||
private final boolean rehash;
|
||||
|
||||
CardinalityAggregatorFactory(String name, ValuesSourceConfig valuesSourceConfig, long precisionThreshold, boolean rehash) {
|
||||
super(name, InternalCardinality.TYPE.name(), valuesSourceConfig);
|
||||
this.precisionThreshold = precisionThreshold;
|
||||
this.rehash = rehash;
|
||||
}
|
||||
|
||||
private int precision(Aggregator parent) {
|
||||
return precisionThreshold < 0 ? defaultPrecision(parent) : HyperLogLogPlusPlus.precisionFromThreshold(precisionThreshold);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Aggregator createUnmapped(AggregationContext context, Aggregator parent) {
|
||||
return new CardinalityAggregator(name, parent == null ? 1 : parent.estimatedBucketCount(), null, true, precision(parent), context, parent);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Aggregator create(ValuesSource valuesSource, long expectedBucketsCount, AggregationContext context, Aggregator parent) {
|
||||
if (!(valuesSource instanceof NumericValuesSource) && !rehash) {
|
||||
throw new AggregationExecutionException("Turning off rehashing for cardinality aggregation [" + name + "] on non-numeric values in not allowed");
|
||||
}
|
||||
return new CardinalityAggregator(name, parent == null ? 1 : parent.estimatedBucketCount(), valuesSource, rehash, precision(parent), context, parent);
|
||||
}
|
||||
|
||||
/*
|
||||
* If one of the parent aggregators is a MULTI_BUCKET one, we might want to lower the precision
|
||||
* because otherwise it might be memory-intensive. On the other hand, for top-level aggregators
|
||||
* we try to focus on accuracy.
|
||||
*/
|
||||
private int defaultPrecision(Aggregator parent) {
|
||||
int precision = HyperLogLogPlusPlus.DEFAULT_PRECISION;
|
||||
while (parent != null) {
|
||||
if (parent.bucketAggregationMode() == BucketAggregationMode.MULTI_BUCKETS) {
|
||||
// if the parent is a multi-bucket aggregator, we substract 5 to the precision,
|
||||
// which will effectively divide the memory usage of each counter by 32
|
||||
precision -= 5;
|
||||
}
|
||||
parent = parent.parent();
|
||||
}
|
||||
|
||||
return Math.max(precision, HyperLogLogPlusPlus.MIN_PRECISION);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch 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.
|
||||
*/
|
||||
|
||||
package org.elasticsearch.search.aggregations.metrics.cardinality;
|
||||
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
import org.elasticsearch.search.aggregations.metrics.ValuesSourceMetricsAggregationBuilder;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class CardinalityBuilder extends ValuesSourceMetricsAggregationBuilder<CardinalityBuilder> {
|
||||
|
||||
private Long precisionThreshold;
|
||||
private Boolean rehash;
|
||||
|
||||
public CardinalityBuilder(String name) {
|
||||
super(name, InternalCardinality.TYPE.name());
|
||||
}
|
||||
|
||||
public CardinalityBuilder precisionThreshold(long precisionThreshold) {
|
||||
this.precisionThreshold = precisionThreshold;
|
||||
return this;
|
||||
}
|
||||
|
||||
public CardinalityBuilder rehash(boolean rehash) {
|
||||
this.rehash = rehash;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void internalXContent(XContentBuilder builder, Params params) throws IOException {
|
||||
super.internalXContent(builder, params);
|
||||
if (precisionThreshold != null) {
|
||||
builder.field("precision_threshold", precisionThreshold);
|
||||
}
|
||||
if (rehash != null) {
|
||||
builder.field("rehash", rehash);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,134 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch 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.
|
||||
*/
|
||||
|
||||
package org.elasticsearch.search.aggregations.metrics.cardinality;
|
||||
|
||||
import org.elasticsearch.common.ParseField;
|
||||
import org.elasticsearch.common.xcontent.XContentParser;
|
||||
import org.elasticsearch.index.fielddata.IndexFieldData;
|
||||
import org.elasticsearch.index.mapper.FieldMapper;
|
||||
import org.elasticsearch.index.mapper.core.Murmur3FieldMapper;
|
||||
import org.elasticsearch.index.mapper.core.NumberFieldMapper;
|
||||
import org.elasticsearch.search.SearchParseException;
|
||||
import org.elasticsearch.search.aggregations.Aggregator;
|
||||
import org.elasticsearch.search.aggregations.AggregatorFactory;
|
||||
import org.elasticsearch.search.aggregations.support.FieldContext;
|
||||
import org.elasticsearch.search.aggregations.support.ValuesSourceConfig;
|
||||
import org.elasticsearch.search.aggregations.support.bytes.BytesValuesSource;
|
||||
import org.elasticsearch.search.aggregations.support.numeric.NumericValuesSource;
|
||||
import org.elasticsearch.search.internal.SearchContext;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
public class CardinalityParser implements Aggregator.Parser {
|
||||
|
||||
private static final ParseField PRECISION_THRESHOLD = new ParseField("precision_threshold");
|
||||
|
||||
@Override
|
||||
public String type() {
|
||||
return InternalCardinality.TYPE.name();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AggregatorFactory parse(String name, XContentParser parser, SearchContext context) throws IOException {
|
||||
long precisionThreshold = -1;
|
||||
Boolean rehash = null;
|
||||
String field = null;
|
||||
String script = null;
|
||||
String scriptLang = null;
|
||||
Map<String, Object> scriptParams = null;
|
||||
|
||||
XContentParser.Token token;
|
||||
String currentFieldName = null;
|
||||
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
|
||||
if (token == XContentParser.Token.FIELD_NAME) {
|
||||
currentFieldName = parser.currentName();
|
||||
} else if (token == XContentParser.Token.VALUE_STRING) {
|
||||
if ("field".equals(currentFieldName)) {
|
||||
field = parser.text();
|
||||
} else if ("script".equals(currentFieldName)) {
|
||||
script = parser.text();
|
||||
} else if ("lang".equals(currentFieldName)) {
|
||||
scriptLang = parser.text();
|
||||
} else {
|
||||
throw new SearchParseException(context, "Unknown key for a " + token + " in [" + name + "]: [" + currentFieldName + "].");
|
||||
}
|
||||
} else if (token == XContentParser.Token.START_OBJECT) {
|
||||
if ("params".equals(currentFieldName)) {
|
||||
scriptParams = parser.map();
|
||||
} else {
|
||||
throw new SearchParseException(context, "Unknown key for a " + token + " in [" + name + "]: [" + currentFieldName + "].");
|
||||
}
|
||||
} else if (token == XContentParser.Token.VALUE_BOOLEAN) {
|
||||
if ("rehash".equals(currentFieldName)) {
|
||||
rehash = parser.booleanValue();
|
||||
} else {
|
||||
throw new SearchParseException(context, "Unknown key for a " + token + " in [" + name + "]: [" + currentFieldName + "].");
|
||||
}
|
||||
} else if (token == XContentParser.Token.VALUE_NUMBER) {
|
||||
if (PRECISION_THRESHOLD.match(currentFieldName)) {
|
||||
precisionThreshold = parser.longValue();
|
||||
} else {
|
||||
throw new SearchParseException(context, "Unknown key for a " + token + " in [" + name + "]: [" + currentFieldName + "].");
|
||||
}
|
||||
} else {
|
||||
throw new SearchParseException(context, "Unexpected token " + token + " in [" + name + "].");
|
||||
}
|
||||
}
|
||||
|
||||
ValuesSourceConfig<?> config = null;
|
||||
|
||||
if (script != null) {
|
||||
config = new ValuesSourceConfig<BytesValuesSource>(BytesValuesSource.class);
|
||||
config.script(context.scriptService().search(context.lookup(), scriptLang, script, scriptParams));
|
||||
}
|
||||
|
||||
if (field != null) {
|
||||
FieldMapper<?> mapper = context.smartNameFieldMapper(field);
|
||||
if (config == null) {
|
||||
if (mapper instanceof NumberFieldMapper) {
|
||||
config = new ValuesSourceConfig<NumericValuesSource>(NumericValuesSource.class);
|
||||
} else {
|
||||
config = new ValuesSourceConfig<BytesValuesSource>(BytesValuesSource.class);
|
||||
if (mapper == null) {
|
||||
config.unmapped(true);
|
||||
}
|
||||
}
|
||||
if (rehash == null && mapper instanceof Murmur3FieldMapper) {
|
||||
rehash = false;
|
||||
}
|
||||
}
|
||||
if (mapper != null) {
|
||||
IndexFieldData<?> indexFieldData = context.fieldData().getForField(mapper);
|
||||
config.fieldContext(new FieldContext(field, indexFieldData));
|
||||
}
|
||||
} else if (config == null) {
|
||||
config = new ValuesSourceConfig<BytesValuesSource>(BytesValuesSource.class);
|
||||
}
|
||||
|
||||
if (rehash == null) {
|
||||
rehash = true;
|
||||
}
|
||||
|
||||
return new CardinalityAggregatorFactory(name, config, precisionThreshold, rehash);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,541 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch 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.
|
||||
*/
|
||||
|
||||
package org.elasticsearch.search.aggregations.metrics.cardinality;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import org.apache.lucene.util.BytesRef;
|
||||
import org.apache.lucene.util.OpenBitSet;
|
||||
import org.apache.lucene.util.RamUsageEstimator;
|
||||
import org.apache.lucene.util.packed.PackedInts;
|
||||
import org.elasticsearch.ElasticsearchException;
|
||||
import org.elasticsearch.common.io.stream.StreamInput;
|
||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||
import org.elasticsearch.common.lease.Releasable;
|
||||
import org.elasticsearch.common.lease.Releasables;
|
||||
import org.elasticsearch.common.util.BigArrays;
|
||||
import org.elasticsearch.common.util.ByteArray;
|
||||
import org.elasticsearch.common.util.IntArray;
|
||||
import org.elasticsearch.common.util.UnsafeUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* Hyperloglog++ counter, implemented based on pseudo code from
|
||||
* http://static.googleusercontent.com/media/research.google.com/fr//pubs/archive/40671.pdf
|
||||
* and its appendix
|
||||
* https://docs.google.com/document/d/1gyjfMHy43U9OWBXxfaeG-3MjGzejW1dlpyMwEYAAWEI/view?fullscreen
|
||||
*
|
||||
* This implementation is different from the original implementation in that it
|
||||
* uses a hash table instead of a sorted list for linear counting. Although this
|
||||
* requires more space and makes hyperloglog (which is less accurate) used sooner,
|
||||
* this is also considerably faster.
|
||||
*
|
||||
* Trying to understand what this class does whithout having read the paper is
|
||||
* considered adventurous.
|
||||
*/
|
||||
public final class HyperLogLogPlusPlus implements Releasable {
|
||||
|
||||
public static final int MIN_PRECISION = 4;
|
||||
public static final int DEFAULT_PRECISION = 14;
|
||||
public static final int MAX_PRECISION = 18;
|
||||
private static final boolean LINEAR_COUNTING = false;
|
||||
private static final boolean HYPERLOGLOG = true;
|
||||
private static final float MAX_LOAD_FACTOR = 0.75f;
|
||||
private static final int P2 = 25;
|
||||
|
||||
/**
|
||||
* Compute the required precision so that <code>count</code> distinct entries
|
||||
* would be counted with linear counting.
|
||||
*/
|
||||
public static int precisionFromThreshold(long count) {
|
||||
final long hashTableEntries = (long) Math.ceil(count / MAX_LOAD_FACTOR);
|
||||
int precision = PackedInts.bitsRequired(hashTableEntries * RamUsageEstimator.NUM_BYTES_INT);
|
||||
precision = Math.max(precision, MIN_PRECISION);
|
||||
precision = Math.min(precision, MAX_PRECISION);
|
||||
return precision;
|
||||
}
|
||||
|
||||
// these static tables come from the appendix of the paper
|
||||
private static final double[][] RAW_ESTIMATE_DATA = {
|
||||
// precision 4
|
||||
{ 11, 11.717, 12.207, 12.7896, 13.2882, 13.8204, 14.3772, 14.9342, 15.5202, 16.161, 16.7722, 17.4636, 18.0396, 18.6766, 19.3566, 20.0454, 20.7936, 21.4856, 22.2666, 22.9946, 23.766, 24.4692, 25.3638, 26.0764, 26.7864, 27.7602, 28.4814, 29.433, 30.2926, 31.0664, 31.9996, 32.7956, 33.5366, 34.5894, 35.5738, 36.2698, 37.3682, 38.0544, 39.2342, 40.0108, 40.7966, 41.9298, 42.8704, 43.6358, 44.5194, 45.773, 46.6772, 47.6174, 48.4888, 49.3304, 50.2506, 51.4996, 52.3824, 53.3078, 54.3984, 55.5838, 56.6618, 57.2174, 58.3514, 59.0802, 60.1482, 61.0376, 62.3598, 62.8078, 63.9744, 64.914, 65.781, 67.1806, 68.0594, 68.8446, 69.7928, 70.8248, 71.8324, 72.8598, 73.6246, 74.7014, 75.393, 76.6708, 77.2394, },
|
||||
// precision 5
|
||||
{ 23, 23.1194, 23.8208, 24.2318, 24.77, 25.2436, 25.7774, 26.2848, 26.8224, 27.3742, 27.9336, 28.503, 29.0494, 29.6292, 30.2124, 30.798, 31.367, 31.9728, 32.5944, 33.217, 33.8438, 34.3696, 35.0956, 35.7044, 36.324, 37.0668, 37.6698, 38.3644, 39.049, 39.6918, 40.4146, 41.082, 41.687, 42.5398, 43.2462, 43.857, 44.6606, 45.4168, 46.1248, 46.9222, 47.6804, 48.447, 49.3454, 49.9594, 50.7636, 51.5776, 52.331, 53.19, 53.9676, 54.7564, 55.5314, 56.4442, 57.3708, 57.9774, 58.9624, 59.8796, 60.755, 61.472, 62.2076, 63.1024, 63.8908, 64.7338, 65.7728, 66.629, 67.413, 68.3266, 69.1524, 70.2642, 71.1806, 72.0566, 72.9192, 73.7598, 74.3516, 75.5802, 76.4386, 77.4916, 78.1524, 79.1892, 79.8414, 80.8798, 81.8376, 82.4698, 83.7656, 84.331, 85.5914, 86.6012, 87.7016, 88.5582, 89.3394, 90.3544, 91.4912, 92.308, 93.3552, 93.9746, 95.2052, 95.727, 97.1322, 98.3944, 98.7588, 100.242, 101.1914, 102.2538, 102.8776, 103.6292, 105.1932, 105.9152, 107.0868, 107.6728, 108.7144, 110.3114, 110.8716, 111.245, 112.7908, 113.7064, 114.636, 115.7464, 116.1788, 117.7464, 118.4896, 119.6166, 120.5082, 121.7798, 122.9028, 123.4426, 124.8854, 125.705, 126.4652, 128.3464, 128.3462, 130.0398, 131.0342, 131.0042, 132.4766, 133.511, 134.7252, 135.425, 136.5172, 138.0572, 138.6694, 139.3712, 140.8598, 141.4594, 142.554, 143.4006, 144.7374, 146.1634, 146.8994, 147.605, 147.9304, 149.1636, 150.2468, 151.5876, 152.2096, 153.7032, 154.7146, 155.807, 156.9228, 157.0372, 158.5852, },
|
||||
// precision 6
|
||||
{ 46, 46.1902, 47.271, 47.8358, 48.8142, 49.2854, 50.317, 51.354, 51.8924, 52.9436, 53.4596, 54.5262, 55.6248, 56.1574, 57.2822, 57.837, 58.9636, 60.074, 60.7042, 61.7976, 62.4772, 63.6564, 64.7942, 65.5004, 66.686, 67.291, 68.5672, 69.8556, 70.4982, 71.8204, 72.4252, 73.7744, 75.0786, 75.8344, 77.0294, 77.8098, 79.0794, 80.5732, 81.1878, 82.5648, 83.2902, 84.6784, 85.3352, 86.8946, 88.3712, 89.0852, 90.499, 91.2686, 92.6844, 94.2234, 94.9732, 96.3356, 97.2286, 98.7262, 100.3284, 101.1048, 102.5962, 103.3562, 105.1272, 106.4184, 107.4974, 109.0822, 109.856, 111.48, 113.2834, 114.0208, 115.637, 116.5174, 118.0576, 119.7476, 120.427, 122.1326, 123.2372, 125.2788, 126.6776, 127.7926, 129.1952, 129.9564, 131.6454, 133.87, 134.5428, 136.2, 137.0294, 138.6278, 139.6782, 141.792, 143.3516, 144.2832, 146.0394, 147.0748, 148.4912, 150.849, 151.696, 153.5404, 154.073, 156.3714, 157.7216, 158.7328, 160.4208, 161.4184, 163.9424, 165.2772, 166.411, 168.1308, 168.769, 170.9258, 172.6828, 173.7502, 175.706, 176.3886, 179.0186, 180.4518, 181.927, 183.4172, 184.4114, 186.033, 188.5124, 189.5564, 191.6008, 192.4172, 193.8044, 194.997, 197.4548, 198.8948, 200.2346, 202.3086, 203.1548, 204.8842, 206.6508, 206.6772, 209.7254, 210.4752, 212.7228, 214.6614, 215.1676, 217.793, 218.0006, 219.9052, 221.66, 223.5588, 225.1636, 225.6882, 227.7126, 229.4502, 231.1978, 232.9756, 233.1654, 236.727, 238.1974, 237.7474, 241.1346, 242.3048, 244.1948, 245.3134, 246.879, 249.1204, 249.853, 252.6792, 253.857, 254.4486, 257.2362, 257.9534, 260.0286, 260.5632, 262.663, 264.723, 265.7566, 267.2566, 267.1624, 270.62, 272.8216, 273.2166, 275.2056, 276.2202, 278.3726, 280.3344, 281.9284, 283.9728, 284.1924, 286.4872, 287.587, 289.807, 291.1206, 292.769, 294.8708, 296.665, 297.1182, 299.4012, 300.6352, 302.1354, 304.1756, 306.1606, 307.3462, 308.5214, 309.4134, 310.8352, 313.9684, 315.837, 316.7796, 318.9858, },
|
||||
// precision 7
|
||||
{ 92, 93.4934, 94.9758, 96.4574, 97.9718, 99.4954, 101.5302, 103.0756, 104.6374, 106.1782, 107.7888, 109.9522, 111.592, 113.2532, 114.9086, 116.5938, 118.9474, 120.6796, 122.4394, 124.2176, 125.9768, 128.4214, 130.2528, 132.0102, 133.8658, 135.7278, 138.3044, 140.1316, 142.093, 144.0032, 145.9092, 148.6306, 150.5294, 152.5756, 154.6508, 156.662, 159.552, 161.3724, 163.617, 165.5754, 167.7872, 169.8444, 172.7988, 174.8606, 177.2118, 179.3566, 181.4476, 184.5882, 186.6816, 189.0824, 191.0258, 193.6048, 196.4436, 198.7274, 200.957, 203.147, 205.4364, 208.7592, 211.3386, 213.781, 215.8028, 218.656, 221.6544, 223.996, 226.4718, 229.1544, 231.6098, 234.5956, 237.0616, 239.5758, 242.4878, 244.5244, 248.2146, 250.724, 252.8722, 255.5198, 258.0414, 261.941, 264.9048, 266.87, 269.4304, 272.028, 274.4708, 278.37, 281.0624, 283.4668, 286.5532, 289.4352, 293.2564, 295.2744, 298.2118, 300.7472, 304.1456, 307.2928, 309.7504, 312.5528, 315.979, 318.2102, 322.1834, 324.3494, 327.325, 330.6614, 332.903, 337.2544, 339.9042, 343.215, 345.2864, 348.0814, 352.6764, 355.301, 357.139, 360.658, 363.1732, 366.5902, 369.9538, 373.0828, 375.922, 378.9902, 382.7328, 386.4538, 388.1136, 391.2234, 394.0878, 396.708, 401.1556, 404.1852, 406.6372, 409.6822, 412.7796, 416.6078, 418.4916, 422.131, 424.5376, 428.1988, 432.211, 434.4502, 438.5282, 440.912, 444.0448, 447.7432, 450.8524, 453.7988, 456.7858, 458.8868, 463.9886, 466.5064, 468.9124, 472.6616, 475.4682, 478.582, 481.304, 485.2738, 488.6894, 490.329, 496.106, 497.6908, 501.1374, 504.5322, 506.8848, 510.3324, 513.4512, 516.179, 520.4412, 522.6066, 526.167, 528.7794, 533.379, 536.067, 538.46, 542.9116, 545.692, 547.9546, 552.493, 555.2722, 557.335, 562.449, 564.2014, 569.0738, 571.0974, 574.8564, 578.2996, 581.409, 583.9704, 585.8098, 589.6528, 594.5998, 595.958, 600.068, 603.3278, 608.2016, 609.9632, 612.864, 615.43, 620.7794, 621.272, 625.8644, 629.206, 633.219, 634.5154, 638.6102, },
|
||||
// precision 8
|
||||
{ 184.2152, 187.2454, 190.2096, 193.6652, 196.6312, 199.6822, 203.249, 206.3296, 210.0038, 213.2074, 216.4612, 220.27, 223.5178, 227.4412, 230.8032, 234.1634, 238.1688, 241.6074, 245.6946, 249.2664, 252.8228, 257.0432, 260.6824, 264.9464, 268.6268, 272.2626, 276.8376, 280.4034, 284.8956, 288.8522, 292.7638, 297.3552, 301.3556, 305.7526, 309.9292, 313.8954, 318.8198, 322.7668, 327.298, 331.6688, 335.9466, 340.9746, 345.1672, 349.3474, 354.3028, 358.8912, 364.114, 368.4646, 372.9744, 378.4092, 382.6022, 387.843, 392.5684, 397.1652, 402.5426, 407.4152, 412.5388, 417.3592, 422.1366, 427.486, 432.3918, 437.5076, 442.509, 447.3834, 453.3498, 458.0668, 463.7346, 469.1228, 473.4528, 479.7, 484.644, 491.0518, 495.5774, 500.9068, 506.432, 512.1666, 517.434, 522.6644, 527.4894, 533.6312, 538.3804, 544.292, 550.5496, 556.0234, 562.8206, 566.6146, 572.4188, 579.117, 583.6762, 590.6576, 595.7864, 601.509, 607.5334, 612.9204, 619.772, 624.2924, 630.8654, 636.1836, 642.745, 649.1316, 655.0386, 660.0136, 666.6342, 671.6196, 678.1866, 684.4282, 689.3324, 695.4794, 702.5038, 708.129, 713.528, 720.3204, 726.463, 732.7928, 739.123, 744.7418, 751.2192, 756.5102, 762.6066, 769.0184, 775.2224, 781.4014, 787.7618, 794.1436, 798.6506, 805.6378, 811.766, 819.7514, 824.5776, 828.7322, 837.8048, 843.6302, 849.9336, 854.4798, 861.3388, 867.9894, 873.8196, 880.3136, 886.2308, 892.4588, 899.0816, 905.4076, 912.0064, 917.3878, 923.619, 929.998, 937.3482, 943.9506, 947.991, 955.1144, 962.203, 968.8222, 975.7324, 981.7826, 988.7666, 994.2648, 1000.3128, 1007.4082, 1013.7536, 1020.3376, 1026.7156, 1031.7478, 1037.4292, 1045.393, 1051.2278, 1058.3434, 1062.8726, 1071.884, 1076.806, 1082.9176, 1089.1678, 1095.5032, 1102.525, 1107.2264, 1115.315, 1120.93, 1127.252, 1134.1496, 1139.0408, 1147.5448, 1153.3296, 1158.1974, 1166.5262, 1174.3328, 1175.657, 1184.4222, 1190.9172, 1197.1292, 1204.4606, 1210.4578, 1218.8728, 1225.3336, 1226.6592, 1236.5768, 1241.363, 1249.4074, 1254.6566, 1260.8014, 1266.5454, 1274.5192, },
|
||||
// precision 9
|
||||
{ 369, 374.8294, 381.2452, 387.6698, 394.1464, 400.2024, 406.8782, 413.6598, 420.462, 427.2826, 433.7102, 440.7416, 447.9366, 455.1046, 462.285, 469.0668, 476.306, 483.8448, 491.301, 498.9886, 506.2422, 513.8138, 521.7074, 529.7428, 537.8402, 545.1664, 553.3534, 561.594, 569.6886, 577.7876, 585.65, 594.228, 602.8036, 611.1666, 620.0818, 628.0824, 637.2574, 646.302, 655.1644, 664.0056, 672.3802, 681.7192, 690.5234, 700.2084, 708.831, 718.485, 728.1112, 737.4764, 746.76, 756.3368, 766.5538, 775.5058, 785.2646, 795.5902, 804.3818, 814.8998, 824.9532, 835.2062, 845.2798, 854.4728, 864.9582, 875.3292, 886.171, 896.781, 906.5716, 916.7048, 927.5322, 937.875, 949.3972, 958.3464, 969.7274, 980.2834, 992.1444, 1003.4264, 1013.0166, 1024.018, 1035.0438, 1046.34, 1057.6856, 1068.9836, 1079.0312, 1091.677, 1102.3188, 1113.4846, 1124.4424, 1135.739, 1147.1488, 1158.9202, 1169.406, 1181.5342, 1193.2834, 1203.8954, 1216.3286, 1226.2146, 1239.6684, 1251.9946, 1262.123, 1275.4338, 1285.7378, 1296.076, 1308.9692, 1320.4964, 1333.0998, 1343.9864, 1357.7754, 1368.3208, 1380.4838, 1392.7388, 1406.0758, 1416.9098, 1428.9728, 1440.9228, 1453.9292, 1462.617, 1476.05, 1490.2996, 1500.6128, 1513.7392, 1524.5174, 1536.6322, 1548.2584, 1562.3766, 1572.423, 1587.1232, 1596.5164, 1610.5938, 1622.5972, 1633.1222, 1647.7674, 1658.5044, 1671.57, 1683.7044, 1695.4142, 1708.7102, 1720.6094, 1732.6522, 1747.841, 1756.4072, 1769.9786, 1782.3276, 1797.5216, 1808.3186, 1819.0694, 1834.354, 1844.575, 1856.2808, 1871.1288, 1880.7852, 1893.9622, 1906.3418, 1920.6548, 1932.9302, 1945.8584, 1955.473, 1968.8248, 1980.6446, 1995.9598, 2008.349, 2019.8556, 2033.0334, 2044.0206, 2059.3956, 2069.9174, 2082.6084, 2093.7036, 2106.6108, 2118.9124, 2132.301, 2144.7628, 2159.8422, 2171.0212, 2183.101, 2193.5112, 2208.052, 2221.3194, 2233.3282, 2247.295, 2257.7222, 2273.342, 2286.5638, 2299.6786, 2310.8114, 2322.3312, 2335.516, 2349.874, 2363.5968, 2373.865, 2387.1918, 2401.8328, 2414.8496, 2424.544, 2436.7592, 2447.1682, 2464.1958, 2474.3438, 2489.0006, 2497.4526, 2513.6586, 2527.19, 2540.7028, 2553.768, },
|
||||
// precision 10
|
||||
{ 738.1256, 750.4234, 763.1064, 775.4732, 788.4636, 801.0644, 814.488, 827.9654, 841.0832, 854.7864, 868.1992, 882.2176, 896.5228, 910.1716, 924.7752, 938.899, 953.6126, 968.6492, 982.9474, 998.5214, 1013.1064, 1028.6364, 1044.2468, 1059.4588, 1075.3832, 1091.0584, 1106.8606, 1123.3868, 1139.5062, 1156.1862, 1172.463, 1189.339, 1206.1936, 1223.1292, 1240.1854, 1257.2908, 1275.3324, 1292.8518, 1310.5204, 1328.4854, 1345.9318, 1364.552, 1381.4658, 1400.4256, 1419.849, 1438.152, 1456.8956, 1474.8792, 1494.118, 1513.62, 1532.5132, 1551.9322, 1570.7726, 1590.6086, 1610.5332, 1630.5918, 1650.4294, 1669.7662, 1690.4106, 1710.7338, 1730.9012, 1750.4486, 1770.1556, 1791.6338, 1812.7312, 1833.6264, 1853.9526, 1874.8742, 1896.8326, 1918.1966, 1939.5594, 1961.07, 1983.037, 2003.1804, 2026.071, 2047.4884, 2070.0848, 2091.2944, 2114.333, 2135.9626, 2158.2902, 2181.0814, 2202.0334, 2224.4832, 2246.39, 2269.7202, 2292.1714, 2314.2358, 2338.9346, 2360.891, 2384.0264, 2408.3834, 2430.1544, 2454.8684, 2476.9896, 2501.4368, 2522.8702, 2548.0408, 2570.6738, 2593.5208, 2617.0158, 2640.2302, 2664.0962, 2687.4986, 2714.2588, 2735.3914, 2759.6244, 2781.8378, 2808.0072, 2830.6516, 2856.2454, 2877.2136, 2903.4546, 2926.785, 2951.2294, 2976.468, 3000.867, 3023.6508, 3049.91, 3073.5984, 3098.162, 3121.5564, 3146.2328, 3170.9484, 3195.5902, 3221.3346, 3242.7032, 3271.6112, 3296.5546, 3317.7376, 3345.072, 3369.9518, 3394.326, 3418.1818, 3444.6926, 3469.086, 3494.2754, 3517.8698, 3544.248, 3565.3768, 3588.7234, 3616.979, 3643.7504, 3668.6812, 3695.72, 3719.7392, 3742.6224, 3770.4456, 3795.6602, 3819.9058, 3844.002, 3869.517, 3895.6824, 3920.8622, 3947.1364, 3973.985, 3995.4772, 4021.62, 4046.628, 4074.65, 4096.2256, 4121.831, 4146.6406, 4173.276, 4195.0744, 4223.9696, 4251.3708, 4272.9966, 4300.8046, 4326.302, 4353.1248, 4374.312, 4403.0322, 4426.819, 4450.0598, 4478.5206, 4504.8116, 4528.8928, 4553.9584, 4578.8712, 4603.8384, 4632.3872, 4655.5128, 4675.821, 4704.6222, 4731.9862, 4755.4174, 4781.2628, 4804.332, 4832.3048, 4862.8752, 4883.4148, 4906.9544, 4935.3516, 4954.3532, 4984.0248, 5011.217, 5035.3258, 5057.3672, 5084.1828, },
|
||||
// precision 11
|
||||
{ 1477, 1501.6014, 1526.5802, 1551.7942, 1577.3042, 1603.2062, 1629.8402, 1656.2292, 1682.9462, 1709.9926, 1737.3026, 1765.4252, 1793.0578, 1821.6092, 1849.626, 1878.5568, 1908.527, 1937.5154, 1967.1874, 1997.3878, 2027.37, 2058.1972, 2089.5728, 2120.1012, 2151.9668, 2183.292, 2216.0772, 2247.8578, 2280.6562, 2313.041, 2345.714, 2380.3112, 2414.1806, 2447.9854, 2481.656, 2516.346, 2551.5154, 2586.8378, 2621.7448, 2656.6722, 2693.5722, 2729.1462, 2765.4124, 2802.8728, 2838.898, 2876.408, 2913.4926, 2951.4938, 2989.6776, 3026.282, 3065.7704, 3104.1012, 3143.7388, 3181.6876, 3221.1872, 3261.5048, 3300.0214, 3339.806, 3381.409, 3421.4144, 3461.4294, 3502.2286, 3544.651, 3586.6156, 3627.337, 3670.083, 3711.1538, 3753.5094, 3797.01, 3838.6686, 3882.1678, 3922.8116, 3967.9978, 4009.9204, 4054.3286, 4097.5706, 4140.6014, 4185.544, 4229.5976, 4274.583, 4316.9438, 4361.672, 4406.2786, 4451.8628, 4496.1834, 4543.505, 4589.1816, 4632.5188, 4678.2294, 4724.8908, 4769.0194, 4817.052, 4861.4588, 4910.1596, 4956.4344, 5002.5238, 5048.13, 5093.6374, 5142.8162, 5187.7894, 5237.3984, 5285.6078, 5331.0858, 5379.1036, 5428.6258, 5474.6018, 5522.7618, 5571.5822, 5618.59, 5667.9992, 5714.88, 5763.454, 5808.6982, 5860.3644, 5910.2914, 5953.571, 6005.9232, 6055.1914, 6104.5882, 6154.5702, 6199.7036, 6251.1764, 6298.7596, 6350.0302, 6398.061, 6448.4694, 6495.933, 6548.0474, 6597.7166, 6646.9416, 6695.9208, 6742.6328, 6793.5276, 6842.1934, 6894.2372, 6945.3864, 6996.9228, 7044.2372, 7094.1374, 7142.2272, 7192.2942, 7238.8338, 7288.9006, 7344.0908, 7394.8544, 7443.5176, 7490.4148, 7542.9314, 7595.6738, 7641.9878, 7694.3688, 7743.0448, 7797.522, 7845.53, 7899.594, 7950.3132, 7996.455, 8050.9442, 8092.9114, 8153.1374, 8197.4472, 8252.8278, 8301.8728, 8348.6776, 8401.4698, 8453.551, 8504.6598, 8553.8944, 8604.1276, 8657.6514, 8710.3062, 8758.908, 8807.8706, 8862.1702, 8910.4668, 8960.77, 9007.2766, 9063.164, 9121.0534, 9164.1354, 9218.1594, 9267.767, 9319.0594, 9372.155, 9419.7126, 9474.3722, 9520.1338, 9572.368, 9622.7702, 9675.8448, 9726.5396, 9778.7378, 9827.6554, 9878.1922, 9928.7782, 9978.3984, 10026.578, 10076.5626, 10137.1618, 10177.5244, 10229.9176, },
|
||||
// precision 12
|
||||
{ 2954, 3003.4782, 3053.3568, 3104.3666, 3155.324, 3206.9598, 3259.648, 3312.539, 3366.1474, 3420.2576, 3474.8376, 3530.6076, 3586.451, 3643.38, 3700.4104, 3757.5638, 3815.9676, 3875.193, 3934.838, 3994.8548, 4055.018, 4117.1742, 4178.4482, 4241.1294, 4304.4776, 4367.4044, 4431.8724, 4496.3732, 4561.4304, 4627.5326, 4693.949, 4761.5532, 4828.7256, 4897.6182, 4965.5186, 5034.4528, 5104.865, 5174.7164, 5244.6828, 5316.6708, 5387.8312, 5459.9036, 5532.476, 5604.8652, 5679.6718, 5753.757, 5830.2072, 5905.2828, 5980.0434, 6056.6264, 6134.3192, 6211.5746, 6290.0816, 6367.1176, 6447.9796, 6526.5576, 6606.1858, 6686.9144, 6766.1142, 6847.0818, 6927.9664, 7010.9096, 7091.0816, 7175.3962, 7260.3454, 7344.018, 7426.4214, 7511.3106, 7596.0686, 7679.8094, 7765.818, 7852.4248, 7936.834, 8022.363, 8109.5066, 8200.4554, 8288.5832, 8373.366, 8463.4808, 8549.7682, 8642.0522, 8728.3288, 8820.9528, 8907.727, 9001.0794, 9091.2522, 9179.988, 9269.852, 9362.6394, 9453.642, 9546.9024, 9640.6616, 9732.6622, 9824.3254, 9917.7484, 10007.9392, 10106.7508, 10196.2152, 10289.8114, 10383.5494, 10482.3064, 10576.8734, 10668.7872, 10764.7156, 10862.0196, 10952.793, 11049.9748, 11146.0702, 11241.4492, 11339.2772, 11434.2336, 11530.741, 11627.6136, 11726.311, 11821.5964, 11918.837, 12015.3724, 12113.0162, 12213.0424, 12306.9804, 12408.4518, 12504.8968, 12604.586, 12700.9332, 12798.705, 12898.5142, 12997.0488, 13094.788, 13198.475, 13292.7764, 13392.9698, 13486.8574, 13590.1616, 13686.5838, 13783.6264, 13887.2638, 13992.0978, 14081.0844, 14189.9956, 14280.0912, 14382.4956, 14486.4384, 14588.1082, 14686.2392, 14782.276, 14888.0284, 14985.1864, 15088.8596, 15187.0998, 15285.027, 15383.6694, 15495.8266, 15591.3736, 15694.2008, 15790.3246, 15898.4116, 15997.4522, 16095.5014, 16198.8514, 16291.7492, 16402.6424, 16499.1266, 16606.2436, 16697.7186, 16796.3946, 16902.3376, 17005.7672, 17100.814, 17206.8282, 17305.8262, 17416.0744, 17508.4092, 17617.0178, 17715.4554, 17816.758, 17920.1748, 18012.9236, 18119.7984, 18223.2248, 18324.2482, 18426.6276, 18525.0932, 18629.8976, 18733.2588, 18831.0466, 18940.1366, 19032.2696, 19131.729, 19243.4864, 19349.6932, 19442.866, 19547.9448, 19653.2798, 19754.4034, 19854.0692, 19965.1224, 20065.1774, 20158.2212, 20253.353, 20366.3264, 20463.22, },
|
||||
// precision 13
|
||||
{ 5908.5052, 6007.2672, 6107.347, 6208.5794, 6311.2622, 6414.5514, 6519.3376, 6625.6952, 6732.5988, 6841.3552, 6950.5972, 7061.3082, 7173.5646, 7287.109, 7401.8216, 7516.4344, 7633.3802, 7751.2962, 7870.3784, 7990.292, 8110.79, 8233.4574, 8356.6036, 8482.2712, 8607.7708, 8735.099, 8863.1858, 8993.4746, 9123.8496, 9255.6794, 9388.5448, 9522.7516, 9657.3106, 9792.6094, 9930.5642, 10068.794, 10206.7256, 10347.81, 10490.3196, 10632.0778, 10775.9916, 10920.4662, 11066.124, 11213.073, 11358.0362, 11508.1006, 11659.1716, 11808.7514, 11959.4884, 12112.1314, 12265.037, 12420.3756, 12578.933, 12734.311, 12890.0006, 13047.2144, 13207.3096, 13368.5144, 13528.024, 13689.847, 13852.7528, 14018.3168, 14180.5372, 14346.9668, 14513.5074, 14677.867, 14846.2186, 15017.4186, 15184.9716, 15356.339, 15529.2972, 15697.3578, 15871.8686, 16042.187, 16216.4094, 16389.4188, 16565.9126, 16742.3272, 16919.0042, 17094.7592, 17273.965, 17451.8342, 17634.4254, 17810.5984, 17988.9242, 18171.051, 18354.7938, 18539.466, 18721.0408, 18904.9972, 19081.867, 19271.9118, 19451.8694, 19637.9816, 19821.2922, 20013.1292, 20199.3858, 20387.8726, 20572.9514, 20770.7764, 20955.1714, 21144.751, 21329.9952, 21520.709, 21712.7016, 21906.3868, 22096.2626, 22286.0524, 22475.051, 22665.5098, 22862.8492, 23055.5294, 23249.6138, 23437.848, 23636.273, 23826.093, 24020.3296, 24213.3896, 24411.7392, 24602.9614, 24805.7952, 24998.1552, 25193.9588, 25389.0166, 25585.8392, 25780.6976, 25981.2728, 26175.977, 26376.5252, 26570.1964, 26773.387, 26962.9812, 27163.0586, 27368.164, 27565.0534, 27758.7428, 27961.1276, 28163.2324, 28362.3816, 28565.7668, 28758.644, 28956.9768, 29163.4722, 29354.7026, 29561.1186, 29767.9948, 29959.9986, 30164.0492, 30366.9818, 30562.5338, 30762.9928, 30976.1592, 31166.274, 31376.722, 31570.3734, 31770.809, 31974.8934, 32179.5286, 32387.5442, 32582.3504, 32794.076, 32989.9528, 33191.842, 33392.4684, 33595.659, 33801.8672, 34000.3414, 34200.0922, 34402.6792, 34610.0638, 34804.0084, 35011.13, 35218.669, 35418.6634, 35619.0792, 35830.6534, 36028.4966, 36229.7902, 36438.6422, 36630.7764, 36833.3102, 37048.6728, 37247.3916, 37453.5904, 37669.3614, 37854.5526, 38059.305, 38268.0936, 38470.2516, 38674.7064, 38876.167, 39068.3794, 39281.9144, 39492.8566, 39684.8628, 39898.4108, 40093.1836, 40297.6858, 40489.7086, 40717.2424, },
|
||||
// precision 14
|
||||
{ 11817.475, 12015.0046, 12215.3792, 12417.7504, 12623.1814, 12830.0086, 13040.0072, 13252.503, 13466.178, 13683.2738, 13902.0344, 14123.9798, 14347.394, 14573.7784, 14802.6894, 15033.6824, 15266.9134, 15502.8624, 15741.4944, 15980.7956, 16223.8916, 16468.6316, 16715.733, 16965.5726, 17217.204, 17470.666, 17727.8516, 17986.7886, 18247.6902, 18510.9632, 18775.304, 19044.7486, 19314.4408, 19587.202, 19862.2576, 20135.924, 20417.0324, 20697.9788, 20979.6112, 21265.0274, 21550.723, 21841.6906, 22132.162, 22428.1406, 22722.127, 23020.5606, 23319.7394, 23620.4014, 23925.2728, 24226.9224, 24535.581, 24845.505, 25155.9618, 25470.3828, 25785.9702, 26103.7764, 26420.4132, 26742.0186, 27062.8852, 27388.415, 27714.6024, 28042.296, 28365.4494, 28701.1526, 29031.8008, 29364.2156, 29704.497, 30037.1458, 30380.111, 30723.8168, 31059.5114, 31404.9498, 31751.6752, 32095.2686, 32444.7792, 32794.767, 33145.204, 33498.4226, 33847.6502, 34209.006, 34560.849, 34919.4838, 35274.9778, 35635.1322, 35996.3266, 36359.1394, 36722.8266, 37082.8516, 37447.7354, 37815.9606, 38191.0692, 38559.4106, 38924.8112, 39294.6726, 39663.973, 40042.261, 40416.2036, 40779.2036, 41161.6436, 41540.9014, 41921.1998, 42294.7698, 42678.5264, 43061.3464, 43432.375, 43818.432, 44198.6598, 44583.0138, 44970.4794, 45353.924, 45729.858, 46118.2224, 46511.5724, 46900.7386, 47280.6964, 47668.1472, 48055.6796, 48446.9436, 48838.7146, 49217.7296, 49613.7796, 50010.7508, 50410.0208, 50793.7886, 51190.2456, 51583.1882, 51971.0796, 52376.5338, 52763.319, 53165.5534, 53556.5594, 53948.2702, 54346.352, 54748.7914, 55138.577, 55543.4824, 55941.1748, 56333.7746, 56745.1552, 57142.7944, 57545.2236, 57935.9956, 58348.5268, 58737.5474, 59158.5962, 59542.6896, 59958.8004, 60349.3788, 60755.0212, 61147.6144, 61548.194, 61946.0696, 62348.6042, 62763.603, 63162.781, 63560.635, 63974.3482, 64366.4908, 64771.5876, 65176.7346, 65597.3916, 65995.915, 66394.0384, 66822.9396, 67203.6336, 67612.2032, 68019.0078, 68420.0388, 68821.22, 69235.8388, 69640.0724, 70055.155, 70466.357, 70863.4266, 71276.2482, 71677.0306, 72080.2006, 72493.0214, 72893.5952, 73314.5856, 73714.9852, 74125.3022, 74521.2122, 74933.6814, 75341.5904, 75743.0244, 76166.0278, 76572.1322, 76973.1028, 77381.6284, 77800.6092, 78189.328, 78607.0962, 79012.2508, 79407.8358, 79825.725, 80238.701, 80646.891, 81035.6436, 81460.0448, 81876.3884, },
|
||||
// precision 15
|
||||
{ 23635.0036, 24030.8034, 24431.4744, 24837.1524, 25246.7928, 25661.326, 26081.3532, 26505.2806, 26933.9892, 27367.7098, 27805.318, 28248.799, 28696.4382, 29148.8244, 29605.5138, 30066.8668, 30534.2344, 31006.32, 31480.778, 31962.2418, 32447.3324, 32938.0232, 33432.731, 33930.728, 34433.9896, 34944.1402, 35457.5588, 35974.5958, 36497.3296, 37021.9096, 37554.326, 38088.0826, 38628.8816, 39171.3192, 39723.2326, 40274.5554, 40832.3142, 41390.613, 41959.5908, 42532.5466, 43102.0344, 43683.5072, 44266.694, 44851.2822, 45440.7862, 46038.0586, 46640.3164, 47241.064, 47846.155, 48454.7396, 49076.9168, 49692.542, 50317.4778, 50939.65, 51572.5596, 52210.2906, 52843.7396, 53481.3996, 54127.236, 54770.406, 55422.6598, 56078.7958, 56736.7174, 57397.6784, 58064.5784, 58730.308, 59404.9784, 60077.0864, 60751.9158, 61444.1386, 62115.817, 62808.7742, 63501.4774, 64187.5454, 64883.6622, 65582.7468, 66274.5318, 66976.9276, 67688.7764, 68402.138, 69109.6274, 69822.9706, 70543.6108, 71265.5202, 71983.3848, 72708.4656, 73433.384, 74158.4664, 74896.4868, 75620.9564, 76362.1434, 77098.3204, 77835.7662, 78582.6114, 79323.9902, 80067.8658, 80814.9246, 81567.0136, 82310.8536, 83061.9952, 83821.4096, 84580.8608, 85335.547, 86092.5802, 86851.6506, 87612.311, 88381.2016, 89146.3296, 89907.8974, 90676.846, 91451.4152, 92224.5518, 92995.8686, 93763.5066, 94551.2796, 95315.1944, 96096.1806, 96881.0918, 97665.679, 98442.68, 99229.3002, 100011.0994, 100790.6386, 101580.1564, 102377.7484, 103152.1392, 103944.2712, 104730.216, 105528.6336, 106324.9398, 107117.6706, 107890.3988, 108695.2266, 109485.238, 110294.7876, 111075.0958, 111878.0496, 112695.2864, 113464.5486, 114270.0474, 115068.608, 115884.3626, 116673.2588, 117483.3716, 118275.097, 119085.4092, 119879.2808, 120687.5868, 121499.9944, 122284.916, 123095.9254, 123912.5038, 124709.0454, 125503.7182, 126323.259, 127138.9412, 127943.8294, 128755.646, 129556.5354, 130375.3298, 131161.4734, 131971.1962, 132787.5458, 133588.1056, 134431.351, 135220.2906, 136023.398, 136846.6558, 137667.0004, 138463.663, 139283.7154, 140074.6146, 140901.3072, 141721.8548, 142543.2322, 143356.1096, 144173.7412, 144973.0948, 145794.3162, 146609.5714, 147420.003, 148237.9784, 149050.5696, 149854.761, 150663.1966, 151494.0754, 152313.1416, 153112.6902, 153935.7206, 154746.9262, 155559.547, 156401.9746, 157228.7036, 158008.7254, 158820.75, 159646.9184, 160470.4458, 161279.5348, 162093.3114, 162918.542, 163729.2842, },
|
||||
// precision 16
|
||||
{ 47271, 48062.3584, 48862.7074, 49673.152, 50492.8416, 51322.9514, 52161.03, 53009.407, 53867.6348, 54734.206, 55610.5144, 56496.2096, 57390.795, 58297.268, 59210.6448, 60134.665, 61068.0248, 62010.4472, 62962.5204, 63923.5742, 64895.0194, 65876.4182, 66862.6136, 67862.6968, 68868.8908, 69882.8544, 70911.271, 71944.0924, 72990.0326, 74040.692, 75100.6336, 76174.7826, 77252.5998, 78340.2974, 79438.2572, 80545.4976, 81657.2796, 82784.6336, 83915.515, 85059.7362, 86205.9368, 87364.4424, 88530.3358, 89707.3744, 90885.9638, 92080.197, 93275.5738, 94479.391, 95695.918, 96919.2236, 98148.4602, 99382.3474, 100625.6974, 101878.0284, 103141.6278, 104409.4588, 105686.2882, 106967.5402, 108261.6032, 109548.1578, 110852.0728, 112162.231, 113479.0072, 114806.2626, 116137.9072, 117469.5048, 118813.5186, 120165.4876, 121516.2556, 122875.766, 124250.5444, 125621.2222, 127003.2352, 128387.848, 129775.2644, 131181.7776, 132577.3086, 133979.9458, 135394.1132, 136800.9078, 138233.217, 139668.5308, 141085.212, 142535.2122, 143969.0684, 145420.2872, 146878.1542, 148332.7572, 149800.3202, 151269.66, 152743.6104, 154213.0948, 155690.288, 157169.4246, 158672.1756, 160160.059, 161650.6854, 163145.7772, 164645.6726, 166159.1952, 167682.1578, 169177.3328, 170700.0118, 172228.8964, 173732.6664, 175265.5556, 176787.799, 178317.111, 179856.6914, 181400.865, 182943.4612, 184486.742, 186033.4698, 187583.7886, 189148.1868, 190688.4526, 192250.1926, 193810.9042, 195354.2972, 196938.7682, 198493.5898, 200079.2824, 201618.912, 203205.5492, 204765.5798, 206356.1124, 207929.3064, 209498.7196, 211086.229, 212675.1324, 214256.7892, 215826.2392, 217412.8474, 218995.6724, 220618.6038, 222207.1166, 223781.0364, 225387.4332, 227005.7928, 228590.4336, 230217.8738, 231805.1054, 233408.9, 234995.3432, 236601.4956, 238190.7904, 239817.2548, 241411.2832, 243002.4066, 244640.1884, 246255.3128, 247849.3508, 249479.9734, 251106.8822, 252705.027, 254332.9242, 255935.129, 257526.9014, 259154.772, 260777.625, 262390.253, 264004.4906, 265643.59, 267255.4076, 268873.426, 270470.7252, 272106.4804, 273722.4456, 275337.794, 276945.7038, 278592.9154, 280204.3726, 281841.1606, 283489.171, 285130.1716, 286735.3362, 288364.7164, 289961.1814, 291595.5524, 293285.683, 294899.6668, 296499.3434, 298128.0462, 299761.8946, 301394.2424, 302997.6748, 304615.1478, 306269.7724, 307886.114, 309543.1028, 311153.2862, 312782.8546, 314421.2008, 316033.2438, 317692.9636, 319305.2648, 320948.7406, 322566.3364, 324228.4224, 325847.1542, },
|
||||
// precision 17
|
||||
{ 94542, 96125.811, 97728.019, 99348.558, 100987.9705, 102646.7565, 104324.5125, 106021.7435, 107736.7865, 109469.272, 111223.9465, 112995.219, 114787.432, 116593.152, 118422.71, 120267.2345, 122134.6765, 124020.937, 125927.2705, 127851.255, 129788.9485, 131751.016, 133726.8225, 135722.592, 137736.789, 139770.568, 141821.518, 143891.343, 145982.1415, 148095.387, 150207.526, 152355.649, 154515.6415, 156696.05, 158887.7575, 161098.159, 163329.852, 165569.053, 167837.4005, 170121.6165, 172420.4595, 174732.6265, 177062.77, 179412.502, 181774.035, 184151.939, 186551.6895, 188965.691, 191402.8095, 193857.949, 196305.0775, 198774.6715, 201271.2585, 203764.78, 206299.3695, 208818.1365, 211373.115, 213946.7465, 216532.076, 219105.541, 221714.5375, 224337.5135, 226977.5125, 229613.0655, 232270.2685, 234952.2065, 237645.3555, 240331.1925, 243034.517, 245756.0725, 248517.6865, 251232.737, 254011.3955, 256785.995, 259556.44, 262368.335, 265156.911, 267965.266, 270785.583, 273616.0495, 276487.4835, 279346.639, 282202.509, 285074.3885, 287942.2855, 290856.018, 293774.0345, 296678.5145, 299603.6355, 302552.6575, 305492.9785, 308466.8605, 311392.581, 314347.538, 317319.4295, 320285.9785, 323301.7325, 326298.3235, 329301.3105, 332301.987, 335309.791, 338370.762, 341382.923, 344431.1265, 347464.1545, 350507.28, 353619.2345, 356631.2005, 359685.203, 362776.7845, 365886.488, 368958.2255, 372060.6825, 375165.4335, 378237.935, 381328.311, 384430.5225, 387576.425, 390683.242, 393839.648, 396977.8425, 400101.9805, 403271.296, 406409.8425, 409529.5485, 412678.7, 415847.423, 419020.8035, 422157.081, 425337.749, 428479.6165, 431700.902, 434893.1915, 438049.582, 441210.5415, 444379.2545, 447577.356, 450741.931, 453959.548, 457137.0935, 460329.846, 463537.4815, 466732.3345, 469960.5615, 473164.681, 476347.6345, 479496.173, 482813.1645, 486025.6995, 489249.4885, 492460.1945, 495675.8805, 498908.0075, 502131.802, 505374.3855, 508550.9915, 511806.7305, 515026.776, 518217.0005, 521523.9855, 524705.9855, 527950.997, 531210.0265, 534472.497, 537750.7315, 540926.922, 544207.094, 547429.4345, 550666.3745, 553975.3475, 557150.7185, 560399.6165, 563662.697, 566916.7395, 570146.1215, 573447.425, 576689.6245, 579874.5745, 583202.337, 586503.0255, 589715.635, 592910.161, 596214.3885, 599488.035, 602740.92, 605983.0685, 609248.67, 612491.3605, 615787.912, 619107.5245, 622307.9555, 625577.333, 628840.4385, 632085.2155, 635317.6135, 638691.7195, 641887.467, 645139.9405, 648441.546, 651666.252, 654941.845, },
|
||||
// precision 18
|
||||
{ 189084, 192250.913, 195456.774, 198696.946, 201977.762, 205294.444, 208651.754, 212042.099, 215472.269, 218941.91, 222443.912, 225996.845, 229568.199, 233193.568, 236844.457, 240543.233, 244279.475, 248044.27, 251854.588, 255693.2, 259583.619, 263494.621, 267445.385, 271454.061, 275468.769, 279549.456, 283646.446, 287788.198, 291966.099, 296181.164, 300431.469, 304718.618, 309024.004, 313393.508, 317760.803, 322209.731, 326675.061, 331160.627, 335654.47, 340241.442, 344841.833, 349467.132, 354130.629, 358819.432, 363574.626, 368296.587, 373118.482, 377914.93, 382782.301, 387680.669, 392601.981, 397544.323, 402529.115, 407546.018, 412593.658, 417638.657, 422762.865, 427886.169, 433017.167, 438213.273, 443441.254, 448692.421, 453937.533, 459239.049, 464529.569, 469910.083, 475274.03, 480684.473, 486070.26, 491515.237, 496995.651, 502476.617, 507973.609, 513497.19, 519083.233, 524726.509, 530305.505, 535945.728, 541584.404, 547274.055, 552967.236, 558667.862, 564360.216, 570128.148, 575965.08, 581701.952, 587532.523, 593361.144, 599246.128, 605033.418, 610958.779, 616837.117, 622772.818, 628672.04, 634675.369, 640574.831, 646585.739, 652574.547, 658611.217, 664642.684, 670713.914, 676737.681, 682797.313, 688837.897, 694917.874, 701009.882, 707173.648, 713257.254, 719415.392, 725636.761, 731710.697, 737906.209, 744103.074, 750313.39, 756504.185, 762712.579, 768876.985, 775167.859, 781359, 787615.959, 793863.597, 800245.477, 806464.582, 812785.294, 819005.925, 825403.057, 831676.197, 837936.284, 844266.968, 850642.711, 856959.756, 863322.774, 869699.931, 876102.478, 882355.787, 888694.463, 895159.952, 901536.143, 907872.631, 914293.672, 920615.14, 927130.974, 933409.404, 939922.178, 946331.47, 952745.93, 959209.264, 965590.224, 972077.284, 978501.961, 984953.19, 991413.271, 997817.479, 1004222.658, 1010725.676, 1017177.138, 1023612.529, 1030098.236, 1036493.719, 1043112.207, 1049537.036, 1056008.096, 1062476.184, 1068942.337, 1075524.95, 1081932.864, 1088426.025, 1094776.005, 1101327.448, 1107901.673, 1114423.639, 1120884.602, 1127324.923, 1133794.24, 1140328.886, 1146849.376, 1153346.682, 1159836.502, 1166478.703, 1172953.304, 1179391.502, 1185950.982, 1192544.052, 1198913.41, 1205430.994, 1212015.525, 1218674.042, 1225121.683, 1231551.101, 1238126.379, 1244673.795, 1251260.649, 1257697.86, 1264320.983, 1270736.319, 1277274.694, 1283804.95, 1290211.514, 1296858.568, 1303455.691, }
|
||||
};
|
||||
|
||||
private static final double[][] BIAS_DATA = {
|
||||
// precision 4
|
||||
{ 10, 9.717, 9.207, 8.7896, 8.2882, 7.8204, 7.3772, 6.9342, 6.5202, 6.161, 5.7722, 5.4636, 5.0396, 4.6766, 4.3566, 4.0454, 3.7936, 3.4856, 3.2666, 2.9946, 2.766, 2.4692, 2.3638, 2.0764, 1.7864, 1.7602, 1.4814, 1.433, 1.2926, 1.0664, 0.999600000000001, 0.7956, 0.5366, 0.589399999999998, 0.573799999999999, 0.269799999999996, 0.368200000000002, 0.0544000000000011, 0.234200000000001, 0.0108000000000033, -0.203400000000002, -0.0701999999999998, -0.129600000000003, -0.364199999999997, -0.480600000000003, -0.226999999999997, -0.322800000000001, -0.382599999999996, -0.511200000000002, -0.669600000000003, -0.749400000000001, -0.500399999999999, -0.617600000000003, -0.6922, -0.601599999999998, -0.416200000000003, -0.338200000000001, -0.782600000000002, -0.648600000000002, -0.919800000000002, -0.851799999999997, -0.962400000000002, -0.6402, -1.1922, -1.0256, -1.086, -1.21899999999999, -0.819400000000002, -0.940600000000003, -1.1554, -1.2072, -1.1752, -1.16759999999999, -1.14019999999999, -1.3754, -1.29859999999999, -1.607, -1.3292, -1.7606, },
|
||||
// precision 5
|
||||
{ 22, 21.1194, 20.8208, 20.2318, 19.77, 19.2436, 18.7774, 18.2848, 17.8224, 17.3742, 16.9336, 16.503, 16.0494, 15.6292, 15.2124, 14.798, 14.367, 13.9728, 13.5944, 13.217, 12.8438, 12.3696, 12.0956, 11.7044, 11.324, 11.0668, 10.6698, 10.3644, 10.049, 9.6918, 9.4146, 9.082, 8.687, 8.5398, 8.2462, 7.857, 7.6606, 7.4168, 7.1248, 6.9222, 6.6804, 6.447, 6.3454, 5.9594, 5.7636, 5.5776, 5.331, 5.19, 4.9676, 4.7564, 4.5314, 4.4442, 4.3708, 3.9774, 3.9624, 3.8796, 3.755, 3.472, 3.2076, 3.1024, 2.8908, 2.7338, 2.7728, 2.629, 2.413, 2.3266, 2.1524, 2.2642, 2.1806, 2.0566, 1.9192, 1.7598, 1.3516, 1.5802, 1.43859999999999, 1.49160000000001, 1.1524, 1.1892, 0.841399999999993, 0.879800000000003, 0.837599999999995, 0.469800000000006, 0.765600000000006, 0.331000000000003, 0.591399999999993, 0.601200000000006, 0.701599999999999, 0.558199999999999, 0.339399999999998, 0.354399999999998, 0.491200000000006, 0.308000000000007, 0.355199999999996, -0.0254000000000048, 0.205200000000005, -0.272999999999996, 0.132199999999997, 0.394400000000005, -0.241200000000006, 0.242000000000004, 0.191400000000002, 0.253799999999998, -0.122399999999999, -0.370800000000003, 0.193200000000004, -0.0848000000000013, 0.0867999999999967, -0.327200000000005, -0.285600000000002, 0.311400000000006, -0.128399999999999, -0.754999999999995, -0.209199999999996, -0.293599999999998, -0.364000000000004, -0.253600000000006, -0.821200000000005, -0.253600000000006, -0.510400000000004, -0.383399999999995, -0.491799999999998, -0.220200000000006, -0.0972000000000008, -0.557400000000001, -0.114599999999996, -0.295000000000002, -0.534800000000004, 0.346399999999988, -0.65379999999999, 0.0398000000000138, 0.0341999999999985, -0.995800000000003, -0.523400000000009, -0.489000000000004, -0.274799999999999, -0.574999999999989, -0.482799999999997, 0.0571999999999946, -0.330600000000004, -0.628800000000012, -0.140199999999993, -0.540600000000012, -0.445999999999998, -0.599400000000003, -0.262599999999992, 0.163399999999996, -0.100599999999986, -0.39500000000001, -1.06960000000001, -0.836399999999998, -0.753199999999993, -0.412399999999991, -0.790400000000005, -0.29679999999999, -0.28540000000001, -0.193000000000012, -0.0772000000000048, -0.962799999999987, -0.414800000000014, },
|
||||
// precision 6
|
||||
{ 45, 44.1902, 43.271, 42.8358, 41.8142, 41.2854, 40.317, 39.354, 38.8924, 37.9436, 37.4596, 36.5262, 35.6248, 35.1574, 34.2822, 33.837, 32.9636, 32.074, 31.7042, 30.7976, 30.4772, 29.6564, 28.7942, 28.5004, 27.686, 27.291, 26.5672, 25.8556, 25.4982, 24.8204, 24.4252, 23.7744, 23.0786, 22.8344, 22.0294, 21.8098, 21.0794, 20.5732, 20.1878, 19.5648, 19.2902, 18.6784, 18.3352, 17.8946, 17.3712, 17.0852, 16.499, 16.2686, 15.6844, 15.2234, 14.9732, 14.3356, 14.2286, 13.7262, 13.3284, 13.1048, 12.5962, 12.3562, 12.1272, 11.4184, 11.4974, 11.0822, 10.856, 10.48, 10.2834, 10.0208, 9.637, 9.51739999999999, 9.05759999999999, 8.74760000000001, 8.42700000000001, 8.1326, 8.2372, 8.2788, 7.6776, 7.79259999999999, 7.1952, 6.9564, 6.6454, 6.87, 6.5428, 6.19999999999999, 6.02940000000001, 5.62780000000001, 5.6782, 5.792, 5.35159999999999, 5.28319999999999, 5.0394, 5.07480000000001, 4.49119999999999, 4.84899999999999, 4.696, 4.54040000000001, 4.07300000000001, 4.37139999999999, 3.7216, 3.7328, 3.42080000000001, 3.41839999999999, 3.94239999999999, 3.27719999999999, 3.411, 3.13079999999999, 2.76900000000001, 2.92580000000001, 2.68279999999999, 2.75020000000001, 2.70599999999999, 2.3886, 3.01859999999999, 2.45179999999999, 2.92699999999999, 2.41720000000001, 2.41139999999999, 2.03299999999999, 2.51240000000001, 2.5564, 2.60079999999999, 2.41720000000001, 1.80439999999999, 1.99700000000001, 2.45480000000001, 1.8948, 2.2346, 2.30860000000001, 2.15479999999999, 1.88419999999999, 1.6508, 0.677199999999999, 1.72540000000001, 1.4752, 1.72280000000001, 1.66139999999999, 1.16759999999999, 1.79300000000001, 1.00059999999999, 0.905200000000008, 0.659999999999997, 1.55879999999999, 1.1636, 0.688199999999995, 0.712600000000009, 0.450199999999995, 1.1978, 0.975599999999986, 0.165400000000005, 1.727, 1.19739999999999, -0.252600000000001, 1.13460000000001, 1.3048, 1.19479999999999, 0.313400000000001, 0.878999999999991, 1.12039999999999, 0.853000000000009, 1.67920000000001, 0.856999999999999, 0.448599999999999, 1.2362, 0.953399999999988, 1.02859999999998, 0.563199999999995, 0.663000000000011, 0.723000000000013, 0.756599999999992, 0.256599999999992, -0.837600000000009, 0.620000000000005, 0.821599999999989, 0.216600000000028, 0.205600000000004, 0.220199999999977, 0.372599999999977, 0.334400000000016, 0.928400000000011, 0.972800000000007, 0.192400000000021, 0.487199999999973, -0.413000000000011, 0.807000000000016, 0.120600000000024, 0.769000000000005, 0.870799999999974, 0.66500000000002, 0.118200000000002, 0.401200000000017, 0.635199999999998, 0.135400000000004, 0.175599999999974, 1.16059999999999, 0.34620000000001, 0.521400000000028, -0.586599999999976, -1.16480000000001, 0.968399999999974, 0.836999999999989, 0.779600000000016, 0.985799999999983, },
|
||||
// precision 7
|
||||
{ 91, 89.4934, 87.9758, 86.4574, 84.9718, 83.4954, 81.5302, 80.0756, 78.6374, 77.1782, 75.7888, 73.9522, 72.592, 71.2532, 69.9086, 68.5938, 66.9474, 65.6796, 64.4394, 63.2176, 61.9768, 60.4214, 59.2528, 58.0102, 56.8658, 55.7278, 54.3044, 53.1316, 52.093, 51.0032, 49.9092, 48.6306, 47.5294, 46.5756, 45.6508, 44.662, 43.552, 42.3724, 41.617, 40.5754, 39.7872, 38.8444, 37.7988, 36.8606, 36.2118, 35.3566, 34.4476, 33.5882, 32.6816, 32.0824, 31.0258, 30.6048, 29.4436, 28.7274, 27.957, 27.147, 26.4364, 25.7592, 25.3386, 24.781, 23.8028, 23.656, 22.6544, 21.996, 21.4718, 21.1544, 20.6098, 19.5956, 19.0616, 18.5758, 18.4878, 17.5244, 17.2146, 16.724, 15.8722, 15.5198, 15.0414, 14.941, 14.9048, 13.87, 13.4304, 13.028, 12.4708, 12.37, 12.0624, 11.4668, 11.5532, 11.4352, 11.2564, 10.2744, 10.2118, 9.74720000000002, 10.1456, 9.2928, 8.75040000000001, 8.55279999999999, 8.97899999999998, 8.21019999999999, 8.18340000000001, 7.3494, 7.32499999999999, 7.66140000000001, 6.90300000000002, 7.25439999999998, 6.9042, 7.21499999999997, 6.28640000000001, 6.08139999999997, 6.6764, 6.30099999999999, 5.13900000000001, 5.65800000000002, 5.17320000000001, 4.59019999999998, 4.9538, 5.08280000000002, 4.92200000000003, 4.99020000000002, 4.7328, 5.4538, 4.11360000000002, 4.22340000000003, 4.08780000000002, 3.70800000000003, 4.15559999999999, 4.18520000000001, 3.63720000000001, 3.68220000000002, 3.77960000000002, 3.6078, 2.49160000000001, 3.13099999999997, 2.5376, 3.19880000000001, 3.21100000000001, 2.4502, 3.52820000000003, 2.91199999999998, 3.04480000000001, 2.7432, 2.85239999999999, 2.79880000000003, 2.78579999999999, 1.88679999999999, 2.98860000000002, 2.50639999999999, 1.91239999999999, 2.66160000000002, 2.46820000000002, 1.58199999999999, 1.30399999999997, 2.27379999999999, 2.68939999999998, 1.32900000000001, 3.10599999999999, 1.69080000000002, 2.13740000000001, 2.53219999999999, 1.88479999999998, 1.33240000000001, 1.45119999999997, 1.17899999999997, 2.44119999999998, 1.60659999999996, 2.16700000000003, 0.77940000000001, 2.37900000000002, 2.06700000000001, 1.46000000000004, 2.91160000000002, 1.69200000000001, 0.954600000000028, 2.49300000000005, 2.2722, 1.33500000000004, 2.44899999999996, 1.20140000000004, 3.07380000000001, 2.09739999999999, 2.85640000000001, 2.29960000000005, 2.40899999999999, 1.97040000000004, 0.809799999999996, 1.65279999999996, 2.59979999999996, 0.95799999999997, 2.06799999999998, 2.32780000000002, 4.20159999999998, 1.96320000000003, 1.86400000000003, 1.42999999999995, 3.77940000000001, 1.27200000000005, 1.86440000000005, 2.20600000000002, 3.21900000000005, 1.5154, 2.61019999999996, },
|
||||
// precision 8
|
||||
{ 183.2152, 180.2454, 177.2096, 173.6652, 170.6312, 167.6822, 164.249, 161.3296, 158.0038, 155.2074, 152.4612, 149.27, 146.5178, 143.4412, 140.8032, 138.1634, 135.1688, 132.6074, 129.6946, 127.2664, 124.8228, 122.0432, 119.6824, 116.9464, 114.6268, 112.2626, 109.8376, 107.4034, 104.8956, 102.8522, 100.7638, 98.3552, 96.3556, 93.7526, 91.9292, 89.8954, 87.8198, 85.7668, 83.298, 81.6688, 79.9466, 77.9746, 76.1672, 74.3474, 72.3028, 70.8912, 69.114, 67.4646, 65.9744, 64.4092, 62.6022, 60.843, 59.5684, 58.1652, 56.5426, 55.4152, 53.5388, 52.3592, 51.1366, 49.486, 48.3918, 46.5076, 45.509, 44.3834, 43.3498, 42.0668, 40.7346, 40.1228, 38.4528, 37.7, 36.644, 36.0518, 34.5774, 33.9068, 32.432, 32.1666, 30.434, 29.6644, 28.4894, 27.6312, 26.3804, 26.292, 25.5496000000001, 25.0234, 24.8206, 22.6146, 22.4188, 22.117, 20.6762, 20.6576, 19.7864, 19.509, 18.5334, 17.9204, 17.772, 16.2924, 16.8654, 15.1836, 15.745, 15.1316, 15.0386, 14.0136, 13.6342, 12.6196, 12.1866, 12.4281999999999, 11.3324, 10.4794000000001, 11.5038, 10.129, 9.52800000000002, 10.3203999999999, 9.46299999999997, 9.79280000000006, 9.12300000000005, 8.74180000000001, 9.2192, 7.51020000000005, 7.60659999999996, 7.01840000000004, 7.22239999999999, 7.40139999999997, 6.76179999999999, 7.14359999999999, 5.65060000000005, 5.63779999999997, 5.76599999999996, 6.75139999999999, 5.57759999999996, 3.73220000000003, 5.8048, 5.63019999999995, 4.93359999999996, 3.47979999999995, 4.33879999999999, 3.98940000000005, 3.81960000000004, 3.31359999999995, 3.23080000000004, 3.4588, 3.08159999999998, 3.4076, 3.00639999999999, 2.38779999999997, 2.61900000000003, 1.99800000000005, 3.34820000000002, 2.95060000000001, 0.990999999999985, 2.11440000000005, 2.20299999999997, 2.82219999999995, 2.73239999999998, 2.7826, 3.76660000000004, 2.26480000000004, 2.31280000000004, 2.40819999999997, 2.75360000000001, 3.33759999999995, 2.71559999999999, 1.7478000000001, 1.42920000000004, 2.39300000000003, 2.22779999999989, 2.34339999999997, 0.87259999999992, 3.88400000000001, 1.80600000000004, 1.91759999999999, 1.16779999999994, 1.50320000000011, 2.52500000000009, 0.226400000000012, 2.31500000000005, 0.930000000000064, 1.25199999999995, 2.14959999999996, 0.0407999999999902, 2.5447999999999, 1.32960000000003, 0.197400000000016, 2.52620000000002, 3.33279999999991, -1.34300000000007, 0.422199999999975, 0.917200000000093, 1.12920000000008, 1.46060000000011, 1.45779999999991, 2.8728000000001, 3.33359999999993, -1.34079999999994, 1.57680000000005, 0.363000000000056, 1.40740000000005, 0.656600000000026, 0.801400000000058, -0.454600000000028, 1.51919999999996, },
|
||||
// precision 9
|
||||
{ 368, 361.8294, 355.2452, 348.6698, 342.1464, 336.2024, 329.8782, 323.6598, 317.462, 311.2826, 305.7102, 299.7416, 293.9366, 288.1046, 282.285, 277.0668, 271.306, 265.8448, 260.301, 254.9886, 250.2422, 244.8138, 239.7074, 234.7428, 229.8402, 225.1664, 220.3534, 215.594, 210.6886, 205.7876, 201.65, 197.228, 192.8036, 188.1666, 184.0818, 180.0824, 176.2574, 172.302, 168.1644, 164.0056, 160.3802, 156.7192, 152.5234, 149.2084, 145.831, 142.485, 139.1112, 135.4764, 131.76, 129.3368, 126.5538, 122.5058, 119.2646, 116.5902, 113.3818, 110.8998, 107.9532, 105.2062, 102.2798, 99.4728, 96.9582, 94.3292, 92.171, 89.7809999999999, 87.5716, 84.7048, 82.5322, 79.875, 78.3972, 75.3464, 73.7274, 71.2834, 70.1444, 68.4263999999999, 66.0166, 64.018, 62.0437999999999, 60.3399999999999, 58.6856, 57.9836, 55.0311999999999, 54.6769999999999, 52.3188, 51.4846, 49.4423999999999, 47.739, 46.1487999999999, 44.9202, 43.4059999999999, 42.5342000000001, 41.2834, 38.8954000000001, 38.3286000000001, 36.2146, 36.6684, 35.9946, 33.123, 33.4338, 31.7378000000001, 29.076, 28.9692, 27.4964, 27.0998, 25.9864, 26.7754, 24.3208, 23.4838, 22.7388000000001, 24.0758000000001, 21.9097999999999, 20.9728, 19.9228000000001, 19.9292, 16.617, 17.05, 18.2996000000001, 15.6128000000001, 15.7392, 14.5174, 13.6322, 12.2583999999999, 13.3766000000001, 11.423, 13.1232, 9.51639999999998, 10.5938000000001, 9.59719999999993, 8.12220000000002, 9.76739999999995, 7.50440000000003, 7.56999999999994, 6.70440000000008, 6.41419999999994, 6.71019999999999, 5.60940000000005, 4.65219999999999, 6.84099999999989, 3.4072000000001, 3.97859999999991, 3.32760000000007, 5.52160000000003, 3.31860000000006, 2.06940000000009, 4.35400000000004, 1.57500000000005, 0.280799999999999, 2.12879999999996, -0.214799999999968, -0.0378000000000611, -0.658200000000079, 0.654800000000023, -0.0697999999999865, 0.858400000000074, -2.52700000000004, -2.1751999999999, -3.35539999999992, -1.04019999999991, -0.651000000000067, -2.14439999999991, -1.96659999999997, -3.97939999999994, -0.604400000000169, -3.08260000000018, -3.39159999999993, -5.29640000000018, -5.38920000000007, -5.08759999999984, -4.69900000000007, -5.23720000000003, -3.15779999999995, -4.97879999999986, -4.89899999999989, -7.48880000000008, -5.94799999999987, -5.68060000000014, -6.67180000000008, -4.70499999999993, -7.27779999999984, -4.6579999999999, -4.4362000000001, -4.32139999999981, -5.18859999999995, -6.66879999999992, -6.48399999999992, -5.1260000000002, -4.4032000000002, -6.13500000000022, -5.80819999999994, -4.16719999999987, -4.15039999999999, -7.45600000000013, -7.24080000000004, -9.83179999999993, -5.80420000000004, -8.6561999999999, -6.99940000000015, -10.5473999999999, -7.34139999999979, -6.80999999999995, -6.29719999999998, -6.23199999999997, },
|
||||
// precision 10
|
||||
{ 737.1256, 724.4234, 711.1064, 698.4732, 685.4636, 673.0644, 660.488, 647.9654, 636.0832, 623.7864, 612.1992, 600.2176, 588.5228, 577.1716, 565.7752, 554.899, 543.6126, 532.6492, 521.9474, 511.5214, 501.1064, 490.6364, 480.2468, 470.4588, 460.3832, 451.0584, 440.8606, 431.3868, 422.5062, 413.1862, 404.463, 395.339, 386.1936, 378.1292, 369.1854, 361.2908, 353.3324, 344.8518, 337.5204, 329.4854, 321.9318, 314.552, 306.4658, 299.4256, 292.849, 286.152, 278.8956, 271.8792, 265.118, 258.62, 252.5132, 245.9322, 239.7726, 233.6086, 227.5332, 222.5918, 216.4294, 210.7662, 205.4106, 199.7338, 194.9012, 188.4486, 183.1556, 178.6338, 173.7312, 169.6264, 163.9526, 159.8742, 155.8326, 151.1966, 147.5594, 143.07, 140.037, 134.1804, 131.071, 127.4884, 124.0848, 120.2944, 117.333, 112.9626, 110.2902, 107.0814, 103.0334, 99.4832000000001, 96.3899999999999, 93.7202000000002, 90.1714000000002, 87.2357999999999, 85.9346, 82.8910000000001, 80.0264000000002, 78.3834000000002, 75.1543999999999, 73.8683999999998, 70.9895999999999, 69.4367999999999, 64.8701999999998, 65.0408000000002, 61.6738, 59.5207999999998, 57.0158000000001, 54.2302, 53.0962, 50.4985999999999, 52.2588000000001, 47.3914, 45.6244000000002, 42.8377999999998, 43.0072, 40.6516000000001, 40.2453999999998, 35.2136, 36.4546, 33.7849999999999, 33.2294000000002, 32.4679999999998, 30.8670000000002, 28.6507999999999, 28.9099999999999, 27.5983999999999, 26.1619999999998, 24.5563999999999, 23.2328000000002, 21.9484000000002, 21.5902000000001, 21.3346000000001, 17.7031999999999, 20.6111999999998, 19.5545999999999, 15.7375999999999, 17.0720000000001, 16.9517999999998, 15.326, 13.1817999999998, 14.6925999999999, 13.0859999999998, 13.2754, 10.8697999999999, 11.248, 7.3768, 4.72339999999986, 7.97899999999981, 8.7503999999999, 7.68119999999999, 9.7199999999998, 7.73919999999998, 5.6224000000002, 7.44560000000001, 6.6601999999998, 5.9058, 4.00199999999995, 4.51699999999983, 4.68240000000014, 3.86220000000003, 5.13639999999987, 5.98500000000013, 2.47719999999981, 2.61999999999989, 1.62800000000016, 4.65000000000009, 0.225599999999758, 0.831000000000131, -0.359400000000278, 1.27599999999984, -2.92559999999958, -0.0303999999996449, 2.37079999999969, -2.0033999999996, 0.804600000000391, 0.30199999999968, 1.1247999999996, -2.6880000000001, 0.0321999999996478, -1.18099999999959, -3.9402, -1.47940000000017, -0.188400000000001, -2.10720000000038, -2.04159999999956, -3.12880000000041, -4.16160000000036, -0.612799999999879, -3.48719999999958, -8.17900000000009, -5.37780000000021, -4.01379999999972, -5.58259999999973, -5.73719999999958, -7.66799999999967, -5.69520000000011, -1.1247999999996, -5.58520000000044, -8.04560000000038, -4.64840000000004, -11.6468000000004, -7.97519999999986, -5.78300000000036, -7.67420000000038, -10.6328000000003, -9.81720000000041, },
|
||||
// precision 11
|
||||
{ 1476, 1449.6014, 1423.5802, 1397.7942, 1372.3042, 1347.2062, 1321.8402, 1297.2292, 1272.9462, 1248.9926, 1225.3026, 1201.4252, 1178.0578, 1155.6092, 1132.626, 1110.5568, 1088.527, 1066.5154, 1045.1874, 1024.3878, 1003.37, 982.1972, 962.5728, 942.1012, 922.9668, 903.292, 884.0772, 864.8578, 846.6562, 828.041, 809.714, 792.3112, 775.1806, 757.9854, 740.656, 724.346, 707.5154, 691.8378, 675.7448, 659.6722, 645.5722, 630.1462, 614.4124, 600.8728, 585.898, 572.408, 558.4926, 544.4938, 531.6776, 517.282, 505.7704, 493.1012, 480.7388, 467.6876, 456.1872, 445.5048, 433.0214, 420.806, 411.409, 400.4144, 389.4294, 379.2286, 369.651, 360.6156, 350.337, 342.083, 332.1538, 322.5094, 315.01, 305.6686, 298.1678, 287.8116, 280.9978, 271.9204, 265.3286, 257.5706, 249.6014, 242.544, 235.5976, 229.583, 220.9438, 214.672, 208.2786, 201.8628, 195.1834, 191.505, 186.1816, 178.5188, 172.2294, 167.8908, 161.0194, 158.052, 151.4588, 148.1596, 143.4344, 138.5238, 133.13, 127.6374, 124.8162, 118.7894, 117.3984, 114.6078, 109.0858, 105.1036, 103.6258, 98.6018000000004, 95.7618000000002, 93.5821999999998, 88.5900000000001, 86.9992000000002, 82.8800000000001, 80.4539999999997, 74.6981999999998, 74.3644000000004, 73.2914000000001, 65.5709999999999, 66.9232000000002, 65.1913999999997, 62.5882000000001, 61.5702000000001, 55.7035999999998, 56.1764000000003, 52.7596000000003, 53.0302000000001, 49.0609999999997, 48.4694, 44.933, 46.0474000000004, 44.7165999999997, 41.9416000000001, 39.9207999999999, 35.6328000000003, 35.5276000000003, 33.1934000000001, 33.2371999999996, 33.3864000000003, 33.9228000000003, 30.2371999999996, 29.1373999999996, 25.2272000000003, 24.2942000000003, 19.8338000000003, 18.9005999999999, 23.0907999999999, 21.8544000000002, 19.5176000000001, 15.4147999999996, 16.9314000000004, 18.6737999999996, 12.9877999999999, 14.3688000000002, 12.0447999999997, 15.5219999999999, 12.5299999999997, 14.5940000000001, 14.3131999999996, 9.45499999999993, 12.9441999999999, 3.91139999999996, 13.1373999999996, 5.44720000000052, 9.82779999999912, 7.87279999999919, 3.67760000000089, 5.46980000000076, 5.55099999999948, 5.65979999999945, 3.89439999999922, 3.1275999999998, 5.65140000000065, 6.3062000000009, 3.90799999999945, 1.87060000000019, 5.17020000000048, 2.46680000000015, 0.770000000000437, -3.72340000000077, 1.16400000000067, 8.05340000000069, 0.135399999999208, 2.15940000000046, 0.766999999999825, 1.0594000000001, 3.15500000000065, -0.287399999999252, 2.37219999999979, -2.86620000000039, -1.63199999999961, -2.22979999999916, -0.15519999999924, -1.46039999999994, -0.262199999999211, -2.34460000000036, -2.8078000000005, -3.22179999999935, -5.60159999999996, -8.42200000000048, -9.43740000000071, 0.161799999999857, -10.4755999999998, -10.0823999999993, },
|
||||
// precision 12
|
||||
{ 2953, 2900.4782, 2848.3568, 2796.3666, 2745.324, 2694.9598, 2644.648, 2595.539, 2546.1474, 2498.2576, 2450.8376, 2403.6076, 2357.451, 2311.38, 2266.4104, 2221.5638, 2176.9676, 2134.193, 2090.838, 2048.8548, 2007.018, 1966.1742, 1925.4482, 1885.1294, 1846.4776, 1807.4044, 1768.8724, 1731.3732, 1693.4304, 1657.5326, 1621.949, 1586.5532, 1551.7256, 1517.6182, 1483.5186, 1450.4528, 1417.865, 1385.7164, 1352.6828, 1322.6708, 1291.8312, 1260.9036, 1231.476, 1201.8652, 1173.6718, 1145.757, 1119.2072, 1092.2828, 1065.0434, 1038.6264, 1014.3192, 988.5746, 965.0816, 940.1176, 917.9796, 894.5576, 871.1858, 849.9144, 827.1142, 805.0818, 783.9664, 763.9096, 742.0816, 724.3962, 706.3454, 688.018, 667.4214, 650.3106, 633.0686, 613.8094, 597.818, 581.4248, 563.834, 547.363, 531.5066, 520.455400000001, 505.583199999999, 488.366, 476.480799999999, 459.7682, 450.0522, 434.328799999999, 423.952799999999, 408.727000000001, 399.079400000001, 387.252200000001, 373.987999999999, 360.852000000001, 351.6394, 339.642, 330.902400000001, 322.661599999999, 311.662200000001, 301.3254, 291.7484, 279.939200000001, 276.7508, 263.215200000001, 254.811400000001, 245.5494, 242.306399999999, 234.8734, 223.787200000001, 217.7156, 212.0196, 200.793, 195.9748, 189.0702, 182.449199999999, 177.2772, 170.2336, 164.741, 158.613600000001, 155.311, 147.5964, 142.837, 137.3724, 132.0162, 130.0424, 121.9804, 120.451800000001, 114.8968, 111.585999999999, 105.933199999999, 101.705, 98.5141999999996, 95.0488000000005, 89.7880000000005, 91.4750000000004, 83.7764000000006, 80.9698000000008, 72.8574000000008, 73.1615999999995, 67.5838000000003, 62.6263999999992, 63.2638000000006, 66.0977999999996, 52.0843999999997, 58.9956000000002, 47.0912000000008, 46.4956000000002, 48.4383999999991, 47.1082000000006, 43.2392, 37.2759999999998, 40.0283999999992, 35.1864000000005, 35.8595999999998, 32.0998, 28.027, 23.6694000000007, 33.8266000000003, 26.3736000000008, 27.2008000000005, 21.3245999999999, 26.4115999999995, 23.4521999999997, 19.5013999999992, 19.8513999999996, 10.7492000000002, 18.6424000000006, 13.1265999999996, 18.2436000000016, 6.71860000000015, 3.39459999999963, 6.33759999999893, 7.76719999999841, 0.813999999998487, 3.82819999999992, 0.826199999999517, 8.07440000000133, -1.59080000000176, 5.01780000000144, 0.455399999998917, -0.24199999999837, 0.174800000000687, -9.07640000000174, -4.20160000000033, -3.77520000000004, -4.75179999999818, -5.3724000000002, -8.90680000000066, -6.10239999999976, -5.74120000000039, -9.95339999999851, -3.86339999999836, -13.7304000000004, -16.2710000000006, -7.51359999999841, -3.30679999999847, -13.1339999999982, -10.0551999999989, -6.72019999999975, -8.59660000000076, -10.9307999999983, -1.8775999999998, -4.82259999999951, -13.7788, -21.6470000000008, -10.6735999999983, -15.7799999999988, },
|
||||
// precision 13
|
||||
{ 5907.5052, 5802.2672, 5697.347, 5593.5794, 5491.2622, 5390.5514, 5290.3376, 5191.6952, 5093.5988, 4997.3552, 4902.5972, 4808.3082, 4715.5646, 4624.109, 4533.8216, 4444.4344, 4356.3802, 4269.2962, 4183.3784, 4098.292, 4014.79, 3932.4574, 3850.6036, 3771.2712, 3691.7708, 3615.099, 3538.1858, 3463.4746, 3388.8496, 3315.6794, 3244.5448, 3173.7516, 3103.3106, 3033.6094, 2966.5642, 2900.794, 2833.7256, 2769.81, 2707.3196, 2644.0778, 2583.9916, 2523.4662, 2464.124, 2406.073, 2347.0362, 2292.1006, 2238.1716, 2182.7514, 2128.4884, 2077.1314, 2025.037, 1975.3756, 1928.933, 1879.311, 1831.0006, 1783.2144, 1738.3096, 1694.5144, 1649.024, 1606.847, 1564.7528, 1525.3168, 1482.5372, 1443.9668, 1406.5074, 1365.867, 1329.2186, 1295.4186, 1257.9716, 1225.339, 1193.2972, 1156.3578, 1125.8686, 1091.187, 1061.4094, 1029.4188, 1000.9126, 972.3272, 944.004199999999, 915.7592, 889.965, 862.834200000001, 840.4254, 812.598399999999, 785.924200000001, 763.050999999999, 741.793799999999, 721.466, 699.040799999999, 677.997200000002, 649.866999999998, 634.911800000002, 609.8694, 591.981599999999, 570.2922, 557.129199999999, 538.3858, 521.872599999999, 502.951400000002, 495.776399999999, 475.171399999999, 459.751, 439.995200000001, 426.708999999999, 413.7016, 402.3868, 387.262599999998, 372.0524, 357.050999999999, 342.5098, 334.849200000001, 322.529399999999, 311.613799999999, 295.848000000002, 289.273000000001, 274.093000000001, 263.329600000001, 251.389599999999, 245.7392, 231.9614, 229.7952, 217.155200000001, 208.9588, 199.016599999999, 190.839199999999, 180.6976, 176.272799999999, 166.976999999999, 162.5252, 151.196400000001, 149.386999999999, 133.981199999998, 130.0586, 130.164000000001, 122.053400000001, 110.7428, 108.1276, 106.232400000001, 100.381600000001, 98.7668000000012, 86.6440000000002, 79.9768000000004, 82.4722000000002, 68.7026000000005, 70.1186000000016, 71.9948000000004, 58.998599999999, 59.0492000000013, 56.9818000000014, 47.5338000000011, 42.9928, 51.1591999999982, 37.2740000000013, 42.7220000000016, 31.3734000000004, 26.8090000000011, 25.8934000000008, 26.5286000000015, 29.5442000000003, 19.3503999999994, 26.0760000000009, 17.9527999999991, 14.8419999999969, 10.4683999999979, 8.65899999999965, 9.86720000000059, 4.34139999999752, -0.907800000000861, -3.32080000000133, -0.936199999996461, -11.9916000000012, -8.87000000000262, -6.33099999999831, -11.3366000000024, -15.9207999999999, -9.34659999999712, -15.5034000000014, -19.2097999999969, -15.357799999998, -28.2235999999975, -30.6898000000001, -19.3271999999997, -25.6083999999973, -24.409599999999, -13.6385999999984, -33.4473999999973, -32.6949999999997, -28.9063999999998, -31.7483999999968, -32.2935999999972, -35.8329999999987, -47.620600000002, -39.0855999999985, -33.1434000000008, -46.1371999999974, -37.5892000000022, -46.8164000000033, -47.3142000000007, -60.2914000000019, -37.7575999999972, },
|
||||
// precision 14
|
||||
{ 11816.475, 11605.0046, 11395.3792, 11188.7504, 10984.1814, 10782.0086, 10582.0072, 10384.503, 10189.178, 9996.2738, 9806.0344, 9617.9798, 9431.394, 9248.7784, 9067.6894, 8889.6824, 8712.9134, 8538.8624, 8368.4944, 8197.7956, 8031.8916, 7866.6316, 7703.733, 7544.5726, 7386.204, 7230.666, 7077.8516, 6926.7886, 6778.6902, 6631.9632, 6487.304, 6346.7486, 6206.4408, 6070.202, 5935.2576, 5799.924, 5671.0324, 5541.9788, 5414.6112, 5290.0274, 5166.723, 5047.6906, 4929.162, 4815.1406, 4699.127, 4588.5606, 4477.7394, 4369.4014, 4264.2728, 4155.9224, 4055.581, 3955.505, 3856.9618, 3761.3828, 3666.9702, 3575.7764, 3482.4132, 3395.0186, 3305.8852, 3221.415, 3138.6024, 3056.296, 2970.4494, 2896.1526, 2816.8008, 2740.2156, 2670.497, 2594.1458, 2527.111, 2460.8168, 2387.5114, 2322.9498, 2260.6752, 2194.2686, 2133.7792, 2074.767, 2015.204, 1959.4226, 1898.6502, 1850.006, 1792.849, 1741.4838, 1687.9778, 1638.1322, 1589.3266, 1543.1394, 1496.8266, 1447.8516, 1402.7354, 1361.9606, 1327.0692, 1285.4106, 1241.8112, 1201.6726, 1161.973, 1130.261, 1094.2036, 1048.2036, 1020.6436, 990.901400000002, 961.199800000002, 924.769800000002, 899.526400000002, 872.346400000002, 834.375, 810.432000000001, 780.659800000001, 756.013800000001, 733.479399999997, 707.923999999999, 673.858, 652.222399999999, 636.572399999997, 615.738599999997, 586.696400000001, 564.147199999999, 541.679600000003, 523.943599999999, 505.714599999999, 475.729599999999, 461.779600000002, 449.750800000002, 439.020799999998, 412.7886, 400.245600000002, 383.188199999997, 362.079599999997, 357.533799999997, 334.319000000003, 327.553399999997, 308.559399999998, 291.270199999999, 279.351999999999, 271.791400000002, 252.576999999997, 247.482400000001, 236.174800000001, 218.774599999997, 220.155200000001, 208.794399999999, 201.223599999998, 182.995600000002, 185.5268, 164.547400000003, 176.5962, 150.689599999998, 157.8004, 138.378799999999, 134.021200000003, 117.614399999999, 108.194000000003, 97.0696000000025, 89.6042000000016, 95.6030000000028, 84.7810000000027, 72.635000000002, 77.3482000000004, 59.4907999999996, 55.5875999999989, 50.7346000000034, 61.3916000000027, 50.9149999999936, 39.0384000000049, 58.9395999999979, 29.633600000001, 28.2032000000036, 26.0078000000067, 17.0387999999948, 9.22000000000116, 13.8387999999977, 8.07240000000456, 14.1549999999988, 15.3570000000036, 3.42660000000615, 6.24820000000182, -2.96940000000177, -8.79940000000352, -5.97860000000219, -14.4048000000039, -3.4143999999942, -13.0148000000045, -11.6977999999945, -25.7878000000055, -22.3185999999987, -24.409599999999, -31.9756000000052, -18.9722000000038, -22.8678000000073, -30.8972000000067, -32.3715999999986, -22.3907999999938, -43.6720000000059, -35.9038, -39.7492000000057, -54.1641999999993, -45.2749999999942, -42.2989999999991, -44.1089999999967, -64.3564000000042, -49.9551999999967, -42.6116000000038, },
|
||||
// precision 15
|
||||
{ 23634.0036, 23210.8034, 22792.4744, 22379.1524, 21969.7928, 21565.326, 21165.3532, 20770.2806, 20379.9892, 19994.7098, 19613.318, 19236.799, 18865.4382, 18498.8244, 18136.5138, 17778.8668, 17426.2344, 17079.32, 16734.778, 16397.2418, 16063.3324, 15734.0232, 15409.731, 15088.728, 14772.9896, 14464.1402, 14157.5588, 13855.5958, 13559.3296, 13264.9096, 12978.326, 12692.0826, 12413.8816, 12137.3192, 11870.2326, 11602.5554, 11340.3142, 11079.613, 10829.5908, 10583.5466, 10334.0344, 10095.5072, 9859.694, 9625.2822, 9395.7862, 9174.0586, 8957.3164, 8738.064, 8524.155, 8313.7396, 8116.9168, 7913.542, 7718.4778, 7521.65, 7335.5596, 7154.2906, 6968.7396, 6786.3996, 6613.236, 6437.406, 6270.6598, 6107.7958, 5945.7174, 5787.6784, 5635.5784, 5482.308, 5337.9784, 5190.0864, 5045.9158, 4919.1386, 4771.817, 4645.7742, 4518.4774, 4385.5454, 4262.6622, 4142.74679999999, 4015.5318, 3897.9276, 3790.7764, 3685.13800000001, 3573.6274, 3467.9706, 3368.61079999999, 3271.5202, 3170.3848, 3076.4656, 2982.38400000001, 2888.4664, 2806.4868, 2711.9564, 2634.1434, 2551.3204, 2469.7662, 2396.61139999999, 2318.9902, 2243.8658, 2171.9246, 2105.01360000001, 2028.8536, 1960.9952, 1901.4096, 1841.86079999999, 1777.54700000001, 1714.5802, 1654.65059999999, 1596.311, 1546.2016, 1492.3296, 1433.8974, 1383.84600000001, 1339.4152, 1293.5518, 1245.8686, 1193.50659999999, 1162.27959999999, 1107.19439999999, 1069.18060000001, 1035.09179999999, 999.679000000004, 957.679999999993, 925.300199999998, 888.099400000006, 848.638600000006, 818.156400000007, 796.748399999997, 752.139200000005, 725.271200000003, 692.216, 671.633600000001, 647.939799999993, 621.670599999998, 575.398799999995, 561.226599999995, 532.237999999998, 521.787599999996, 483.095799999996, 467.049599999998, 465.286399999997, 415.548599999995, 401.047399999996, 380.607999999993, 377.362599999993, 347.258799999996, 338.371599999999, 310.096999999994, 301.409199999995, 276.280799999993, 265.586800000005, 258.994399999996, 223.915999999997, 215.925399999993, 213.503800000006, 191.045400000003, 166.718200000003, 166.259000000005, 162.941200000001, 148.829400000002, 141.645999999993, 123.535399999993, 122.329800000007, 89.473399999988, 80.1962000000058, 77.5457999999926, 59.1056000000099, 83.3509999999951, 52.2906000000075, 36.3979999999865, 40.6558000000077, 42.0003999999899, 19.6630000000005, 19.7153999999864, -8.38539999999921, -0.692799999989802, 0.854800000000978, 3.23219999999856, -3.89040000000386, -5.25880000001052, -24.9052000000083, -22.6837999999989, -26.4286000000138, -34.997000000003, -37.0216000000073, -43.430400000012, -58.2390000000014, -68.8034000000043, -56.9245999999985, -57.8583999999973, -77.3097999999882, -73.2793999999994, -81.0738000000129, -87.4530000000086, -65.0254000000132, -57.296399999992, -96.2746000000043, -103.25, -96.081600000005, -91.5542000000132, -102.465200000006, -107.688599999994, -101.458000000013, -109.715800000005, },
|
||||
// precision 16
|
||||
{ 47270, 46423.3584, 45585.7074, 44757.152, 43938.8416, 43130.9514, 42330.03, 41540.407, 40759.6348, 39988.206, 39226.5144, 38473.2096, 37729.795, 36997.268, 36272.6448, 35558.665, 34853.0248, 34157.4472, 33470.5204, 32793.5742, 32127.0194, 31469.4182, 30817.6136, 30178.6968, 29546.8908, 28922.8544, 28312.271, 27707.0924, 27114.0326, 26526.692, 25948.6336, 25383.7826, 24823.5998, 24272.2974, 23732.2572, 23201.4976, 22674.2796, 22163.6336, 21656.515, 21161.7362, 20669.9368, 20189.4424, 19717.3358, 19256.3744, 18795.9638, 18352.197, 17908.5738, 17474.391, 17052.918, 16637.2236, 16228.4602, 15823.3474, 15428.6974, 15043.0284, 14667.6278, 14297.4588, 13935.2882, 13578.5402, 13234.6032, 12882.1578, 12548.0728, 12219.231, 11898.0072, 11587.2626, 11279.9072, 10973.5048, 10678.5186, 10392.4876, 10105.2556, 9825.766, 9562.5444, 9294.2222, 9038.2352, 8784.848, 8533.2644, 8301.7776, 8058.30859999999, 7822.94579999999, 7599.11319999999, 7366.90779999999, 7161.217, 6957.53080000001, 6736.212, 6548.21220000001, 6343.06839999999, 6156.28719999999, 5975.15419999999, 5791.75719999999, 5621.32019999999, 5451.66, 5287.61040000001, 5118.09479999999, 4957.288, 4798.4246, 4662.17559999999, 4512.05900000001, 4364.68539999999, 4220.77720000001, 4082.67259999999, 3957.19519999999, 3842.15779999999, 3699.3328, 3583.01180000001, 3473.8964, 3338.66639999999, 3233.55559999999, 3117.799, 3008.111, 2909.69140000001, 2814.86499999999, 2719.46119999999, 2624.742, 2532.46979999999, 2444.7886, 2370.1868, 2272.45259999999, 2196.19260000001, 2117.90419999999, 2023.2972, 1969.76819999999, 1885.58979999999, 1833.2824, 1733.91200000001, 1682.54920000001, 1604.57980000001, 1556.11240000001, 1491.3064, 1421.71960000001, 1371.22899999999, 1322.1324, 1264.7892, 1196.23920000001, 1143.8474, 1088.67240000001, 1073.60380000001, 1023.11660000001, 959.036400000012, 927.433199999999, 906.792799999996, 853.433599999989, 841.873800000001, 791.1054, 756.899999999994, 704.343200000003, 672.495599999995, 622.790399999998, 611.254799999995, 567.283200000005, 519.406599999988, 519.188400000014, 495.312800000014, 451.350799999986, 443.973399999988, 431.882199999993, 392.027000000002, 380.924200000009, 345.128999999986, 298.901400000002, 287.771999999997, 272.625, 247.253000000026, 222.490600000019, 223.590000000026, 196.407599999977, 176.425999999978, 134.725199999986, 132.4804, 110.445599999977, 86.7939999999944, 56.7038000000175, 64.915399999998, 38.3726000000024, 37.1606000000029, 46.170999999973, 49.1716000000015, 15.3362000000197, 6.71639999997569, -34.8185999999987, -39.4476000000141, 12.6830000000191, -12.3331999999937, -50.6565999999875, -59.9538000000175, -65.1054000000004, -70.7576000000117, -106.325200000021, -126.852200000023, -110.227599999984, -132.885999999999, -113.897200000007, -142.713800000027, -151.145399999979, -150.799200000009, -177.756200000003, -156.036399999983, -182.735199999996, -177.259399999981, -198.663600000029, -174.577600000019, -193.84580000001, },
|
||||
// precision 17
|
||||
{ 94541, 92848.811, 91174.019, 89517.558, 87879.9705, 86262.7565, 84663.5125, 83083.7435, 81521.7865, 79977.272, 78455.9465, 76950.219, 75465.432, 73994.152, 72546.71, 71115.2345, 69705.6765, 68314.937, 66944.2705, 65591.255, 64252.9485, 62938.016, 61636.8225, 60355.592, 59092.789, 57850.568, 56624.518, 55417.343, 54231.1415, 53067.387, 51903.526, 50774.649, 49657.6415, 48561.05, 47475.7575, 46410.159, 45364.852, 44327.053, 43318.4005, 42325.6165, 41348.4595, 40383.6265, 39436.77, 38509.502, 37594.035, 36695.939, 35818.6895, 34955.691, 34115.8095, 33293.949, 32465.0775, 31657.6715, 30877.2585, 30093.78, 29351.3695, 28594.1365, 27872.115, 27168.7465, 26477.076, 25774.541, 25106.5375, 24452.5135, 23815.5125, 23174.0655, 22555.2685, 21960.2065, 21376.3555, 20785.1925, 20211.517, 19657.0725, 19141.6865, 18579.737, 18081.3955, 17578.995, 17073.44, 16608.335, 16119.911, 15651.266, 15194.583, 14749.0495, 14343.4835, 13925.639, 13504.509, 13099.3885, 12691.2855, 12328.018, 11969.0345, 11596.5145, 11245.6355, 10917.6575, 10580.9785, 10277.8605, 9926.58100000001, 9605.538, 9300.42950000003, 8989.97850000003, 8728.73249999998, 8448.3235, 8175.31050000002, 7898.98700000002, 7629.79100000003, 7413.76199999999, 7149.92300000001, 6921.12650000001, 6677.1545, 6443.28000000003, 6278.23450000002, 6014.20049999998, 5791.20299999998, 5605.78450000001, 5438.48800000001, 5234.2255, 5059.6825, 4887.43349999998, 4682.935, 4496.31099999999, 4322.52250000002, 4191.42499999999, 4021.24200000003, 3900.64799999999, 3762.84250000003, 3609.98050000001, 3502.29599999997, 3363.84250000003, 3206.54849999998, 3079.70000000001, 2971.42300000001, 2867.80349999998, 2727.08100000001, 2630.74900000001, 2496.6165, 2440.902, 2356.19150000002, 2235.58199999999, 2120.54149999999, 2012.25449999998, 1933.35600000003, 1820.93099999998, 1761.54800000001, 1663.09350000002, 1578.84600000002, 1509.48149999999, 1427.3345, 1379.56150000001, 1306.68099999998, 1212.63449999999, 1084.17300000001, 1124.16450000001, 1060.69949999999, 1007.48849999998, 941.194499999983, 879.880500000028, 836.007500000007, 782.802000000025, 748.385499999975, 647.991500000004, 626.730500000005, 570.776000000013, 484.000500000024, 513.98550000001, 418.985499999952, 386.996999999974, 370.026500000036, 355.496999999974, 356.731499999994, 255.92200000002, 259.094000000041, 205.434499999974, 165.374500000034, 197.347500000033, 95.718499999959, 67.6165000000037, 54.6970000000438, 31.7395000000251, -15.8784999999916, 8.42500000004657, -26.3754999999655, -118.425500000012, -66.6629999999423, -42.9745000000112, -107.364999999991, -189.839000000036, -162.611499999999, -164.964999999967, -189.079999999958, -223.931499999948, -235.329999999958, -269.639500000048, -249.087999999989, -206.475499999942, -283.04449999996, -290.667000000016, -304.561499999953, -336.784499999951, -380.386500000022, -283.280499999993, -364.533000000054, -389.059499999974, -364.454000000027, -415.748000000021, -417.155000000028, },
|
||||
// precision 18
|
||||
{ 189083, 185696.913, 182348.774, 179035.946, 175762.762, 172526.444, 169329.754, 166166.099, 163043.269, 159958.91, 156907.912, 153906.845, 150924.199, 147996.568, 145093.457, 142239.233, 139421.475, 136632.27, 133889.588, 131174.2, 128511.619, 125868.621, 123265.385, 120721.061, 118181.769, 115709.456, 113252.446, 110840.198, 108465.099, 106126.164, 103823.469, 101556.618, 99308.004, 97124.508, 94937.803, 92833.731, 90745.061, 88677.627, 86617.47, 84650.442, 82697.833, 80769.132, 78879.629, 77014.432, 75215.626, 73384.587, 71652.482, 69895.93, 68209.301, 66553.669, 64921.981, 63310.323, 61742.115, 60205.018, 58698.658, 57190.657, 55760.865, 54331.169, 52908.167, 51550.273, 50225.254, 48922.421, 47614.533, 46362.049, 45098.569, 43926.083, 42736.03, 41593.473, 40425.26, 39316.237, 38243.651, 37170.617, 36114.609, 35084.19, 34117.233, 33206.509, 32231.505, 31318.728, 30403.404, 29540.0550000001, 28679.236, 27825.862, 26965.216, 26179.148, 25462.08, 24645.952, 23922.523, 23198.144, 22529.128, 21762.4179999999, 21134.779, 20459.117, 19840.818, 19187.04, 18636.3689999999, 17982.831, 17439.7389999999, 16874.547, 16358.2169999999, 15835.684, 15352.914, 14823.681, 14329.313, 13816.897, 13342.874, 12880.882, 12491.648, 12021.254, 11625.392, 11293.7610000001, 10813.697, 10456.209, 10099.074, 9755.39000000001, 9393.18500000006, 9047.57900000003, 8657.98499999999, 8395.85900000005, 8033, 7736.95900000003, 7430.59699999995, 7258.47699999996, 6924.58200000005, 6691.29399999999, 6357.92500000005, 6202.05700000003, 5921.19700000004, 5628.28399999999, 5404.96799999999, 5226.71100000001, 4990.75600000005, 4799.77399999998, 4622.93099999998, 4472.478, 4171.78700000001, 3957.46299999999, 3868.95200000005, 3691.14300000004, 3474.63100000005, 3341.67200000002, 3109.14000000001, 3071.97400000005, 2796.40399999998, 2756.17799999996, 2611.46999999997, 2471.93000000005, 2382.26399999997, 2209.22400000005, 2142.28399999999, 2013.96100000001, 1911.18999999994, 1818.27099999995, 1668.47900000005, 1519.65800000005, 1469.67599999998, 1367.13800000004, 1248.52899999998, 1181.23600000003, 1022.71900000004, 1088.20700000005, 959.03600000008, 876.095999999903, 791.183999999892, 703.337000000058, 731.949999999953, 586.86400000006, 526.024999999907, 323.004999999888, 320.448000000091, 340.672999999952, 309.638999999966, 216.601999999955, 102.922999999952, 19.2399999999907, -0.114000000059605, -32.6240000000689, -89.3179999999702, -153.497999999905, -64.2970000000205, -143.695999999996, -259.497999999905, -253.017999999924, -213.948000000091, -397.590000000084, -434.006000000052, -403.475000000093, -297.958000000101, -404.317000000039, -528.898999999976, -506.621000000043, -513.205000000075, -479.351000000024, -596.139999999898, -527.016999999993, -664.681000000099, -680.306000000099, -704.050000000047, -850.486000000034, -757.43200000003, -713.308999999892, }
|
||||
};
|
||||
|
||||
private static final long[] THRESHOLDS = new long[] {
|
||||
10, 20, 40, 80, 220, 400, 900, 1800, 3100, 6500, 11500, 20000, 50000, 120000, 350000
|
||||
};
|
||||
|
||||
private final BigArrays bigArrays;
|
||||
private final OpenBitSet algorithm;
|
||||
private ByteArray runLens;
|
||||
private final Hashset hashSet;
|
||||
private final int p, m;
|
||||
private final double alphaMM;
|
||||
|
||||
public HyperLogLogPlusPlus(int precision, BigArrays bigArrays, long initialBucketCount) {
|
||||
Preconditions.checkArgument(precision >= 4, "precision must be >= 4");
|
||||
Preconditions.checkArgument(precision <= 18, "precision must be <= 18");
|
||||
p = precision;
|
||||
m = 1 << p;
|
||||
this.bigArrays = bigArrays;
|
||||
algorithm = new OpenBitSet();
|
||||
runLens = bigArrays.newByteArray(initialBucketCount << p);
|
||||
hashSet = new Hashset(initialBucketCount);
|
||||
final double alpha;
|
||||
switch (p) {
|
||||
case 4:
|
||||
alpha = 0.673;
|
||||
break;
|
||||
case 5:
|
||||
alpha = 0.697;
|
||||
break;
|
||||
default:
|
||||
alpha = 0.7213 / (1 + 1.079 / m);
|
||||
break;
|
||||
}
|
||||
alphaMM = alpha * m * m;
|
||||
}
|
||||
|
||||
public long maxBucket() {
|
||||
return runLens.size() >>> p;
|
||||
}
|
||||
|
||||
private void ensureCapacity(long numBuckets) {
|
||||
runLens = bigArrays.grow(runLens, numBuckets << p);
|
||||
}
|
||||
|
||||
public void merge(long thisBucket, HyperLogLogPlusPlus other, long otherBucket) {
|
||||
Preconditions.checkArgument(p == other.p);
|
||||
ensureCapacity(thisBucket + 1);
|
||||
if (other.algorithm.get(otherBucket) == LINEAR_COUNTING) {
|
||||
final IntArray values = other.hashSet.values(otherBucket);
|
||||
try {
|
||||
for (long i = 0; i < values.size(); ++i) {
|
||||
final int encoded = values.get(i);
|
||||
if (algorithm.get(thisBucket) == LINEAR_COUNTING) {
|
||||
collectLcEncoded(thisBucket, encoded);
|
||||
} else {
|
||||
collectHllEncoded(thisBucket, encoded);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
Releasables.release(values);
|
||||
}
|
||||
} else {
|
||||
if (algorithm.get(thisBucket) != HYPERLOGLOG) {
|
||||
upgradeToHll(thisBucket);
|
||||
}
|
||||
final long thisStart = thisBucket << p;
|
||||
final long otherStart = otherBucket << p;
|
||||
for (int i = 0; i < m; ++i) {
|
||||
runLens.set(thisStart + i, (byte) Math.max(runLens.get(thisStart + i), other.runLens.get(otherStart + i)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void collect(long bucket, long hash) {
|
||||
ensureCapacity(bucket + 1);
|
||||
if (algorithm.get(bucket) == LINEAR_COUNTING) {
|
||||
collectLc(bucket, hash);
|
||||
} else {
|
||||
collectHll(bucket, hash);
|
||||
}
|
||||
}
|
||||
|
||||
private void collectLc(long bucket, long hash) {
|
||||
final int k = encodeHash(hash, p);
|
||||
collectLcEncoded(bucket, k);
|
||||
}
|
||||
|
||||
private void collectLcEncoded(long bucket, int encoded) {
|
||||
final int newSize = hashSet.add(bucket, encoded);
|
||||
if (newSize > hashSet.threshold) {
|
||||
upgradeToHll(bucket);
|
||||
}
|
||||
}
|
||||
|
||||
private void collectHll(long bucket, long hash) {
|
||||
final long index = index(hash, p);
|
||||
final int runLen = runLen(hash, p);
|
||||
collectHll(bucket, index, runLen);
|
||||
}
|
||||
|
||||
private void collectHllEncoded(long bucket, int encoded) {
|
||||
final int runLen = decodeRunLen(encoded, p);
|
||||
final int index = decodeIndex(encoded, p);
|
||||
collectHll(bucket, index, runLen);
|
||||
}
|
||||
|
||||
private void collectHll(long bucket, long index, int runLen) {
|
||||
final long bucketIndex = (bucket << p) + index;
|
||||
runLens.set(bucketIndex, (byte) Math.max(runLen, runLens.get(bucketIndex)));
|
||||
}
|
||||
|
||||
public long cardinality(long bucket) {
|
||||
if (algorithm.get(bucket) == LINEAR_COUNTING) {
|
||||
return cardinalityLc(bucket);
|
||||
} else {
|
||||
return cardinalityHll(bucket);
|
||||
}
|
||||
}
|
||||
|
||||
private long cardinalityLc(long bucket) {
|
||||
final long m = 1 << P2;
|
||||
final long v = m - hashSet.size(bucket);
|
||||
return linearCounting(m, v);
|
||||
}
|
||||
|
||||
private long cardinalityHll(long bucket) {
|
||||
double inverseSum = 0;
|
||||
int zeros = 0;
|
||||
for (long i = bucket << p, end = i + m; i < end; ++i) {
|
||||
final int runLen = runLens.get(i);
|
||||
inverseSum += 1. / (1L << runLen);
|
||||
if (runLen == 0) {
|
||||
++zeros;
|
||||
}
|
||||
}
|
||||
double e1 = alphaMM / inverseSum;
|
||||
double e2 = e1 <= 5 * m ? e1 - estimateBias(e1) : e1;
|
||||
long h;
|
||||
if (zeros != 0) {
|
||||
h = linearCounting(m, zeros);
|
||||
} else {
|
||||
h = Math.round(e2);
|
||||
}
|
||||
if (h <= threshold()) {
|
||||
return h;
|
||||
} else {
|
||||
return Math.round(e2);
|
||||
}
|
||||
}
|
||||
|
||||
void upgradeToHll(long bucket) {
|
||||
ensureCapacity(bucket + 1);
|
||||
final IntArray values = hashSet.values(bucket);
|
||||
try {
|
||||
runLens.fill(bucket << p, (bucket << p) + m, (byte) 0);
|
||||
for (long i = 0; i < values.size(); ++i) {
|
||||
final int encoded = values.get(i);
|
||||
collectHllEncoded(bucket, encoded);
|
||||
}
|
||||
algorithm.set(bucket);
|
||||
} finally {
|
||||
Releasables.release(values);
|
||||
}
|
||||
}
|
||||
|
||||
static long linearCounting(long m, long v) {
|
||||
return Math.round(m * Math.log((double) m / v));
|
||||
}
|
||||
|
||||
static long mask(int bits) {
|
||||
return (1L << bits) - 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode the hash on 32 bits. The encoded hash cannot be equal to <code>0</code>.
|
||||
*/
|
||||
static int encodeHash(long hash, int p) {
|
||||
final long e = hash >>> (64 - P2);
|
||||
final long encoded;
|
||||
if ((e & mask(P2 - p)) == 0) {
|
||||
final int runLen = 1 + Math.min(Long.numberOfLeadingZeros(hash << P2), 64 - P2);
|
||||
encoded = (e << 7) | (runLen << 1) | 1;
|
||||
} else {
|
||||
encoded = e << 1;
|
||||
}
|
||||
assert PackedInts.bitsRequired(encoded) <= 32;
|
||||
assert encoded != 0;
|
||||
return (int) encoded;
|
||||
}
|
||||
|
||||
static int decodeRunLen(int encoded, int p) {
|
||||
if ((encoded & 1) == 1) {
|
||||
return (((encoded >>> 1) & 0x3F) + (P2 - p));
|
||||
} else {
|
||||
final int bits = encoded << (31 + p - P2);
|
||||
assert bits != 0;
|
||||
return 1 + Integer.numberOfLeadingZeros(bits);
|
||||
}
|
||||
}
|
||||
|
||||
static int decodeIndex(int encoded, int p) {
|
||||
long index;
|
||||
if ((encoded & 1) == 1) {
|
||||
index = encoded >>> 7;
|
||||
} else {
|
||||
index = encoded >>> 1;
|
||||
}
|
||||
return (int) (index >>> (P2 - p));
|
||||
}
|
||||
|
||||
static long index(long hash, int p) {
|
||||
return hash >>> (64 - p);
|
||||
}
|
||||
|
||||
static int runLen(long hash, int p) {
|
||||
return 1 + Math.min(Long.numberOfLeadingZeros(hash << p), 64 - p);
|
||||
}
|
||||
|
||||
|
||||
private double estimateBias(double e) {
|
||||
final double[] rawEstimateData = rawEstimateData();
|
||||
final double[] biasData = biasData();
|
||||
int index = Arrays.binarySearch(rawEstimateData, e);
|
||||
if (index >= 0) {
|
||||
return biasData[index];
|
||||
} else {
|
||||
index = -1 - index;
|
||||
if (index == 0) {
|
||||
return biasData[0];
|
||||
} else if (index >= biasData.length) {
|
||||
return biasData[biasData.length - 1];
|
||||
} else {
|
||||
double w1 = (e - rawEstimateData[index - 1]);
|
||||
assert w1 >= 0;
|
||||
double w2 = (rawEstimateData[index] - e);
|
||||
assert w2 >= 0;
|
||||
return (biasData[index - 1] * w1 + biasData[index] * w2) / (w1 + w2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private double[] biasData() {
|
||||
return BIAS_DATA[p - 4];
|
||||
}
|
||||
|
||||
private double[] rawEstimateData() {
|
||||
return RAW_ESTIMATE_DATA[p - 4];
|
||||
}
|
||||
|
||||
private long threshold() {
|
||||
return THRESHOLDS[p - 4];
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean release() throws ElasticsearchException {
|
||||
Releasables.release(runLens, hashSet.sizes);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* We are actually using HyperLogLog's runLens array but interpreting it as a hash set
|
||||
* for linear counting.
|
||||
*/
|
||||
private class Hashset {
|
||||
|
||||
private final int capacity;
|
||||
private final int threshold;
|
||||
private final int mask;
|
||||
private IntArray sizes;
|
||||
private final BytesRef readSpare;
|
||||
private final ByteBuffer writeSpare;
|
||||
|
||||
public Hashset(long initialBucketCount) {
|
||||
capacity = m / 4; // because ints take 4 bytes
|
||||
threshold = (int) (capacity * MAX_LOAD_FACTOR);
|
||||
mask = capacity - 1;
|
||||
sizes = bigArrays.newIntArray(initialBucketCount);
|
||||
readSpare = new BytesRef();
|
||||
writeSpare = ByteBuffer.allocate(4).order(ByteOrder.LITTLE_ENDIAN);
|
||||
}
|
||||
|
||||
private long index (long bucket, int index) {
|
||||
return (bucket << p) + (index << 2);
|
||||
}
|
||||
|
||||
private int get(long bucket, int index) {
|
||||
runLens.get(index(bucket, index), 4, readSpare);
|
||||
return UnsafeUtils.readIntLE(readSpare.bytes, readSpare.offset);
|
||||
}
|
||||
|
||||
private void set(long bucket, int index, int value) {
|
||||
writeSpare.putInt(0, value);
|
||||
runLens.set(index(bucket, index), writeSpare.array(), 0, 4);
|
||||
}
|
||||
|
||||
private int recomputedSize(long bucket) {
|
||||
int size = 0;
|
||||
for (int i = 0; i <= mask; ++i) {
|
||||
final int v = get(bucket, i);
|
||||
if (v != 0) {
|
||||
++size;
|
||||
}
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
public int size(long bucket) {
|
||||
if (bucket >= sizes.size()) {
|
||||
return 0;
|
||||
}
|
||||
final int size = sizes.get(bucket);
|
||||
assert size == recomputedSize(bucket);
|
||||
return size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add <code>k</code> to the hash table associated with <code>bucket</code>.
|
||||
* Return <tt>-1</tt> if the value was already in the set or the new set size if it was added.
|
||||
*/
|
||||
public int add(long bucket, int k) {
|
||||
sizes = bigArrays.grow(sizes, bucket + 1);
|
||||
assert k != 0;
|
||||
for (int i = (k & mask); ; i = (i + 1) & mask) {
|
||||
final int v = get(bucket, i);
|
||||
if (v == 0) {
|
||||
// means unused, take it!
|
||||
set(bucket, i, k);
|
||||
return sizes.increment(bucket, 1);
|
||||
} else if (v == k) {
|
||||
// k is already in the set
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public IntArray values(final long bucket) {
|
||||
final int size = size(bucket);
|
||||
final IntArray values = bigArrays.newIntArray(size);
|
||||
if (size == 0) {
|
||||
return values;
|
||||
}
|
||||
int i = 0;
|
||||
for (int j = 0; j < capacity; ++j) {
|
||||
final int k = get(bucket, j);
|
||||
if (k != 0) {
|
||||
values.set(i++, k);
|
||||
}
|
||||
}
|
||||
assert i == values.size();
|
||||
return values;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void writeTo(long bucket, StreamOutput out) throws IOException {
|
||||
out.writeVInt(p);
|
||||
if (algorithm.get(bucket) == LINEAR_COUNTING) {
|
||||
out.writeBoolean(LINEAR_COUNTING);
|
||||
final IntArray hashes = hashSet.values(bucket);
|
||||
boolean success = false;
|
||||
try {
|
||||
out.writeVLong(hashes.size());
|
||||
for (long i = 0; i < hashes.size(); ++i) {
|
||||
out.writeInt(hashes.get(i));
|
||||
}
|
||||
success = true;
|
||||
} finally {
|
||||
Releasables.release(success, hashes);
|
||||
}
|
||||
} else {
|
||||
out.writeBoolean(HYPERLOGLOG);
|
||||
for (long i = bucket << p, end = i + m; i < end; ++i) {
|
||||
out.writeByte(runLens.get(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static HyperLogLogPlusPlus readFrom(StreamInput in, BigArrays bigArrays) throws IOException {
|
||||
final int precision = in.readVInt();
|
||||
HyperLogLogPlusPlus counts = new HyperLogLogPlusPlus(precision, bigArrays, 1);
|
||||
final boolean algorithm = in.readBoolean();
|
||||
if (algorithm == LINEAR_COUNTING) {
|
||||
counts.algorithm.clear(0);
|
||||
final long size = in.readVLong();
|
||||
for (long i = 0; i < size; ++i) {
|
||||
final int encoded = in.readInt();
|
||||
counts.hashSet.add(0, encoded);
|
||||
}
|
||||
} else {
|
||||
counts.algorithm.set(0);
|
||||
for (int i = 0; i < counts.m; ++i) {
|
||||
counts.runLens.set(i, in.readByte());
|
||||
}
|
||||
}
|
||||
return counts;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,138 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch 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.
|
||||
*/
|
||||
|
||||
package org.elasticsearch.search.aggregations.metrics.cardinality;
|
||||
|
||||
import org.elasticsearch.common.io.stream.StreamInput;
|
||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||
import org.elasticsearch.common.util.BigArrays;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
import org.elasticsearch.search.aggregations.AggregationStreams;
|
||||
import org.elasticsearch.search.aggregations.InternalAggregation;
|
||||
import org.elasticsearch.search.aggregations.metrics.MetricsAggregation;
|
||||
import org.elasticsearch.search.aggregations.support.numeric.ValueFormatterStreams;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
public final class InternalCardinality extends MetricsAggregation.SingleValue implements Cardinality {
|
||||
|
||||
public final static Type TYPE = new Type("cardinality");
|
||||
|
||||
public final static AggregationStreams.Stream STREAM = new AggregationStreams.Stream() {
|
||||
@Override
|
||||
public InternalCardinality readResult(StreamInput in) throws IOException {
|
||||
InternalCardinality result = new InternalCardinality();
|
||||
result.readFrom(in);
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
public static void registerStreams() {
|
||||
AggregationStreams.registerStream(STREAM, TYPE.stream());
|
||||
}
|
||||
|
||||
private HyperLogLogPlusPlus counts;
|
||||
|
||||
InternalCardinality(String name, HyperLogLogPlusPlus counts) {
|
||||
super(name);
|
||||
this.counts = counts;
|
||||
}
|
||||
|
||||
private InternalCardinality() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public double value() {
|
||||
return getValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getValue() {
|
||||
return counts == null ? 0 : counts.cardinality(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type type() {
|
||||
return TYPE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readFrom(StreamInput in) throws IOException {
|
||||
name = in.readString();
|
||||
valueFormatter = ValueFormatterStreams.readOptional(in);
|
||||
if (in.readBoolean()) {
|
||||
counts = HyperLogLogPlusPlus.readFrom(in, BigArrays.NON_RECYCLING_INSTANCE);
|
||||
} else {
|
||||
counts = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeTo(StreamOutput out) throws IOException {
|
||||
out.writeString(name);
|
||||
ValueFormatterStreams.writeOptional(valueFormatter, out);
|
||||
if (counts != null) {
|
||||
out.writeBoolean(true);
|
||||
counts.writeTo(0, out);
|
||||
} else {
|
||||
out.writeBoolean(false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public InternalAggregation reduce(ReduceContext reduceContext) {
|
||||
List<InternalAggregation> aggregations = reduceContext.aggregations();
|
||||
InternalCardinality reduced = null;
|
||||
for (InternalAggregation aggregation : aggregations) {
|
||||
final InternalCardinality cardinality = (InternalCardinality) aggregation;
|
||||
if (cardinality.counts != null) {
|
||||
if (reduced == null) {
|
||||
reduced = cardinality;
|
||||
} else {
|
||||
reduced.merge(cardinality);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (reduced == null) { // all empty
|
||||
reduced = (InternalCardinality) aggregations.get(0);
|
||||
}
|
||||
|
||||
return reduced;
|
||||
}
|
||||
|
||||
public void merge(InternalCardinality other) {
|
||||
assert counts != null && other != null;
|
||||
counts.merge(0, other.counts, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||
builder.startObject(name);
|
||||
final long cardinality = getValue();
|
||||
builder.field(CommonFields.VALUE, cardinality);
|
||||
if (valueFormatter != null) {
|
||||
builder.field(CommonFields.VALUE_AS_STRING, valueFormatter.format(cardinality));
|
||||
}
|
||||
builder.endObject();
|
||||
return builder;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,162 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch 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.
|
||||
*/
|
||||
|
||||
package org.elasticsearch.benchmark.search.aggregations;
|
||||
|
||||
import com.carrotsearch.randomizedtesting.generators.RandomInts;
|
||||
import org.elasticsearch.action.admin.cluster.health.ClusterHealthResponse;
|
||||
import org.elasticsearch.action.bulk.BulkRequestBuilder;
|
||||
import org.elasticsearch.action.bulk.BulkResponse;
|
||||
import org.elasticsearch.action.search.SearchResponse;
|
||||
import org.elasticsearch.action.search.SearchType;
|
||||
import org.elasticsearch.client.Client;
|
||||
import org.elasticsearch.common.StopWatch;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.unit.TimeValue;
|
||||
import org.elasticsearch.node.Node;
|
||||
import org.elasticsearch.search.aggregations.metrics.cardinality.Cardinality;
|
||||
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static org.elasticsearch.client.Requests.createIndexRequest;
|
||||
import static org.elasticsearch.cluster.metadata.IndexMetaData.SETTING_NUMBER_OF_REPLICAS;
|
||||
import static org.elasticsearch.cluster.metadata.IndexMetaData.SETTING_NUMBER_OF_SHARDS;
|
||||
import static org.elasticsearch.common.settings.ImmutableSettings.settingsBuilder;
|
||||
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
|
||||
import static org.elasticsearch.node.NodeBuilder.nodeBuilder;
|
||||
import static org.elasticsearch.search.aggregations.AggregationBuilders.cardinality;
|
||||
|
||||
public class CardinalityAggregationSearchBenchmark {
|
||||
|
||||
private static final Random R = new Random();
|
||||
private static final String CLUSTER_NAME = CardinalityAggregationSearchBenchmark.class.getSimpleName();
|
||||
private static final int NUM_DOCS = 10000000;
|
||||
private static final int LOW_CARD = 1000;
|
||||
private static final int HIGH_CARD = 1000000;
|
||||
private static final int BATCH = 100;
|
||||
private static final int WARM = 5;
|
||||
private static final int RUNS = 10;
|
||||
private static final int ITERS = 5;
|
||||
|
||||
public static void main(String[] args) {
|
||||
Settings settings = settingsBuilder()
|
||||
.put("index.refresh_interval", "-1")
|
||||
.put(SETTING_NUMBER_OF_SHARDS, 5)
|
||||
.put(SETTING_NUMBER_OF_REPLICAS, 0)
|
||||
.build();
|
||||
|
||||
Node[] nodes = new Node[1];
|
||||
for (int i = 0; i < nodes.length; i++) {
|
||||
nodes[i] = nodeBuilder().clusterName(CLUSTER_NAME)
|
||||
.settings(settingsBuilder().put(settings).put("name", "node" + i))
|
||||
.node();
|
||||
}
|
||||
|
||||
Node clientNode = nodeBuilder()
|
||||
.clusterName(CLUSTER_NAME)
|
||||
.settings(settingsBuilder().put(settings).put("name", "client")).client(true).node();
|
||||
|
||||
Client client = clientNode.client();
|
||||
|
||||
try {
|
||||
client.admin().indices().create(createIndexRequest("index").settings(settings).mapping("type",
|
||||
jsonBuilder().startObject().startObject("type").startObject("properties")
|
||||
.startObject("low_card_str_value")
|
||||
.field("type", "multi_field")
|
||||
.startObject("fields")
|
||||
.startObject("low_card_str_value")
|
||||
.field("type", "string")
|
||||
.endObject()
|
||||
.startObject("hash")
|
||||
.field("type", "murmur3")
|
||||
.endObject()
|
||||
.endObject()
|
||||
.endObject()
|
||||
.startObject("high_card_str_value")
|
||||
.field("type", "multi_field")
|
||||
.startObject("fields")
|
||||
.startObject("high_card_str_value")
|
||||
.field("type", "string")
|
||||
.endObject()
|
||||
.startObject("hash")
|
||||
.field("type", "murmur3")
|
||||
.endObject()
|
||||
.endObject()
|
||||
.endObject()
|
||||
.startObject("low_card_num_value")
|
||||
.field("type", "long")
|
||||
.endObject()
|
||||
.startObject("high_card_num_value")
|
||||
.field("type", "long")
|
||||
.endObject()
|
||||
.endObject().endObject().endObject())).actionGet();
|
||||
|
||||
System.out.println("Indexing " + NUM_DOCS + " documents");
|
||||
|
||||
StopWatch stopWatch = new StopWatch().start();
|
||||
for (int i = 0; i < NUM_DOCS; ) {
|
||||
BulkRequestBuilder request = client.prepareBulk();
|
||||
for (int j = 0; j < BATCH && i < NUM_DOCS; ++j) {
|
||||
final int lowCard = RandomInts.randomInt(R, LOW_CARD);
|
||||
final int highCard = RandomInts.randomInt(R, HIGH_CARD);
|
||||
request.add(client.prepareIndex("index", "type", Integer.toString(i)).setSource("low_card_str_value", "str" + lowCard, "high_card_str_value", "str" + highCard, "low_card_num_value", lowCard , "high_card_num_value", highCard));
|
||||
++i;
|
||||
}
|
||||
BulkResponse response = request.execute().actionGet();
|
||||
if (response.hasFailures()) {
|
||||
System.err.println("--> failures...");
|
||||
System.err.println(response.buildFailureMessage());
|
||||
}
|
||||
if ((i % 100000) == 0) {
|
||||
System.out.println("--> Indexed " + i + " took " + stopWatch.stop().lastTaskTime());
|
||||
stopWatch.start();
|
||||
}
|
||||
}
|
||||
|
||||
client.admin().indices().prepareRefresh("index").execute().actionGet();
|
||||
} catch (Exception e) {
|
||||
System.out.println("Index already exists, skipping index creation");
|
||||
}
|
||||
|
||||
ClusterHealthResponse clusterHealthResponse = client.admin().cluster().prepareHealth().setWaitForGreenStatus().setTimeout("10m").execute().actionGet();
|
||||
if (clusterHealthResponse.isTimedOut()) {
|
||||
System.err.println("--> Timed out waiting for cluster health");
|
||||
}
|
||||
|
||||
for (int i = 0; i < WARM + RUNS; ++i) {
|
||||
if (i >= WARM) {
|
||||
System.out.println("RUN " + (i - WARM));
|
||||
}
|
||||
for (String field : new String[] {"low_card_str_value", "low_card_str_value.hash", "high_card_str_value", "high_card_str_value.hash", "low_card_num_value", "high_card_num_value"}) {
|
||||
long start = System.nanoTime();
|
||||
SearchResponse resp = null;
|
||||
for (int j = 0; j < ITERS; ++j) {
|
||||
resp = client.prepareSearch("index").setSearchType(SearchType.COUNT).addAggregation(cardinality("cardinality").field(field)).execute().actionGet();
|
||||
}
|
||||
long end = System.nanoTime();
|
||||
final long cardinality = ((Cardinality) resp.getAggregations().get("cardinality")).getValue();
|
||||
if (i >= WARM) {
|
||||
System.out.println(field + "\t" + new TimeValue((end - start) / ITERS, TimeUnit.NANOSECONDS) + "\tcardinality=" + cardinality);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch 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.
|
||||
*/
|
||||
|
||||
package org.elasticsearch.common.hashing;
|
||||
|
||||
import com.google.common.hash.HashCode;
|
||||
import com.google.common.hash.Hashing;
|
||||
import org.elasticsearch.common.hash.MurmurHash3;
|
||||
import org.elasticsearch.test.ElasticsearchTestCase;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.LongBuffer;
|
||||
|
||||
public class MurmurHash3Tests extends ElasticsearchTestCase {
|
||||
|
||||
public void testHash128() {
|
||||
final int iters = atLeast(100);
|
||||
for (int i = 0; i < iters; ++i) {
|
||||
final int seed = randomInt();
|
||||
final int offset = randomInt(20);
|
||||
final int len = randomInt(randomBoolean() ? 20 : 200);
|
||||
final byte[] bytes = new byte[len + offset + randomInt(3)];
|
||||
getRandom().nextBytes(bytes);
|
||||
HashCode h1 = Hashing.murmur3_128(seed).hashBytes(bytes, offset, len);;
|
||||
MurmurHash3.Hash128 h2 = MurmurHash3.hash128(bytes, offset, len, seed, new MurmurHash3.Hash128());
|
||||
assertEquals(h1, h2);
|
||||
}
|
||||
}
|
||||
|
||||
private void assertEquals(HashCode h1, MurmurHash3.Hash128 h2) {
|
||||
final LongBuffer longs = ByteBuffer.wrap(h1.asBytes()).order(ByteOrder.LITTLE_ENDIAN).asLongBuffer();
|
||||
assertEquals(2, longs.limit());
|
||||
assertEquals(h1.asLong(), h2.h1);
|
||||
assertEquals(longs.get(), h2.h1);
|
||||
assertEquals(longs.get(), h2.h2);
|
||||
}
|
||||
|
||||
}
|
|
@ -144,6 +144,27 @@ public class BigArraysTests extends ElasticsearchTestCase {
|
|||
array.release();
|
||||
}
|
||||
|
||||
public void testByteArrayFill() {
|
||||
final int len = randomIntBetween(1, 100000);
|
||||
final int fromIndex = randomIntBetween(0, len - 1);
|
||||
final int toIndex = randomBoolean()
|
||||
? Math.min(fromIndex + randomInt(100), len) // single page
|
||||
: randomIntBetween(fromIndex, len); // likely multiple pages
|
||||
final ByteArray array2 = bigArrays.newByteArray(len, randomBoolean());
|
||||
final byte[] array1 = new byte[len];
|
||||
for (int i = 0; i < len; ++i) {
|
||||
array1[i] = randomByte();
|
||||
array2.set(i, array1[i]);
|
||||
}
|
||||
final byte rand = randomByte();
|
||||
Arrays.fill(array1, fromIndex, toIndex, rand);
|
||||
array2.fill(fromIndex, toIndex, rand);
|
||||
for (int i = 0; i < len; ++i) {
|
||||
assertEquals(array1[i], array2.get(i), 0.001d);
|
||||
}
|
||||
array2.release();
|
||||
}
|
||||
|
||||
public void testFloatArrayFill() {
|
||||
final int len = randomIntBetween(1, 100000);
|
||||
final int fromIndex = randomIntBetween(0, len - 1);
|
||||
|
|
|
@ -0,0 +1,431 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch 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.
|
||||
*/
|
||||
|
||||
package org.elasticsearch.search.aggregations.metrics;
|
||||
|
||||
import org.elasticsearch.action.index.IndexRequestBuilder;
|
||||
import org.elasticsearch.action.search.SearchResponse;
|
||||
import org.elasticsearch.common.settings.ImmutableSettings;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
|
||||
import org.elasticsearch.search.aggregations.metrics.cardinality.Cardinality;
|
||||
import org.elasticsearch.test.ElasticsearchIntegrationTest;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
|
||||
import static org.elasticsearch.search.aggregations.AggregationBuilders.cardinality;
|
||||
import static org.elasticsearch.search.aggregations.AggregationBuilders.terms;
|
||||
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertSearchResponse;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.greaterThan;
|
||||
import static org.hamcrest.core.IsNull.notNullValue;
|
||||
|
||||
public class CardinalityTests extends ElasticsearchIntegrationTest {
|
||||
|
||||
@Override
|
||||
public Settings indexSettings() {
|
||||
return ImmutableSettings.builder()
|
||||
.put("index.number_of_shards", between(1, 5))
|
||||
.put("index.number_of_replicas", between(0, 1))
|
||||
.build();
|
||||
}
|
||||
|
||||
long numDocs;
|
||||
long precisionThreshold;
|
||||
|
||||
@Before
|
||||
public void init() throws Exception {
|
||||
|
||||
prepareCreate("idx").addMapping("type",
|
||||
jsonBuilder().startObject().startObject("type").startObject("properties")
|
||||
.startObject("str_value")
|
||||
.field("type", "string")
|
||||
.startObject("fields")
|
||||
.startObject("hash")
|
||||
.field("type", "murmur3")
|
||||
.endObject()
|
||||
.endObject()
|
||||
.endObject()
|
||||
.startObject("str_values")
|
||||
.field("type", "string")
|
||||
.startObject("fields")
|
||||
.startObject("hash")
|
||||
.field("type", "murmur3")
|
||||
.endObject()
|
||||
.endObject()
|
||||
.endObject()
|
||||
.startObject("l_value")
|
||||
.field("type", "long")
|
||||
.startObject("fields")
|
||||
.startObject("hash")
|
||||
.field("type", "murmur3")
|
||||
.endObject()
|
||||
.endObject()
|
||||
.endObject()
|
||||
.startObject("l_values")
|
||||
.field("type", "long")
|
||||
.startObject("fields")
|
||||
.startObject("hash")
|
||||
.field("type", "murmur3")
|
||||
.endObject()
|
||||
.endObject()
|
||||
.endObject()
|
||||
.startObject("d_value")
|
||||
.field("type", "double")
|
||||
.startObject("fields")
|
||||
.startObject("hash")
|
||||
.field("type", "murmur3")
|
||||
.endObject()
|
||||
.endObject()
|
||||
.endObject()
|
||||
.startObject("d_values")
|
||||
.field("type", "double")
|
||||
.startObject("fields")
|
||||
.startObject("hash")
|
||||
.field("type", "murmur3")
|
||||
.endObject()
|
||||
.endObject()
|
||||
.endObject()
|
||||
.endObject()
|
||||
.endObject().endObject()).execute().actionGet();
|
||||
|
||||
numDocs = randomIntBetween(2, 100);
|
||||
precisionThreshold = randomIntBetween(0, 1 << randomInt(20));
|
||||
IndexRequestBuilder[] builders = new IndexRequestBuilder[(int) numDocs];
|
||||
for (int i = 0; i < numDocs; ++i) {
|
||||
builders[i] = client().prepareIndex("idx", "type").setSource(jsonBuilder()
|
||||
.startObject()
|
||||
.field("str_value", "s" + i)
|
||||
.field("str_values", new String[]{"s" + (i * 2), "s" + (i * 2 + 1)})
|
||||
.field("l_value", i)
|
||||
.field("l_values", new int[] {i * 2, i * 2 + 1})
|
||||
.field("d_value", i)
|
||||
.field("d_values", new double[]{i * 2, i * 2 + 1})
|
||||
.endObject());
|
||||
}
|
||||
indexRandom(true, builders);
|
||||
createIndex("idx_unmapped");
|
||||
ensureSearchable();
|
||||
}
|
||||
|
||||
private void assertCount(Cardinality count, long value) {
|
||||
if (value <= precisionThreshold) {
|
||||
// linear counting should be picked, and should be accurate
|
||||
assertEquals(value, count.getValue());
|
||||
} else {
|
||||
// error is not bound, so let's just make sure it is > 0
|
||||
assertThat(count.getValue(), greaterThan(0L));
|
||||
}
|
||||
}
|
||||
private String singleNumericField(boolean hash) {
|
||||
return (randomBoolean() ? "l_value" : "d_value") + (hash ? ".hash" : "");
|
||||
}
|
||||
|
||||
private String multiNumericField(boolean hash) {
|
||||
return (randomBoolean() ? "l_values" : "d_values") + (hash ? ".hash" : "");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void unmapped() throws Exception {
|
||||
SearchResponse response = client().prepareSearch("idx_unmapped").setTypes("type")
|
||||
.addAggregation(cardinality("cardinality").precisionThreshold(precisionThreshold).field("str_value"))
|
||||
.execute().actionGet();
|
||||
|
||||
assertSearchResponse(response);
|
||||
|
||||
Cardinality count = response.getAggregations().get("cardinality");
|
||||
assertThat(count, notNullValue());
|
||||
assertThat(count.getName(), equalTo("cardinality"));
|
||||
assertCount(count, 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void partiallyUnmapped() throws Exception {
|
||||
SearchResponse response = client().prepareSearch("idx", "idx_unmapped").setTypes("type")
|
||||
.addAggregation(cardinality("cardinality").precisionThreshold(precisionThreshold).field("str_value"))
|
||||
.execute().actionGet();
|
||||
|
||||
assertSearchResponse(response);
|
||||
|
||||
Cardinality count = response.getAggregations().get("cardinality");
|
||||
assertThat(count, notNullValue());
|
||||
assertThat(count.getName(), equalTo("cardinality"));
|
||||
assertCount(count, numDocs);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void singleValuedString() throws Exception {
|
||||
SearchResponse response = client().prepareSearch("idx").setTypes("type")
|
||||
.addAggregation(cardinality("cardinality").precisionThreshold(precisionThreshold).field("str_value"))
|
||||
.execute().actionGet();
|
||||
|
||||
assertSearchResponse(response);
|
||||
|
||||
Cardinality count = response.getAggregations().get("cardinality");
|
||||
assertThat(count, notNullValue());
|
||||
assertThat(count.getName(), equalTo("cardinality"));
|
||||
assertCount(count, numDocs);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void singleValuedStringHashed() throws Exception {
|
||||
SearchResponse response = client().prepareSearch("idx").setTypes("type")
|
||||
.addAggregation(cardinality("cardinality").precisionThreshold(precisionThreshold).field("str_value.hash"))
|
||||
.execute().actionGet();
|
||||
|
||||
assertSearchResponse(response);
|
||||
|
||||
Cardinality count = response.getAggregations().get("cardinality");
|
||||
assertThat(count, notNullValue());
|
||||
assertThat(count.getName(), equalTo("cardinality"));
|
||||
assertCount(count, numDocs);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void singleValuedNumeric() throws Exception {
|
||||
SearchResponse response = client().prepareSearch("idx").setTypes("type")
|
||||
.addAggregation(cardinality("cardinality").precisionThreshold(precisionThreshold).field(singleNumericField(false)))
|
||||
.execute().actionGet();
|
||||
|
||||
assertSearchResponse(response);
|
||||
|
||||
Cardinality count = response.getAggregations().get("cardinality");
|
||||
assertThat(count, notNullValue());
|
||||
assertThat(count.getName(), equalTo("cardinality"));
|
||||
assertCount(count, numDocs);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void singleValuedNumericHashed() throws Exception {
|
||||
SearchResponse response = client().prepareSearch("idx").setTypes("type")
|
||||
.addAggregation(cardinality("cardinality").precisionThreshold(precisionThreshold).field(singleNumericField(true)))
|
||||
.execute().actionGet();
|
||||
|
||||
assertSearchResponse(response);
|
||||
|
||||
Cardinality count = response.getAggregations().get("cardinality");
|
||||
assertThat(count, notNullValue());
|
||||
assertThat(count.getName(), equalTo("cardinality"));
|
||||
assertCount(count, numDocs);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void multiValuedString() throws Exception {
|
||||
SearchResponse response = client().prepareSearch("idx").setTypes("type")
|
||||
.addAggregation(cardinality("cardinality").precisionThreshold(precisionThreshold).field("str_values"))
|
||||
.execute().actionGet();
|
||||
|
||||
assertSearchResponse(response);
|
||||
|
||||
Cardinality count = response.getAggregations().get("cardinality");
|
||||
assertThat(count, notNullValue());
|
||||
assertThat(count.getName(), equalTo("cardinality"));
|
||||
assertCount(count, numDocs * 2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void multiValuedStringHashed() throws Exception {
|
||||
SearchResponse response = client().prepareSearch("idx").setTypes("type")
|
||||
.addAggregation(cardinality("cardinality").precisionThreshold(precisionThreshold).field("str_values.hash"))
|
||||
.execute().actionGet();
|
||||
|
||||
assertSearchResponse(response);
|
||||
|
||||
Cardinality count = response.getAggregations().get("cardinality");
|
||||
assertThat(count, notNullValue());
|
||||
assertThat(count.getName(), equalTo("cardinality"));
|
||||
assertCount(count, numDocs * 2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void multiValuedNumeric() throws Exception {
|
||||
SearchResponse response = client().prepareSearch("idx").setTypes("type")
|
||||
.addAggregation(cardinality("cardinality").precisionThreshold(precisionThreshold).field(multiNumericField(false)))
|
||||
.execute().actionGet();
|
||||
|
||||
assertSearchResponse(response);
|
||||
|
||||
Cardinality count = response.getAggregations().get("cardinality");
|
||||
assertThat(count, notNullValue());
|
||||
assertThat(count.getName(), equalTo("cardinality"));
|
||||
assertCount(count, numDocs * 2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void multiValuedNumericHashed() throws Exception {
|
||||
SearchResponse response = client().prepareSearch("idx").setTypes("type")
|
||||
.addAggregation(cardinality("cardinality").precisionThreshold(precisionThreshold).field(multiNumericField(true)))
|
||||
.execute().actionGet();
|
||||
|
||||
assertSearchResponse(response);
|
||||
|
||||
Cardinality count = response.getAggregations().get("cardinality");
|
||||
assertThat(count, notNullValue());
|
||||
assertThat(count.getName(), equalTo("cardinality"));
|
||||
assertCount(count, numDocs * 2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void singleValuedStringScript() throws Exception {
|
||||
SearchResponse response = client().prepareSearch("idx").setTypes("type")
|
||||
.addAggregation(cardinality("cardinality").precisionThreshold(precisionThreshold).script("doc['str_value'].value"))
|
||||
.execute().actionGet();
|
||||
|
||||
assertSearchResponse(response);
|
||||
|
||||
Cardinality count = response.getAggregations().get("cardinality");
|
||||
assertThat(count, notNullValue());
|
||||
assertThat(count.getName(), equalTo("cardinality"));
|
||||
assertCount(count, numDocs);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void multiValuedStringScript() throws Exception {
|
||||
SearchResponse response = client().prepareSearch("idx").setTypes("type")
|
||||
.addAggregation(cardinality("cardinality").precisionThreshold(precisionThreshold).script("doc['str_values'].values"))
|
||||
.execute().actionGet();
|
||||
|
||||
assertSearchResponse(response);
|
||||
|
||||
Cardinality count = response.getAggregations().get("cardinality");
|
||||
assertThat(count, notNullValue());
|
||||
assertThat(count.getName(), equalTo("cardinality"));
|
||||
assertCount(count, numDocs * 2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void singleValuedNumericScript() throws Exception {
|
||||
SearchResponse response = client().prepareSearch("idx").setTypes("type")
|
||||
.addAggregation(cardinality("cardinality").precisionThreshold(precisionThreshold).script("doc['" + singleNumericField(false) + "'].value"))
|
||||
.execute().actionGet();
|
||||
|
||||
assertSearchResponse(response);
|
||||
|
||||
Cardinality count = response.getAggregations().get("cardinality");
|
||||
assertThat(count, notNullValue());
|
||||
assertThat(count.getName(), equalTo("cardinality"));
|
||||
assertCount(count, numDocs);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void multiValuedNumericScript() throws Exception {
|
||||
SearchResponse response = client().prepareSearch("idx").setTypes("type")
|
||||
.addAggregation(cardinality("cardinality").precisionThreshold(precisionThreshold).script("doc['" + multiNumericField(false) + "'].values"))
|
||||
.execute().actionGet();
|
||||
|
||||
assertSearchResponse(response);
|
||||
|
||||
Cardinality count = response.getAggregations().get("cardinality");
|
||||
assertThat(count, notNullValue());
|
||||
assertThat(count.getName(), equalTo("cardinality"));
|
||||
assertCount(count, numDocs * 2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void singleValuedStringValueScript() throws Exception {
|
||||
SearchResponse response = client().prepareSearch("idx").setTypes("type")
|
||||
.addAggregation(cardinality("cardinality").precisionThreshold(precisionThreshold).field("str_value").script("_value"))
|
||||
.execute().actionGet();
|
||||
|
||||
assertSearchResponse(response);
|
||||
|
||||
Cardinality count = response.getAggregations().get("cardinality");
|
||||
assertThat(count, notNullValue());
|
||||
assertThat(count.getName(), equalTo("cardinality"));
|
||||
assertCount(count, numDocs);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void multiValuedStringValueScript() throws Exception {
|
||||
SearchResponse response = client().prepareSearch("idx").setTypes("type")
|
||||
.addAggregation(cardinality("cardinality").precisionThreshold(precisionThreshold).field("str_values").script("_value"))
|
||||
.execute().actionGet();
|
||||
|
||||
assertSearchResponse(response);
|
||||
|
||||
Cardinality count = response.getAggregations().get("cardinality");
|
||||
assertThat(count, notNullValue());
|
||||
assertThat(count.getName(), equalTo("cardinality"));
|
||||
assertCount(count, numDocs * 2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void singleValuedNumericValueScript() throws Exception {
|
||||
SearchResponse response = client().prepareSearch("idx").setTypes("type")
|
||||
.addAggregation(cardinality("cardinality").precisionThreshold(precisionThreshold).field(singleNumericField(false)).script("_value"))
|
||||
.execute().actionGet();
|
||||
|
||||
assertSearchResponse(response);
|
||||
|
||||
Cardinality count = response.getAggregations().get("cardinality");
|
||||
assertThat(count, notNullValue());
|
||||
assertThat(count.getName(), equalTo("cardinality"));
|
||||
assertCount(count, numDocs);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void multiValuedNumericValueScript() throws Exception {
|
||||
SearchResponse response = client().prepareSearch("idx").setTypes("type")
|
||||
.addAggregation(cardinality("cardinality").precisionThreshold(precisionThreshold).field(multiNumericField(false)).script("_value"))
|
||||
.execute().actionGet();
|
||||
|
||||
assertSearchResponse(response);
|
||||
|
||||
Cardinality count = response.getAggregations().get("cardinality");
|
||||
assertThat(count, notNullValue());
|
||||
assertThat(count.getName(), equalTo("cardinality"));
|
||||
assertCount(count, numDocs * 2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void asSubAgg() throws Exception {
|
||||
SearchResponse response = client().prepareSearch("idx").setTypes("type")
|
||||
.addAggregation(terms("terms").field("str_value").subAggregation(cardinality("cardinality").precisionThreshold(precisionThreshold).field("str_values")))
|
||||
.execute().actionGet();
|
||||
|
||||
assertSearchResponse(response);
|
||||
|
||||
Terms terms = response.getAggregations().get("terms");
|
||||
for (Terms.Bucket bucket : terms.getBuckets()) {
|
||||
Cardinality count = bucket.getAggregations().get("cardinality");
|
||||
assertThat(count, notNullValue());
|
||||
assertThat(count.getName(), equalTo("cardinality"));
|
||||
assertCount(count, 2);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void asSubAggHashed() throws Exception {
|
||||
SearchResponse response = client().prepareSearch("idx").setTypes("type")
|
||||
.addAggregation(terms("terms").field("str_value").subAggregation(cardinality("cardinality").precisionThreshold(precisionThreshold).field("str_values.hash")))
|
||||
.execute().actionGet();
|
||||
|
||||
assertSearchResponse(response);
|
||||
|
||||
Terms terms = response.getAggregations().get("terms");
|
||||
for (Terms.Bucket bucket : terms.getBuckets()) {
|
||||
Cardinality count = bucket.getAggregations().get("cardinality");
|
||||
assertThat(count, notNullValue());
|
||||
assertThat(count.getName(), equalTo("cardinality"));
|
||||
assertCount(count, 2);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,137 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch 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.
|
||||
*/
|
||||
|
||||
package org.elasticsearch.search.aggregations.metrics.cardinality;
|
||||
|
||||
import com.carrotsearch.hppc.IntOpenHashSet;
|
||||
import com.carrotsearch.hppc.hash.MurmurHash3;
|
||||
import org.elasticsearch.common.util.BigArrays;
|
||||
import org.elasticsearch.test.ElasticsearchTestCase;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.elasticsearch.search.aggregations.metrics.cardinality.HyperLogLogPlusPlus.MAX_PRECISION;
|
||||
import static org.elasticsearch.search.aggregations.metrics.cardinality.HyperLogLogPlusPlus.MIN_PRECISION;
|
||||
import static org.hamcrest.Matchers.closeTo;
|
||||
|
||||
public class HyperLogLogPlusPlusTests extends ElasticsearchTestCase {
|
||||
|
||||
@Test
|
||||
public void encodeDecode() {
|
||||
final int iters = atLeast(100000);
|
||||
// random hashes
|
||||
for (int i = 0; i < iters; ++i) {
|
||||
final int p1 = randomIntBetween(4, 24);
|
||||
final long hash = randomLong();
|
||||
testEncodeDecode(p1, hash);
|
||||
}
|
||||
// special cases
|
||||
for (int p1 = MIN_PRECISION; p1 <= MAX_PRECISION; ++p1) {
|
||||
testEncodeDecode(p1, 0);
|
||||
testEncodeDecode(p1, 1);
|
||||
testEncodeDecode(p1, ~0L);
|
||||
}
|
||||
}
|
||||
|
||||
private void testEncodeDecode(int p1, long hash) {
|
||||
final long index = HyperLogLogPlusPlus.index(hash, p1);
|
||||
final int runLen = HyperLogLogPlusPlus.runLen(hash, p1);
|
||||
final int encoded = HyperLogLogPlusPlus.encodeHash(hash, p1);
|
||||
assertEquals(index, HyperLogLogPlusPlus.decodeIndex(encoded, p1));
|
||||
assertEquals(runLen, HyperLogLogPlusPlus.decodeRunLen(encoded, p1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void accuracy() {
|
||||
final long bucket = randomInt(20);
|
||||
final int numValues = randomIntBetween(1, 1000000);
|
||||
final int maxValue = randomIntBetween(1, randomBoolean() ? 1000: 1000000);
|
||||
final int p = randomIntBetween(14, MAX_PRECISION);
|
||||
IntOpenHashSet set = new IntOpenHashSet();
|
||||
HyperLogLogPlusPlus e = new HyperLogLogPlusPlus(p, BigArrays.NON_RECYCLING_INSTANCE, 1);
|
||||
for (int i = 0; i < numValues; ++i) {
|
||||
final int n = randomInt(maxValue);
|
||||
set.add(n);
|
||||
final long hash = MurmurHash3.hash((long) n);
|
||||
e.collect(bucket, hash);
|
||||
if (randomInt(100) == 0) {
|
||||
//System.out.println(e.cardinality(bucket) + " <> " + set.size());
|
||||
assertThat((double) e.cardinality(bucket), closeTo(set.size(), 0.1 * set.size()));
|
||||
}
|
||||
}
|
||||
assertThat((double) e.cardinality(bucket), closeTo(set.size(), 0.1 * set.size()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void merge() {
|
||||
final int p = randomIntBetween(MIN_PRECISION, MAX_PRECISION);
|
||||
final HyperLogLogPlusPlus single = new HyperLogLogPlusPlus(p, BigArrays.NON_RECYCLING_INSTANCE, 0);
|
||||
final HyperLogLogPlusPlus[] multi = new HyperLogLogPlusPlus[randomIntBetween(2, 100)];
|
||||
final long[] bucketOrds = new long[multi.length];
|
||||
for (int i = 0; i < multi.length; ++i) {
|
||||
bucketOrds[i] = randomInt(20);
|
||||
multi[i] = new HyperLogLogPlusPlus(p, BigArrays.NON_RECYCLING_INSTANCE, 5);
|
||||
}
|
||||
final int numValues = randomIntBetween(1, 100000);
|
||||
final int maxValue = randomIntBetween(1, randomBoolean() ? 1000: 1000000);
|
||||
for (int i = 0; i < numValues; ++i) {
|
||||
final int n = randomInt(maxValue);
|
||||
final long hash = MurmurHash3.hash((long) n);
|
||||
single.collect(0, hash);
|
||||
// use a gaussian so that all instances don't collect as many hashes
|
||||
final int index = (int) (Math.pow(randomDouble(), 2));
|
||||
multi[index].collect(bucketOrds[index], hash);
|
||||
if (randomInt(100) == 0) {
|
||||
HyperLogLogPlusPlus merged = new HyperLogLogPlusPlus(p, BigArrays.NON_RECYCLING_INSTANCE, 0);
|
||||
for (int j = 0; j < multi.length; ++j) {
|
||||
merged.merge(0, multi[j], bucketOrds[j]);
|
||||
}
|
||||
assertEquals(single.cardinality(0), merged.cardinality(0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void fakeHashes() {
|
||||
// hashes with lots of leading zeros trigger different paths in the code that we try to go through here
|
||||
final int p = randomIntBetween(MIN_PRECISION, MAX_PRECISION);
|
||||
final HyperLogLogPlusPlus counts = new HyperLogLogPlusPlus(p, BigArrays.NON_RECYCLING_INSTANCE, 0);
|
||||
|
||||
counts.collect(0, 0);
|
||||
assertEquals(1, counts.cardinality(0));
|
||||
if (randomBoolean()) {
|
||||
counts.collect(0, 1);
|
||||
assertEquals(2, counts.cardinality(0));
|
||||
}
|
||||
counts.upgradeToHll(0);
|
||||
// all hashes felt into the same bucket so hll would expect a count of 1
|
||||
assertEquals(1, counts.cardinality(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void precisionFromThreshold() {
|
||||
assertEquals(4, HyperLogLogPlusPlus.precisionFromThreshold(0));
|
||||
assertEquals(6, HyperLogLogPlusPlus.precisionFromThreshold(10));
|
||||
assertEquals(10, HyperLogLogPlusPlus.precisionFromThreshold(100));
|
||||
assertEquals(13, HyperLogLogPlusPlus.precisionFromThreshold(1000));
|
||||
assertEquals(16, HyperLogLogPlusPlus.precisionFromThreshold(10000));
|
||||
assertEquals(18, HyperLogLogPlusPlus.precisionFromThreshold(100000));
|
||||
assertEquals(18, HyperLogLogPlusPlus.precisionFromThreshold(1000000));
|
||||
}
|
||||
|
||||
}
|
|
@ -298,6 +298,11 @@ public class MockBigArrays extends BigArrays {
|
|||
in.set(index, buf, offset, len);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fill(long fromIndex, long toIndex, byte value) {
|
||||
in.fill(fromIndex, toIndex, value);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class IntArrayWrapper extends AbstractArrayWrapper implements IntArray {
|
||||
|
|
Loading…
Reference in New Issue