Windows 搜索中的查询进程

本主题的组织方式如下:

Windows 搜索中的查询基于以下四种方法:

  • 高级查询语法 (AQS)
  • 自然查询语法 (NQS)
  • 结构化查询语言 (Structured Query Language) (SQL)
  • 结构化查询接口

AQS 是 Windows 搜索用于查询索引以及优化和缩小搜索参数的默认查询语法。 AQS 主要面向用户,用户可以使用 AQS 生成 AQS 查询,但也可供开发人员用于以编程方式生成查询。 在 Windows 7 中,引入了规范 AQS,并且必须用于以编程方式生成 AQS 查询。 在 Windows 7 及更高版本中,可以根据是否满足 AQS 条件提供快捷菜单选项。 有关详细信息,请参阅 创建上下文菜单处理程序中的“使用高级查询语法获取静态谓词的动态行为”。 AQS 查询可以限制为特定类型的文件,称为文件类型。 有关详细信息,请参阅 文件类型和关联。 有关相关属性的参考文档,请参阅 System.KindSystem.KindText

NQS 是一种比 AQS 更宽松的查询语法,类似于人类语言。 如果选择了 NQS 而不是默认的 AQS,则 Windows 搜索可以使用 NQS 来查询索引。

SQL 是一种用于定义查询的文本语言。 SQL 在许多不同的数据库技术中很常见。 Windows 搜索使用 SQL,实现 SQL 的子集,并通过向语言添加元素来扩展 SQL。 Windows 搜索 SQL 扩展了标准 SQL-92 和 SQL-99 数据库查询语法,以增强其基于文本的搜索的有用性。 Windows 搜索 SQL 的所有功能都与 Windows XP 和 Windows Server 2003 及更高版本的 Windows 搜索兼容。 有关 Windows 搜索 SQL 的详细信息,请参阅 使用 Windows 搜索 SQL 语法查询索引Windows 搜索 SQL 语法概述

本主题稍后将介绍结构化查询 API。 有关结构化查询 API 的参考文档,请参阅 查询接口 ISearchQueryHelper 等接口可帮助从一组输入值构造 SQL 字符串。 此接口将 AQS 用户查询转换为 Windows 搜索 SQL,并指定可在 SQL 中表示但不能在 AQS 中表示的查询限制。 ISearchQueryHelper 还会获取用于连接到 Windows 搜索数据库的 OLE DB 连接字符串。

本地和远程查询

可以在本地或远程执行查询。 以下示例中显示了使用 FROM 子句 的本地查询。 本地查询仅查询本地 SystemIndex 目录。

FROM SystemIndex

以下示例显示了使用 FROM 子句 的远程查询。 添加 ComputerName 会将前面的示例转换为远程查询。

FROM [<ComputerName>.]SystemIndex

默认情况下,Windows XP 和 Windows Server 2003 未安装 Windows 搜索。 只有 Windows Search 4 (WS4) 提供远程查询支持。 以前版本的 Windows 桌面搜索 (WDS) (如 3.01 及更早版本)不支持远程查询。 使用 Windows 资源管理器,可以查询远程计算机的本地索引,以查找文件系统项 (由“file:”协议) 处理的项目。

若要通过远程查询检索项,该项必须满足以下要求:

  • 可通过通用命名约定 (UNC) 路径进行访问。
  • 存在于客户端有权访问的远程计算机上。
  • 设置其安全性以允许客户端具有读取访问权限。

Windows 资源管理器具有共享项目的功能,包括 网络和共享中心的“公共”共享 (\\Machine\Public\...) ,以及通过共享向导共享的项目的“用户”共享 (\\Machine\Users\...) 。 在共享文件夹 () 后,可以通过在 FROM 子句中指定远程计算机的计算机名称,并在 SCOPE 子句中指定远程计算机上的 UNC 路径来查询本地索引。 以下示例显示了使用 FROM 和 SCOPE 子句的远程查询。

SELECT System.ItemName FROM MachineName.SystemIndex WHERE SCOPE='file://MachineName/<path>' 

此处提供的示例使用 SQL。

结构化查询 API 概述

结构化查询提供通过单个属性的查询的布尔组合来搜索信息的功能。 本主题概述了最重要的结构化查询 API 和方法的功能。 有关结构化查询 API 的参考文档,请参阅 查询接口

IQueryParser

IQueryParser::P arse 方法分析用户输入字符串,并生成 IQuerySolution 形式的解释。 如果该方法的 pCustomProperties 参数不为 null,则它是 IRichChunk 对象的枚举, (每个识别的自定义属性) 一个。 其他 IQueryParser 方法允许应用程序为各种类型的命名实体设置多个选项,例如区域设置、架构、断字符和处理程序。 IQueryParser::GetSchemaProvider 返回 ISchemaProvider 接口,用于浏览加载的架构。

