功能说明
打散子句可以在一定程度上保证展示结果的多样性,以提升用户体验。如一次查询可以查出很多的文档,但是如果某个用户的多个文档分值都比较高,则都排在了前面,导致一页中所展示的结果几乎都属于同一用户,这样既不利于结果展示也不利于用户体验。对此,打散子句可以对每个用户的文档进行抽取,使得每个用户都有展示文档的机会。
子句语法
distinct=dist_key:field,dist_count:1,dist_times:1,reserved:false
参数说明:
dist_key:必选参数,要打散的属性字段。
dist_times:可选参数,抽取的轮数,默认为1。
dist_count:可选参数,一轮抽取的文档数,默认为1。
reserved:可选参数,true/false,是否保留抽取之后剩余的文档,默认为true。如果为false,为不保留,则搜索结果的total(总匹配结果数)会不准确。
update_total_hit:可选参数,true/false,默认为false。当reserved为false时,设置update_total_hit为true,则最终total_hit会减去被distinct丢弃的数目(不一定准确),为false则不减。
dist_filter:可选参数,过滤条件,被过滤的doc不参与distinct,只在后面的排序中,这些被过滤的doc将和被distinct出来的第一组doc一起参与排序。默认是全部参与distinct。
grade:可选参数,指定档位划分阈值,所有的文档将根据档位划分阈值划分成若干档,每个档位中各自根据distinct参数做distinct,可以不指定该参数,默认是所有文档都在同一档。档位的划分按照文档排序时第一维的排序依据的分数进行划分,两个档位阈值之间用 “|” 分开,档位的个数没有限制。例如:1、grade:3.0 :表示根据第一维排序依据的分数分成两档,(< 3.0)的是第一档,(>= 3.0) 的是第二档;2、grade:3.0|5.0 :表示分成三档,(< 3.0)是第一档,(>= 3.0,< 5.0)是第二档,(>= 5.0)是第三档。档位的先后顺序和第一维排序依据的顺序一致,即如果第一维排序依据是降序,则档位也是降序,反之亦然。
示例:
distinct=dist_key:company_id,dist_count:2,dist_times:10
备注:按照company_id字段进行打散抽取10轮,每轮取2个结果,抽取后的文档排在后面
dist_count和dist_times说明:
以下样例用来解释和说明dist_count和dist_times的用法及含义:
假设有6篇文档,id为主键,name为需要做打散的字段:
doc 1: id:1 name:a
doc 2: id:2 name:a
doc 3: id:3 name:a
doc 4: id:4 name:b
doc 5: id:5 name:c
doc 6: id:6 name:c
case1:
distinct=dist_key:name,dist_count:2,dist_times:1 打散结果是:doc1 doc2 doc4 doc5 doc6
case2:
distinct=dist_key:name,dist_count:1,dist_times:2 打散结果是:doc1 doc4 doc5 doc2 doc6
case3:
distinct=dist_key:name,dist_count:1,dist_times:1 打散结果是:doc1 doc4 doc5
多阶段distinct
现在问天引擎的searcher上的排序可以分为两个大的阶段,粗排和精排,其中精排的轮数视用户配置的scorer的个数而定。多阶段的distinct是指用户除了可以在排序阶段(粗排)做distinct以外,还可以对排序之后的结果集再追加一轮distinct。不妨将这两种distinct分别称为排序时distinct和排序后distinct。多阶段的distinct允许用户指定在对所有query命中的结果做完distinct后再对粗排和精排后的结果做一次distinct的,比如第一阶段的distinct使用一个较粗粒度的distinct,即具有较大的dist_count,保证每个key都有足够多的结果,第二阶段的distinct再做一个较小的粒度的distinct。多阶段的distinct还允许用户指定在粗排时不做distinct,在粗排和精排后再做一轮distinct
Note
如果指定了在粗排和精排后追加一轮distinct,在query中(start + hit)大于scorer的rank_size的时候,翻页是不稳定的。
多阶段distinct语法如下:distinct = sub_distinct_clause_when_sort;sub_distinct_clause_after_sort其中,sub_distinct_clause_when_sort为排序时distinct clause;sub_distinct_clause_after_sort为排序后distinct clause。
按照语法规则,多阶段distinct有如下三种形式:
distinct = sub_dist_clause;none_sub_dist_clause排序时distinct按照sub_dist_clause中定义做打散;排序后不做打散。例如:"distinct=dist_key:company_id,dist_count:1,dist_times:1;none_dist"
distinct = sub_dist_clause1;sub_dist_clause2排序时distinct按照sub_dist_clause1中定义做打散;排序后distinct按照sub_dist_clause2中定义做打散。例如:
"distinct=dist_key:company_id,dist_count:2,dist_times:1;dist_key:company_id,dist_count:1,dist_times:1"
distinct = none_sub_dist_clause;sub_dist_clause排序时不做打散;排序后distinct按照sub_dist_clause中定义做打散。例如:"distinct=none_dist;dist_key:company_id,dist_count:1,dist_times:1"
distinct = sub_dist_clause如果只有一个dist子句,在粗排和排序后阶段都会按照sub_dist_clause中定义做打散。例如:"distinct=dist_key:company_id,dist_count:1,dist_times:1"而disctinc = none_sub_dist_clause; none_sub_dist_clause这种形式是不合法的。因为如果排序时和排序后都不做distinct,那么distinct子句就没有意义了
distinct uniq插件
如上面描述,如果reserved=false情况下,会导致搜索结果中的total及viewtotal不准确,如果用户需要依赖于这个值进行翻页或者其他处理,则会有问题。为此,系统提供了distinct uniq的插件来解决在dist_times:1,dist_count:1,reserved:false的情况下的total及viewtotal展示不准确。
在kvpairs中添加duniqfield:field即可。例:kvpairs=duniqfield:name
注意:
field必须与distinct子句中的dist_key一致;
该插件仅在dist_times:1,dist_count:1,reserved:false查询下起作用,任何参数值有变化都将无效。
出于性能考虑,目前该插件最大支持total值为5000,即使真实搜索结果数超过5000,也会返回5000。
示例:
distinct=dist_key:company_id,dist_count:1,dist_times:1,reserved:false&&kvpairs=duniqfield:company_id
注意事项
distinct为非必选子句;
在distinct中出现的字段必须在定义应用结构的时配置为属性字段。
不支持array类型,只支持int和literal字段类型。
不支持指定多个 dist_key 。