Azure Search使用方法总结

前言

Azure 认知搜索是一种完全托管的云搜索服务,只需要将需要检索的数据上传到Azure Search服务上,就可以通过调用REST API的方式检索到想要的内容 ,我在使用Azure认知搜索服务的时候感觉很方便,因为它在使用的时候只需要去调用它的REST API就可以了,我们公司在使用Azure Search的时候采用的是后端发送HTTP请求得到搜索内容后后端加工之后再发送给前端,但我认为如果只是自己想要一个简单得搜索服务得小伙伴得话也完全可以前端直接使用检索后的内容,很方便。当然了想要自己使用这个服务的小伙伴要自己去注册Azure云服务,它里面大部分的服务都有免费的策略,我觉得这些免费策略足够我们去进行云服务的体验了。(注册时需要VISA信用卡)。接下来我回去介绍我在项目中接触到的Azure Search的使用方法,去实现一个从零开始的demo,内容肯定不会特别详细全面,有更大更深的需求的伙伴请直接去看官方文档。

介绍

付费策略

首先我介绍一下它的付费策略,毕竟用的是别人的服务是要花钱的。具体的付费策略就去官网上找吧,我只说一下免费的限制,免费的每一个服务限制最多只能创建三个索引(索引的概念我下面会说)所以使用时要注意。

概念

接下来我介绍一下概念,这是认知某一个事物的开始。认知搜索包含 搜索服务索引(index)文档(document) 的概念

  • 搜索服务包含一个或多个索引。
  • 索引提供搜索文档的持久存储。同时索引也规定了存储数据的格式和数据检索时的规则
  • 搜索文档以 JSON 文档的形式从外部源加载,并推送到索引以使其可供搜索。

对于上面的概念,我认为索引可以理解为数据库里面得表,而文档就是表中得每一行数据,我觉得这样有助于理解,这样去想得话实际上Azure Search就是提供了可检索方式查询得数据库而已。不只是Azure Search包括作为搜索引擎内核的solr也是这样一个数据库

创建服务

说完了概念我就来简单说一下创建一个AzureSearch服务的操作方法。并带领大家创建一个简单的demo

1. 从Azure Portal创建AzureSearch服务与索引追加。

  • 首先进入Azure Portal选择Create a resource

  • 然后搜索Azure Cognitive Search点击创建创建时选择好订阅,资源组,以及收费策略(每个订阅下免费的只能创建一个)

  • 进入新创建的服务中选择Add index就可以选择创建索引。创建一个最普通的索引我认为不需要选择Suggester。创建字段的时候选择相应的类型与属性。字段类型很好理解,就是这个字段存的是什么类型的数据。AzureSearch的索引字段类型我认为分为两大类,一类是基本类型,另一类是集合类型。其实也很好理解,基本类型就是我们比较熟悉的字符串,数字,布尔类型之类的,在AZAearch里面包括以下的基本类型(Edm.Boolean, Edm.ComplexType, Edm.DateTimeOffset, Edm.Double, Edm.GeographyPoint, Edm.Int32, Edm.Int64, Edm.String)。而集合类型就是以上各个类型的集合或者说数组,从类型的名字上看也可以理解这句话,比如string的集合就是Collection(Edm.String),所以我认为AZSearch的字段类型并不复杂。而属性就是指这个字段有什么作用,其中包括以下几种(Retrievable,Filterable,Sortable,Facetable,Searchable)我只用到过(Retrievable,Filterable,Searchable)。那么我认为其中Retrievable是每一个字段都需要的,因为只有把这个属性选上,该字段的值才能在返回值中返回。而Filterable则规定了这个字段是否可以通过逻辑判断语句进行筛。简单理解就是该字段是否可以通过value=?这种简单的方式进行判断,这种属性我认为适合id类型的字段只需要判断相等就可以了。而Searchable则是表示这个字段是否可以通过分词解析的方式进行检索,与该属性配套的需要选择它的解析器Analyzer,解析器可以选择它默认提供的也可以自定义。这个属性就是需要分词解析的字段需要制定的属性。

  • 点击创建之后就创建完成了,在Index Definition (JSON)中就可以看到创建的索引的JSON格式

2. 通过REST API追加文档。

