Primero:
- Asegúrese de deshabilitar las funciones que no usará (
NOOFFSETS
,NOHL
,NOFREQS
,STOPWORDS 0
) - Usar
SORTABLE
para suNUMERIC
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.