J'exécute une requête sur mon instance de base de données Cosmos et je reçois parfois 0 résultat, alors que je sais que je devrais obtenir des résultats.

        var options = new QueryRequestOptions()
        {
            MaxItemCount = 25
        };
        var query = @"
                    select c.id,c.callTime,c.direction,c.action,c.result,c.duration,c.hasR,c.hasV,c.callersIndexed,c.callers,c.files
                    from c
                    where
                    c.ownerId=@ownerId
                    and c.callTime>=@dateFrom
                    and c.callTime<=@dateTo
                    and (CONTAINS(c.phoneNums_s, @name)
                    or CONTAINS(c.names_s, @name)
                    or CONTAINS(c.xNums_s, @name))
                    order by c.callTime desc";
        var queryIterator = container.GetItemQueryIterator<CallIndex>(new QueryDefinition(query)
        .WithParameter("@ownerId", "62371255008")
        .WithParameter("@name", "harr")
        .WithParameter("@dateFrom", dateFrom) // 5/30/2020 5:00:00 AM +00:00
        .WithParameter("@dateTo", dateTo) // 8/29/2020 4:59:59 AM +00:00
        .WithParameter("@xnum", null), requestOptions: options, continuationToken: null);
        if (queryIterator.HasMoreResults)
        {
            var feed = queryIterator.ReadNextAsync().Result;
            model.calls = feed.ToList(); //feed.Resource is empty; feed.Count is 0;
            model.CosmosContinuationToken = feed.ContinuationToken; //feed.ContinuationToken is populated with a large token value, indicating that there are more results, even though this fetch returned 0 items.
            model.TotalRecords = feed.Count(); // 0
        }

Comme vous pouvez le voir, même si j'ai reçu 0 résultat, le jeton de continuation indique qu'il y a plus de données après cette première demande. Et, après avoir inspecté visuellement les données directement dans la base de données (explorateur de données dans le portail Azure), je vois les enregistrements qui devraient correspondre, mais ils ne se trouvent pas dans cette requête. Pour tester davantage, j'ai exécuté la même requête exacte quelques secondes plus tard et j'ai reçu les résultats:

        var query = @"
                    select c.id,c.callTime,c.direction,c.action,c.result,c.duration,c.hasR,c.hasV,c.callersIndexed,c.callers,c.files
                    from c
                    where
                    c.ownerId=@ownerId
                    and c.callTime>=@dateFrom
                    and c.callTime<=@dateTo
                    and (CONTAINS(c.phoneNums_s, @name)
                    or CONTAINS(c.names_s, @name)
                    or CONTAINS(c.xNums_s, @name))
                    order by c.callTime desc";
        var queryIterator = container.GetItemQueryIterator<CallIndex>(new QueryDefinition(query)
        .WithParameter("@ownerId", "62371255008")
        .WithParameter("@name", "harr")
        .WithParameter("@dateFrom", dateFrom) // 5/30/2020 5:00:00 AM +00:00
        .WithParameter("@dateTo", dateTo) // 8/29/2020 4:59:59 AM +00:00
        .WithParameter("@xnum", null), requestOptions: options, continuationToken: null);
        if (queryIterator.HasMoreResults)
        {
            var feed = queryIterator.ReadNextAsync().Result;
            model.calls = feed.ToList(); //feed.Resource has 25 items; feed.Count is 25;
            model.CosmosContinuationToken = feed.ContinuationToken; //feed.ContinuationToken is populated, but it is considerably smaller than the token I received from the first request.
            model.TotalRecords = feed.Count(); // 25
        }

C'est la requête exacte comme avant, mais cette fois le feed m'a donné les résultats que j'attendais. Cela s'est produit plus d'une fois et continue de se produire par intermittence. Qu'est-ce que ça donne? S'agit-il d'un bogue dans Azure Cosmos? Si tel est le cas, cela semble être un bug sérieux qui brise les fonctionnalités de base de Cosmos (et des bases de données en général).

