Dataverse 搜索查询

查询操作基于搜索词返回搜索结果。

除了搜索词,还可以通过传递以下参数的值来影响结果:

Name 类型 说明 更多信息
search 字符串 必需。 要搜索的文本。 搜索参数
count 布尔型 是否返回总记录计数。 count 参数
entities 字符串 将搜索范围限制为表的子集。 entities 参数
facets 字符串 Facet 支持在检索数据结果后向下钻取数据结果的功能。 facets 参数
filter 字符串 限制返回的搜索结果的范围。 filter 参数
options 字符串 选项是用于配置以便于搜索某个搜索词的设置。 options 参数
orderby 字符串 指定如何按优先顺序对结果进行排序。 orderby 参数
skip 整数 指定要跳过的搜索结果数。 skip 和 top 参数
top 整数 指定要检索的搜索结果数。 skip 和 top 参数

Parameters

本部分包括有关上表中引入的参数的详细信息。

search 参数

类型:string
必需:true

搜索参数包含要搜索的文本。 它是唯一必需的参数。 搜索词长度必须至少为一个字符,并且具有 100 个字符的限制。

简单搜索语法

默认情况下,搜索参数支持简单的搜索语法,如下表所述:

功能 说明
布尔运算符 AND 运算符,用+表示
OR 运算符;用 | 表示
NOT 运算符通过符号 - 表示
优先运算符 搜索词 hotel+(wifi | luxury) 用于查找包含字词 hotel 以及 wifiluxury(或两者)的结果。
通配符 支持尾随通配符。 例如, Alp* 搜索“alpine”。
完全匹配 用引号 " "括起来的查询。

注释

若要使用任何搜索运算符作为搜索文本的一部分,请在字符前添加一个反斜杠来转义该字符。\ 需要转义的特殊字符包括: + - & | ! ( ) { } [ ] ^ " ~ * ? : \ /

例如,被转义的电话号码可能如下所示:\+1\(800\)555\-1234

通过使用参数options,可以启用Lucerne 查询语法,从而支持不同运算符。

count 参数

类型:bool
可选:true

是否返回总记录计数。 如果未设置此参数,则 Count 响应属性为 -1.

entities 参数

类型:string
可选:true

默认情况下,搜索包括启用搜索的所有表。 若要搜索特定子集,请使用 entities 参数。

设置实体时,还可以指定要返回的列和要搜索的列。 还可以为表格包含筛选条件。

若要获取为环境启用的表列表,请使用 搜索状态 API 并查找在 entitylogicalnameentitystatusresults列出的表。

SearchEntity 类型

使用此类型可组合要传递给 entities 参数的表数组。

字段名称 类型 说明
name 字符串 必填。 表的逻辑名称。 指定查询的范围。
selectColumns string[] 可选。 响应中返回表文档时要投影的列列表。 如果为空,则仅返回表主名称。
searchColumns string[] 可选。 查询范围所限定的列列表。 如果为空,则仅搜索表主名称。
filter 字符串 可选。 应用于实体的过滤器。

Example

以下示例显示了使用上述架构的一些 JSON 数据。

[
   {
      "name":"account",
      "selectColumns":["name","address1_city"],
      "searchColumns":["name","address1_city"],
      "filter":"modifiedon ge 2018-01-01T00:00:00Z"
   },
   {
      "name":"contact",
      "selectColumns":["fullname","address1_city"],
      "searchColumns":["fullname","address1_city"],
      "filter":"modifiedon ge 2018-01-01T00:00:00Z"
   }
]

若要使用此数据,请先转义字符串,然后将其作为entities参数的值传递至请求正文中。

{
    "search": "maria",
    "entities":"[{\"name\":\"account\",\"selectColumns\":[\"name\",\"address1_city\"],\"searchColumns\":[\"name\",\"address1_city\"],\"filter\":\"modifiedon ge 2018-01-01T00:00:00Z\"},{\"name\":\"contact\",\"selectColumns\":[\"fullname\",\"address1_city\"],\"searchColumns\":[\"fullname\",\"address1_city\"],\"filter\":\"modifiedon ge 2018-01-01T00:00:00Z\"}]"
}

facets 参数

类型:string
可选:true

facet 参数是可选的。 字符串可能包含用于自定义分面的参数,以逗号分隔的名称/值对表示。 使用维度对搜索结果进行分组。

面定义

将 facet 定义为字符串数组,例如:

[
"entityname,count:100",
"account:primarycontactid,count:100",
"ownerid,count:100",
"modifiedon,values:2019-04-27T00:00:00|2020-03-27T00:00:00|2020-04-20T00:00:00|2020-04-27T00:00:00",
"createdon,values:2019-04-27T00:00:00|2020-03-27T00:00:00|2020-04-20T00:00:00|2020-04-27T00:00:00"
]

