sql >> Databasteknik >  >> NoSQL >> Redis

Sök igen sammanlagd avkastning topp 5 i varje grupp

Först:

  • Se till att inaktivera funktioner som du inte kommer att använda (NOOFFSETS , NOHL ,NOFREQS , STOPWORDS 0 )
  • Använd SORTABLE för din NUMERIC score .

Här är schemat jag använde för att testa:

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

Du vill tänka på FT.AGGREGATE som en pipeline.

Det första steget blir att sortera produkterna efter @score, så att senare, nere i pipelinen, när vi REDUCE TOLIST 1 @product_name , listan kommer ut sorterad:

SORTBY 2 @score DESC

Jag tror att du redan gör LOAD /APPLY för att hantera taggarna, som TAG fälten skulle annars grupperas efter den fullständiga kommaseparerade sträng-tagglistan, per produkt. Se Tillåt GROUPBY om problem med taggfält. Så vårt nästa steg är i pipelinen är:

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

Vi grupperar sedan efter @TAG och tillämpar de två minskningarna. Vår produktlista kommer ut sorterad.

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

Slutligen sorterar vi efter @total_score :

SORTBY 2 @total_score DESC

Här en sista vy av kommandot:

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

Här en fullständig lista med kommandon för att illustrera resultatet. Jag använde productXX med poäng XX för att enkelt visuellt verifiera sorteringen av produkter.

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

Du får hela listan över produkter sorterade, inte bara topp 5. Komplexitetsmässigt gör det ingen skillnad, vi betalade priset. Effekten är i buffring, nätverksnyttolast och din klient.

Du kan begränsa till topp 5 med ett Lua-skript:

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

Här en vänlig bild av Lua-manuset ovan:

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

Vi skickar en nyckel (indexet) och ett argument (gränsen för toppprodukter, 5 i ditt fall):1 product_tags 3 .

Med detta begränsade vi effekten till enbart buffring, sparad nätverksnyttolast och belastning på din klient.




  1. BSON-bibliotek för java?

  2. Är det möjligt att få enstaka resultat sammanlagt?

  3. Varför misslyckas Travis med att ansluta använder Redis cache_store när den distribueras till Heroku?

  4. 3 sätt att dölja ett index från frågeplanen i MongoDB