public NonTemporalBucketApproach(int qMaxFrequency, int qMaxSum, int autoCompleteAfterNChars, StandardEvalOutput evalOutput, PrefixProfile queryPrefixProfile)
     : base(autoCompleteAfterNChars, evalOutput, queryPrefixProfile)
 {
     _qMaxFrequency = qMaxFrequency;
     _qMaxSum = qMaxSum;
     _indexEntries = new Dictionary<string, NonTemporalBucket<BaseIndexEntry>>();
 }
        /// <summary>
        /// MultipleNs must be specified in ascending order for the NTBs
        /// </summary>
        /// <param name="multipleNs"></param>
        /// <param name="multipleMaxSingleQueryN"></param>
        /// <param name="trainAfterNQueriesForPrefix">How many queries to observe between training the ML model (i.e., predict queries in this window of N - OR: 'the prediction horizon'). Note the model won't start training until after (largest NTB size) + (trainAfter parameter) has been reached</param>
        /// <param name="autoCompleteAfterNChars"></param>
        /// <param name="evalOutput"></param>
        /// <param name="queryPrefixProfile"></param>
        public noSGDLRMNTB(int[] multipleNs, int[] multipleMaxSingleQueryN, int trainAfterNQueriesForPrefix, string queryLogFile, int autoCompleteAfterNChars, StandardEvalOutput evalOutput, PrefixProfile queryPrefixProfile, int baseNtbSize = 200)
            : base(autoCompleteAfterNChars, evalOutput, queryPrefixProfile)
        {
            if (multipleNs.Length != multipleMaxSingleQueryN.Length)
                throw new Exception("Must be the same length");

            _trainAfterNQueriesForPrefix = trainAfterNQueriesForPrefix;
            _multipleNs = multipleNs;
            _multipleMaxSingleQueryN = multipleMaxSingleQueryN;
            _ntbs = new Dictionary<string, NonTemporalBucket<BaseIndexEntry>>[multipleNs.Length];
            _trainingNtb = new Dictionary<string, NonTemporalBucket<BaseIndexEntry>>();

            _lrModel = new OnlineSGDNonOverlappingLinearRegressionModel(multipleNs.Length, _multipleNs[0], _trainAfterNQueriesForPrefix);

            for (int i = 0; i < multipleNs.Length; i++)
            {
                _ntbs[i] = new Dictionary<string, NonTemporalBucket<BaseIndexEntry>>();
            }

            _ntbsCreated = new HashSet<string>();

            // Calculate the total number of queries stored across all NTBs (max overall NTB capacity)
            _totalQueriesAcrossAllNTBs = _multipleNs.Sum();

            _overallNtb = new Dictionary<string, NonTemporalBucket<BaseIndexEntry>>();

            _baseNtb = new Dictionary<string, NonTemporalBucket<BaseIndexEntry>>();

            _baseNtbSize = baseNtbSize;
        }
        public BaseApproach(int autoCompleteAfterNChars, StandardEvalOutput evalOutput, PrefixProfile queryPrefixProfile)
        {
            _autoCompleteAfterNChars = autoCompleteAfterNChars;
            _evalOutput = evalOutput;
            _queryPrefixProfile = queryPrefixProfile;

            _evalThreadPool = new SmartThreadPool(1000, 6);
            _evalThreadPool.Start(); // Setup and start the threadpool
        }