数组中的每个项都表示对查询返回的数据进行分组的不同方法。 对于返回的每个属性,请使用下表中的值指定适当的分面:

Facet 类型 说明
count 分面术语的最大数目。 默认值是10。 没有上限。
sort 设置为count-countvalue-value。 使用countcount降序排序。 使用 -count 按升序对 count 进行排序。 使用 value 按升序对 value 进行排序。 使用-valuevalue降序排序。
values 设置为以管道符(|)分隔的数值或 Edm.DateTimeOffset 值,以定义动态分面条目值集。 这些值必须按顺序按升序列出才能获取预期结果。
interval 数字或分钟、小时、日、周、月、季度、年等日期时间值的整数间隔大于零。
timeoffset 设置为 ([+-]hh:mm[+-]hhmm[+-]hh) 。 如果使用,请将timeoffset参数与间隔选项结合使用,并且仅在应用于Edm.DateTimeOffset类型的字段时。 该值指定在设置时间边界时要考虑的 UTC 时间偏移量。

注释

您可以在同一属性规范中合并countsort,但不能将它们与intervalvalues合并。 你也不能将 intervalvalues 组合在一起。

使用一个包含分面定义的转义字符串来设置facets的值。

{
    "search": "maria",
    "facets": "[\"entityname,count:100\",\"account:primarycontactid,count:100\",\"ownerid,count:100\",\"modifiedon,values:2019-04-27T00:00:00|2020-03-27T00:00:00|2020-04-20T00:00:00|2020-04-27T00:00:00\",\"createdon,values:2019-04-27T00:00:00|2020-03-27T00:00:00|2020-04-20T00:00:00|2020-04-27T00:00:00\"]"    
}

有关详细信息,请参阅:

filter 参数

类型:string
可选:true

筛选器限制搜索结果的范围。 使用筛选器排除不需要的结果。 此顶级筛选器有助于跨多个实体(例如 createdonmodifiedon)筛选常见列。

使用以下语法应用筛选器: <attribute logical name> <filter> 表逻辑名称指定筛选器适用的实体。

筛选器使用以下查询运算符:

操作员 说明 Example
比较运算符    
eq Equal revenue eq 100000
ne 不等于 revenue ne 100000
gt 大于 revenue gt 100000
ge 大于或等于 revenue ge 100000
lt 少于 revenue lt 100000
le 小于或等于 revenue le 100000
逻辑运算符    
and 逻辑与 revenue lt 100000 and revenue gt 2000
or 逻辑或 name eq 'sample' or name eq 'test'
not 逻辑非 not name eq 'sample'
分组运算符    
( ) 优先分组 (name eq 'sample') or name eq 'test') and revenue gt 5000

options 参数

类型:string
可选:true

选项是用于配置搜索词的设置。 将 options 值设置为这些选项经过序列化后的 Dictionary<string, string> ,例如 "{'querytype': 'lucene', 'searchmode': 'all', 'besteffortsearchenabled': 'true', 'grouprankingenabled': 'true'}"

下表列出了这些选项:

选项 说明
querytype 值可以是 simpleluceneLucerne 查询语法
besteffortsearchenabled 如果找不到搜索请求词的匹配项,则启用智能查询工作流可返回可能的结果集。
groupranking 在优化后的响应中启用结果排名,以便在搜索结果页面中按表格分组显示结果。
searchmode 当指定为all时,必须匹配搜索词才能将文档视为符合项。 将其值设置为 any 默认值以匹配搜索词中的任何单词。

Lucene 查询语法

Lucene 查询语法支持以下功能:

功能 说明
布尔运算符 提供比简单查询语法更全面的扩展集。
AND 运算符,表示为AND&&+
OR 运算符; 表示为 OR||
NOT 运算符; 由 NOT! 表示
通配符 除了尾随通配符外,还支持前导通配符。
尾随通配符 – alp*
前导通配符 - /.*pine/
模糊搜索 支持拼错最多两个字符的查询。
Uniersty~ 返回 University
Blue~1 返回 glueblues
术语提升 以不同的方式权衡查询中的特定术语。
Rock^2 electronic 返回结果,其中匹配 rock 项比匹配 electronic项更重要。
邻近搜索 返回字词在 彼此的 x 个单词内的结果,以获取更多上下文结果。
例如,"airport hotel"~5返回结果,其中airporthotel在五个单词之内,从而增加找到靠近机场的酒店的机会。
正则表达式搜索 例如, /[mh]otel/ 匹配 motelhotel

