msgraph-sdk-dotnet icon indicating copy to clipboard operation
msgraph-sdk-dotnet copied to clipboard

post request on search/query can be super slow

Open Bodaway opened this issue 1 year ago • 2 comments

Hi ! I'm having some trouble using the endpoint search/query and I'm looking for some tips and advice to optimize it.

1st problem: Although 2 graph queries are launched in parallel and waited for by a Task.WhenAll the queries are executed one after the other as if they were put in a queue.

2nd problem: Requests on the endpoint search/query can be super slow (3s or more) but this is not constant. The same request can take 3s or 400ms

below is an example of the object sent to the endpoint search. Thanks for your help.

{ "AdditionalData": {}, "BackingStore": { "ReturnOnlyChangedValues": false, "InitializationCompleted": true }, "Requests": [ { "AdditionalData": { "trimDuplicates": true }, "AggregationFilters": null, "Aggregations": null, "BackingStore": { "ReturnOnlyChangedValues": false, "InitializationCompleted": true }, "ContentSources": null, "EnableTopResults": null, "EntityTypes": [ 2 ], "Fields": [ "id", "name", "lastModifiedDateTime", "lastModifiedBy", "webUrl", "createdBy", "parentReference", "remoteItem" ], "From": 0, "OdataType": null, "Query": { "AdditionalData": {}, "BackingStore": { "ReturnOnlyChangedValues": false, "InitializationCompleted": true }, "OdataType": null, "QueryString": "createdby:\"Nestor Wilke\" OR createdby:\"Allan Deyoung\" OR createdby:\"Christie Cline\" OR createdby:\"MOD Administrator\" OR createdby:\"Adele Vance\" OR createdby:\"Diego Siciliani\" OR createdby:\"Brian Johnson (TAILSPIN)\" OR createdby:\"Robert Smitho\" OR createdby:\"Quentin PLA\" AND filetype:(docx OR doc OR xlsx OR xls OR xlsm OR pptx OR ppt OR form OR pdf OR jpg OR png OR heic OR heif OR jpeg OR gif OR tiff OR raw OR svg OR bmp OR mp4 OR avi OR mov OR webm OR mkv OR flv OR wmv OR mpeg OR m4v OR 3gp OR zip OR rar OR tar OR 7z OR gzip OR cab OR one OR onetoc2) AND lastmodifiedtime>2022-01-01 AND lastmodifiedtime<2023-05-05 AND (createdBy<>\"System Account\" AND createdBy<>\"SharePoint App\")", "QueryTemplate": null }, "QueryAlterationOptions": null, "Region": null, "ResultTemplateOptions": null, "SharePointOneDriveOptions": null, "Size": 10, "SortProperties": [ { "AdditionalData": {}, "BackingStore": { "ReturnOnlyChangedValues": false, "InitializationCompleted": true }, "IsDescending": true, "Name": "LastModifiedDateTime", "OdataType": null } ] } ] }

Bodaway avatar May 05 '23 10:05 Bodaway

Thanks for raising this @Bodaway

Any chance you can share samples of the code that it attempted to be executed in parallel?

Also, have you considered using batching to make the requests?

  • https://learn.microsoft.com/en-us/graph/sdks/batch-requests?tabs=csharp#simple-batching-example
  • https://github.com/microsoftgraph/msgraph-sdk-dotnet/blob/dev/docs/upgrade-to-v5.md#batch-requests

andrueastman avatar May 09 '23 09:05 andrueastman

Hello @andrueastman, Thanks for batch idea, but here it's 2 separate functionnal process that i don't want to merge.

    public async Task<Result<MessagePreview[]>> SearchMessages(TextCommand command)
    {
        var messageCommand = new TextCommand(command);
        var teamsMessagesT = SearchTeamsMessages(messageCommand);
        var emailsT =  SearchMails(messageCommand);

        await Task.WhenAll(teamsMessagesT, emailsT);

        var takeMessage = messageCommand.Take > 1 ? (int)Math.Floor(command.Take / 2.0) : messageCommand.Take;
        var takeMails = takeMessage % 2 != 0 ? takeMessage + 1 : messageCommand.Take;

        return (emailsT.Result, teamsMessagesT.Result.IsResultOk())
            .Reduce((t1, t2) => t1.Take(takeMails).Concat(t2.ExtractOkData().Take(takeMessage)).OrderBy(m => m.SentDateTime).ToArray().IsResultOk())
            .Map(mes => Result<MessagePreview[]>.setOk(mes));
    }

graph requests are send in function SearchMails & SearchTeamsMessages at the beginning. The 2 functions call the graph in the same way with differents parameters :


    private async Task<Result<SearchHit[]>> PostSearchQuery(QueryPostRequestBody body)
    {
        try
        {
            QueryResponse? response = await _graphClient.Search.Query.PostAsync(body);

            SearchHit[] hitList = response.Value.SelectMany(response =>
                    response.HitsContainers.SelectMany(container =>
                        container.Hits?.ToArray() ?? Array.Empty<SearchHit>()))
                .ToArray();

            return hitList.IsResultOk();
        }
        catch (Exception ex)
        {
            return Result<SearchHit[]>.setFail(ex);
        }
    }

Some things seem to block the outgoing connection and queue up the send to the graph. I'm looking for the problem but I don't understand why. See screenshots of application insight below

image

237161629-bbc2297e-f4f8-4230-8e0c-adb6c571335d 237161671-f0ca0443-d4a4-4c25-94bc-a602313a443a

Thanks for your help.

Bodaway avatar May 09 '23 16:05 Bodaway