首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >每个组的搜索总回报前5位

每个组的搜索总回报前5位
EN

Stack Overflow用户
提问于 2019-12-30 12:23:23
回答 1查看 1.4K关注 0票数 2

假设我有这种格式的文档:

代码语言:javascript
运行
复制
product_name TEXT tags TAG score NUMERIC 

[product1, [tag1, tag2, tag3], 10]
[product2, [tag2, tag3, tag4], 100]
....

我希望查询按产品得分最高和的顺序返回标签,并返回每个标签的前5位产品:

代码语言:javascript
运行
复制
[tag3, 110, [product2, product 1]]
[tag2, 110, [product2, product 1]]
[tag4, 100, [product2]]
[tag1, 10, [product 1]]

到目前为止,我所拥有的是分别存储每个产品/标签密钥(每个标签重复),因此对于每个产品,我们对每个标签有一个单独的文档,id是产品名称和标记:product_name TEXT tag TAG score NUMERIC的组合。现在,我可以运行一个聚合查询来获取顶部标记的列表:

代码语言:javascript
运行
复制
FT.AGGREGATE product_tags * 
   GROUP BY 1 @TAG 
     REDUCE SUM 1 @score as total_score
   SORT BY 2 @total_score DESC

这将给我的顶部标签的顺序,但如果我想得到前5产品的每个标签,我发现只有REDUCE TOLIST 1 @product_name,将返回所有的产品,没有排序,还有REDUCE FIRST_VALUE 4 @product_name BY @score DESC,它将只返回第一个顶级产品。

有什么方法可以让每个标签在一个查询中获得5个顶级产品吗?如果没有,是否可以更改文档存储格式(或添加额外的格式)以使这种查询成为可能,或者使用尽可能少的查询?

应该没关系,但我正在使用客户端。

EN

回答 1

Stack Overflow用户

发布于 2019-12-31 06:32:03

第一:

  • 确保禁用不使用的功能(NOOFFSETSNOHLNOFREQSSTOPWORDS 0)
  • 使用SORTABLE表示您的NUMERIC score

下面是我用来测试的模式:

代码语言:javascript
运行
复制
FT.CREATE product_tags NOOFFSETS NOHL NOFREQS STOPWORDS 0
    SCHEMA product_name TEXT tags TAG score NUMERIC SORTABLE

您想把FT.AGGREGATE 看作是一种管道。

第一步是按@score对产品进行排序,以便稍后在进行REDUCE TOLIST 1 @product_name时,将列表排序如下:

代码语言:javascript
运行
复制
SORTBY 2 @score DESC

我认为您已经在使用LOAD/APPLY来处理标记,否则TAG字段将按每个产品的完整逗号分隔的字符串标记列表进行分组。见允许标记字段上的GROUPBY发出。因此,我们的下一步工作是:

代码语言:javascript
运行
复制
LOAD 1 @tags 
APPLY split(@tags) as TAG 

然后,我们按@TAG进行分组,并应用这两种缩减。我们的产品清单将按顺序排列。

代码语言:javascript
运行
复制
GROUPBY 1 @TAG
    REDUCE SUM 1 @score AS total_score
    REDUCE TOLIST 1 @product_name AS products

最后,我们按照@total_score进行排序。

代码语言:javascript
运行
复制
SORTBY 2 @total_score DESC

这里是命令的最后视图:

代码语言:javascript
运行
复制
FT.AGGREGATE product_tags *
    SORTBY 2 @score DESC 
    LOAD 1 @tags 
    APPLY split(@tags) as TAG
    GROUPBY 1 @TAG
        REDUCE SUM 1 @score AS total_score 
        REDUCE TOLIST 1 @product_name AS products
    SORTBY 2 @total_score DESC

这里有一个完整的命令列表来说明结果。我使用productXX和分数XX来直观地验证产品的排序。

