복붙노트

[REDIS] 레디 스 정렬 범위로 필터링 및 제 10 반환

REDIS

레디 스 정렬 범위로 필터링 및 제 10 반환

우리는 필드 간단한 MySQL의 테이블 (사용자)가 가정 :

id
rating
salary

내가 지정된 범위 (50 ~ 100)으로 가장 높은 평가 및 급여 10 명의 사용자를 얻으려면, 즉 MySQL은이 것

SELECT id from user WHERE salary>50 and salary<100 ORDER by rating limit 0, 10

이 100K 사용자 테이블에이 20ms 동안 실행됩니다.

내가 레디 스에서 동일한 있다고 가정 : Zlist 평가 (평가 => USER_ID) Zlist 급여 (급여 => USER_ID)

내가 레디 스에 본 모든 솔루션과 같은 불필요한 항목을 제거, 100,000 급여 Zlist을 복사하고, 100,000 평가 목록을 병합 포함

zinterstore 1 search salary
zremrange search -inf 50
zremrange search 100 +inf
zinterstore 2 search rating weights 0 1
zrange search 0 10

이는 절대적으로 느린 (그들 중 대부분을 제거하기 위해 100,000 요소를 복사 이유는 무엇입니까?).

적어도 상대적으로 효율적인 레디 스와이를 구현하는 방법은 없나요?

해결법

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

    1.당신이 설명하는 사용 사례는없는 NoSQL 솔루션에 우아하게 모델링 할 수 없습니다. 그것은 레디 스 제한되지 않습니다.

    당신이 설명하는 사용 사례는없는 NoSQL 솔루션에 우아하게 모델링 할 수 없습니다. 그것은 레디 스 제한되지 않습니다.

    나를 좀 더 있다고 설명하자. 당신은 하나 개의 필드에 범위 쿼리를 실행하고, 다른에 정렬된다. 이되는 NoSQL 솔루션에 좋은 일이 아니다. 예를 들어 Google App Engine은 이러한 쿼리를 금지한다. GAE 쿼리 제한에서 봐, 그리고 "다른 정렬 순서보다 먼저 정렬이어야합니다 불평등 필터의 속성"섹션을 읽어

    당신은 여전히 ​​효율적으로 쿼리를 실행할 수 있다고하는 데,하지만 해결책은 우아 될 수 없습니다.

    
    String userids[];
    for(rating = 10; rating > 0; rating--) {
      for(salary = min_salary; salary < max_salary; salary += 5000) {
          String salary_key = "users_with_salary:" + salary + "-" + (salary+5000);
          String rating_key = "users_with_rating:" + rating + "-" + (rating+1);
    
          userids.append(redis.sinter(salary_key, rating_key));
    
          if(userids.length > 10) {
             break;
          }
       }
    }
    
    

    레디 스 2.6 루아 스크립트와 함께, 당신도 루아 서버에서이 작업을 실행할 수 있습니다.

    당신이 당신의 데이터를 복잡한 쿼리를 실행하려면 결론적으로, 그것은 관계형 데이터베이스에 모델링하는 것이 가장 좋습니다.

  2. ==============================

    2.당신이 급여는 50에서 100 사이에있는 사용자 수와 TMP 세트에 결과를 저장하기 위해 "ZRANGEBYSCORE 급여 50 100"를 사용할 수있는 스크립팅. 당신이 키에 해시에서 "사용자 : [ID]를"사용자의 평가를 저장할 가정하면, 다음 "사용자가 SORT의 tmp를 : * -> 평가 LIMIT 0 10"할 수 있습니다.

    당신이 급여는 50에서 100 사이에있는 사용자 수와 TMP 세트에 결과를 저장하기 위해 "ZRANGEBYSCORE 급여 50 100"를 사용할 수있는 스크립팅. 당신이 키에 해시에서 "사용자 : [ID]를"사용자의 평가를 저장할 가정하면, 다음 "사용자가 SORT의 tmp를 : * -> 평가 LIMIT 0 10"할 수 있습니다.

    불행하게도 당신이 할 수없는 현재 SORT이 방법을 사용하기 위해 별도의 해시에 전용 또는 추가하거나 귀하의 평가 값을 저장해야합니다 있도록 ZSET의 항목과 관련된 점수 BY.

    물론, 당신은 또한 사용할 수있는 "ZINTERSTORE의 tmp2 2 등급의 tmp 가중치를 1 0"다음 "ZRANGE의 tmp2 0 10"그러나 그것은 tmp2의 모든 정렬의 오버 헤드를 필요로하기 때문에 그대로 그 (SORT를 사용하는 것보다 훨씬 효율적인 것 LIMIT와 SORT 효과적으로 실제로 반환 결과 10 정렬 부분 퀵 알고리즘을 사용하는 반면)이 생성된다. 당신은 어떤 경우에 적합 할 수 있습니다 평가에 의해 순위 50에서 100 사이의 급여와 사용자의 임시 ZSET를 저장하지만 신속 범위에서 다른 사용자에게 반환 할 수 있도록 tmp2 주위를 유지 할 수 있습니다.

    나는이 설명하는 SORT 방법은 실제로 알고리즘 좋은 같은 SQL 데이터베이스를 얻을 수있는 것처럼 생각합니다. 당신은 하나 개의 필드에 범위에 의해 필터 인덱스를 사용하면, 나는 또 다른 필드에 인덱스가 작은 결과 집합을 정렬의 효율성을 개선하는 데 사용될 수없는 방법을 알고. 나는 SQL 데이터베이스는 단순히 반환 종류의 결과 만에 부분 퀵 또는 그에 상당하는 것이라고 생각합니다.

  3. from https://stackoverflow.com/questions/10205635/redis-filter-by-range-sort-and-return-10-first by cc-by-sa and MIT license