追加文档有两种方式,一种是从Azure的其他存储服务中导入,另一种就是调用REST API插入数据。我没有使用过第一种导入的方式,我这次介绍一下第二种方式,当然调用API也是我们公司使用的方式。在上面创建索引的过程当中也可以使用调用API的方式创建,并且使用API创建是主要创建方式,具体内容我会在后面写。在调用API的时候需要遵守一定的规则

  • 必须通过 HTTPS (在默认端口 443) 上发出请求。
  • 请求必须在 URI 中包含 api 版本 。 此值必须设置为受支持的版本,格式如下: GET https://[search service name].search.windows.net/indexes?api-version=2020-06-30
  • 请求标头必须包含为你预配的搜索服务生成的 api 密钥 。 具有有效的密钥可以在发送请求的应用程序与处理请求的服务之间建立信任关系,这种信任关系以每个请求为基础。
  • 可以设置 Accept HTTP 标头。 如果未设置标头,则假定默认值为 application/json 。

以上的这些规则我觉得不必死记硬背,因为发送完请求出现问题时,自然会返回相应的错误信息,这是只要去看错误信息就可以知道请求时哪里有问题了。需要注意的是第三点,就是发送请求时必须要去验证api密钥,每个服务都有自己的密钥,我在之前添加文档的时候就会忘记换了一个别的服务的地址而忘了更改相应的密钥,这是后端就会返回来403错误。密钥的位置就在服务的Settings的keys里面打开就是了。在下面我复制了一下官网对于密钥的介绍,我的简单的记忆就是管理员钥拥有所有权限,查询密钥只有查询权限,查询密钥可以自己添加,知道这些我认为就够了,但为了详细,我还是在下面写了一遍

密钥 说明 限制
管理员密钥 管理密钥授予所有操作的完全权限,包括管理服务、获取状态和对象定义以及创建和删除 索引、 索引器 和 数据源 的能力。创建服务时,会自动生成两个管理 api 密钥(在门户中称为 " 主 密钥" 和 " 辅助 密钥"),并可按需单独重新生成。 由于有两个密钥,可以在滚动其中一个密钥时,使用另一个密钥来持续访问服务。只能在 HTTP 请求标头中指定管理密钥。 不能在 URL 中放置管理 api 密钥 。 每个服务最多有 2 个管理员密钥
查询密钥 查询密钥向文档中的内容授予只读访问权限,通常分发给发出搜索请求的客户端应用程序。按需创建查询密钥。 可以在门户中手动创建查询密钥,或者通过管理 REST API 以编程方式创建查询密钥。可以在 HTTP 请求标头中为搜索、建议或查找操作指定查询密钥。 或者,可以在 URL 中以参数形式传递查询密钥。 根据客户端应用程序编写请求的方式,以查询参数的形式传递密钥可能更方便:GET /indexes/hotels/docs?search=*&$orderby=lastRenovationDate desc&api-version=2020-06-30&api-key=[query key] 每个服务 50 个密钥

我认为上面的内容是基础知识但并不是真正的应用,能够记住固然很好但记不住也无所谓,实践中去出了错再去比较,这样我认为记的会更牢固。知道了上面的内容,我就开始介绍如何追加文档,追加文档是通过调用下面这个API去实现的。

POST https://[service name].search.windows.net/indexes/[index name]/docs/index?api-version=[api-version]   
  Content-Type: application/json   
  api-key: [admin key]

其中[service name]是创建的服务的名称,[index name]是创建的索引的名称,[api-version] 是api版本必须要添加,当前版本为 api-version=2020-06-30,[admin key]就是管理员密钥。追加文档的RequestBody的格式如下:

{  
  "value": [  
    {  
      "@search.action": "upload (default) | merge | mergeOrUpload | delete",  
      "key_field_name": "unique_key_of_document", (key/value pair for key field from index schema)  
      "field_name": field_value (key/value pairs matching index schema)  
        ...  
    },  
    ...  
  ]  
}

这个里面的search.action就是要去进行的操作,去选择是创建还是合并还是删除文档,里面的key_field_name就是那个key field其余的就是其他的字段。文档上介绍所有的字段名都是必须的,不过文档也介绍了删除操作中指定的任何字段(而不是键字段)都将被忽略。这句话我的理解就是删除某个文档时只需指定key字段就可以,我实际操作也是这样做的没问题。

