Beispiel #1
0
        /// <summary>
        ///     Merges the given CardinalityEstimator instances and returns the result
        /// </summary>
        /// <param name="estimators">Instances of CardinalityEstimator</param>
        /// <returns>The merged CardinalityEstimator</returns>
        public static CardinalityEstimator Merge(IList <CardinalityEstimator> estimators)
        {
            if (!estimators.Any())
            {
                throw new ArgumentException(string.Format("Was asked to merge 0 instances of {0}", typeof(CardinalityEstimator)),
                                            "estimators");
            }

            var ans = new CardinalityEstimator(estimators[0].bitsPerIndex);

            foreach (CardinalityEstimator estimator in estimators)
            {
                ans.Merge(estimator);
            }

            return(ans);
        }
        /// <summary>
        ///     Merges the given CardinalityEstimator instances and returns the result
        /// </summary>
        /// <param name="estimators">Instances of CardinalityEstimator</param>
        /// <returns>The merged CardinalityEstimator</returns>
        public static CardinalityEstimator Merge(IList <CardinalityEstimator> estimators)
        {
            if (!estimators.Any())
            {
                throw new ArgumentException($"Was asked to merge 0 instances of {typeof(CardinalityEstimator)}",
                                            nameof(estimators));
            }

            var ans = new CardinalityEstimator(estimators[0]._bitsPerIndex);

            foreach (CardinalityEstimator estimator in estimators)
            {
                ans.Merge(estimator);
            }

            return(ans);
        }
        /// <summary>
        ///     Serialize the given <paramref name="cardinalityEstimator" /> to <paramref name="stream" />
        /// </summary>
        public void Serialize(Stream stream, CardinalityEstimator cardinalityEstimator)
        {
            using (var bw = new BinaryWriter(stream))
            {
                bw.Write(DataFormatMajorVersion);
                bw.Write(DataFormatMinorVersion);

                CardinalityEstimatorState data = cardinalityEstimator.GetState();

                bw.Write((byte)data.HashFunctionId);
                bw.Write(data.BitsPerIndex);
                bw.Write((byte)(((data.IsSparse ? 1 : 0) << 1) + (data.DirectCount != null ? 1 : 0)));
                if (data.DirectCount != null)
                {
                    bw.Write(data.DirectCount.Count);
                    foreach (ulong element in data.DirectCount)
                    {
                        bw.Write(element);
                    }
                }
                else if (data.IsSparse)
                {
                    bw.Write(data.LookupSparse.Count);
                    foreach (KeyValuePair <ushort, byte> element in data.LookupSparse)
                    {
                        bw.Write(element.Key);
                        bw.Write(element.Value);
                    }
                }
                else
                {
                    bw.Write(data.LookupDense.Length);
                    foreach (byte element in data.LookupDense)
                    {
                        bw.Write(element);
                    }
                }

                bw.Write(data.CountAdditions);
                bw.Flush();
            }
        }
        /// <summary>
        ///     Deserialize a <see cref="CardinalityEstimator" /> from the given <paramref name="stream" />
        /// </summary>
        public CardinalityEstimator Deserialize(Stream stream)
        {
            using (var br = new BinaryReader(stream))
            {
                int dataFormatMajorVersion = br.ReadUInt16();
                int dataFormatMinorVersion = br.ReadUInt16();

                AssertDataVersionCanBeRead(dataFormatMajorVersion, dataFormatMinorVersion);

                HashFunctionId hashFunctionId;
                if (dataFormatMajorVersion >= 2)
                {
                    // Starting with version 2.0, the serializer writes the hash function ID
                    hashFunctionId = (HashFunctionId)br.ReadByte();
                }
                else
                {
                    // Versions before 2.0 all used FNV-1a
                    hashFunctionId = HashFunctionId.Fnv1A;
                }

                int  bitsPerIndex  = br.ReadInt32();
                byte flags         = br.ReadByte();
                bool isSparse      = ((flags & 2) == 2);
                bool isDirectCount = ((flags & 1) == 1);

                HashSet <ulong>            directCount  = null;
                IDictionary <ushort, byte> lookupSparse = isSparse ? new Dictionary <ushort, byte>() : null;
                byte[] lookupDense = null;

                if (isDirectCount)
                {
                    int count = br.ReadInt32();
                    directCount = new HashSet <ulong>();

                    for (var i = 0; i < count; i++)
                    {
                        ulong element = br.ReadUInt64();
                        directCount.Add(element);
                    }
                }
                else if (isSparse)
                {
                    int count = br.ReadInt32();

                    for (var i = 0; i < count; i++)
                    {
                        ushort elementKey   = br.ReadUInt16();
                        byte   elementValue = br.ReadByte();
                        lookupSparse.Add(elementKey, elementValue);
                    }
                }
                else
                {
                    int count = br.ReadInt32();
                    lookupDense = br.ReadBytes(count);
                }

                // Starting with version 2.1, the serializer writes CountAdditions
                ulong countAdditions = 0UL;
                if (dataFormatMajorVersion >= 2 && dataFormatMinorVersion >= 1)
                {
                    countAdditions = br.ReadUInt64();
                }

                var data = new CardinalityEstimatorState
                {
                    HashFunctionId = hashFunctionId,
                    BitsPerIndex   = bitsPerIndex,
                    DirectCount    = directCount,
                    IsSparse       = isSparse,
                    LookupDense    = lookupDense,
                    LookupSparse   = lookupSparse,
                    CountAdditions = countAdditions,
                };

                var result = new CardinalityEstimator(data);

                return(result);
            }
        }
Beispiel #5
0
        /// <summary>
        ///     Merges the given <paramref name="other" /> CardinalityEstimator instance into this one
        /// </summary>
        /// <param name="other">another instance of CardinalityEstimator</param>
        public void Merge(CardinalityEstimator other)
        {
            if (other == null)
            {
                throw new ArgumentNullException("other");
            }

            if (other.m != this.m)
            {
                throw new ArgumentOutOfRangeException("other",
                                                      "Cannot merge CardinalityEstimator instances with different accuracy/map sizes");
            }

            this.CountAdditions += other.CountAdditions;
            if (this.isSparse && other.isSparse)
            {
                // Merge two sparse instances
                foreach (KeyValuePair <ushort, byte> kvp in other.lookupSparse)
                {
                    ushort index     = kvp.Key;
                    byte   otherRank = kvp.Value;
                    byte   thisRank;
                    this.lookupSparse.TryGetValue(index, out thisRank);
                    this.lookupSparse[index] = Math.Max(thisRank, otherRank);
                }

                // Switch to dense if necessary
                if (this.lookupSparse.Count > this.sparseMaxElements)
                {
                    SwitchToDenseRepresentation();
                }
            }
            else
            {
                // Make sure this (target) instance is dense, then merge
                SwitchToDenseRepresentation();
                if (other.isSparse)
                {
                    foreach (KeyValuePair <ushort, byte> kvp in other.lookupSparse)
                    {
                        ushort index = kvp.Key;
                        byte   rank  = kvp.Value;
                        this.lookupDense[index] = Math.Max(this.lookupDense[index], rank);
                    }
                }
                else
                {
                    for (var i = 0; i < this.m; i++)
                    {
                        this.lookupDense[i] = Math.Max(this.lookupDense[i], other.lookupDense[i]);
                    }
                }
            }

            if (other.directCount != null)
            {
                // Other instance is using direct counter. If this instance is also using direct counter, merge them.
                if (this.directCount != null)
                {
                    this.directCount.UnionWith(other.directCount);
                }
            }
            else
            {
                // Other instance is not using direct counter, make sure this instance doesn't either
                this.directCount = null;
            }
        }