コード例 #1
0
        public AggregationResult Compute(Partition p)
        {
            if (p == null)
            {
                throw new ArgumentNullException("p");
            }

            Stopwatch         w      = Stopwatch.StartNew();
            AggregationResult result = new AggregationResult(this);

            result.AggregationContext = this.Aggregator.CreateContext();

            // Get any columns passed to the aggregation function
            IUntypedColumn[] columns = null;
            if (this.AggregationColumns != null)
            {
                columns = new IUntypedColumn[this.AggregationColumns.Length];

                for (int i = 0; i < this.AggregationColumns.Length; ++i)
                {
                    string columnName = this.AggregationColumns[i];

                    if (!p.Columns.TryGetValue(columnName, out columns[i]))
                    {
                        result.Details.AddError(ExecutionDetails.ColumnDoesNotExist, columnName);
                        return(result);
                    }
                }
            }

            // Find the number of dimensions and number of "cells" for which we'll aggregate
            List <string> resultBlockColumns = new List <string>();
            int           rowCount           = 1;

            for (int i = 0; i < this.Dimensions.Count; ++i)
            {
                AggregationDimension dimension = this.Dimensions[i];

                if (!String.IsNullOrEmpty(dimension.Name))
                {
                    resultBlockColumns.Add(dimension.Name);
                }
                else
                {
                    resultBlockColumns.Add(StringExtensions.Format("Dimension {0}", i + 1));
                }

                rowCount *= (dimension.GroupByWhere.Count + 1);
            }

            resultBlockColumns.Add("Aggregate");

            // Create the DataBlock to hold the final results
            result.Values = new DataBlock(resultBlockColumns, rowCount);

            // Find the set of items in the base query
            ShortSet baseWhereSet = new ShortSet(p.Count);

            this.Where.TryEvaluate(p, baseWhereSet, result.Details);
            result.Total = baseWhereSet.Count();

            // If this is only one dimension, use only one ShortSet and aggregate as we go
            if (this.Dimensions.Count == 1)
            {
                AggregationDimension dimension       = this.Dimensions[0];
                ShortSet             setForDimension = new ShortSet(p.Count);
                int nextBlockRow = 0;

                foreach (IExpression dimensionValue in dimension.GroupByWhere)
                {
                    // Get the set for this value intersected with the base set
                    setForDimension.Clear();
                    dimensionValue.TryEvaluate(p, setForDimension, result.Details);
                    setForDimension.And(baseWhereSet);

                    // Compute and store the aggregate value
                    if (!setForDimension.IsEmpty())
                    {
                        result.Values[nextBlockRow, 1] = this.Aggregator.Aggregate(result.AggregationContext, setForDimension, columns);
                    }

                    nextBlockRow++;
                }

                // Add the total
                result.Values[nextBlockRow, 1] = this.Aggregator.Aggregate(result.AggregationContext, baseWhereSet, columns);
            }
            else
            {
                // Compute the set of items actually matching each dimension-value
                List <List <Tuple <IExpression, ShortSet> > > allDimensionValueSets = new List <List <Tuple <IExpression, ShortSet> > >();
                foreach (AggregationDimension dimension in this.Dimensions)
                {
                    List <Tuple <IExpression, ShortSet> > dimensionSet = new List <Tuple <IExpression, ShortSet> >();

                    // Add one item for each value in this dimension
                    foreach (IExpression dimensionValue in dimension.GroupByWhere)
                    {
                        ShortSet setForDimensionValue = new ShortSet(p.Count);
                        dimensionValue.TryEvaluate(p, setForDimensionValue, result.Details);

                        dimensionSet.Add(new Tuple <IExpression, ShortSet>(dimensionValue, setForDimensionValue));
                    }

                    // Add one 'Total row' item
                    dimensionSet.Add(new Tuple <IExpression, ShortSet>(new AllExpression(), baseWhereSet));

                    allDimensionValueSets.Add(dimensionSet);
                }

                // Run the aggregator over the items
                AggregateAllDimensionsFlat(result.AggregationContext, result.Values, p.Count, baseWhereSet, allDimensionValueSets, columns, this.Aggregator);
            }

            // Add the dimension names to the result if this is the only partition; otherwise, merge will add it
            if (p.Mask.Equals(PartitionMask.All))
            {
                AddDimensionsToBlock(result.Values);
            }

            // Capture timing and return
            result.Runtime = w.Elapsed;
            return(result);
        }