Ou est-ce prévu? Est-il possible que dans la première requête, je doive continuer vers ReadNextAsync jusqu'à ce que j'obtienne des résultats en utilisant le jeton de continuation?

Toute aide est appréciée, car cela brise les fonctionnalités très basiques de mon application.

De plus, je voudrais ajouter que les données renvoyées par la requête n'ont pas été nouvellement ajoutées entre le moment de ma première tentative de requête et ma deuxième tentative de requête. Ces données existent depuis un certain temps.

0
Matt Spinks 29 août 2020 à 00:06

2 réponses

Meilleure réponse

Votre code est correct, vous devez vider la vérification de la requête HasMoreResults (même si je changerais le .Result par await pour éviter un éventuel blocage). Ce qui peut arriver dans les requêtes entre partitions, c'est que vous pourriez obtenir une page vide si les partitions initiales vérifiées pour les résultats n'en ont pas.

Parfois, les requêtes peuvent avoir des pages vides même lorsqu'il y a des résultats sur une page future. Les raisons pourraient être:

  • Le SDK peut effectuer plusieurs appels réseau.
  • La requête peut prendre du temps pour récupérer les documents.

Référence: https://docs.microsoft. com / azure / cosmos-db / troubleshoot-query-performance # common-sdk-issues

2
Matias Quaranta 29 août 2020 à 17:52

Essayez d'utiliser le code ci-dessous:

Méthode de requête Cosmos DB:

public async Task<DocDbQueryResult> QueryCollectionBaseWithPagingInternalAsync(FeedOptions feedOptions, string queryString, IDictionary<string, object> queryParams, string collectionName)
        {
            string continuationToken = feedOptions.RequestContinuation;
            List<JObject> documents = new List<JObject>();
            IDictionary<string, object> properties = new Dictionary<string, object>();
            int executionCount = 0;
            double requestCharge = default(double);
            double totalRequestCharge = default(double);

            do
            {
                feedOptions.RequestContinuation = continuationToken;
                var query = this.documentDbClient.CreateDocumentQuery<JObject>(
                    UriFactory.CreateDocumentCollectionUri(this.databaseName, collectionName),
                    new SqlQuerySpec
                    {
                        QueryText = queryString,
                        Parameters = ToSqlQueryParamterCollection(queryParams),
                    },
                    feedOptions)
                .AsDocumentQuery();

                var response = await query.ExecuteNextAsync<JObject>().ConfigureAwait(false);
                documents.AddRange(response.AsEnumerable());
                executionCount++;
                requestCharge = executionCount == 1 ? response.RequestCharge : requestCharge;
                totalRequestCharge += response.RequestCharge;
                continuationToken = response.ResponseContinuation;
            }
            while (!string.IsNullOrWhiteSpace(continuationToken) && documents.Count < feedOptions.MaxItemCount);

            var pagedDocuments = documents.Take(feedOptions.MaxItemCount.Value);
            var result = new DocDbQueryResult
            {
                ResultSet = new JArray(pagedDocuments),
                TotalResults = Convert.ToInt32(pagedDocuments.Count()),
                ContinuationToken = continuationToken
            };

            // if query params are not null, use existing query params also to be passed as properties.
            if (queryParams != null)
            {
                properties = queryParams;
            }

            properties.Add("TotalRequestCharge", totalRequestCharge);
            properties.Add("ExecutionCount", executionCount);

            return result;
        }

Méthode ToSqlQueryParamterCollection:

private static SqlParameterCollection ToSqlQueryParamtereCollection(IDictionary<string, object> queryParams)
        {
            var coll = new SqlParameterCollection();
            if (queryParams != null)
            {
                foreach (var paramKey in queryParams.Keys)
                {
                    coll.Add(new SqlParameter(paramKey, queryParams[paramKey]));
                }
            }

            return coll;
        }
0
singhh-msft 29 août 2020 à 10:26