orderby 参数

类型:string
可选:true

使用 orderby 参数替代默认排序。 默认情况下,结果按相关性分数的降序列出(@search.score)。 对于分数相同的结果,排序是随机的。 只有当查询类型为 lucene 并且查询字符串中包含通配符时,才能使用此参数。

使用逗号分隔子句的列表,其中每个子句由后跟 asc 列名(升序,即默认值)或 desc (降序)组成。

对于包含多个表类型的一组结果,子句列表 orderby 必须可在全局范围内适用(例如,modifiedoncreatedon@search.score)。 例如,若要按相关性对结果进行排名(按重要性顺序排列),其次是最近修改的记录优先列出:

"orderby": ["@search.score desc", "modifiedon desc"]

如果查询请求包含特定表类型的筛选器, orderby 可以选择指定特定于表的列。

skiptop 参数

类型:int
可选:true

将这些参数与 count 参数 一起使用来创建分页体验。

默认情况下,每次返回最多 50 个结果。 使用 top 可以将其提高到 100,但更常用的是 top 来指定较小的结果集(例如 10),然后在用户移动到下一页时使用 skip 来跳过之前返回的结果。

响应

查询操作的响应是包含 JSON 数据的转义字符串。

未转义的响应包含使用以下属性的 JSON。

Name 类型 说明
Error ErrorDetail 提供 Azure 认知搜索中的错误信息。
Value QueryResult[] 匹配记录的集合。
Facets Dictionary<string, FacetResult[]> 如果查询请求分面,则提供一个包含分面值的字典。
QueryContext QueryContext 此属性用于后端搜索。 它包含在将来的功能版本中,当前未使用。
Count 长型 如果请求正文包含 "Count": true,则计算所有与搜索匹配的文档数量,此时忽略 top 和 skip 参数。

响应类型

本部分介绍响应返回的类型。

错误详细信息

作为响应的一部分返回的 Azure 认知搜索错误。

Name 类型 说明
code 字符串 错误代码。
message 字符串 错误消息。
propertybag Dictionary<string, object> 更多错误信息。

查询结果

响应QueryResult属性中返回的每个Value项都表示 Dataverse 中的记录。

Name 类型 说明
Id 字符串 记录的标识符。
EntityName 字符串 表的逻辑名称。
ObjectTypeCode 整数 对象类型代码。
Attributes Dictionary<string, object> 记录属性
Highlights Dictionary<string, string[]> 亮点。
Score 双精度 文档分数。

FacetResult

一个分面查询结果,用于报告某个字段位于特定范围内或具有特定值或间隔的文档数。

Name 类型 说明
count 长? 属于此层面定义的存储桶中的文档数量。
from 对象 指示分面范围的非独占下限的值,或 null 表示没有下限。
to 对象 表示分面范围专属上限的值,或者为 null 表示没有上限。
type Value | Range 分面的类型。
value 对象 分面的值,如果它是间隔分面,则为非独占下限。
optionalvalue 对象 分面的另一个或可选值,在查找时填充。

QueryContext

作为响应的一部分返回的查询上下文。 此属性用于后端搜索。 它包含在将来的功能版本中,当前未使用。

Name 类型 说明
originalquery 字符串 请求中指定的查询字符串。
alteredquery 字符串 Dataverse 搜索用于执行查询的查询字符串。 如果原始查询字符串包含拼写错误或未产生最佳结果,Dataverse 搜索将使用更改的查询字符串。
reason string[] Dataverse 搜索查询更改决策背后的原因。
spellsuggestions string[] 表示用户意图的可能字词的拼写建议。 仅当 Dataverse 由于拼写检查而更改查询搜索时填充。

例子

以下示例演示如何使用查询操作。 对于在 2022 年 8 月 15 日之后创建的记录,这些示例分别对帐户和联系人表 namefullname 列执行搜索操作,并按 createdon 字段降序对前七个结果进行排序。

此示例来自 GitHub 上的 SDK for .NET 搜索操作示例 。 静态 OutputSearchQuery 方法接受 搜索参数的值。