3. 检索

我们现在已经创建完服务与索引了,并且添加了文档,那么我们现在就可以去检索了检索有两种方式,一个是通过GET方法发送请求去检索,另一个就是通过POST方法发送请求去检索,但是鉴于GET方法提供的检索的方式太少并且还并不比POST方便,所以我认为应该采用POST方式去检索。下面我分别介绍以下两种方式。

第一种方式:GET方法

GET方法检索使用下面的API

GET https://[service name].search.windows.net/indexes/[index name]/docs?[query parameters] 
  Content-Type: application/json   
  api-key: [admin or query key]

其中的[service namr]和[admin or query key]我就不再介绍了,我重点介绍一下[query parameters]。[query parameters]一共包含下面五个内容。

search
$filter
facet
highlightPreTag
highlightPostTag

其中search内指定的就是想要检索的内容,而filter就是需要通过filter筛选的内容,facet指的是分面,但这个属性我也没有使用过所以我就不介绍了。highlightPreTag和highlightPostTag分别指定的是在突出显示的字词前面预置的字符串标记和追加到突出显示的字词的字符串标记,我觉得比较常用的是highlightPostTag用它来标记检索的高亮部分,用法也很简单只需指定highlightPostTag=[field name]就可以让指定的字段标高亮。search与filter我想相对详细的说一下。

search内指定的就是想要检索的内容,正常情况下只要设定search='内容'即可,其中被检索内容外面的那一层单引号是需要加上去的。这样的话只需要根据服务的analyzer的分词规则就可以检索到相应的内容。当然假如只检索一个英文字母的话,一般情况下是检索不到内容,因为一般分词器都不会这样分词的,那么如果我们想要只通过一个字母检索内容的话可以在检索内容的后面加一个*号,类似于这样search='a*'这样就会把所有a开头的单词检索出来。

filter筛选就是通过等于,不等于,大于等这样的逻辑去进行筛选在GET方法的时候是使用param去调用的,所以使用的方式是$filter=id eq '123456'这样的方式。当然不只是eq还有以下多种判断方式,我接下来介绍一下其他的判断方式。

  1. 最基本的方式逻辑判断。这是通过逻辑判断语句来实现的,主要包括eq, ne, gt, lt, ge, le,这些语句的意思分别为相等,不等,大于,小于,大于等于,小于等于。当然这种方式只限于普通类型可以使用而集合类型是不能直接使用的,这也好理解,数组没办法去直接等于某个值,所以有关于集合类型要使用到下面的方式
  2. 使用 anyall 的集合筛选表达式。这两个逻辑判断方式是专门针对数组的,any表示数组中有任意一个符合条件就可以,all表示数组中所有的数值都需要符合条件才可以。这样干说可能不好理解,我举个例子就好理解了。假设我有一个索引他表示学生学生有很多字段包括id,年龄,性别,成绩。其中成绩是一个int的集合类型里面装着是他的各个成绩叫做Scores。我想查所有成绩都及格的学生就可以这样$filter=Scores/all(score: score gt 60)这样查询就可以了。同理any也是一样。
  3. 使用and, or, not进行连接。这种方式我就不多介绍了,只需要注意优先级,加好括号就行了
  4. 使用search.in进行筛选。这种方式提供了一种多个筛选值的筛选方式,最开始介绍的eq等后面的筛选条件只支持一种,而想要用到多种就必须用到and或者or,但过多的使用and或者or会大幅度的降低查询的性能,并且有一情况使用or就很麻烦比如选择成绩等于60或70或80的人,要是使用or就是这样$filter=score eq 60 or score eq 70 or score eq 80。这种情况就使用search.in就好了。上面的内容就可以改成$filter=search.in(score, 60, 70, 80)这样不仅简单还优化了查询的性能。
  5. 最后我介绍一种方式叫search.ismatch。其实还有几个其他的方式,但我没用过我就不介绍了。search.ismatch很奇怪因为它用在filter中但它并不要求这个字段是Filterable的,但它要求这个字段是Searchable的。其实我的理解就是这个方法提供了在筛选中使用查询的方式。search.ismatch的用法就是$filter=search.ismatch(name, '张三')就表示通过查询张三的结果作为筛选条件。

