Redis
 sql >> Datenbank >  >> NoSQL >> Redis

Redisearch aggregierte Rendite Top 5 jeder Gruppe

Erstens:

  • Deaktivieren Sie Funktionen, die Sie nicht verwenden (NOOFFSETS , NOHL ,NOFREQS , STOPWORDS 0 )
  • Verwenden Sie SORTABLE für Ihren NUMERIC score .

Hier ist das Schema, das ich zum Testen verwendet habe:

FT.CREATE product_tags NOOFFSETS NOHL NOFREQS STOPWORDS 0
    SCHEMA product_name TEXT tags TAG score NUMERIC SORTABLE

Sie möchten an FT.AGGREGATE denken als Pipeline.

Der erste Schritt besteht darin, die Produkte nach @score zu sortieren, damit sie später, unten in der Pipeline, wenn wir REDUCE TOLIST 1 @product_name , die Liste wird sortiert ausgegeben:

SORTBY 2 @score DESC

Ich denke, Sie machen bereits LOAD /APPLY um mit den Tags umzugehen, als TAG Felder würden andernfalls nach der vollständigen, durch Kommas getrennten String-Tags-Liste pro Produkt gruppiert. Siehe Problem GROUPBY für Tag-Felder zulassen. Unser nächster Schritt ist also in der Pipeline:

LOAD 1 @tags 
APPLY split(@tags) as TAG 

Wir gruppieren dann nach @TAG und wenden die beiden Reduzierungen an. Unsere Produktliste wird sortiert ausgegeben.

GROUPBY 1 @TAG
    REDUCE SUM 1 @score AS total_score
    REDUCE TOLIST 1 @product_name AS products

Schließlich sortieren wir nach @total_score :

SORTBY 2 @total_score DESC

Hier eine letzte Ansicht des Befehls:

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

Hier eine vollständige Liste der Befehle zur Veranschaulichung des Ergebnisses. Ich habe productXX verwendet mit Punktzahl XX zur einfachen visuellen Überprüfung der Sortierung von Produkten.

> 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"

Sie erhalten die vollständige Liste der sortierten Produkte, nicht nur die Top 5. In Bezug auf die Komplexität spielt es keine Rolle, wir haben den Preis bezahlt. Die Auswirkungen liegen in der Pufferung, der Netzwerknutzlast und Ihrem Client.

Sie können mit einem Lua-Skript auf die Top 5 beschränken:

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

Hier eine freundliche Ansicht des obigen Lua-Skripts:

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

Wir übergeben einen Schlüssel (den Index) und ein Argument (das Limit für Top-Produkte, in Ihrem Fall 5):1 product_tags 3 .

Damit haben wir die Auswirkungen auf das Puffern beschränkt, Netzwerknutzlast eingespart und Ihren Client belastet.