如何使用 VLV 进行搜索
Active Directory 支持虚拟列表视图 (VLV) 搜索。 此搜索样式专为大型结果集而设计,可使应用程序显示数千个条目的子集,而无需实际检索每个条目。
VLV 搜索有两种不同的使用方法。 第一种是根据数字偏移量来检索特定条目的属性。 这种方法在响应滚动操作检索搜索结果时非常有用。
使用 VLV 搜索的第二种方法是搜索部分或全部文本属性,并仅显示搜索结果。 通讯簿就是一个示例。 如果用户键入“s”,则应用程序就可以使用 VLV 搜索来搜索以“s”开头的公用名条目。 如果用户随后在“s”后面添加一个“m”,应用程序就可以使用另一个 VLV 搜索来搜索以“sm”开头的公用名条目。
要执行 VLV 搜索,请指示 ADSI 使用 VLV 控件。 为此,请使用 ADS_SEARCHPREF_VLV 搜索选项和 ADSTYPE_PROV_SPECIFIC 值来调用 IDirectorySearch::SetSearchPreference 方法。 ADSTYPE_PROV_SPECIFIC 值是指向 ADS_VLV 结构的指针,该结构包含了有关搜索的数据。 GetVLVItemCount 示例函数展示了如何设置这两种搜索首选项。
所有 VLV 搜索都必须使用服务器端结果排序,这可以通过设置 ADS_SEARCHPREF_SORT_ON 搜索首选项来执行。 有关 ADS_SEARCHPREF_SORT_ON 搜索首选项的更多信息,请参阅使用 IDirectorySearch 对搜索结果排序。
在执行 VLV 搜索时,将通过调用具有 ADS_VLV_RESPONSE 标识符的 IDirectorySearch::GetColumn 在列中返回有关搜索的一定数量的元数据。 该数据包含在 ADS_VLV 结构中。 特别重要的是 dwContentCount 和 lpContextID 成员。 dwContentCount 成员将包含符合 VLV 搜索条件的结果数量。 此值可用于估算该类型搜索返回的项目总数。 lpContextID 成员包含一个服务器定义的值,该值可传递给下一次搜索, 使用 lpContextID 可以增强搜索性能。 请注意,lpContextID 是服务器定义的值,其长度包含在 dwContextIDLength 成员中。 在调用 IDirectorySearch::FreeColumn 方法时会释放该缓冲区,因此调用方必须分配一个适当大小的缓冲区,并在两次搜索之间复制和保存缓冲区的内容。
有关 LDAP VLV 控制的更多信息,请参阅使用 LDAP VLV 控件进行搜索。
有关详细信息,请参阅:
- 获取项目数
- 按偏移量搜索
- 按字符串搜索
- 使用 VLV 搜索的示例代码
获取项目数
要估算特定搜索将返回的项目数,请执行以下步骤。
用所有零值或 NULL 值填充 ADS_VLV 结构。
在 ADS_SEARCHPREF_INFO 中填写以下值。
填写 ADS_SORTKEY 结构,如使用 IDirectorySearch 对搜索结果排序中所示,以便根据所需属性进行排序。
填写另一个 ADS_SEARCHPREF_INFO 将 ADS_SORTKEY 结构添加到搜索首选项中,如使用 IDirectorySearch 对搜索结果排序中所示。
添加任何其他所需的搜索首选项,并调用 IDirectorySearch::SetSearchPreference 以设置搜索首选项。
使用 IDirectorySearch::ExecuteSearch 执行搜索。
通过调用 IDirectorySearch::GetFirstRow 来获取第一行结果。
使用 ADS_VLV_RESPONSE 来调用 IDirectorySearch::GetColumn,以获取 VLV 搜索元数据。
将 ADS_SEARCH_COLUMN 结构的 pADsValues->ProviderSpecific.lpValue 转换为 ADS_VLV 结构指针。 此 ADS_VLV 结构的 dwContentCount 成员包含该类型搜索将返回的项目的大致数量。
如果要执行同类型的其他 VLV 搜索,请复制 lpContextID 数据并保存,以备下一次 VLV 搜索使用。
GetVLVItemCount 示例函数演示了如何执行此操作。
按偏移量搜索
VLV 搜索之所以如此快速,是因为可以通过数字偏移量来搜索特定结果。 例如,如果一次搜索会返回 10,000 个项目,那么 VLV 搜索就可以获取大约第 4072 个项目的信息,而无需检索该项目之前的所有项目。
偏移量是以偏移量与内容计数的比率来指定的。 比率之所以有用,是因为服务器可能无法准确估计列表中存在的条目数量,或者列表大小可能会在用户浏览列表期间发生变化。 由于必须指明列表的开始和结束,因此可以在第一个搜索请求中使用内容计数的估计值以及偏移值。 服务器根据其对内容计数的理解,使用这些数据计算出列表中的相应偏移量,并通过 ADS_VLV 结构中的 dwContentCount 成员发送给客户端。 例如,如果估计列表大小为 3000,并希望偏移量为列表条目 1500,则应将 dwContentCount 设置为 3000,并将 dwOffset 设置为 1500。 如果服务器估计实际列表大小为 4500,则会将偏移量重新计算为 2250,并在 dwContentCount 和 dwOffset 中返回新的估计值。
注意
VLV 搜索中的所有数值都是近似值,不应作为绝对值使用。 例如,如果对 100 个定量中的第 50 个项目发出 VLV 搜索,则并不能保证得到准确的中间项目。
要按偏移量搜索特定项目,请执行以下步骤。
在 ADS_VLV 结构中填写以下值。 结构中的其他成员应设置为零或 NULL。
- 将 dwContentCount 成员设置为要检索项目比例的最大值。
- 将 dwOffset 成员设置为要检索的一个或多个项目相对于 dwContentCount 的比率。
- 将 lpContextID 成员设置为上下文 ID 缓冲区副本的地址,并将 dwContextIDLength 设置为上下文 ID 缓冲区的长度(以字节为单位)。 如果未保存任何上下文 ID,则这两个成员都应为零或 NULL。
设置搜索首选项,如“获取项数”过程的步骤 2 到步骤 5 中所示。
使用 IDirectorySearch::ExecuteSearch 执行搜索。
通过调用 IDirectorySearch::GetFirstRow 来获取第一行结果。
使用要检索的属性名称调用 IDirectorySearch::GetColumn 以获取所请求项目的实际数据。
使用 ADS_VLV_RESPONSE 来调用 IDirectorySearch::GetColumn,以获取 VLV 搜索元数据。
将 ADS_SEARCH_COLUMN 结构的 pADsValues->ProviderSpecific.lpValue 转换为 ADS_VLV 结构指针。
复制 lpContextID 数据并保存,以备下一次 VLV 搜索使用。
GetVLVItemText 示例函数演示了如何执行此操作。
还可以通过单次搜索调用来检索多行数据。 为此,可在步骤 1 中适当设置 ADS_VLV 结构的 dwBeforeCount 和 dwAfterCount 成员。 dwBeforeCount 成员包含在相关项目之前出现在列表中的项目数,而 dwAfterCount 成员包含在相关项目之后出现在列表中的项目数。 这两个计数都不包括项目本身,因此将 dwBeforeCount 设置为 10 和 dwAfterCount 设置为 10 将总共返回 21 个项目。 此选项可在客户端缓存搜索结果。
按字符串搜索
还可以使用 VLV 搜索来查找具有字符串属性的项目,该属性的值与字符串的全部或部分匹配,而无需检索所有项目。 字符串匹配是针对 ADS_SEARCHPREF_SORT_ON 搜索首选项的 ADS_SORTKEY 结构中指定的属性进行的。
要按字符串搜索特定项目,请执行以下步骤。
在 ADS_VLV 结构中填写以下值。 结构中的其他成员应设置为零或 NULL。
- 将 pszTarget 成员设置为指向以 NULL 结尾的字符串的指针,该字符串包含要搜索的字符串。
- 将 lpContextID 成员设置为上下文 ID 缓冲区副本的地址,并将 dwContextIDLength 设置为上下文 ID 缓冲区的长度(以字节为单位)。 如果未保存任何上下文 ID,则这两个成员都应为零或 NULL。
设置搜索首选项,如“获取项数”过程的步骤 2 到步骤 5 中所示。
使用 IDirectorySearch::ExecuteSearch 执行搜索。
通过调用 IDirectorySearch::GetFirstRow 来获取第一行结果。
使用要检索的属性名称调用 IDirectorySearch::GetColumn 以获取所请求项目的实际数据。
使用 ADS_VLV_RESPONSE 来调用 IDirectorySearch::GetColumn,以获取 VLV 搜索元数据。
将 ADS_SEARCH_COLUMN 结构的 pADsValues->ProviderSpecific.lpValue 转换为 ADS_VLV 结构指针。
复制 lpContextID 数据并保存,以备下一次 VLV 搜索使用。 如果需要,dwOffset 成员包含字符串属性以 pszTarget中指定的值开头的第一个项目的单索引。
GetVLVItemsByString 示例函数演示了如何执行此操作。
与通过索引搜索类似,也可以通过单次搜索调用来检索多行数据。 这同样是通过适当设置 ADS_VLV 结构的 dwBeforeCount 和 dwAfterCount 成员来实现的。