sql >> Base de Datos >  >> NoSQL >> Redis

Vuelva a investigar el rendimiento agregado de los 5 mejores de cada grupo

Primero:

  • Asegúrese de deshabilitar las funciones que no usará (NOOFFSETS , NOHL ,NOFREQS , STOPWORDS 0 )
  • Usar SORTABLE para su NUMERIC score .

Aquí está el esquema que usé para probar:

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

Quieres pensar en FT.AGGREGATE como canalización.

El primer paso será ordenar los productos por @puntuación, para que luego, en el pipeline, cuando REDUCE TOLIST 1 @product_name , la lista sale ordenada:

SORTBY 2 @score DESC

Creo que ya estás haciendo LOAD /APPLY para lidiar con las etiquetas, como TAG de lo contrario, los campos se agruparían por la lista completa de etiquetas de cadenas separadas por comas, por producto. Consulte Permitir GROUPBY en el problema de los campos de etiquetas. Así que nuestro siguiente paso en el proceso es:

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

Luego agrupamos por @TAG y aplicamos las dos reducciones. Nuestra lista de productos saldrá ordenada.

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

Finalmente, ordenamos por @total_score :

SORTBY 2 @total_score DESC

Aquí una vista final del comando:

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

Aquí una lista completa de comandos para ilustrar el resultado. Usé productXX con puntuación XX para verificar fácilmente visualmente la clasificación de los productos.

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

Obtiene la lista completa de productos ordenados, no solo los 5 principales. En cuanto a la complejidad, no hay diferencia, pagamos el precio. El impacto está en el almacenamiento en búfer, la carga útil de la red y su cliente.

Puedes limitarte a los 5 mejores usando un script de Lua:

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

Aquí una vista amigable del script de Lua arriba:

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

Estamos pasando una clave (el índice) y un argumento (el límite para los mejores productos, 5 en su caso):1 product_tags 3 .

Con esto, limitamos el impacto solo al almacenamiento en búfer, guardamos la carga útil de la red y la carga en su cliente.