private async Task IndexDocumentsAsync(IReadOnlyCollection <T> documents)
        {
            if (HasMultipleIndexes)
            {
                foreach (var documentGroup in documents.GroupBy(TimeSeriesType.GetDocumentIndex))
                {
                    await TimeSeriesType.EnsureIndexAsync(documentGroup.First()).AnyContext();
                }
            }

            if (documents.Count == 1)
            {
                var document = documents.Single();
                var response = await _client.IndexAsync(document, i => {
                    i.Type(ElasticType.Name);

                    if (GetParentIdFunc != null)
                    {
                        i.Parent(GetParentIdFunc(document));
                    }

                    if (GetDocumentIndexFunc != null)
                    {
                        i.Index(GetDocumentIndexFunc(document));
                    }

                    if (HasVersion)
                    {
                        var versionDoc = (IVersioned)document;
                        i.Version(versionDoc.Version);
                    }

                    return(i);
                }).AnyContext();

                _logger.Trace(() => response.GetRequest());
                if (!response.IsValid)
                {
                    string message = response.GetErrorMessage();
                    _logger.Error().Exception(response.ConnectionStatus.OriginalException).Message(message).Property("request", response.GetRequest()).Write();
                    throw new ApplicationException(message, response.ConnectionStatus.OriginalException);
                }

                if (HasVersion)
                {
                    var versionDoc = (IVersioned)document;
                    versionDoc.Version = response.Version != null?Int64.Parse(response.Version) : -1;
                }
            }
            else
            {
                var response = await _client.IndexManyAsync(documents, GetParentIdFunc, GetDocumentIndexFunc, ElasticType.Name).AnyContext();

                _logger.Trace(() => response.GetRequest());
                if (HasVersion)
                {
                    foreach (var hit in response.Items)
                    {
                        var document = documents.FirstOrDefault(d => d.Id == hit.Id);
                        if (document == null)
                        {
                            continue;
                        }

                        var versionDoc = (IVersioned)document;
                        if (hit.Version != null)
                        {
                            versionDoc.Version = Int64.Parse(hit.Version);
                        }
                    }
                }

                if (!response.IsValid)
                {
                    string message = response.GetErrorMessage();
                    _logger.Error().Exception(response.ConnectionStatus.OriginalException).Message(message).Property("request", response.GetRequest()).Write();
                    throw new ApplicationException(message, response.ConnectionStatus.OriginalException);
                }
            }
        }
        public async Task RemoveAsync(IEnumerable <T> documents, bool sendNotification = true)
        {
            var docs = documents?.ToList();

            if (docs == null || docs.Any(d => d == null))
            {
                throw new ArgumentNullException(nameof(documents));
            }

            if (docs.Count == 0)
            {
                return;
            }

            if (HasMultipleIndexes)
            {
                foreach (var documentGroup in docs.GroupBy(TimeSeriesType.GetDocumentIndex))
                {
                    await TimeSeriesType.EnsureIndexAsync(documentGroup.First()).AnyContext();
                }
            }

            await OnDocumentsRemovingAsync(docs).AnyContext();

            // TODO: support Parent and child docs.
            if (docs.Count == 1)
            {
                var document = docs.First();
                var response = await _client.DeleteAsync(document, descriptor => descriptor.Index(GetDocumentIndexFunc?.Invoke(document)).Type(ElasticType.Name)).AnyContext();

                _logger.Trace(() => response.GetRequest());

                if (!response.IsValid)
                {
                    string message = response.GetErrorMessage();
                    _logger.Error().Exception(response.ConnectionStatus.OriginalException).Message(message).Property("request", response.GetRequest()).Write();
                    throw new ApplicationException(message, response.ConnectionStatus.OriginalException);
                }
            }
            else
            {
                var documentsByIndex = docs.GroupBy(d => GetDocumentIndexFunc?.Invoke(d));
                var response         = await _client.BulkAsync(bulk => {
                    foreach (var group in documentsByIndex)
                    {
                        bulk.DeleteMany <T>(group.Select(g => g.Id), (b, id) => b.Index(group.Key).Type(ElasticType.Name));
                    }

                    return(bulk);
                }).AnyContext();

                _logger.Trace(() => response.GetRequest());

                if (!response.IsValid)
                {
                    string message = response.GetErrorMessage();
                    _logger.Error().Exception(response.ConnectionStatus.OriginalException).Message(message).Property("request", response.GetRequest()).Write();
                    throw new ApplicationException(message, response.ConnectionStatus.OriginalException);
                }
            }

            await OnDocumentsRemovedAsync(docs, sendNotification).AnyContext();
        }