복붙노트

[REDIS] 레디 스 매장의 UID를 설정하고 최선의 방법을 분류

REDIS

레디 스 매장의 UID를 설정하고 최선의 방법을 분류

나는이 사용자 ID의 user_ids 및 태그로 구성된 데이터를 가지고있다. user_ids 여러 번 발생 및 태그 (500)의 사전 지정 번호를 가지고 있지만 기능에 힘 변화가. 무엇 저장해야하는 것은, 자신의 태그와 자신의 카운트 USER_ID입니다. 나는 쉽게 최고 점수와 태그를 찾을 나중에 원하는 .. 등 태그가 증가되어 나타납니다 때마다

레디 스에서 내 구현 분류 세트를 사용하여 수행됩니다

다음과 같이 작동합니다 :

zincrby USER_ID : X 1 "tag0"

zincrby USER_ID : X 1 "tag499"

zincrby는 USER_ID : 예 1 "을 TAG3"

등등

내가 가장 높은 점수와 함께 태그를 얻고 싶은 마음에 가지고, 더 좋은 방법은 무엇입니까?

두 번째 문제는 지금 I 'm 내가 그것을 생산 시스템으로 목표 아니에요 알고 클라이언트 측 조작이 키를 검색하는 "* 키"를 사용한다는 것입니다.

게다가 그것은 (10000의 범위에서) 키를 지정된 수의 반복에 메모리 문제에 대한 좋은 것입니다. 그러나 나는 그들이 따르지 않는, 키가 메모리에 저장해야하는 것을 알고 I는 "zmalloc"에러 (4기가바이트 64 비트 비안 서버)를 피할 수 있도록 특정 패턴의 부분 검색을 허용한다. 키는 2 천만의 범위에 달할. 이견있는 사람?

해결법

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

    1.내 첫 번째 점은 매장 20M이 세트를 분류에 4기가바이트 꽉 참고하는 것입니다. 20M 사용자, 20 개 태그와 그들 각각의 64 비트에 8기가바이트에 대해 수행하게 빠른 시도 쇼 상자 (그리고 레디 스 2.4와 함께 제공 ziplist 메모리 최적화를 설정 정렬 된 것이 계정 - 심지어 이전 버전이 시도하지 않음) .

    내 첫 번째 점은 매장 20M이 세트를 분류에 4기가바이트 꽉 참고하는 것입니다. 20M 사용자, 20 개 태그와 그들 각각의 64 비트에 8기가바이트에 대해 수행하게 빠른 시도 쇼 상자 (그리고 레디 스 2.4와 함께 제공 ziplist 메모리 최적화를 설정 정렬 된 것이 계정 - 심지어 이전 버전이 시도하지 않음) .

    정렬 된 세트는 사용 사례를 지원하는 이상적인 데이터 구조입니다. 당신이 설명 된 바와 같이 나는 정확히를 사용합니다.

    당신이 지적한 바와 같이, KEYS 키에 반복 사용할 수 없습니다. 그것은 오히려 디버그 명령으로 의미한다. 키 반복을 지원하기 위해,이 액세스 경로를 제공하는 데이터 구조를 추가해야합니다. 반복을 지원할 수있는 레디 스의 부분만을 목록 및 (범위 방법을 통해) 정렬 된 세트이다. 그러나, 그들은 (목록)에 O (N ^ 2)를 반복 알고리즘을 O (N)를 변형 경향 또는 O (nlogn) (대 ZSET). 이 키가 제거 / 추가로 유지하기 어려울 것 때문에 목록은 저장 키에 빈약 한 선택입니다.

    보다 효율적인 솔루션은 일반 세트로 구성된 인덱스를 추가하는 것입니다. 당신은 양동이에 특정 사용자를 연결하는 해시 함수를 사용하고,이 버킷에 해당하는 세트에 사용자 ID를 추가해야합니다. 사용자 ID는 숫자 값 인 경우, 간단한 모듈로 기능이 충분합니다. 그렇지 않은 경우, 간단한 문자열의 해시 기능은 트릭을 할 것입니다.

    그래서 사용자에 반복을 지원하는 : 1000 사용자 : 2000 사용자 : 1001의이 모듈로 1000 기능을 선택할 수 있습니다. 사용자 : 1000 사용자 : 2000 버킷 인덱스에 넣어 될 것입니다 : 0 사용자 동안 : 1001 버킷 인덱스에 넣어 될 것이다 : 1.

    그래서 zsets의 상단에, 우리는 이제 다음 키를 가지고 :

    index:0 => set[ 1000, 2000 ]
    index:1 => set[ 1001 ]
    

    세트에서 키의 접두사가 필요, 그리고 레디 스의 세트 (Sripathi Krishnan에 의해 제안 된 세트 최적화 정수)가 작은만큼을 유지 제공 직렬화하여 메모리 사용을 최적화 할 수 없습니다.

    글로벌 반복 (1000)은 0 내지 버킷에 간단한 루프로 구성 (제외). 각각의 버킷은 SMEMBERS 명령의 대응하는 세트를 검색하기 위해 적용되며, 클라이언트에 대하여 반복 수 후 각 항목에 대한.

    다음은 파이썬의 예입니다 :

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    # ----------------------------------------------------
    
    import redis, random
    
    POOL = redis.ConnectionPool(host='localhost', port=6379, db=0)
    
    NUSERS = 10000
    NTAGS = 500
    NBUCKETS = 1000
    
    # ----------------------------------------------------
    # Fill redis with some random data
    
    def fill(r):
      p = r.pipeline()
      # Create only 10000 users for this example
      for id in range(0,NUSERS):
        user = "user:%d" % id
        # Add the user in the index: a simple modulo is used to hash the user id
        # and put it in the correct bucket
        p.sadd( "index:%d" % (id%NBUCKETS), id )
        # Add random tags to the user
        for x in range(0,20):
          tag = "tag:%d" % (random.randint(0,NTAGS))
          p.zincrby( user, tag, 1 )
        # Flush the pipeline every 1000 users
        if id % 1000 == 0:
          p.execute()
          print id
      # Flush one last time
      p.execute()
    
    # ----------------------------------------------------
    # Iterate on all the users and display their 5 highest ranked tags
    
    def iterate(r):
      # Iterate on the buckets of the key index
      # The range depends on the function used to hash the user id
      for x in range(0,NBUCKETS):
        # Iterate on the users in this bucket
        for id in r.smembers( "index:%d"%(x) ):
          user = "user:%d" % int(id)
          print user,r.zrevrangebyscore(user,"+inf","-inf", 0, 5, True )
    
    # ----------------------------------------------------
    # Main function
    
    def main():
      r = redis.Redis(connection_pool=POOL)
      r.flushall()
      m = r.info()["used_memory"]
      fill(r)
      info = r.info()
      print "Keys: ",info["db0"]["keys"]
      print "Memory: ",info["used_memory"]-m
      iterate(r)
    
    # ----------------------------------------------------
    
    main()
    

    정수를 조정하면이 데이터 구조의 글로벌 메모리 소비를 평가하기 위해이 프로그램을 사용할 수 있습니다.

    이 모든 항목에서 반복 O (1) 추가 복잡성 / 제거 사용자 및 사실 O (n)의 복잡도를 제공하기 때문에 IMO이 전략은 간단하고 효율적입니다. 유일한 단점은 키 반복 순서는 무작위입니다.

  2. from https://stackoverflow.com/questions/9127736/redis-sorted-sets-and-best-way-to-store-uids by cc-by-sa and MIT license