第一种方式:POST方法

POST方法比较常用,但与GET方法其实没有太大的差别,POST方法调用以下URL

POST https://[service name].search.windows.net/indexes/[index name]/docs/search?api-version=[api-version]  
  Content-Type: application/json  
  api-key: [admin or query key]

当通过 GET 调用时,请求 URL 的长度不能超过 8 KB,而 POST 的请求大小限制大约为 16 MB。所以我认为POST请求才是大部分场景下要使用的。GET请求中的检索内容与检索方式都是设定在URl的parameters里面的,而POST请求的检索内容与检索方式则是设定在Request Body当中,它的格式如下所示。

{  
     "count": true | false (default),  
     "facets": [ "facet_expression_1", "facet_expression_2", ... ],  
     "filter": "odata_filter_expression",  
     "highlight": "highlight_field_1, highlight_field_2, ...",  
     "highlightPreTag": "pre_tag",  
     "highlightPostTag": "post_tag",  
     "minimumCoverage": # (% of index that must be covered to declare query successful; default 100),  
     "orderby": "orderby_expression",  
     "queryType": "simple" (default) | "full",
     "scoringParameters": [ "scoring_parameter_1", "scoring_parameter_2", ... ],  
     "scoringProfile": "scoring_profile_name",  
     "scoringStatistics" : "local" | "global",
     "search": "simple_query_expression",  
     "searchFields": "field_name_1, field_name_2, ...",  
     "searchMode": "any" (default) | "all",  
     "select": "field_name_1, field_name_2, ...",  
     "sessionId" : "session_id",
     "skip": # (default 0),  
     "top": #  
   }

这里面大部分的参数我都用过,但我要是一一解释就解释不过来,这里我贴上官方文档的表格,如果还有需要的话可以详细参考官方文档