代码语言:javascript
运行
复制
> FT.CREATE product_tags NOOFFSETS NOHL NOFREQS STOPWORDS 0 SCHEMA product_name TEXT tags TAG score NUMERIC SORTABLE
OK
> FT.ADD product_tags pt:product10 1 FIELDS product_name product10 tags tag2,tag3,tag4 score 10
OK
> FT.ADD product_tags pt:product1 1 FIELDS product_name product1  tags tag1,tag2,tag3 score 1
OK
> FT.ADD product_tags pt:product100 1 FIELDS product_name product100 tags tag2,tag3 score 100
OK
> FT.ADD product_tags pt:product5 1 FIELDS product_name product5 tags tag1,tag4 score 5
OK
> FT.SEARCH product_tags *
1) (integer) 4
2) "pt:product5"
3) 1) "product_name"
   2) "product5"
   3) "tags"
   4) "tag1,tag4"
   5) "score"
   6) "5"
4) "pt:product100"
5) 1) "product_name"
   2) "product100"
   3) "tags"
   4) "tag2,tag3"
   5) "score"
   6) "100"
6) "pt:product1"
7) 1) "product_name"
   2) "product1"
   3) "tags"
   4) "tag1,tag2,tag3"
   5) "score"
   6) "1"
8) "pt:product10"
9) 1) "product_name"
   2) "product10"
   3) "tags"
   4) "tag2,tag3,tag4"
   5) "score"
   6) "10"
> FT.AGGREGATE product_tags * SORTBY 2 @score DESC LOAD 1 @tags APPLY split(@tags) as TAG GROUPBY 1 @TAG REDUCE SUM 1 @score AS total_score REDUCE TOLIST 1 @product_name AS products SORTBY 2 @total_score DESC
1) (integer) 4
2) 1) "TAG"
   2) "tag2"
   3) "total_score"
   4) "111"
   5) "products"
   6) 1) "product100"
      2) "product10"
      3) "product1"
3) 1) "TAG"
   2) "tag3"
   3) "total_score"
   4) "111"
   5) "products"
   6) 1) "product100"
      2) "product10"
      3) "product1"
4) 1) "TAG"
   2) "tag4"
   3) "total_score"
   4) "15"
   5) "products"
   6) 1) "product10"
      2) "product5"
5) 1) "TAG"
   2) "tag1"
   3) "total_score"
   4) "6"
   5) "products"
   6) 1) "product5"
      2) "product1"

你得到了完整的产品列表,而不仅仅是前5名。从复杂性的角度看,这并没有什么不同,我们付出了代价。其影响在于缓冲、网络有效负载和客户端。

您可以使用Lua脚本限制到前5名:

代码语言:javascript
运行
复制
eval "local arr = redis.call('FT.AGGREGATE', KEYS[1], '*', 'SORTBY', '2', '@score', 'DESC', 'LOAD', '1', '@tags', 'APPLY', 'split(@tags)', 'as', 'TAG', 'GROUPBY', '1', '@TAG', 'REDUCE', 'SUM', '1', '@score', 'AS', 'total_score', 'REDUCE', 'TOLIST', '1', '@product_name', 'AS', 'products', 'SORTBY', '2', '@total_score', 'DESC') \n for i=2,(arr[1]+1) do \n arr[i][6] = {unpack(arr[i][6], 1, ARGV[1])} \n end \n return arr" 1 product_tags 5

这里是上面Lua脚本的友好视图:

代码语言:javascript
运行
复制
local arr = redis.call('FT.AGGREGATE', KEYS[1], ..., 'DESC')
for i=2,(arr[1]+1) do 
    arr[i][6] = {unpack(arr[i][6], 1, ARGV[1])}
end
return arr

我们正在传递一个键(索引)和一个参数(顶级产品的限制,在您的例子中是5):1 product_tags 3

在此情况下,我们将影响限制为仅缓冲、保存网络有效负载和加载到您的客户端。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/59530799

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档