Redis 데이터 구조 세트

Set 유형은 순서가 지정되지 않은 고유한 키-값 컬렉션이며 저장 순서는 삽입된 순서대로 저장되지 않습니다. Redis의 컬렉션은 해시 테이블을 통해 구현되므로 추가, 삭제, 검색의 복잡성은 O(1)입니다. 목록과 비교할 때 컬렉션에는 순서가 지정되지 않은 것과 반복할 수 없다는 두 가지 특성이 있습니다.

세트는 대부분의 2^32-1요소를 저장할 수 있습니다. 이 개념은 기본적으로 수학의 개체 집합과 유사합니다.수학적 집합의 개념은 특정 속성을 가진 구체적이거나 추상적인 개체의 집합을 나타냅니다.

간단히 말해서 Redis 컬렉션은 고유한 값의 조합입니다. Redis는 집합(Set)의 데이터 구조를 이용하여 일부 집합 형태의 데이터를 저장할 수 있으며, 몇 가지 간단한 명령을 통해 교집합, 합집합, 차이 등 집합의 기본 연산도 지원합니다.


1. 데이터 유형 설정

1.1 세트타입 소개

Set 유형은 순서가 지정되지 않은 고유한 키-값 컬렉션이며 저장 순서는 삽입된 순서대로 저장되지 않습니다. Redis의 컬렉션은 해시 테이블을 통해 구현되므로 추가, 삭제, 검색의 복잡성은 O(1)입니다. 목록과 비교할 때 컬렉션에는 순서가 지정되지 않은 것과 반복할 수 없다는 두 가지 특성이 있습니다.

세트는 대부분의 2^32-1요소를 저장할 수 있습니다. 이 개념은 기본적으로 수학의 개체 집합과 유사합니다.수학적 집합의 개념은 특정 속성을 가진 구체적이거나 추상적인 개체의 집합을 나타냅니다.

간단히 말해서 Redis 컬렉션은 고유한 값의 조합입니다. Redis는 집합(Set)의 데이터 구조를 이용하여 일부 집합 형태의 데이터를 저장할 수 있으며, 몇 가지 간단한 명령을 통해 교집합, 합집합, 차이 등 집합의 기본 연산도 지원합니다.

1.2 적용 시나리오 설정

일반적인 적용 시나리오에는 투표 시스템, 라벨링 시스템, 상호 친구, 공통 관심, 공통 취미, 복권, 제품 심사 열, 액세스 IP 통계 등이 포함됩니다.

사용되는 장면:

  • 좋아요, 싫어요, 즐겨찾기: 세트 유형은 사용자가 하나만 좋아할 수 있음을 보장합니다.
  • 상호 관심, 태그: 세트 유형은 교차 작업을 지원하므로 친구, 공식 계정 등의 상호 관심을 계산하는 데 사용할 수 있습니다.
  • 경품 행사: 특정 활동에서 당첨자의 사용자 이름을 저장합니다. 세트 유형에는 중복 제거 기능이 있으므로 동일한 사용자가 두 번 당첨되지 않도록 할 수 있습니다.

2. 기본 구조 설정

2.1 List의 기본 구조 소개

Redis Set의 기본 저장소는 정수 집합 IntSet과 해시 테이블을 채택하고 둘은 상호 변환되며, IntSet 저장소를 사용하려면 다음 두 가지 조건을 충족해야 하며, 그렇지 않으면 HashTable을 사용하며 조건은 다음과 같습니다.

  • 바인딩 개체가 보유한 모든 요소는 정수 값입니다.
  • 컬렉션 개체에 의해 저장되는 요소 수는 512개를 초과하지 않습니다.

Set의 SADD 명령을 예로 들면 전체 추가 과정은 다음과 같습니다.

  • 세트가 존재하는지 확인하고 세트 조합을 생성하십시오.
  • 들어오는 Set 컬렉션에 따라 하나씩 추가하며, 추가 시 메모리 압축이 필요합니다.
  • setTypeAdd는 세트 추가 프로세스 중에 인코딩 변환을 수행할지 여부를 결정합니다.
void saddCommand(redisClient *c) {
    robj *set;
    int j, added = 0;
 
    // 取出集合对象
    set = lookupKeyWrite(c->db,c->argv[1]);
 
    // 对象不存在,创建一个新的,并将它关联到数据库
    if (set == NULL) {
        set = setTypeCreate(c->argv[2]);
        dbAdd(c->db,c->argv[1],set);
 
    // 对象存在,检查类型
    } else {
        if (set->type != REDIS_SET) {
            addReply(c,shared.wrongtypeerr);
            return;
        }
    }
 
    // 将所有输入元素添加到集合中
    for (j = 2; j < c->argc; j++) {
        c->argv[j] = tryObjectEncoding(c->argv[j]);
        // 只有元素未存在于集合时,才算一次成功添加
        if (setTypeAdd(set,c->argv[j])) added++;
    }
 
    // 如果有至少一个元素被成功添加,那么执行以下程序
    if (added) {
        // 发送键修改信号
        signalModifiedKey(c->db,c->argv[1]);
        // 发送事件通知
        notifyKeyspaceEvent(REDIS_NOTIFY_SET,"sadd",c->argv[1],c->db->id);
    }
 
    // 将数据库设为脏
    server.dirty += added;
 
    // 返回添加元素的数量
    addReplyLongLong(c,added);
}

집합의 단일 요소를 추가하는 과정을 좀 더 심층적으로 분석합니다. 우선, 그것이 이미 HashTable 코드라면 일반 HashTable 요소를 추가하고 IntSet로 판명되면 다음으로 넘어갑니다. 다음과 같은 판단을 내려야 합니다.

  • int 객체(isObjectRepresentableAsLongLong)로 변환할 수 있는 경우 IntSet을 사용하여 저장합니다.
  • IntSet으로 저장한 경우 길이가 5 12(REDIS_SET_MAX_INTSET_ENTRIES)를 초과하면 HashTable 인코딩으로 변환됩니다.
  • 다른 경우에는 HashTable이 저장용으로 사용됩니다.
