搜索和交换中的 EWS

了解如何使用 EWS 托管 API 或 EWS 在 Exchange 中搜索项目。

这听起来是不是很熟悉? 你终于开始了已经推迟了几个星期的项目,你需要有关你的经理几周前通过电子邮件发送给你的项目的信息。 收件箱中包含数百条或数千封邮件。 你是做什么工作的? 是否滚动浏览电子邮件扫描每个主题和发件人,直到找到它? 还是使用喜欢的电子邮件客户端中的搜索功能快速了解所需内容?

搜索可以说是任何电子邮件客户端的必备功能。 但是,除了允许用户搜索其邮箱外,还可以使用搜索。 你的应用是否需要处理特定时间范围内的约会? 也许你需要报告具有特定状态的所有任务项,或者将所有具有特定公司名称的联系人移动到其他文件夹。 搜索有助于满足所有这些要求。

搜索基础知识

EWS 托管 API 和 EWS 提供两种用于指定搜索的基本方法。 可以使用 搜索筛选器查询字符串。 使用的方法取决于搜索背后的意图。

表 1. 搜索筛选器和搜索查询的方案

若要… 使用... 注意
将搜索限制为特定属性或属性集
搜索筛选器
搜索筛选器提供对搜索属性的最佳控制级别。 尽管查询字符串可以通过使用高级查询语法 (AQS) 来面向一组有限的属性,但搜索筛选器可以面向任何属性。
创建具有多个条件的搜索
搜索筛选器
使用搜索筛选器,可以将多个搜索条件与逻辑 AND 或 PR 联接在一起,从而允许搜索“主题包含'会议笔记',发件人等于'Sadie Daniels'”。 尽管查询字符串也可以联接多个搜索条件,但它们仅限于查询字符串支持的属性集。
搜索自定义属性
搜索筛选器
搜索筛选器可以面向自定义属性。 查询字符串不搜索自定义属性。
对字符串属性执行区分大小写的搜索
搜索筛选器
查询字符串搜索不区分大小写。
在搜索字符串属性时控制包含模式
搜索筛选器
查询字符串搜索始终是子字符串搜索。 如果需要搜索特定前缀或需要完全匹配,则搜索筛选器是最佳选择。
搜索文件夹
搜索筛选器
EWS 不支持使用查询字符串搜索文件夹。
创建搜索文件夹
搜索筛选器
EWS 不支持使用查询字符串创建搜索文件夹。
搜索所有常用属性
查询字符串
不包含 AQS 的查询字符串将搜索所有常用属性。 例如,查询字符串值“Mack Chaves”将返回由 Mack Chaves 发送的所有消息,以及正文或主题中包含“Mack Chaves”的任何消息。
基于简单用户输入构造搜索
查询字符串
查询字符串是一个不错的选择,它允许最终用户通过键入简单字符串来执行快速搜索。 由于查询字符串搜索包括所有常用属性,因此结果将包含包含用户搜索词的任何项。

使用搜索筛选器

搜索筛选器提供广泛的搜索选项,并最大程度控制搜索的执行方式。 可以使用搜索筛选器执行基本相等搜索和比较搜索,但也可以在字符串属性的内容中搜索或执行位掩码比较。

例如,可以使用 EWS 托管 API 中的 SearchFilter.ContainsSubstring 类搜索项目主题的内容。 在此示例中,将创建一个搜索筛选器来搜索子字符串“会议笔记”的主题,忽略大小写。

SearchFilter.ContainsSubstring subjectFilter = new SearchFilter.ContainsSubstring(ItemSchema.Subject,
    "meeting notes", ContainmentMode.Substring, ComparisonMode.IgnoreCase);

还可以针对自定义属性进行搜索。 在此示例中,在自定义属性 ItemIndex 中搜索大于 3 的值。

Guid MyAppGuid = new Guid("{AA3DF801-4FC7-401F-BBC1-7C93D6498C2E}");
ExtendedPropertyDefinition customPropDefinition =
    new ExtendedPropertyDefinition(MyAppGuid, "ItemIndex", MapiPropertyType.Integer);
SearchFilter.IsGreaterThan customPropFilter =
    new SearchFilter.IsGreaterThan(customPropDefinition, 3);

还可以组合多个搜索筛选器来创建更复杂的搜索。 例如,可以使用 SearchFilter.SearchFilterCollection 类将前两个筛选器与逻辑 AND 组合在一起。

SearchFilter.SearchFilterCollection compoundFilter =
    new SearchFilter.SearchFilterCollection(LogicalOperator.And, subjectFilter, customPropFilter);

使用查询字符串

查询字符串提供了不同的搜索方法。 使用查询字符串搜索时,对搜索的字段以及搜索执行方式的控制较少。 不是说这是件坏事! 在某些情况下,你可能想要投一个更宽的网,可以说。

例如,可以使用 ExchangeService.FindItems EWS 托管 API 方法搜索“会议笔记”。

FindItemsResults<Item> results = service.FindItems(folder, "meeting notes", view);

如果将此搜索结果与之前 SearchFilter.ContainsSubstring 搜索示例的结果进行比较,则此搜索将包含更多结果。 搜索筛选器搜索将仅返回主题中包含“会议笔记”的项目,而此搜索将返回主题、正文和其他字段中具有“会议笔记”的项目。

让我们看看如何优化查询字符串,以更接近从搜索筛选器看到的结果。 使用 AQS,可以将搜索限制为主题。

FindItemsResults<Item> results = service.FindItems(folder, "subject:meeting notes", view);

