Esempio n. 1
0
        public Func <XArray> CurrentGetter()
        {
            Func <XArray> leftGetter  = _left.CurrentGetter();
            Func <XArray> rightGetter = _right.CurrentGetter();

            return(() => Transform(leftGetter(), rightGetter()));
        }
Esempio n. 2
0
        public Func <XArray> CurrentGetter()
        {
            Func <XArray> numeratorGetter   = _numerator.CurrentGetter();
            Func <XArray> denominatorGetter = _denominator.CurrentGetter();

            return(() => Transform(numeratorGetter(), denominatorGetter()));
        }
Esempio n. 3
0
        public SumAggregator(IXColumn sumOverColumn)
        {
            _sumColumn        = sumOverColumn;
            _sumCurrentGetter = sumOverColumn.CurrentGetter();

            ColumnDetails = new ColumnDetails($"{sumOverColumn.ColumnDetails.Name}.Sum", typeof(long));
        }
Esempio n. 4
0
        public Func <XArray> CurrentGetter()
        {
            Func <XArray> sourceGetter = _column.CurrentGetter();

            int[] remapArray = null;

            return(() => _remapper.Remap(sourceGetter(), ref remapArray));
        }
Esempio n. 5
0
        public Func <XArray> CurrentGetter()
        {
            Func <XArray> sourceGetter = _column.CurrentGetter();

            int[] remapArray = null;

            return(() => sourceGetter().Select(_currentSelector, ref remapArray));
        }
Esempio n. 6
0
        public void SetCurrentSourceIndex(int index)
        {
            IXColumn source = _sources[index];

            if (_isSubscribed && source != null)
            {
                _currentGetter = source.CurrentGetter();
            }
        }
        public Func <XArray> CurrentGetter()
        {
            Func <XArray> getter1 = _column1.CurrentGetter();
            Func <XArray> getter2 = _column2.CurrentGetter();

            return(() =>
            {
                _beforeBatch?.Invoke();
                return Convert(getter1(), getter2());
            });
        }
Esempio n. 8
0
        public Func <XArray> CurrentGetter()
        {
            if (_table.NextCalled)
            {
                throw new AssertFailedException("Column Getters must all be requested before the first Next() call (so callees know what to retrieve).");
            }
            Func <XArray> getter = _column.CurrentGetter();

            return(() =>
            {
                XArray result = getter();
                Assert.AreEqual(_table.CurrentRowCount, result.Count, "Getter must return count matching Table.Next() and Table.CurrentRowCount.");
                return result;
            });
        }
Esempio n. 9
0
 public void SetCurrentSourceIndex(int index)
 {
     if (index < _sources.Count)
     {
         IXColumn source = _sources[index];
         if (_isSubscribed)
         {
             _currentGetter = source?.CurrentGetter() ?? null;
         }
     }
     else
     {
         _currentGetter = null;
     }
 }
Esempio n. 10
0
        public Func <XArray> CurrentGetter()
        {
            Func <XArray> sourceGetter = _column.CurrentGetter();

            if (ValuesGetter() != null)
            {
                // Get values mapped and replace values array with the converted array
                return(() => sourceGetter().ReplaceValues(_convertedValues));
            }
            else
            {
                // Otherwise, convert from the underlying current getter
                return(() => _converter(sourceGetter()));
            }
        }
Esempio n. 11
0
        public Join(IXTable source, string joinFromColumn, IXTable joinToSource, string joinToColumn, string joinSidePrefix)
        {
            if (source == null)
            {
                throw new ArgumentNullException("source");
            }

            _source       = source;
            _joinToSource = joinToSource;

            // Request the JoinFromColumn Getter
            IXColumn joinFrom = source.Columns.Find(joinFromColumn);

            _joinColumnType       = joinFrom.ColumnDetails.Type;
            _joinFromColumnGetter = joinFrom.CurrentGetter();

            // Request the JoinToColumn Reader (we'll need it cached)
            _joinToColumn = _joinToSource.Columns.Find(joinToColumn);
            Type joinToColumnType = _joinToColumn.ColumnDetails.Type;

            if (joinToColumnType != _joinColumnType)
            {
                throw new ArgumentException($"Join requires columns of matching types; join from {_joinColumnType.Name} to {joinToColumnType.Name} not supported.");
            }
            _joinToSeekGetter = _joinToColumn.SeekGetter();

            // Build a remapper for left side columns
            _sourceJoinedRowsFilter = new RowRemapper();

            // Build column wrappers
            _columns          = new IXColumn[source.Columns.Count + joinToSource.Columns.Count];
            _rightSideColumns = new SeekedColumn[joinToSource.Columns.Count];

            // Left Side columns are filtered to rows that joined (inner join)
            for (int i = 0; i < source.Columns.Count; ++i)
            {
                _columns[i] = new RemappedColumn(source.Columns[i], _sourceJoinedRowsFilter);
            }

            // Right side columns are seeked to the right side matching rows
            for (int i = 0; i < joinToSource.Columns.Count; ++i)
            {
                SeekedColumn column = new SeekedColumn(RenamedColumn.Build(joinToSource.Columns[i], joinSidePrefix + joinToSource.Columns[i].ColumnDetails.Name));
                _rightSideColumns[i] = column;
                _columns[i + source.Columns.Count] = column;
            }
        }