コード例 #2
0
        private static void AggregateAllDimensionsFlat(object aggregationContext, DataBlock block, ushort itemCount, ShortSet baseWhereSet, List <List <Tuple <IExpression, ShortSet> > > allDimensionValueSets, IUntypedColumn[] columns, IAggregator aggregator)
        {
            int nextBlockRow = 0;

            int dimensionCount = allDimensionValueSets.Count;

            int currentDimension = 0;

            int[]      nextIndexPerDimension = new int[dimensionCount];
            ShortSet[] setsPerDimension      = new ShortSet[dimensionCount + 1];

            setsPerDimension[0] = baseWhereSet;
            for (int i = 1; i < setsPerDimension.Length; ++i)
            {
                setsPerDimension[i] = new ShortSet(itemCount);
            }

            object[] aggregationResults = new object[block.RowCount];

            while (currentDimension >= 0)
            {
                if (currentDimension == dimensionCount)
                {
                    // Leaf: Compute Aggregate, then ask for next combination
                    aggregationResults[nextBlockRow] = aggregator.Aggregate(aggregationContext, setsPerDimension[currentDimension], columns);
                    nextBlockRow++;
                    currentDimension--;
                }
                else if (nextIndexPerDimension[currentDimension] < allDimensionValueSets[currentDimension].Count)
                {
                    // Non-leaf, more values: Get next value and combine
                    Tuple <IExpression, ShortSet> dimensionValue = allDimensionValueSets[currentDimension][nextIndexPerDimension[currentDimension]];

                    ShortSet current = setsPerDimension[currentDimension + 1];
                    current.FromAnd(setsPerDimension[currentDimension], dimensionValue.Item2);

                    nextIndexPerDimension[currentDimension]++;
                    currentDimension++;

                    // Skip rest of range if set already empty [slower; IsEmpty too expensive]
                    if (current.IsEmpty())
                    {
                        int rowsToSkip = 1;
                        for (int i = currentDimension; i < dimensionCount; ++i)
                        {
                            rowsToSkip *= allDimensionValueSets[i].Count;
                        }

                        nextBlockRow += rowsToSkip;
                        currentDimension--;
                    }
                }
                else
                {
                    // Non-leaf, no more values: Pop up to previous dimension for next value there
                    nextIndexPerDimension[currentDimension] = 0;
                    currentDimension--;
                }
            }

            block.SetColumn(block.ColumnCount - 1, aggregationResults);
        }
コード例 #3
0
        public virtual object Aggregate(object context, ShortSet matches, IUntypedColumn[] columns)
        {
            if (columns == null || columns.Length < 1)
            {
                throw new ArgumentException(StringExtensions.Format("At least one column must be passed to {0}.", this.GetType().Name));
            }
            if (matches == null)
            {
                throw new ArgumentNullException("matches");
            }
            if (matches.IsEmpty())
            {
                return(DefaultValue);
            }

            // Enumerate set once and get values once, avoiding any per-item method calls
            ushort[] items    = matches.Values;
            Array    values   = columns[0].GetValues(items);
            Type     itemType = columns[0].ColumnType;

            // Cast to a specific type at the array level to avoid per item casting
            if (itemType.Equals(typeof(long)))
            {
                return(AggregateLong((long[])values));
            }
            else if (itemType.Equals(typeof(int)))
            {
                return(AggregateInt((int[])values));
            }
            else if (itemType.Equals(typeof(short)))
            {
                return(AggregateShort((short[])values));
            }
            else if (itemType.Equals(typeof(byte)))
            {
                return(AggregateByte((byte[])values));
            }
            else if (itemType.Equals(typeof(ulong)))
            {
                return(AggregateULong((ulong[])values));
            }
            else if (itemType.Equals(typeof(uint)))
            {
                return(AggregateUInt((uint[])values));
            }
            else if (itemType.Equals(typeof(ushort)))
            {
                return(AggregateUShort((ushort[])values));
            }
            else if (itemType.Equals(typeof(double)))
            {
                return(AggregateDouble((double[])values));
            }
            else if (itemType.Equals(typeof(float)))
            {
                return(AggregateFloat((float[])values));
            }
            else if (itemType.Equals(typeof(DateTime)))
            {
                return(AggregateDateTime((DateTime[])values));
            }
            else if (itemType.Equals(typeof(TimeSpan)))
            {
                return(AggregateTimeSpan((TimeSpan[])values));
            }
            else if (itemType.Equals(typeof(Guid)))
            {
                return(AggregateGuid((Guid[])values));
            }
            else if (itemType.Equals(typeof(ByteBlock)))
            {
                return(AggregateByteBlock((ByteBlock[])values));
            }
            else
            {
                throw new NotImplementedException(StringExtensions.Format("{0} is unable to aggregate type {1}.", this.GetType().Name, values.GetValue(0).GetType().Name));
            }
        }