IQuerySolution: IConditionFactory

IQuerySolution 接口提供有关分析输入字符串的结果的所有信息。 由于 IQuerySolution 也是 IConditionFactory 接口,因此可以创建其他条件树节点。 IQuerySolution::GetQuery 方法为解释生成条件树。 IQuerySolution::GetQuery 还返回语义类型。

IConditionFactory

IConditionFactory 创建条件树节点。 如果 IConditionFactory::MakeNot简化参数VARIANT_TRUE,则生成的 ICondition 将得到简化,并且不需要是否定节点。 如果 IConditionFactory::MakeAndOrpSubConditions 参数不为 null,则该参数应是 ICondition 对象的枚举,并成为子树。IConditionFactory::MakeLeaf 使用指定的属性名称、操作和值构造叶节点。 pValueType 参数中的字符串应该是架构中的语义类型的名称。 如果 expand 参数 为VARIANT_TRUE 并且属性是虚拟的,则生成的条件树通常是将 属性扩展到其定义的构成部分而产生的分离。 如果不是 null, pPropertyNameTermpOperatorTermpValueTerm 参数应标识指示属性、操作和值的术语。

ICondition : IPersistStream

ICondition 接口是条件树中的单个节点。 该节点可以是否定节点、AND 节点、OR 节点或叶节点。 对于非叶节点 ,ICondition::GetSubConditions 返回子树的枚举。 对于叶节点, ICondition 的以下方法返回以下值:

IRichChunk

每个 IRichChunk 对象标识一个令牌范围和一个字符串。 IRichChunk 是一个实用工具接口,表示有关范围的信息 (通常由起始位置和长度标识) 标记范围。 此范围信息包括字符串和/或 VARIANT

IConditionGenerator

IConditionGenerator 接口由应用程序提供,用于处理命名实体类型的识别和条件树生成。 条件生成器通过 IQueryParser::SetMultiOption 提供给 IQueryParser IQueryParser 使用 ISchemaProvider 为当前加载的架构调用 IConditionGenerator::Initialize。 这样做允许 IConditionGenerator 获取所需的任何架构信息。 分析输入字符串时,IQueryParser 调用每个 IConditionGenerator 的 IConditionGenerator::RecognizeNamedEntities 方法,以便报告它在输入字符串中识别的命名实体的出现情况。 IQueryParser 可以使用当前区域设置,并且应使用输入的标记化,因为它需要报告任何命名实体的令牌范围。

IQueryParser 即将发出叶节点,并且值的语义类型与 IConditionGenerator 的命名实体类型匹配时, IQueryParser 使用要生成的节点的信息调用 IConditionGenerator::GenerateforLeaf 。 如果 IConditionGenerator 返回S_OK,则它应返回一个条件树 (该树不必是) 叶节点,并通知 IQueryParser 是否抑制它通常生成的替代字符串解释(作为预防措施)。

ITokenCollection

ITokenCollection::NumberOfTokens 方法返回标记数。ITokenCollection::GetToken 返回有关第 i个令牌的信息。 开头和长度是输入字符串中的字符位置。 仅当有文本替代输入字符串中的字符时,返回的文本才为非 null。 例如,当输入字符串中的短划线位于应解释为否定的上下文中时,该短划线用于替代使用 NOT 的短划线。

INamedEntityCollector

IConditionGenerator 为其识别的每个命名实体调用 INamedEntityCollector::Add 。 范围是令牌范围。 它必须始终是 beginSpanbeginActual<endActualendSpanbeginSpanendSpan 可能与 beginActualendActual 不同,前提是命名实体以语义上微不足道的标记(如引号 (结尾,但命名实体) 涵盖这些标记)。 该值必须表示为字符串,随后将显示在 对 IConditionGenerator::GenerateForLeaf 的调用中。

ISchemaProvider

ISchemaProvider 接口可用于浏览实体的加载架构, (类型) 和关系 (属性) 。 以下是各个方法的用途:

IEntity

IEntity 接口是一个架构实体,它表示一个类型,该类型具有一个名称,具有许多与其他类型的命名关系, (属性) ,并且派生自基实体。 下面是其各个方法的用途:

IRelationship

IRelationship 接口表示两个实体之间的关系:源和目标。 以下是各个方法的用途:

  • IRelationship::IsReal 报告关系是否真实。 例如,如果实体 A 派生自实体 B 并从中继承名为 R 的关系,则 A 可能仍有自己的名为 R 的关系。但是,关系 A 和 R 之间的目标类型必须与 B 的目标类型相同,并且它存在的唯一原因是存储特定于 B 的元数据。这种B的关系据说不是真的。
  • IRelationship::Medadata 返回 IMetaData 接口的枚举,此实体的每个元数据对对应一个。
  • IRelationship::D efaultPhrase 在重述中返回用于此关系的默认短语。 每个关系都有一个默认短语,用于表示该短语,以便于生成条件树的 AQS 或 NQS 重述。

