You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何限制Microsoft Search API范围至Word/PDF及解决DriveItem无DriveId问题

问题描述

背景

我正在编写基于Microsoft Search API的逻辑,用于查找匹配查询条件的SharePoint文档(支持短语搜索与关键词搜索)。

存在的问题

  1. 返回结果不仅包含SharePoint/OneDrive文档,还包含Teams消息记录等内容,需要将搜索范围限定为Word文档或PDF等指定类型。
  2. 部分返回的DriveItem缺失DriveId,而后续调用Graph API获取文件内容需要该ID。

环境/配置

使用MS Graph 1.0,csproj文件中的引用如下:

<PackageReference Include="AutoMapper" Version="12.0.1" />
<PackageReference Include="AutoMapper.Extensions.Microsoft.DependencyInjection" Version="12.0.1" />
<PackageReference Include="Azure.Identity" Version="1.9.0" />
<PackageReference Include="Microsoft.Azure.Functions.Extensions" Version="1.1.0" />
<PackageReference Include="Microsoft.NET.Sdk.Functions" Version="4.1.1" />
<PackageReference Include="Microsoft.Azure.Services.AppAuthentication" Version="1.6.0" />
<PackageReference Include="Microsoft.Graph" Version="5.18.0" />
<PackageReference Include="Microsoft.Graph.Core" Version="3.0.9" />
<PackageReference Include="Microsoft.Identity.Client" Version="4.54.1" />  

代码

函数应用核心逻辑:

public async Task<string> Search()
{
    var ApplicationClientID = Environment.GetEnvironmentVariable("CLIENT_ID");
    var ApplicationClientSecret = Environment.GetEnvironmentVariable("CLIENT_SECRET");
    var AzureTenantID = Environment.GetEnvironmentVariable("TENANT_ID");
    string[] scopes = new[] { "https://graph.microsoft.com/.default" };

    // using Azure.Identity;
    var options = new ClientSecretCredentialOptions
    {
        AuthorityHost = AzureAuthorityHosts.AzurePublicCloud,
    };

    try
    {
        var clientSecretCredential = new ClientSecretCredential(
            AzureTenantID, ApplicationClientID, ApplicationClientSecret, options);
        var graphClient = new GraphServiceClient(clientSecretCredential, scopes, "https://graph.microsoft.com/v1.0");
        Console.WriteLine($"searchQuery :{searchQuery}");
        var requestBody = new Microsoft.Graph.Search.Query.QueryPostRequestBody
        {
            Requests = new List<SearchRequest>
                {
                    new SearchRequest
                    {
                        EntityTypes = new List<EntityType?>
                        {
                            EntityType.DriveItem,
                        },
                        Query = new SearchQuery
                        {
                            QueryString = this.searchQuery,
                        },
                        Fields = new List<string>
                        {
                            "driveId",
                            "listItemId",
                            "author",
                            "title",
                            "url",
                            "rank"
                        },
                        QueryAlterationOptions = new SearchAlterationOptions
                        {
                            EnableSuggestion = true,
                            EnableModification = true,
                        }
                        , Region ="US"
                    },
                },
        };

     
        var searchResults = await graphClient.Search.Query.PostAsync(requestBody).ConfigureAwait(false);
        //return searchResults;
        var jsonResults = ExtractDriveItemDetails(searchResults);
        return jsonResults;
    }
    catch (Exception ex)
    {
        log.LogError(ex.Message);
        return null;
    }
}

提取结果的方法:

private static string ExtractDriveItemDetails(Microsoft.Graph.Search.Query.QueryResponse searchResults)
{
    List<System.Collections.Generic.Dictionary<string, string?>> listOfDriveItems = new List<System.Collections.Generic.Dictionary<string, string?>>();

    // Iterate through all the items in searchResults
    foreach (var hitContainer in searchResults.Value.SelectMany(result => result.HitsContainers))
    {
        foreach (var hit in hitContainer.Hits)
        {
            // Check if the resource is a DriveItem
            if (hit.Resource is DriveItem driveItem)
            {
                var driveItemDetails = new Dictionary<string, string?>();

                // Get the AdditionalData dictionary from the driveItem
                var additionalData = driveItem.ListItem.Fields.AdditionalData;

                // Use TryGetValue to safely access the values and handle null or missing keys
                string? driveId;
                if (additionalData.TryGetValue("driveId", out var driveIdValue) && driveIdValue is string driveIdString)
                {
                    driveId = driveIdString;
                }
                else
                {
                    driveId = null;
                }
                
                driveItemDetails.Add("itemId", driveItem.ListItem.Id.ToString());
                driveItemDetails.Add("title", additionalData["title"] as string);
                driveItemDetails.Add("author", additionalData["author"] as string);
                driveItemDetails.Add("url", additionalData["url"] as string);

                listOfDriveItems.Add(driveItemDetails);
            }
        }
    }

    string json = JsonConvert.SerializeObject(listOfDriveItems);
    return json;
}

解决方案

1. 限定搜索结果为指定文件类型

在搜索查询字符串中添加filetype:筛选运算符,精准指定要返回的文件格式。比如要只返回Word和PDF文档,修改QueryString部分的代码:

Query = new SearchQuery
{
    QueryString = $"{this.searchQuery} filetype:docx OR filetype:pdf",
},

如果需要支持更多格式,直接追加OR filetype:xxx即可,例如filetype:xlsx对应Excel文件、filetype:pptx对应PPT文件。

注:你当前代码已经将EntityTypes设置为DriveItem,这能排除非文档类实体,结合filetype筛选可进一步缩小范围到目标格式。

2. 解决DriveId缺失问题

当前从driveItem.ListItem.Fields.AdditionalData取driveId的方式不可靠,可通过以下两种方案获取稳定的DriveId:

方案一:直接从DriveItem的ParentReference属性获取

DriveItem自带的ParentReference.DriveId是官方推荐的可靠来源,修改提取逻辑:

string? driveId = driveItem.ParentReference?.DriveId;

方案二:从文件URL解析

如果ParentReference也无DriveId,可从文件的WebUrl中提取,SharePoint/OneDrive文件URL通常包含/drives/{driveId}/片段,用正则解析:

string? driveId = null;
if (!string.IsNullOrEmpty(driveItem.WebUrl))
{
    var match = Regex.Match(driveItem.WebUrl, @"drives/([^/]+)/");
    if (match.Success)
    {
        driveId = match.Groups[1].Value;
    }
}

最后记得把获取到的driveId加入返回字典:

driveItemDetails.Add("driveId", driveId);

内容的提问来源于stack exchange,提问作者dot

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 11:17:09