这更接近,但结果仍然不完全一样。 使用包含多个字词的查询字符串时,即使这些单词不是按指定的顺序,或者它们彼此不相邻,也会获得匹配项。 使用查询字符串“subject:meeting notes”,你将获得“会议笔记”、“会议笔记”等匹配项。 若要进一步细化,可以将搜索词包装在双引号中,以指示仅需要该短语。

FindItemsResults<Item> results = service.FindItems(folder, "subject:\"meeting notes\"", view);

在搜索结果中请求特定属性

默认情况下,搜索结果将包含与搜索匹配的项上的所有属性。 在某些情况下,这可能是你想要的,但在大多数情况下,应用程序只需要一组离散的属性。 在这种情况下,应将返回的属性集限制为应用程序所需的属性集。 在以下示例中, ItemView 类用于将返回的属性限制为主题、接收的日期/时间以及项的 ID。

ItemView view = new ItemView(10);
// Creating a new PropertySet with this constructor includes
// ItemSchema.Id.
view.PropertySet = new PropertySet(ItemSchema.Subject, ItemSchema.DateTimeReceived);

控制搜索深度

在视图上设置遍历可控制搜索的深度和范围。

表 2. 搜索遍历值

遍历值 应用于 说明

项目和文件夹
浅层搜索仅限于所搜索文件夹的直接子级。

仅 (搜索文件夹) 和文件夹的项目
深层搜索以递归方式搜索正在搜索的文件夹和子文件夹。
相关
项目
关联的搜索仅包括正在搜索的文件夹中的关联项。 关联的项目是文件夹中的隐藏项目。
SoftDeleted
项目和文件夹
此遍历类型已弃用。 SoftDeleted 搜索仅包括转储中的项。 Exchange Online 中的“可恢复项目文件夹”已取代了转储,Exchange Online作为Office 365的一部分,以及从 Exchange 2010 开始的 Exchange 版本。

管理搜索结果

EWS 托管 API 和 EWS 还允许更改搜索结果的返回方式。 可以使用视图指定结果中包含的属性、对结果进行排序和对结果进行分页,以便每个响应仅返回一定数量的结果。 还可以按特定字段值对结果进行分组,并通过指定遍历类型来控制搜索的深度。 最后,可以使用搜索文件夹创建持久搜索,这些搜索会在新项目到达时动态更新。

排序

可以让服务器返回排序结果,这样可以更轻松地按顺序显示或处理项。 在此示例中,结果将按接收的日期/时间排序,最新项排在第一位。

view.OrderBy.Add(ItemSchema.DateTimeReceived, SortDirection.Descending);

分页

使用 EWS 托管 API 或 EWS 发送搜索请求时,可以指定一个视图大小,用于控制返回的最大项数。 但是,服务器上与搜索匹配的项目数可能大于视图大小。 在这种情况下,服务器指示有更多项可用。 可以使用 分页重复搜索 并获取下一组结果。

例如,可以发送视图大小为 10 的搜索请求。 服务器上可能有 15 个项目与搜索匹配,但只会返回前 10 个项目,以及 FindItemsResults<TItem> (指示器。 如果使用的是 EWS 托管 API) 服务器上有更多结果,则 MoreAvailable 属性。 然后,可以发送偏移量为 10 的相同搜索,以请求接下来的 10 项与搜索匹配的项目。 服务器将返回剩余的五个项目。

图 1. 分页搜索示例

此说明显示分页搜索。初始请求是发送 10  封邮件。第二个请求是发送接下来 10 封邮件。

分组

使用 Exchange,可以按特定字段对搜索结果进行分组。 这有助于将搜索结果分解为更易于管理的集。 例如,可以搜索“会议笔记”,并按发件人对结果进行分组。 如下图所示,返回的项目将分为多个组,其中与一个组中同一发件人的条件匹配的所有项、另一个组中另一个发件人的所有匹配项等。

图 2. 按发件人分组的搜索结果

此说明显示根据发件人分组的搜索结果。

搜索结果文件夹

使用常规搜索时,将执行搜索,将结果返回到应用程序进行处理,并且搜索不再存在。 搜索文件夹提供了一种使搜索持久化的方法。 对于要多次执行的搜索,这是一个不错的选择。 搜索文件夹使搜索始终处于打开状态,而不是重复执行同一搜索,导致服务器每次从头开始评估搜索,从而允许服务器在向搜索范围添加或删除项目时更新现有结果集。 搜索文件夹的作用类似于常规文件夹,因为它们显示为包含项目的文件夹。 区别在于,文件夹中包含的唯一项目是与文件夹关联的搜索条件匹配的项目。 创建搜索文件夹后,应用程序只需检查文件夹的内容即可获取最新搜索结果。

掌握创建搜索筛选器后,创建搜索文件夹非常简单。 在以下示例中,将创建一个搜索文件夹,以显示主题包含“会议笔记”的所有电子邮件。

static void CreateSearchFolder(ExchangeService service)
{
    SearchFilter.ContainsSubstring subjectFilter = new SearchFilter.ContainsSubstring(ItemSchema.Subject,
        "meeting notes", ContainmentMode.Substring, ComparisonMode.IgnoreCase);
    SearchFolder searchFolder = new SearchFolder(service);
    searchFolder.DisplayName = "Meeting Notes";
    searchFolder.SearchParameters.RootFolderIds.Add(WellKnownFolderName.Inbox);
    searchFolder.SearchParameters.Traversal = SearchFolderTraversal.Deep;
    searchFolder.SearchParameters.SearchFilter = subjectFilter;
    searchFolder.Save(WellKnownFolderName.SearchFolders);
}

本节内容

另请参阅