Esempio n. 12
0
        public Choose(IXTable source, ChooseDirection direction, IXColumn rankColumn, IList <IXColumn> keyColumns)
        {
            if (source == null)
            {
                throw new ArgumentNullException("source");
            }
            _source = source;

            // Build a typed dictionary to handle the rank and key column types
            _dictionary = new ChooseDictionary(direction, rankColumn.ColumnDetails, keyColumns.Select((col) => col.ColumnDetails).ToArray());

            // Retrieve the getters for all columns
            _rankColumnGetter = rankColumn.CurrentGetter();
            _keyColumnGetters = keyColumns.Select((col) => col.CurrentGetter()).ToArray();

            _chosenRowsFilter = new RowRemapper();

            _columns = source.Columns.Select((col) => new RemappedColumn(col, _chosenRowsFilter)).ToArray();
        }
Esempio n. 13
0
        public TermExpression(IXTable source, IXColumn left, CompareOperator op, IXColumn right)
        {
            _evaluate = EvaluateNormal;

            // Save arguments as-is for ToString()
            _left  = left;
            _cOp   = op;
            _right = right;

            // Disallow constant <op> constant [likely error not wrapping column name]
            if (_left is ConstantColumn && _right is ConstantColumn)
            {
                throw new ArgumentException($"({left} {op.ToQueryForm()} {right}) is comparing two constants. Wrap [ColumnNames] in braces.");
            }

            // If the left side is a constant and the operator can be swapped, move it to the right side.
            // Comparers can check if the right side is constant and run a faster loop when that's the case.
            if (_left.IsConstantColumn() && !(_right.IsConstantColumn()))
            {
                if (op.TryInvertCompareOperator(out op))
                {
                    _left  = right;
                    _right = left;
                }
            }

            // Disallow unquoted constants used as strings
            if (_right.IsConstantColumn() && _left.ColumnDetails.Type == typeof(String8) && _right.ColumnDetails.Type == typeof(String8))
            {
                ConstantColumn cRight = _right as ConstantColumn;
                if (cRight != null && !cRight.IsNull && cRight.WasUnwrappedLiteral)
                {
                    throw new ArgumentException($"{right} is compared to a string, but is unquoted. Strings must be quoted.");
                }
            }

            // Convert the right side to the left side type if required
            // This means constants will always be casted to the other side type.
            if (_left.ColumnDetails.Type != _right.ColumnDetails.Type)
            {
                _right = CastedColumn.Build(source, _right, _left.ColumnDetails.Type, ValueKinds.Invalid);
            }

            // Get the left and right getters
            _leftGetter  = _left.CurrentGetter();
            _rightGetter = _right.CurrentGetter();

            // Null comparison is generic
            if (_right.IsNullConstant())
            {
                if (op == CompareOperator.Equal)
                {
                    _comparer = WhereIsNull;
                }
                else if (op == CompareOperator.NotEqual)
                {
                    _comparer = WhereIsNotNull;
                }
                else
                {
                    throw new ArgumentException($"Only equals and not equals operators are supported against null.");
                }
            }
            else if (_left.IsNullConstant())
            {
                _left = _right;
                if (op == CompareOperator.Equal)
                {
                    _comparer = WhereIsNull;
                }
                else if (op == CompareOperator.NotEqual)
                {
                    _comparer = WhereIsNotNull;
                }
                else
                {
                    throw new ArgumentException($"Only equals and not equals operators are supported against null.");
                }
            }
            else
            {
                // Get a comparer which can compare the values
                _comparer = TypeProviderFactory.Get(left.ColumnDetails.Type).TryGetComparer(op);
                if (_comparer == null)
                {
                    throw new ArgumentException($"No comparer found for type {left.ColumnDetails.Type.Name}.");
                }
            }

            // Optimize Enum to Constant comparisons to use the underlying indices
            if (_left.IsEnumColumn() && _right.IsConstantColumn())
            {
                // Get an optimized comparer against the indices rather than values
                IXColumn replacedRight = _right;
                _comparer = SetComparer.ConvertToEnumIndexComparer(_left, _comparer, ref replacedRight, source);

                // Get the indices on the left side
                _leftGetter = _left.IndicesCurrentGetter();

                // Use the updated value for the right side
                _rightGetter = replacedRight.CurrentGetter();
            }

            // Allow String8 to constant Contains queries to compare on the raw byte[] and int[]
            if (op == CompareOperator.Contains && _right.IsConstantColumn() && _left.ColumnDetails.Type == typeof(String8) && !_left.IsEnumColumn())
            {
                Func <object> rawGetter = _left.ComponentGetter(ColumnComponent.String8Raw);

                if (rawGetter != null)
                {
                    String8         rightValue      = (String8)_right.ValuesGetter()().Array.GetValue(0);
                    String8Comparer string8Comparer = new String8Comparer();

                    _evaluate = (vector) =>
                    {
                        String8Raw raw = (String8Raw)rawGetter();
                        string8Comparer.WhereContains(raw, rightValue, vector);
                    };
                }
            }
        }