IMetaData

元数据是键值对,每个键值对都与实体、关系或整个架构相关联。 由于键不一定是唯一的,因此可将元数据集合视为多映射。 调用 IMetaData::GetData 以检索元数据对的键和值。

查询方案

以下方案介绍了在常见查询方案中 Windows 搜索中使用结构化查询 API,例如创建条件树和查询索引。

条件提取和查询分析

创建查询时,通过告知系统搜索位置来定义其范围。 这会限制搜索结果。 定义范围后,应用筛选器,并返回筛选器集。 通过构建具有叶节点的条件树(类似于图形)来限制搜索结果。 然后提取这些条件。 条件树是叶条件 (AND、OR、NOT) 的布尔组合,每个条件都通过操作将属性与值相关联。 叶节点表示通过某些操作对单个属性对值的限制。

筛选器限制需要描述限制的逻辑表达式。 定义此表达式从 ICondition 接口开始,该接口用于在条件树中创建单个节点。 由于以下示例中只有一个条件,因此树不会更改。

    
    [
        object,
        uuid(0FC988D4-C935-4b97-A973-46282EA175C8),
        pointer_default(unique)
    ]
    interface ICondition : IPersistStream
    {
        HRESULT GetConditionType([out, retval] CONDITION_TYPE* pNodeType);
        HRESULT GetSubConditions([in] REFIID riid, [out, retval, iid_is(riid)] void** ppv);
        [local] HRESULT GetComparisonInfo([out, annotation("__deref_opt_out")] LPWSTR *ppszPropertyName, [out, annotation("__out_opt")] CONDITION_OPERATION *pOperation, [out, annotation("__out_opt")] PROPVARIANT *pValue);
        HRESULT GetValueType([out, retval] LPWSTR* ppszValueTypeName);
        HRESULT GetValueNormalization([out, retval] LPWSTR* ppszNormalization);
        [local] HRESULT GetInputTerms([out, annotation("__out_opt")] IRichChunk** ppPropertyTerm, [out, annotation("__out_opt")] IRichChunk** ppOperationTerm, [out, annotation("__out_opt")] IRichChunk** ppValueTerm);
        HRESULT Clone([out, retval] ICondition** ppc);
    };


如果有多个筛选条件,则使用 AND 和其他布尔运算符实现单个树。 AND-trees 和 OR-trees 表示其子树的结合和分解。 NOT 树表示其单个子树的否定。 AQS 提供了一种使用布尔运算符实现逻辑表达式的文本方法,通常更简单。

