/// <summary>
        /// Get documents from a scroll.
        /// </summary>
        /// <param name="response">Response from a scroll request to Elasticsearch.</param>
        /// <returns>The next set of species observation.</returns>
        private DocumentFilterResponse GetScroll(ElasticsearchResponse <DynamicResponse> response)
        {
            DocumentFilterResponse documentFilterResponse;
            Int32  startIndex, stopIndex;
            String maxScore, shardInformation, documentCount;

            String[] splitShardInformation;

            documentFilterResponse = new DocumentFilterResponse();
            if (response.Body.IsNotNull())
            {
                documentFilterResponse.ElapsedTime = (Int32)(response.Body.Values.ElementAt(1));

                // Get shard information.
                shardInformation      = (String)(response.Body.Values.ElementAt(4));
                splitShardInformation = shardInformation.Split(':');
                documentFilterResponse.ShardTotalCount      = splitShardInformation[1].Substring(0, splitShardInformation[1].IndexOf(',')).WebParseInt32();
                documentFilterResponse.ShardSuccessfulCount = splitShardInformation[2].Substring(0, splitShardInformation[2].IndexOf(',')).WebParseInt32();
                if (documentFilterResponse.ShardSuccessfulCount == documentFilterResponse.ShardTotalCount)
                {
                    documentFilterResponse.ShardFailedCount = splitShardInformation[3].Substring(0, splitShardInformation[3].IndexOf('}')).WebParseInt32();
                }
                else
                {
                    documentFilterResponse.ShardFailedCount = splitShardInformation[3].Substring(0, splitShardInformation[3].IndexOf(',')).WebParseInt32();
                }

                documentFilterResponse.DocumentCount = 0;
                documentFilterResponse.DocumentsJson = (String)(response.Body.Values.ElementAt(5));
                documentFilterResponse.TimedOut      = (Boolean)(response.Body.Values.ElementAt(2));
                if (!documentFilterResponse.TimedOut)
                {
                    // Get species observation count.
                    startIndex    = documentFilterResponse.DocumentsJson.IndexOf(':') + 1;
                    stopIndex     = documentFilterResponse.DocumentsJson.IndexOf(',');
                    documentCount = documentFilterResponse.DocumentsJson.Substring(startIndex, stopIndex - startIndex);
                    documentFilterResponse.DocumentCount = documentCount.WebParseInt64();
                    startIndex = stopIndex + 1;

                    if (documentFilterResponse.DocumentCount > 0)
                    {
                        // Get max score
                        startIndex = documentFilterResponse.DocumentsJson.IndexOf(':', startIndex) + 1;
                        stopIndex  = documentFilterResponse.DocumentsJson.IndexOf(',', startIndex);
                        maxScore   = documentFilterResponse.DocumentsJson.Substring(startIndex, stopIndex - startIndex);
                        if (maxScore != "null")
                        {
                            documentFilterResponse.MaxScore = maxScore.WebParseDouble();
                        }
                    }
                }
            }

            return(documentFilterResponse);
        }
        /// <summary>
        /// Get documents that matches filter.
        /// </summary>
        /// <param name="type">Type name.</param>
        /// <param name="filter">Filter for species observations.</param>
        /// <returns>Documents that matches filter.</returns>
        protected DocumentFilterResponse GetDocuments(String type, String filter)
        {
            ElasticsearchResponse <DynamicResponse> response;
            Int32 startIndex, stopIndex;
            DocumentFilterResponse documentFilterResponse;
            String shardInformation, documentCount;

            String[] splitShardInformation;

            response = _client.Search <DynamicResponse>(IndexName, type, filter, qs => qs.AddQueryString("filter_path", "took,timed_out,_shards,hits.total,hits.hits._source"));
            CheckResponse(response);
            documentFilterResponse = new DocumentFilterResponse();
            if (response.Body.IsNotNull())
            {
                // Get shard information.
                shardInformation      = (String)(response.Body.Values.ElementAt(2));
                splitShardInformation = shardInformation.Split(':');
                documentFilterResponse.ShardTotalCount      = splitShardInformation[1].Substring(0, splitShardInformation[1].IndexOf(',')).WebParseInt32();
                documentFilterResponse.ShardSuccessfulCount = splitShardInformation[2].Substring(0, splitShardInformation[2].IndexOf(',')).WebParseInt32();
                documentFilterResponse.ShardFailedCount     = splitShardInformation[3].Substring(0, splitShardInformation[3].IndexOf('}')).WebParseInt32();

                documentFilterResponse.DocumentCount = 0;
                documentFilterResponse.DocumentsJson = (String)(response.Body.Values.ElementAt(3));
                documentFilterResponse.TimedOut      = (Boolean)(response.Body.Values.ElementAt(1));
                if (!documentFilterResponse.TimedOut)
                {
                    // Get species observation count.
                    startIndex = documentFilterResponse.DocumentsJson.IndexOf(':') + 1;
                    stopIndex  = documentFilterResponse.DocumentsJson.IndexOf(',');
                    if (stopIndex < 0)
                    {
                        // There are no character ',' in the response when 0 documents matched.
                        stopIndex = documentFilterResponse.DocumentsJson.IndexOf('}');
                    }

                    documentCount = documentFilterResponse.DocumentsJson.Substring(startIndex, stopIndex - startIndex);
                    documentFilterResponse.DocumentCount = documentCount.WebParseInt64();
                }

                //Debug.WriteLine("Total document count = " +
                //                documentFilterResponse.DocumentCount +
                //                ", time = " + documentFilterResponse.ElapsedTime + "ms" +
                //                ", timed out = " + documentFilterResponse.TimedOut + ".");
            }

            return(documentFilterResponse);
        }
        /// <summary>
        /// Start scroll of documents that matches search criteria.
        /// </summary>
        /// <param name="type">Type name.</param>
        /// <param name="filter">Filter for species observations.</param>
        /// <param name="scroll">Information about the scroll.</param>
        /// <param name="response">Response from a scroll request to Elasticsearch.</param>
        /// <returns>The first set of species observation.</returns>
        public DocumentFilterResponse StartScroll(String type,
                                                  String filter,
                                                  ElasticsearchScroll scroll)
        {
            ElasticsearchResponse <DynamicResponse> response;
            StringBuilder          scrollInformation;
            DocumentFilterResponse documentFilterResponse;
            Int32  startIndex, stopIndex;
            String maxScore, shardInformation, documentCount;

            String[] splitShardInformation;

            scrollInformation = new StringBuilder();
            scrollInformation.Append("{");
            scrollInformation.Append("\"size\" : 10000");
            scrollInformation.Append(", \"_source\" : {\"include\": [\"DarwinCore_Id\"]}");
            //scrollInformation.Append(", \"_source\" : {\"include\": [\"DarwinCore_Id\", \"Taxon_DyntaxaTaxonID\", \"Taxon_Species_TaxonId\"]}");
            //            scrollInformation.Append(", \"filter\": { \"terms\": { \"Taxon_Species_TaxonId\":[1]}}");
            scrollInformation.Append(", \"sort\" : [\"_doc\"]");
            scrollInformation.Append("}");
            response = _client.Search <DynamicResponse>(IndexName, type, scrollInformation.ToString(), s => s.Scroll(new TimeSpan(0, scroll.KeepAlive, 0)));
            CheckResponse(response);
            scroll.ScrollId        = (String)(response.Body.Values.ElementAt(0));
            documentFilterResponse = new DocumentFilterResponse();
            if (response.Body.IsNotNull())
            {
                documentFilterResponse.ElapsedTime = (Int32)(response.Body.Values.ElementAt(1));

                // Get shard information.
                shardInformation      = (String)(response.Body.Values.ElementAt(3));
                splitShardInformation = shardInformation.Split(':');
                documentFilterResponse.ShardTotalCount      = splitShardInformation[1].Substring(0, splitShardInformation[1].IndexOf(',')).WebParseInt32();
                documentFilterResponse.ShardSuccessfulCount = splitShardInformation[2].Substring(0, splitShardInformation[2].IndexOf(',')).WebParseInt32();
                if (documentFilterResponse.ShardSuccessfulCount == documentFilterResponse.ShardTotalCount)
                {
                    documentFilterResponse.ShardFailedCount = splitShardInformation[3].Substring(0, splitShardInformation[3].IndexOf('}')).WebParseInt32();
                }
                else
                {
                    documentFilterResponse.ShardFailedCount = splitShardInformation[3].Substring(0, splitShardInformation[3].IndexOf(',')).WebParseInt32();
                }

                documentFilterResponse.DocumentCount = 0;
                documentFilterResponse.DocumentsJson = (String)(response.Body.Values.ElementAt(4));
                documentFilterResponse.TimedOut      = (Boolean)(response.Body.Values.ElementAt(2));
                if (!documentFilterResponse.TimedOut)
                {
                    // Get species observation count.
                    startIndex    = documentFilterResponse.DocumentsJson.IndexOf(':') + 1;
                    stopIndex     = documentFilterResponse.DocumentsJson.IndexOf(',');
                    documentCount = documentFilterResponse.DocumentsJson.Substring(startIndex, stopIndex - startIndex);
                    documentFilterResponse.DocumentCount = documentCount.WebParseInt64();
                    startIndex = stopIndex + 1;

                    if (documentFilterResponse.DocumentCount > 0)
                    {
                        // Get max score
                        startIndex = documentFilterResponse.DocumentsJson.IndexOf(':', startIndex) + 1;
                        stopIndex  = documentFilterResponse.DocumentsJson.IndexOf(',', startIndex);
                        maxScore   = documentFilterResponse.DocumentsJson.Substring(startIndex, stopIndex - startIndex);
                        if (maxScore != "null")
                        {
                            documentFilterResponse.MaxScore = maxScore.WebParseDouble();
                        }
                    }
                }
            }

            return(documentFilterResponse);
        }
        /// <summary>
        /// Get documents from a started scroll.
        /// </summary>
        /// <param name="scroll">Information about the scroll.</param>
        public DocumentFilterResponse GetScroll(ElasticsearchScroll scroll)
        {
            DocumentFilterResponse documentFilterResponse;
            ElasticsearchResponse <DynamicResponse> response;
            StringBuilder scrollInformation;
            Int32         startIndex, stopIndex;
            String        maxScore, shardInformation, documentCount;

            String[] splitShardInformation;

            scrollInformation = new StringBuilder();
            scrollInformation.Append("{");
            scrollInformation.Append("\"scroll\" : \"" + scroll.KeepAlive + "m\"");
            scrollInformation.Append(", \"scroll_id\" : \"" + scroll.ScrollId + "\"");
            scrollInformation.Append("}");
            response = _client.Scroll <DynamicResponse>(scrollInformation.ToString());
            CheckResponse(response);
            documentFilterResponse = new DocumentFilterResponse();
            scroll.ScrollId        = (String)(response.Body.Values.ElementAt(0));
            if (response.Body.IsNotNull())
            {
                documentFilterResponse.ElapsedTime = (Int32)(response.Body.Values.ElementAt(1));

                // Get shard information.
                shardInformation      = (String)(response.Body.Values.ElementAt(4));
                splitShardInformation = shardInformation.Split(':');
                documentFilterResponse.ShardTotalCount      = splitShardInformation[1].Substring(0, splitShardInformation[1].IndexOf(',')).WebParseInt32();
                documentFilterResponse.ShardSuccessfulCount = splitShardInformation[2].Substring(0, splitShardInformation[2].IndexOf(',')).WebParseInt32();
                if (documentFilterResponse.ShardSuccessfulCount == documentFilterResponse.ShardTotalCount)
                {
                    documentFilterResponse.ShardFailedCount = splitShardInformation[3].Substring(0, splitShardInformation[3].IndexOf('}')).WebParseInt32();
                }
                else
                {
                    documentFilterResponse.ShardFailedCount = splitShardInformation[3].Substring(0, splitShardInformation[3].IndexOf(',')).WebParseInt32();
                }

                documentFilterResponse.DocumentCount = 0;
                documentFilterResponse.DocumentsJson = (String)(response.Body.Values.ElementAt(5));
                documentFilterResponse.TimedOut      = (Boolean)(response.Body.Values.ElementAt(2));
                if (!documentFilterResponse.TimedOut)
                {
                    // Get species observation count.
                    startIndex    = documentFilterResponse.DocumentsJson.IndexOf(':') + 1;
                    stopIndex     = documentFilterResponse.DocumentsJson.IndexOf(',');
                    documentCount = documentFilterResponse.DocumentsJson.Substring(startIndex, stopIndex - startIndex);
                    documentFilterResponse.DocumentCount = documentCount.WebParseInt64();
                    startIndex = stopIndex + 1;

                    if (documentFilterResponse.DocumentCount > 0)
                    {
                        // Get max score
                        startIndex = documentFilterResponse.DocumentsJson.IndexOf(':', startIndex) + 1;
                        stopIndex  = documentFilterResponse.DocumentsJson.IndexOf(',', startIndex);
                        maxScore   = documentFilterResponse.DocumentsJson.Substring(startIndex, stopIndex - startIndex);
                        if (maxScore != "null")
                        {
                            documentFilterResponse.MaxScore = maxScore.WebParseDouble();
                        }
                    }
                }
            }

            return(documentFilterResponse);
        }