Esempio n. 14
0
 public Func <XArray> CurrentGetter()
 {
     return(_column.CurrentGetter());
 }
Esempio n. 15
0
        /// <summary>
        ///  Build a GroupBy Dictionary for Peek.
        /// </summary>
        /// <remarks>
        ///  Peek identifies each distinct common value and the approximate percentage of rows with it.
        ///  If we have many matching rows, we can sample - the sample will have any common values in it.
        ///  However, we don't know how many matches we have in advance.
        ///  Therefore, we build a Dictionary of all rows, 1/8 of rows, 1/64 of rows, and 1/512 of rows.
        ///  As soon as a given sample has enough samples to be statistically valid, we stop collecting the larger subsets.
        ///  This strategy allows us to run the overall query only once, end up with a large enough sample, and avoid building giant Dictionaries.
        /// </remarks>
        /// <param name="cancellationToken">CancellationToken to request early stop</param>
        private void BuildDictionary(CancellationToken cancellationToken)
        {
            // Short-circuit path if there's one key column and it's an EnumColumn
            if (_column.IsEnumColumn())
            {
                BuildSingleEnumColumnDictionary(cancellationToken);
                return;
            }

            // Build a Random instance to sample rows
            Random r = new Random();

            // Build a Dictionary and CountAggregator for each sample
            GroupByDictionary[] dictionaries = new GroupByDictionary[SampleCount];
            CountAggregator[]   counts       = new CountAggregator[SampleCount];
            int[][]             remapArrays  = new int[SampleCount][];
            for (int i = 0; i < SampleCount; ++i)
            {
                dictionaries[i] = new GroupByDictionary(new ColumnDetails[] { _column.ColumnDetails });
                counts[i]       = new CountAggregator();
            }

            // Retrieve the column getter
            Func <XArray> columnGetter = _column.CurrentGetter();

            // Track which sample we'll currently report
            int currentSample = 0;

            XArray[] arrays = new XArray[1];
            int      count;

            while ((count = _source.Next(XTableExtensions.DefaultBatchSize, cancellationToken)) != 0)
            {
                // Get the column values
                arrays[0] = columnGetter();

                // Build the GroupBy count for all rows and successive 1/8 samples
                for (int i = 0; i < SampleCount; ++i)
                {
                    // Add these to the Join Dictionary
                    if (i >= currentSample)
                    {
                        // Choose buckets for each row
                        XArray indicesForRows = dictionaries[i].FindOrAdd(arrays);

                        // Identify the bucket for each row and aggregate them
                        counts[i].Add(indicesForRows, dictionaries[i].Count);

                        // If this sample now has enough values, stop collecting bigger row sets
                        if (currentSample == i - 1 && counts[i].TotalRowCount > RequiredSampleSize)
                        {
                            // If every row was unique, stop early and don't set outputs (zero rows)
                            if (ShouldStopEarly(dictionaries[currentSample], counts[currentSample]))
                            {
                                return;
                            }

                            dictionaries[currentSample] = null;
                            counts[currentSample]       = null;
                            currentSample++;
                        }
                    }

                    // Each successive dictionary has ~1/8 of the rows of the previous one
                    if (i < SampleCount - 1)
                    {
                        ArraySelector sample = Sampler.Eighth(arrays[0].Selector, r, ref remapArrays[i]);
                        arrays[0] = arrays[0].Reselect(sample);
                    }
                }
            }

            // Once the loop is done, get the distinct values and aggregation results
            PostSortAndFilter(dictionaries[currentSample].DistinctKeys()[0], counts[currentSample].Values, counts[currentSample].TotalRowCount, currentSample == 0);
        }