在下一个示例中,我们将条件树 (ICondition) 转换为可视形式。 查询分析程序使用 IQueryParser 接口将 ICondition 转换为 rtf) 查询字符串 (格式的富文本。 IQueryParser::RestateToString 方法返回查询文本,而 IQueryParser::P arse 方法生成 IQuerySolution 接口。 以下示例演示如何执行所有这些操作。

    [
        object,
        uuid(2EBDEE67-3505-43f8-9946-EA44ABC8E5B0),
        pointer_default(unique)
    ]
    interface IQueryParser : IUnknown
    {
        HRESULT Parse([in] LPCWSTR pszInputString, [in] IEnumUnknown* pCustomProperties, [out, retval] IQuerySolution** ppSolution);
        HRESULT SetOption([in] STRUCTURED_QUERY_SINGLE_OPTION option, [in] PROPVARIANT const* pOptionValue);
        HRESULT GetOption([in] STRUCTURED_QUERY_SINGLE_OPTION option, [out, retval] PROPVARIANT* pOptionValue);
        HRESULT SetMultiOption([in] STRUCTURED_QUERY_MULTIOPTION option, [in] LPCWSTR pszOptionKey, [in] PROPVARIANT const* pOptionValue);
        HRESULT GetSchemaProvider([out, retval] ISchemaProvider** ppSchemaProvider);
        HRESULT RestateToString([in] ICondition* pCondition, [in] BOOL fUseEnglish, [out] LPWSTR* ppszQueryString);
        HRESULT ParsePropertyValue([in] LPCWSTR pszPropertyName, [in] LPCWSTR pszInputString, [out, retval] IQuerySolution** ppSolution);
        HRESULT RestatePropertyValueToString([in] ICondition* pCondition, [in] BOOL fUseEnglish, [out] LPWSTR* ppszPropertyName, [out] LPWSTR* ppszQueryString);
    };

IQueryParser::P arse 的main输入是要分析的用户输入字符串,但应用程序还可以通知查询分析程序在输入 (中识别到的应用程序特定语法) 的任何属性。 IQueryParser::P arse 的输出是 IQuerySolution,它提供与该分析调用相关的所有信息。 有一些方法可用于获取输入字符串、输入字符串的标记化方式、任何分析错误,以及将分析的查询作为条件树(由 ICondition 表示)。 以下示例显示 ...

    [
        object,
        uuid(D6EBC66B-8921-4193-AFDD-A1789FB7FF57),
        pointer_default(unique)
    ]
    interface IQuerySolution : IConditionFactory
    {
        [local] HRESULT GetQuery([out, annotation("__out_opt")] ICondition** ppQueryNode, [out, annotation("__out_opt")] IEntity** ppMainType);
        HRESULT GetErrors([in] REFIID riid, [out, retval, iid_is(riid)] void** ppParseErrors);
        [local] HRESULT GetLexicalData([out, annotation("__deref_opt_out")] LPWSTR* ppszInputString, [out, annotation("__out_opt")] ITokenCollection** ppTokens, [out, annotation("__out_opt")] LCID* pLocale, [out, annotation("__out_opt")] IUnknown** ppWordBreaker);
    }    

    

在前面的示例中, IQuerySolution::GetQuery 可以获取有关查询的任何信息,包括原始文本、构成文本的标记或条件树。 下表列出了可能返回的查询值的示例。

返回的查询值的示例 说明
author:relja OR author:tyler IQueryParser::RestateToString 返回的查询文本
?author?, ?:?, ?relja?, ?OR?, ?author?, ?:?, ?tyler? 令牌的分解
未解析的条件树 未解析的条件树

 

返回的初始条件树未解析。 在未解析的条件树中,日期和时间引用(如 date:yesterday)不会转换为绝对时间。 此外,虚拟属性不会展开。 虚拟属性是充当多个属性的聚合的属性。

例如,查询 kind:email from:reljai 生成以下未解析和已解析的条件树。 未解析的条件树位于左侧,解析的条件树位于右侧。

未解析和已解析的条件树

可以通过调用 IConditionFactory::Resolve 来获取已解析的树。 但是,传递 SQRO_DONT_RESOLVE_DATETIME 会使日期和时间无法解决。 未解析的条件树有一些优点,因为未解析的条件树包含有关查询的信息。 每个叶节点都指向 IQuerySolution::GetLexicalData 返回的令牌,这些标记对应于使用 IRichChunk 接口时的属性、运算符和值。 以下示例显示 ...

    interface ITokenCollection : IUnknown
    {
        HRESULT NumberOfTokens(ULONG* pCount);
        HRESULT GetToken([in] ULONG i, [out, annotation("__out_opt")] ULONG* pBegin, [out, annotation("__out_opt")] ULONG* pLength, [out, annotation("__deref_opt_out")] LPWSTR* ppsz);
    };

ICondition:: GetInputTerms([out, annotation("__out_opt")] 
IRichChunk** ppPropertyTerm, [out, annotation("__out_opt")] 
IRichChunk** ppOperationTerm, [out, annotation("__out_opt")] 
IRichChunk** ppValueTerm);

    interface IRichChunk : IUnknown
    {
        HRESULT GetData([out, annotation("__out_opt")] ULONG* pFirstPos, [out, annotation("__out_opt")] ULONG* pLength, [out, annotation("__deref_opt_out")] LPWSTR* ppsz, [out, annotation("__out_opt")] PROPVARIANT* pValue);
    }

查询索引

查询索引的方法有多种。 有些基于 SQL,另一些则基于 AQS。 还可以使用查询接口以编程方式 查询 Windows 搜索索引。 有三个特定于查询索引的接口: ISearchQueryHelperIRowsetPrioritizationIRowsetEvents。 有关概念信息,请参阅 以编程方式查询索引

可以使用 ISearchQueryHelper 接口开发组件或帮助程序类来查询索引。 此接口作为 ISearchCatalogManager (和 ISearchCatalogManager2) 的帮助程序类实现,并通过调用 ISearchCatalogManager::GetQueryHelper 获得。 有关概念信息,请参阅 使用 ISearchQueryHelper 查询索引

ISearchQueryHelper 允许你:

  • 获取用于连接到 Windows 搜索数据库的 OLE DB 连接字符串。
  • 将 AQS 用户查询转换为 Windows 搜索 SQL。
  • 指定可在 SQL 中表示但不能在 AQS 中表示的查询限制。

Windows 7 及更高版本支持索引优先顺序和行集事件。 使用 IRowsetPrioritization 时,有一个优先级堆栈,使客户端能够请求为特定查询中使用的范围提供高于正常优先级。 IRowsetEvents 提供对行集中项的更改的通知,包括添加新项、删除项和修改项数据。 使用行集事件通知可确保现有查询的结果尽可能保持最新。 有关概念信息,请参阅 为 Windows 7 中的优先级和行集事件编制索引

Windows 搜索中的索引、查询和通知

索引中包含的内容

Windows 搜索中的索引过程

Windows 搜索中的通知进程

URL 格式设置要求