名称 类型 说明
api-version string 必需。 用于请求的 REST API 的版本。 有关支持的版本的列表,请参阅 API 版本控制。 对于此操作,无论是使用 GET 还是 POST 调用 搜索文档 ,api 版本都指定为 URI 参数。
$count 布尔值 可选。 有效值为 "true" 或 "false"。 默认值为 "false"。 当通过 POST 调用时,此参数命名为 count,而不是 $count。 指定是否要获取结果的总计数。 这是与搜索和 $filter 参数匹配的所有文档的计数,将忽略 $top$skip。 将此值设置为 "true" 可能会降低性能。 返回的计数是一个近似值。 如果只想获取不含任何文档的计数,则可以使用 $top = 0。
facet 字符串 可选。 按 facet 的字段。 字符串可能包含用于自定义分面的参数,以逗号分隔的名称/值对表示。 当通过 POST 调用时,此参数命名为 facet 而不是 facet。有效值为 "count"、"sort"、"values"、"interval" 和 "timeoffset"。"计数" 是最大方面术语数;默认值为10。 术语数没有上限,但较高的值将会降低性能,尤其是在多面字段包含大量独特术语时。 例如,"facet = category,count: 5" 获取分面结果中的前五个类别。 如果 count 参数小于唯一字词数,结果可能不准确。 这由分面查询分布在各个分片上的方式所导致。 递增计数通常会提高字词计数的准确性,但会降低性能。"sort" 可以设置为 "count"、"-count"、"value"、"-value"。 使用 count 按计数降序排序。 使用-count 按计数进行升序排序。 使用值按值进行升序排序。 使用-值按值降序排序 (例如,"facet = category,count:3,sort: count" 获取分面中的前三个类别按每个城市名称的文档数的降序排序) 。 如果前三个类别是预算、汽车旅馆和奢侈品,并且预算命中 5 次、汽车旅馆命中 6 次、奢侈品命中 4 次,则存储桶的顺序将为汽车旅馆、预算、奢侈品。 对于 "值","facet = 评分,sort:-value" 按值以降序方式为所有可能的分级生成存储桶 (例如,如果分级为1到5,则存储桶将按5、4、3、2、1进行排序,而不考虑每个分级) 匹配的文档数。"值" 可设置为以管道分隔的数值或 Edm。 DateTimeOffset 值指定一组动态的方面输入值 (例如,"facet = baseRate,值: 10 | 20" 生成三个存储桶:一个用于基本速率为0,但不包含10个,一个用于10个,但不包含20个,一个用于20个和更高的) 。 字符串 "facet = lastRenovationDate,values: 2010-02-01T00:00: 00Z" 产生两个存储桶:一个用于2010年2月之前的酒店翻新,另一个用于年2月 1 2010 日的酒店翻新。对于数字,"interval" 是大于0的整数间隔,或者为日期时间值的分钟、小时、日、周、月、季度、年。 例如,"facet = baseRate,interval: 100" 基于大小100的基本速率范围生成存储桶。 如果基本费率全都介于 60 和600 之间,则会有0-100、100-200、200-300、300-400、400-500 和500-600 的存储桶。 当酒店为翻新时,字符串 "facet = lastRenovationDate,interval: year" 为每年生成一个存储桶。可以将 "timeoffset" 设置为 ( [+-] hh: mm、[+-] hhmm 或 [+-] hh) 。 如果使用,则 timeoffset 参数必须与 interval 选项结合使用,并且仅在应用于类型为的字段时。 该值指定在设置时间边界时要考虑的 UTC 时间偏移量。 例如: "facet = lastRenovationDate,interval: day,timeoffset:-01:00" 使用在目标时区) 中以 01:00:00 UTC 开始 (午夜开始的日边界。计数和排序可以组合在同一方面规范中,但不能与间隔或值组合在一起,并且不能将间隔和值组合在一起。如果未指定 timeoffset,将根据 UTC 时间计算日期时间的间隔方面。 例如:对于 "facet = lastRenovationDate,interval: day",day 边界以 00:00:00 UTC 开始。
$filter 字符串 可选。 使用标准 OData 语法的结构化搜索表达式。 只能在筛选器中使用可筛选字段。 当通过 POST 调用时,此参数命名为 filter 而不是 $filter。 有关 Azure 认知搜索支持的 OData 表达式语法子集的详细信息,请参阅 azure 认知搜索的 Odata 表达式语法 。
highlight 字符串 可选。 用于命中突出显示的逗号分隔的字段名称集。 只有可搜索字段可用于命中突出显示。 默认情况下,Azure 认知搜索每个字段最多返回5个亮点。 可以通过在字段名称后面追加 "-<最大数量的突出显示>" 来为每个字段配置限制。 例如,"高光 = 标题-3,说明-10" 将从 "标题" 字段返回最多3个突出显示的命中,并从 "说明" 字段返回最多10个命中。 最大突出显示数必须是1到1000之间的整数。
highlightPostTag 字符串 可选。 默认为 "</em>"。 追加到突出显示的字词的字符串标记。 必须设置为 highlightPreTag。 URL 中的保留字符必须采用百分比编码形式(例如,使用 %23 而不是 #)。
highlightPreTag 字符串 可选。 默认为 "</em>"。 在突出显示的字词前面预置的字符串标记。 必须设置为 highlightPostTag。 URL 中的保留字符必须采用百分比编码形式(例如,使用 %23 而不是 #)。
minimumCoverage 整型 可选。 有效值为0到100之间的一个数字,表示必须可用于处理查询的索引的百分比,然后才能将其报告为成功。 默认值为 "100"。100% 覆盖率是指响应请求的所有分片, (服务运行状况问题和维护活动降低) 的覆盖范围。 在默认设置下,小于完全覆盖率将返回 HTTP 状态代码503。如果出现503个错误,并且你想要提高查询成功的概率,则降低 minimumCoverage 会很有用,特别是对于为某个副本配置的服务。 如果设置了 minimumCoverage 并搜索成功,它将返回 HTTP 200,并 @search.coverage 在响应中包含一个值,以指示查询中包含的索引的百分比。 在这种情况下,并非所有匹配的文档都能保证出现在搜索结果中,但如果搜索可用性比召回更重要,则降低范围可能是一项可行的缓解策略。
$orderby 字符串 可选。 逗号分隔的表达式列表,结果将根据它进行排序。 当通过 POST 调用时,此参数命名为 orderby,而不是 $orderby。 每个表达式可以是字段名称,也可以是对 geo () 函数的调用。 每个表达式可以后跟 "asc" 来指示升序,使用 "desc" 指示降序。 如果排序字段中有 null 值,则以升序显示空值,最后按降序顺序显示。 默认值为升序。 排序的依据将是文档的匹配分数。 如果未指定 $orderby,则默认排序顺序为按文档匹配分数的降序排序。 $orderby 的子句限制为32个。
queryType 字符串 可选。 有效值为 "简单" 或 "完整"。 默认为“simple”。"简单" 使用允许符号(如、和)的 简单查询语法 来解释查询字符串 + * "" 。 默认情况下,将在每个文档 (的所有可搜索字段中计算查询,并在每个文档的 searchFields) 中指示"full" 使用 完整的 Lucene 查询语法 解释查询字符串,该语法允许进行特定于字段的搜索。 不支持使用 Lucene 查询语言的范围查询,但支持提供类似功能的 $filter。
scoringParameter 字符串 可选。 指示计分函数中定义的每个参数的值, (例如 referencePointParameter) 使用 "名称-value1,value2,..." 格式当通过 POST 调用时,此参数名为 scoringParameters 而不是 scoringParameter。 此外,将其指定为字符串的 JSON 数组,其中每个字符串都是一个单独的名称-值对。对于包含函数的计分配置文件,使用字符将函数与输入列表分隔开 - 。 例如,名为 "mylocation" "&scoringParameter = mylocation--122.2,44.8" 的函数。 第一个短划线分隔函数名称和值列表,而第二个短划线是此示例中的第一个值 () 的一部分。对于计分参数(例如可包含逗号的标记提升),可使用单引号转义列表中的任何此类值。 如果值本身包含单引号,可通过双重单引号转义它们。 假设你有一个名为 "提升参数" 的参数 "mytag" ,而你想要在标记值 "Hello,O'Brien" 和 "Smith" 上提升,则查询字符串选项将是 "&scoringParameter = mytag-'Hello,O" "Brien",Smith "。 对于包含逗号的值,只需要引号。
scoringProfile 字符串 可选。 用于为匹配的文档评估匹配分数以便对结果进行排序的评分配置文件的名称。
scoringStatistics 字符串 可选。 有效值为 "local" 或 "global"。 默认值为 "local"。 指定是否计算评分统计信息(例如文档频率),全局 (跨所有分片) ,以获得更一致的评分,或在当前分片) 本地 (,以降低延迟。 请参阅 在 Azure 认知搜索中评分统计信息。 对于使用 模糊搜索 ( "~" ) 的字词,将始终以本地方式计算评分统计信息。
search 字符串 可选。 要搜索的文本。 默认情况下会搜索所有可搜索字段,除非指定了 searchFields。 在索引中,可搜索字段中的文本会被标记为标记,因此多个字词可以用空格分隔 (例如: "search = hello world" ) 。 若要匹配任何字词,请使用 *(这对布尔筛选器查询可能很有用)。 忽略此参数与将其设置为 * 具有相同的效果。 有关搜索语法的详细信息,请参阅 简单查询语法 。查询可搜索字段时,结果有时可能会令人吃惊。 标记器包含用于处理英语文本中常见情况(如撇号、数字中的逗号等)的逻辑。 例如,"search = 123456" 将匹配单个字词 "123456",而不是单独的 "123" 和 "456" 术语,因为逗号用作较大数字的千位分隔符。 出于此原因,我们建议使用空格而不是标点符号来分隔搜索参数中的字词。
searchMode 字符串 可选。 有效值为 "any" 或 "all",默认值为 "any"。 指定要将文档算作匹配项,是必须匹配任一搜索词还是必须匹配所有搜索词。
searchFields 字符串 可选。 要对指定文本搜索的逗号分隔的字段名称列表。 目标字段在索引架构中必须标记为可搜索。
$select 字符串 可选。 要包含在结果集中的以逗号分隔的字段列表。 此子句中只能包括标记为可检索的字段。 如果未指定或设置为 *,会在投影中包含架构中标记为可检索的所有字段。 当通过 POST 调用时,此参数命名为 select 而不是 $select。
sessionID 字符串 可选。 使用 sessionId 有助于改善搜索具有多个副本的服务的关联分数一致性。 在多副本配置中,同一查询的各个文档的相关性分数可能略有不同。 当提供了会话 ID 时,服务将尽力将给定请求路由到该会话的相同副本。 请注意,重复重复使用相同的会话 ID 值可能会干扰跨副本请求的负载均衡,并对搜索服务的性能产生负面影响。 用作 sessionId 的值不能以“_”字符开头。 如果服务没有任何副本,此参数不会影响性能或评分一致性。
$skip 整型 可选。 要跳过的搜索结果数。 当通过 POST 调用时,此参数命名为 skip 而不是 $skip。 此值不能大于100000。 如果需要按顺序扫描文档,但由于此限制而不能使用 $skip,请考虑对索引中的每个文档使用 $orderby 具有唯一值 (如文档键,例如,使用范围查询) 和 $filter
$top 整型 可选。 要检索的搜索结果数。 默认值为50。 当通过 POST 调用时,此参数名为 top,而不是 $top。 如果指定一个大于1000的值,并且结果超过1000个,则仅返回第一个1000结果,并提供指向下一页结果的链接 (参见 @odata.nextLink 下面的示例) 。Azure 认知搜索使用 服务器端分页 来防止查询一次检索过多的文档。 默认页面大小为50,而最大页面大小为1000。 这意味着,如果未指定 $top,默认 搜索文档 最多返回50个结果。 如果结果数超过50,则响应包括检索最多50个结果的下一页的信息 (参阅 @odata.nextLink @search.nextPageParameters 下面的 示例 中的 "" 和 ""。 同样,如果为 $top 指定一个大于1000的值,并且有超过1000个结果,则仅返回第一个1000结果,以及检索最多1000个结果的下一页的信息。

4.结果

最后的检索结果参考下面的格式,如果返回200相应那就是检索成功了

{
    "@odata.count": # (if $count=true was provided in the query),
    "@search.coverage": # (if minimumCoverage was provided in the query),
    "@search.facets": { (if faceting was specified in the query)
      "facet_field": [
        {
          "value": facet_entry_value (for non-range facets),
          "from": facet_entry_value (for range facets),
          "to": facet_entry_value (for range facets),
          "count": number_of_documents
        }
      ],
      ...
    },
    "@search.nextPageParameters": { (request body to fetch the next page of results if not all results could be returned in this response and Search was called with POST)
      "count": ... (value from request body if present),
      "facets": ... (value from request body if present),
      "filter": ... (value from request body if present),
      "highlight": ... (value from request body if present),
      "highlightPreTag": ... (value from request body if present),
      "highlightPostTag": ... (value from request body if present),
      "minimumCoverage": ... (value from request body if present),
      "orderby": ... (value from request body if present),
      "scoringParameters": ... (value from request body if present),
      "scoringProfile": ... (value from request body if present),
      "scoringStatistics": ... (value from request body if present),
      "search": ... (value from request body if present),
      "searchFields": ... (value from request body if present),
      "searchMode": ... (value from request body if present),
      "select": ... (value from request body if present),
      "sessionId" : ... (value from request body if present),
      "skip": ... (page size plus value from request body if present),
      "top": ... (value from request body if present minus page size),
    },
    "value": [
      {
        "@search.score": document_score (if a text query was provided),
        "@search.highlights": {
          field_name: [ subset of text, ... ],
          ...
        },
        "@search.features": {
          "field_name": {
            "uniqueTokenMatches": feature_score,
            "similarityScore": feature_score,
            "termFrequency": feature_score,
          },
          ...
        },
        key_field_name: document_key,
        field_name: field_value (retrievable fields or specified projection),
        ...
      },
      ...
    ],
    "@odata.nextLink": (URL to fetch the next page of results if not all results could be returned in this response; Applies to both GET and POST)
  }

总结

到此为止我就介绍完了如何从零开始制作一个AZSearch的检索demo,我介绍的内容应该还比较全面如果大家还有什么不懂的话,可以参考官方文档,文档链接如下:
https://docs.microsoft.com/zh-cn/rest/api/searchservice/

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,658评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,482评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,213评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,395评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,487评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,523评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,525评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,300评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,753评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,048评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,223评论 1 343
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,905评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,541评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,168评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,417评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,094评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,088评论 2 352

推荐阅读更多精彩内容