搜索和交换中的 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. 分页搜索示例
分组
使用 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);
}