/// <summary>
/// Demonstrate query API
/// </summary>
/// <param name="service">The authenticated IOrganizationService instance to use.</param>
/// <param name="searchTerm">The term to search for</param>
/// <returns></returns>
static void OutputSearchQuery(IOrganizationService service, string searchTerm)
{
    Console.WriteLine("OutputSearchQuery START\n");

    searchqueryRequest request = new() { 
        search = searchTerm,
        count = true,
        top = 7,
        entities = JsonConvert.SerializeObject(new List<SearchEntity>()
        {
            new SearchEntity()
            {
                Name = "account",
                SelectColumns = new List<string>() { "name", "createdon" },
                SearchColumns = new List<string>() { "name" },
                Filter = "statecode eq 0"
            },
            new SearchEntity()
            {
                Name = "contact",
                SelectColumns = new List<string>() { "fullname", "createdon" },
                SearchColumns = new List<string>() { "fullname" },
                Filter = "statecode eq 0"
            }
        }),
        orderby = JsonConvert.SerializeObject(new List<string>() { "createdon desc" }),
        filter = "createdon gt 2022-08-15"

    };
    
    var searchqueryResponse = (searchqueryResponse)service.Execute(request);

    var queryResults = JsonConvert.DeserializeObject<SearchQueryResults>(searchqueryResponse.response);
  

    Console.WriteLine($"\tCount:{queryResults.Count}");
    Console.WriteLine("\tValue:");
    queryResults.Value.ForEach(result =>
    {

        Console.WriteLine($"\t\tId:{result.Id}");
        Console.WriteLine($"\t\tEntityName:{result.EntityName}");
        Console.WriteLine($"\t\tObjectTypeCode:{result.ObjectTypeCode}");
        Console.WriteLine("\t\tAttributes:");
        foreach (string key in result.Attributes.Keys)
        {
            Console.WriteLine($"\t\t\t{key}:{result.Attributes[key]}");
        }
        Console.WriteLine("\t\tHighlights:");
        foreach (string key in result.Highlights.Keys)
        {
            Console.WriteLine($"\t\t\t{key}:");

            foreach (string value in result.Highlights[key])
            {
                Console.WriteLine($"\t\t\t\t{value}:");
            }
        }
        Console.WriteLine($"\t\tScore:{result.Score}\n");

    });
    Console.WriteLine("OutputSearchQuery END\n");
}

输出

使用经过身份验证的OutputSearchQuery类实例调用方法,并在调用过程中将searchTerm设为“Contoso”时:

OutputSearchQuery(service: serviceClient, searchTerm: "Contoso");

输出如下所示:

OutputSearchQuery START

        Count:1
        Value:
                Id:8b35eda1-ef69-ee11-9ae7-000d3a88a4a2
                EntityName:account
                ObjectTypeCode:0
                Attributes:
                        @search.objecttypecode:1
                        name:Contoso Pharmaceuticals (sample)
                        createdon:10/13/2023 5:41:21 PM
                        createdon@OData.Community.Display.V1.FormattedValue:10/13/2023 5:41 PM
                Highlights:
                        name:
                                {crmhit}Contoso{/crmhit} Pharmaceuticals (sample):
                Score:4.986711

OutputSearchQuery END

辅助类

该方法 OutputSearchQuery 取决于以下支持类来发送请求并处理结果:

searchqueryRequest 和 searchqueryResponse 类

使用 Power Platform CLI 下的 pac modelbuilder build 命令生成这些类,如 生成适用于 .NET 的 SDK 早期绑定类中所述。

SearchEntity 类

使用此类撰写 SearchEntity 类型 数据。

public sealed class SearchEntity
{
    /// <summary>
    /// Gets or sets the logical name of the table. Specifies scope of the query.
    /// </summary>
    [DataMember(Name = "name", IsRequired = true)]
    public string Name { get; set; }

    /// <summary>
    /// Gets or sets the list of columns that needs to be projected when table documents are returned in response. 
    /// If empty, only PrimaryName will be returned.
    /// </summary>
    [DataMember(Name = "selectcolumns")]
    public List<string> SelectColumns { get; set; }

    /// <summary>
    /// Gets or sets the list of columns to scope the query on.
    /// If empty, only PrimaryName will be searched on. 
    /// </summary>
    [DataMember(Name = "searchcolumns")]
    public List<string> SearchColumns { get; set; }

    /// <summary>
    /// Gets or sets the filters applied on the entity.
    /// </summary>
    [DataMember(Name = "filter")]
    public string Filter { get; set; }
}
SearchQueryResults 类

使用此类从 searchqueryResponse.response 字符串属性反序列化 JSON 数据。

public sealed class SearchQueryResults
{
    /// <summary>
    /// Provides error information from Azure Cognitive search.
    /// </summary>
    public ErrorDetail? Error { get; set; }

    /// <summary>
    /// A collection of matching records.
    /// </summary>
    public List<QueryResult>? Value { get; set; }

    /// <summary>
    /// If facets were requested in the query, a dictionary of facet values.
    /// </summary>
    public Dictionary<string, IList<FacetResult>>? Facets { get; set; }

