Redis
 sql >> Baza danych >  >> NoSQL >> Redis

Agregacja Redisearch zwraca 5 pierwszych z każdej grupy

Po pierwsze:

  • Pamiętaj, aby wyłączyć funkcje, których nie będziesz używać (NOOFFSETS , NOHL ,NOFREQS , STOPWORDS 0 )
  • Użyj SORTABLE dla Twojego NUMERIC score .

Oto schemat, którego użyłem do testowania:

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

Chcesz pomyśleć o FT.AGGREGATE jako potok.

Pierwszym krokiem będzie posortowanie produktów według @score, aby później, w dalszej kolejności, kiedy REDUCE TOLIST 1 @product_name , lista wychodzi posortowana:

SORTBY 2 @score DESC

Myślę, że już robisz LOAD /APPLY radzić sobie z tagami, jak TAG w przeciwnym razie pola byłyby pogrupowane według pełnej listy tagów ciągów oddzielonych przecinkami, dla każdego produktu. Zobacz Zezwalaj GROUPBY na problem z polami znaczników. Więc nasz następny krok jest w przygotowaniu:

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

Następnie grupujemy według @TAG i stosujemy dwie redukcje. Lista naszych produktów zostanie posortowana.

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

Na koniec sortujemy według @total_score :

SORTBY 2 @total_score DESC

Oto końcowy widok polecenia:

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

Oto pełna lista poleceń ilustrujących wynik. Użyłem productXX z wynikiem XX do łatwej weryfikacji wizualnej sortowania produktów.

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

Dostajesz posortowaną pełną listę produktów, a nie tylko 5. Złożoność nie ma znaczenia, zapłaciliśmy cenę. Wpływ ma na buforowanie, ładunek sieciowy i klienta.

Możesz ograniczyć się do 5 najlepszych za pomocą skryptu 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

Oto przyjazny widok powyższego skryptu Lua:

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

Przekazujemy jeden klucz (indeks) i jeden argument (limit dla najlepszych produktów, w Twoim przypadku 5):1 product_tags 3 .

Dzięki temu ograniczyliśmy wpływ tylko do buforowania, zapisanego ładunku sieciowego i obciążenia klienta.




  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. Jak zaimplementować funkcję limitu czasu pubsub w redis?

  2. Czas utworzenia klucza w redis

  3. Ustaw klucz prefiksu pamięci podręcznej Redis w Symfony

  4. Jak wywołać funkcję po zakończeniu funkcji asynchronicznych w pętli?

  5. Serie RedisTimeoutException przy użyciu StackExchange.Redis