2.2 정수 집합 IntSet

정수 집합 IntSet은 Redis에서 정수 값 집합을 저장하는 데 사용하는 데이터 구조로, int 유형 데이터를 저장하는 데 사용할 수 있으며 중복 요소가 나타나지 않도록 보장할 수 있습니다. 따라서 세트에 정수 요소만 포함되어 있고 그 수가 크지 않은 경우 Redis는 정수 세트를 기본 구현으로 사용하도록 선택합니다.

IntSet 내부는 실제로 배열(int8_t coentents[] 배열)로 되어 있으며, 데이터 검색은 이진 검색으로 이루어지기 때문에 데이터가 순서대로 저장됩니다.

img

컬렉션에 정수 값 요소만 있고 숫자가 가벼운 경우 Redis는 정수 컬렉션을 Redis 컬렉션의 기본 데이터 구조로 사용합니다. 다음 코드를 참조하세요:

typedef struct IntSet{
    
    
     // 编码格式
     uint32_t encoding;
     // 集合中的元素个数
     uint32_t length;
     // 保存元素数据
     int8_t contents[];
} IntSet;

그것을 분석해 봅시다:

속성 설명하다
"부호화" 부호화
"길이" 배열의 요소 수, 즉 배열의 전체 길이
"내용물[]" 각 요소가 배열의 배열 항목(항목)인 정수 컬렉션입니다. 특징: 값의 오름차순으로 정렬되며 중복된 내용이 포함되어 있지 않습니다.

"contents"는 정수 컬렉션의 각 요소를 저장하는 정수 컬렉션의 기본 구현이며, 각 요소는 배열에서 작은 것부터 큰 것 순으로 정렬되며 반복되지 않습니다(순서와 고유성을 보장하는 방법은 다음과 같습니다). 나중에 삽입에 대해 논의하는 것이 좋습니다). "contents" 배열은 int8_t 유형으로 선언되었지만 실제 유형은 "encoding" 값에 따라 달라집니다. 정수 집합을 연산할 때 "인코딩" 값을 먼저 얻습니다.

예를 들어 SADD numbers 1 3 5컬렉션 개체에 데이터를 삽입할 때 메모리에 있는 컬렉션 개체의 구조는 다음과 같습니다.

이미지-20230823235054892

2.3, 해시 테이블 HashTable

Redis의 키-값은 dictEntry 객체를 통해 구현되며, dictEntry를 다시 패키징하여 해시 테이블을 얻습니다. 이것이 해시 테이블 객체 dicttht입니다.

typedef struct dictht {
    dictEntry **table;//哈希表数组
    unsigned long size;//哈希表大小
    unsigned long sizemask;//掩码大小,用于计算索引值,总是等于size-1
    unsigned long used;//哈希表中的已有节点数
} dictht;

추신: 테이블은 배열이며 각 요소는 dictEntry 개체입니다.

hashtable인코딩된 컬렉션 개체는 기본 구현으로 사전을 사용합니다. 사전의 각 키는 문자열 개체이고, 각 문자열 개체는 컬렉션 요소에 해당하며 사전의 값은 입니다 NULL. SADD fruits "apple" "banana" "cherry"컬렉션 개체에 데이터를 삽입하기 위해 실행하면 컬렉션 개체의 메모리 구조는 다음과 같습니다.

이미지-20230823235716144


3. 공통 명령 설정

3.1 컬렉션 요소 추가

SADD 명령을 사용하여 컬렉션 요소 추가

SADD set value

값이 이미 존재하는 경우 추가하지 않고 0을 반환합니다.

이미지-20230821235344528

3.2 컬렉션의 모든 값 보기

컬렉션의 모든 값을 보려면 SMEMBERS 명령을 사용하십시오.

SMEMBERS set

이미지-20230821235614136

3.3 값이 집합에 있는지 확인

SISMEMBER 명령을 사용하여 값이 세트에 있는지 확인

이미지-20230821235954832

3.4 컬렉션에 저장된 값 개수 보기

SCARD 명령을 사용하여 컬렉션에 저장된 값 수를 확인하세요.

SCARD set

이미지-20230822000410786

3.5 컬렉션에서 지정된 값을 가진 요소 삭제

SREM을 사용하여 컬렉션에서 지정된 값을 가진 요소 제거

SREM set value

이미지-20230822000710429

3.6 집합에서 요소를 무작위로 선택

SRANDMEMBER 명령을 사용하여 컬렉션의 요소를 무작위로 선택

SRANDMEMBER set

이미지-20230822000949807

3.7 컬렉션의 요소를 무작위로 삭제

SPOP 명령을 사용하여 컬렉션의 요소를 무작위로 삭제합니다.

SPOP set

이미지-20230822001227634

3.8 한 세트의 값을 다른 세트로 이동

SMOVE 명령을 사용하여 한 세트에서 다른 세트로 값을 이동합니다.

SMOVE source target value

이미지-20230822001457709

3.9 집합 연산: 차이 집합

SDIFF 명령을 사용하여 작업 설정: 차이

SDIFF set1 set2

이미지-20230822001906994

3.10 집합 연산: 교차점

SINTER 명령을 사용하여 작업 설정: 교차점

SINTER set1 set2

이미지-20230822002039149

3.11 집합 연산: 합집합

집합 작업에는 SUNION 명령을 사용합니다.

SUNION set1 set2

이미지-20230822001939037

추천

출처blog.csdn.net/weixin_45187434/article/details/132463207