    /// <summary>
    /// The query context returned as part of response. This property is used for backend search. It is included for future feature releases and is not currently used.
    /// </summary>
    public QueryContext? QueryContext { get; set; }

    /// <summary>
    /// If `"Count": true` is included in the body of the request, the count of all documents that match the search, ignoring top and skip.
    /// </summary>
    public long Count { get; set; }
}
ErrorDetail 类

使用此类反序列化 ErrorDetail 数据。

public sealed class ErrorDetail
{
    /// <summary>
    /// Gets or sets the error code.
    /// </summary>
    [DataMember(Name = "code")]
    public string Code { get; set; }

    /// <summary>
    /// Gets or sets the error message.
    /// </summary>
    [DataMember(Name = "message")]
    public string Message { get; set; }

    /// <summary>
    /// Gets or sets additional error information.
    /// </summary>
    [DataMember(Name = "propertybag")]
    public Dictionary<string, object> PropertyBag { get; set; }
}
QueryResult 类

使用此类反序列化 QueryResult 数据。

public sealed class QueryResult
{
    /// <summary>
    /// Gets or sets the identifier of the record
    /// </summary>
    public string Id { get; set; }

    /// <summary>
    /// Gets or sets the logical name of the table
    /// </summary>
    public string EntityName { get; set; }

    /// <summary>
    /// Gets or sets the object type code
    /// </summary>
    public int ObjectTypeCode { get; set; }

    /// <summary>
    /// Gets or sets the record attributes
    /// </summary>
    public Dictionary<string, object> Attributes { get; set; }

    /// <summary>
    /// Gets or sets the highlights
    /// </summary>
    public Dictionary<string, string[]> Highlights { get; set; }

    // Gets or sets the document score
    public double Score { get; set; }
}
FacetResult 类

使用此类反序列化 FacetResult 数据。

public sealed class FacetResult
{
    /// <summary>
    /// Gets or sets the count of documents falling within the bucket described by this facet.
    /// </summary>
    [DataMember(Name = "count")]
    public long? Count { get; set; }

    /// <summary>
    /// Gets or sets value indicating the inclusive lower bound of the facet's range, or null to indicate that there is no lower bound.
    /// </summary>
    [DataMember(Name = "from")]
    public object From { get; set; }

    /// <summary>
    /// Gets or sets value indicating the exclusive upper bound of the facet's range, or null to indicate that there is no upper bound.
    /// </summary>
    [DataMember(Name = "to")]
    public object To { get; set; }

    /// <summary>
    /// Gets or sets type of the facet - Value or Range.
    /// </summary>
    [DataMember(Name = "type")]
    public FacetType Type { get; set; }

    /// <summary>
    /// Gets or sets value of the facet, or the inclusive lower bound if it's an interval facet.
    /// </summary>
    [DataMember(Name = "value")]
    public object Value { get; set; }

    /// <summary>
    /// Gets or sets additional/ Optional value of the facet, will be populated while faceting on lookups.
    /// </summary>
    [DataMember(Name = "optionalvalue")]
    public object OptionalValue { get; set; }
}
FacetType 类

指定分面查询结果的类型。

public enum FacetType
{
    /// <summary>
    /// The facet counts documents with a particular field value.
    /// </summary>
    [EnumMember(Value = "value")]
    Value = 0,

    /// <summary>
    /// The facet counts documents with a field value in a particular range.
    /// </summary>
    [EnumMember(Value = "range")]
    Range = 1,
}
QueryContext 类

使用此类反序列化 QueryContext 数据。

public sealed class QueryContext
{
    /// <summary>
    /// Gets or sets the query string as specified in the request.
    /// </summary>
    [DataMember(Name = "originalquery")]
    public string OriginalQuery { get; set; }

    /// <summary>
    /// Gets or sets the query string that Dataverse search used to perform the query. 
    /// Dataverse search uses the altered query string if the original query string contained spelling mistakes or did not yield optimal results.
    /// </summary>
    [DataMember(Name = "alteredquery")]
    public string AlteredQuery { get; set; }

    /// <summary>
    /// Gets or sets the reason behind query alter decision by Dataverse search.
    /// </summary>
    [DataMember(Name = "reason")]
    public List<string> Reason { get; set; }

    /// <summary>
    /// Gets or sets the spell suggestion that are the likely words that represent user's intent. 
    /// This will be populated only when the query was altered by Dataverse search due to spell check.
    /// </summary>
    [DataMember(Name = "spellsuggestions")]
    public List<string> SpellSuggestions { get; set; }
}

另请参阅

搜索Dataverse记录
Dataverse 搜索建议
Dataverse 搜索自动完成
Dataverse 搜索统计信息和状态
Dataverse 旧版搜索