Contains evaluation information
        /// <summary>
        /// First sorts the AutoCompletionList, then performs evaluation.
        /// </summary>
        /// <param name="queryTime"></param>
        /// <param name="partialQuery"></param>
        /// <param name="fullQuery"></param>
        /// <param name="autoCompletionList"></param>
        public void SortAndOutput(EvaluationOutput eo)
        {
            // Try and minimise the dataset first
            eo.AutoCompletionList = new AutoCompletionList(GetTopAutoCompletions(eo.AutoCompletionList)); // Sort the reduced list

            // Changed 9/4/2013 - No longer a highly inefficient sort
            //eo.AutoCompletionList.Sort();

            eo.AutoCompletionList = new AutoCompletionList(eo.AutoCompletionList.Where(x => x != null).Take(4)); // Take the 4 top autocompletions that aren't null TODO: fix null problem

            // Set the ranks on the AutoCompletionList
            eo.AutoCompletionList.SetRanks();

            // Output in the format: runId|prefixLength|queryCount|fullQuery|partialQuery|queryTime|autoCompletionCount|hitRank|isPartialMatch|reciprocalRank|partialReciprocalRank|completionList

            int hitRank = 0;

            // Find the hit rank, if any
            foreach (AutoCompletion autoCompletion in eo.AutoCompletionList)
            {
                if (autoCompletion.QueryCompletion == eo.FullQuery)
                {
                    hitRank = autoCompletion.Rank;
                    break;
                }
            }

            double reciprocalRank = 0;
            if (hitRank > 0)
                reciprocalRank = 1.0 / hitRank;

            eo.ReciprocalRank = reciprocalRank;
            eo.RunIdentifier = _runIdentifier;

            // Update the live MRR
            _evalQueryCount++;
            _totalRR += reciprocalRank;

            if (!_isDebug)
            {
                lock (_outputFileStream)
                    _outputFileStream.WriteLine("{0}\t{1}\t{2}\t{3}\t{4}\t{5}\t{6}\t{7}\t{8}\t{9}\t{10}\t{11}", _runIdentifier, _prefixLength, eo.QueryCount.ToString(), eo.FullQuery, eo.PartialQuery, eo.QueryTime.ToString("yyyy-MM-dd HH:mm:ss"), eo.AutoCompletionList.Count.ToString(), hitRank.ToString(), "null", reciprocalRank, reciprocalRank, String.Join(";", eo.AutoCompletionList));
            }
            else
            {
                // Debug output
                if (OnEvaluationOutput != null)
                    OnEvaluationOutput(eo);
            }
        }
        /// <summary>
        /// Queue the evaluation thread
        /// </summary>
        private void QueueEvaluationThread(DateTime queryTime, string partialQuery, string query, AutoCompletionList autoCompletionList)
        {
            EvaluationOutput eo = new EvaluationOutput(queryTime, partialQuery, query, autoCompletionList, _queryCount);

            if (_isConcurrent)
                _evalThreadPool.QueueWorkItem(_evalOutput.SortAndOutput, eo);
            else
                _evalOutput.SortAndOutput(eo); // Single-threaded only
        }