복붙노트

[REDIS] 각 그룹의 Redisearch 집계 반환 상위 5

REDIS

각 그룹의 Redisearch 집계 반환 상위 5

나는이 형식의 문서가 있다고 가정 :

product_name TEXT tags TAG score NUMERIC 

[product1, [tag1, tag2, tag3], 10]
[product2, [tag2, tag3, tag4], 100]
....

나는 제품의 점수 중 가장 높은 금액 순으로 태그를 반환하는 쿼리와 각 태그에 대한 제품의 상위 5 개 원하는 :

[tag3, 110, [product2, product 1]]
[tag2, 110, [product2, product 1]]
[tag4, 100, [product2]]
[tag1, 10, [product 1]]

내가 지금까지 (각 태그에 대해 반복) 개별적으로 각 제품 / 태그 키를 저장하는 것을 각각의 제품에 대한 우리는 각 태그에 대해 하나의 별도의 문서를 가지고 있으며 ID는 제품 이름과 태그 조합 : 제품 _ TEXT 태그 TAG 점수 숫자. 지금은 상위 태그의 목록을 가져 집계 쿼리를 실행할 수 있습니다 :

FT.AGGREGATE product_tags * 
   GROUP BY 1 @TAG 
     REDUCE SUM 1 @score as total_score
   SORT BY 2 @total_score DESC

이 순서대로 나에게 상위 태그를 제공하지만 난 내가 찾은 각 태그에 대한 상위 5 개 제품을 얻으려면 TOLIST 모든 제품이 정렬되지 반환 한 @product_name을 줄이기에만 존재하고 @score BY FIRST_VALUE 4 @product_name을 줄이려면이됩니다 첫 번째 최고 제품을 반환합니다 DESC.

의 하나 개의 쿼리에서 각 태그에 대한 상위 5 개 제품을 가정 해 봅시다 얻을 방법이 있나요. 없는 경우에는 문서 저장 형식을 변경 (또는 추가를 추가) 가능한 한 적은 쿼리로 쿼리 수의 또는이 종류를 만들 수있는 방법으로 할 수 있습니다?

문제가되지해야하지만 파이썬 Redisearch 클라이언트를 사용하고 있습니다.

해결법

  1. ==============================

    1.먼저:

    먼저:

    여기에 내가 시험에 사용되는 스키마는 다음과 같습니다

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

    당신은 파이프 라인으로 FT.AGGREGATE 생각합니다.

    첫 번째 단계는 우리가 TOLIST 1 @product_name을 줄이려 할 때 나중에, 아래로 파이프 라인의 것을, 목록 정렬 나온다 그래서, @score으로 제품을 분류하는 것입니다 :

    SORTBY 2 @score DESC
    

    나는 당신이 이미 TAG 필드가 다른 제품 당 전체 쉼표로 구분 된 문자열 태그 목록에 의해 그룹화하는 것처럼, 태그를 다루는 적용 / LOAD을하고있다 생각합니다. 태그 필드 문제에 GROUPBY 허용을 참조하십시오. 파이프 라인은 그렇게 우리의 다음 단계입니다 :

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

    우리 @TAG하여 다음 그룹 및 두 감축을 적용합니다. 우리의 제품 목록 정렬 나올 것입니다.

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

    마지막으로, 일종의 우리 @total_score의 :

    SORTBY 2 @total_score DESC
    

    명령의 최종보기 여기 :

    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
    

    결과를 설명하기 위해 명령의 전체 목록은 여기. 나는 쉽게 제품의 분류 시각적으로 확인하기 위해 점수 XX와 productXX을 사용했다.

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

    당신은 우리가 가격을 지불,이 차이가 없습니다뿐만 아니라 상위 5 복잡성이 많다는, 제품의 전체 목록이 정렬지고있다. 영향은 버퍼링, 네트워크 페이로드 및 클라이언트입니다.

    당신은 루아 스크립트를 사용하여 5 맨 위로 제한 할 수 있습니다 :

    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
    

    루아 스크립트 위의 여기에 친절한보기 :

    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
    

    1 product_tags 3 : 우리는 (귀하의 경우 상위 제품에 대한 제한, 5) 하나의 키 (인덱스)와 하나 개의 인수를 전달하고 있습니다.

    이, 우리는 클라이언트에만 저장 네트워크 페이로드 및로드 버퍼링에 미치는 영향을 제한했다.

  2. from https://stackoverflow.com/questions/59530799/redisearch-aggregate-return-top-5-of-each-group by cc-by-sa and MIT license