日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 综合教程 >内容正文

综合教程

Redis之ZSet命令

發(fā)布時(shí)間:2023/12/13 综合教程 32 生活家
生活随笔 收集整理的這篇文章主要介紹了 Redis之ZSet命令 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

0.前言

  Redis有序集合ZSet可以按分?jǐn)?shù)進(jìn)行排序, 存儲(chǔ)結(jié)構(gòu)可能使用ziplist,skiplist和hash表, zset_max_ziplist_entries和zset_max_ziplist_value兩個(gè)字段控制zset采用何種存儲(chǔ)方式, zset_max_ziplist_entries表示ziplist中存儲(chǔ)score和member占用的內(nèi)存空間超過(guò)該值, 則存儲(chǔ)結(jié)構(gòu)會(huì)轉(zhuǎn)變?yōu)閟kiplist和hash表; zset_max_ziplist_value表示ziplist中存儲(chǔ)的member值占用的內(nèi)存空間超過(guò)該值, 則存儲(chǔ)結(jié)構(gòu)會(huì)轉(zhuǎn)變?yōu)閟kiplist和hash表. 存儲(chǔ)使用ziplist時(shí), ziplist存儲(chǔ)格式為[member, score, member, score....], 以score值升序進(jìn)行排序.存儲(chǔ)使用skiplist時(shí), 需要hash表配合使用, hash表存儲(chǔ)以member為key, score為值, 加快member檢索score速度; skiplist存儲(chǔ)score和member, 并以score值進(jìn)行升序排序.

1.目錄

1.ZADD命令
2.ZCOUNT命令
3.ZRANGE命令
4.交集并集命令

2.ZADD命令

添加元素到有序集合中, 命令格式 : ZADD key score member [[score member] [score member] ...], 入口函數(shù)zaddCommand

void zaddCommand(redisClient *c) {
    zaddGenericCommand(c,0);
}
/*函數(shù)向有序集合中添加一個(gè)元素, 在incr值設(shè)置時(shí), 同時(shí)可以實(shí)現(xiàn)對(duì)score值進(jìn)行累加操作*/
void zaddGenericCommand(redisClient *c, int incr) {
    static char *nanerr = "resulting score is not a number (NaN)";
    robj *key = c->argv[1];
    robj *ele;
    robj *zobj;
    robj *curobj;
    double score = 0, *scores = NULL, curscore = 0.0;
    int j, elements = (c->argc-2)/2;
    int added = 0, updated = 0;

    if (c->argc % 2) {
        addReply(c,shared.syntaxerr);
        return;
    }

    /* 獲取scores值, score必須為數(shù)字, 否則直接返回錯(cuò)誤*/
    scores = zmalloc(sizeof(double)*elements);
    for (j = 0; j < elements; j++) {
        if (getDoubleFromObjectOrReply(c,c->argv[2+j*2],&scores[j],NULL)
            != REDIS_OK) goto cleanup;
    }

    /* 如果有序集合不存在, 直接進(jìn)行創(chuàng)建 */
    zobj = lookupKeyWrite(c->db,key);
    if (zobj == NULL) {
          /*對(duì)限制條件進(jìn)行判斷,選擇存儲(chǔ)結(jié)構(gòu)*/
        if (server.zset_max_ziplist_entries == 0 ||
            server.zset_max_ziplist_value < sdslen(c->argv[3]->ptr))
        {
               /*創(chuàng)建有序集合, 存儲(chǔ)結(jié)構(gòu)式skiplist*/
            zobj = createZsetObject();
        } else {
               /*創(chuàng)建有序集合, 存儲(chǔ)結(jié)構(gòu)式ziplist*/
            zobj = createZsetZiplistObject();
        }
        dbAdd(c->db,key,zobj);
    } else {
        if (zobj->type != REDIS_ZSET) {
            addReply(c,shared.wrongtypeerr);
            goto cleanup;
        }
    }

    for (j = 0; j < elements; j++) {
        score = scores[j];

        if (zobj->encoding == REDIS_ENCODING_ZIPLIST) {
            unsigned char *eptr;

            /* 在skiplist中進(jìn)行查找, 找到則刪除原來(lái)的, 插入新的, 否則直接進(jìn)行插入操作*/
            ele = c->argv[3+j*2];
            if ((eptr = zzlFind(zobj->ptr,ele,&curscore)) != NULL) {
                   /*incr值設(shè)置, 則需要進(jìn)行累加*/
                if (incr) {
                    score += curscore;
                    if (isnan(score)) {
                        addReplyError(c,nanerr);
                        goto cleanup;
                    }
                }
                /* 如果member和score都沒(méi)有變化, 則不進(jìn)行任何操作*/
                if (score != curscore) {
                    zobj->ptr = zzlDelete(zobj->ptr,eptr);
                    zobj->ptr = zzlInsert(zobj->ptr,ele,score);
                    server.dirty++;
                    updated++;
                }
            } else {
                /* 同樣插入元素時(shí)進(jìn)行檢測(cè)ziplist轉(zhuǎn)skiplist的閥值*/
                zobj->ptr = zzlInsert(zobj->ptr,ele,score);
                if (zzlLength(zobj->ptr) > server.zset_max_ziplist_entries)
                    zsetConvert(zobj,REDIS_ENCODING_SKIPLIST);
                if (sdslen(ele->ptr) > server.zset_max_ziplist_value)
                    zsetConvert(zobj,REDIS_ENCODING_SKIPLIST);
                server.dirty++;
                added++;
            }
        } else if (zobj->encoding == REDIS_ENCODING_SKIPLIST) {
            zset *zs = zobj->ptr;
            zskiplistNode *znode;
            dictEntry *de;
               /*存儲(chǔ)結(jié)構(gòu)為skiplist時(shí), 首先從hash表中通過(guò)member查找到score, 同樣找到刪除原來(lái)的, 找不到則直接插入*/
            ele = c->argv[3+j*2] = tryObjectEncoding(c->argv[3+j*2]);
            de = dictFind(zs->dict,ele);
            if (de != NULL) {
                curobj = dictGetKey(de);
                curscore = *(double*)dictGetVal(de);
                if (incr) {
                    score += curscore;
                    if (isnan(score)) {
                        addReplyError(c,nanerr);
                        goto cleanup;
                    }
                }
                /* member和score完全一樣, 則不進(jìn)行任何操作*/
                if (score != curscore) {
                    redisAssertWithInfo(c,curobj,zslDelete(zs->zsl,curscore,curobj));
                    znode = zslInsert(zs->zsl,score,curobj);
                    incrRefCount(curobj); /* Re-inserted in skiplist. */
                    dictGetVal(de) = &znode->score; /* Update score ptr. */
                    server.dirty++;
                    updated++;
                }
            } else {
                znode = zslInsert(zs->zsl,score,ele);
                incrRefCount(ele); /* Inserted in skiplist. */
                redisAssertWithInfo(c,NULL,dictAdd(zs->dict,ele,&znode->score) == DICT_OK);
                incrRefCount(ele); /* Added to dictionary. */
                server.dirty++;
                added++;
            }
        } else {
            redisPanic("Unknown sorted set encoding");
        }
    }
    if (incr) /* ZINCRBY */
        addReplyDouble(c,score);
    else /* ZADD */
        addReplyLongLong(c,added);

cleanup:
    zfree(scores);
    if (added || updated) {
        signalModifiedKey(c->db,key);
        notifyKeyspaceEvent(REDIS_NOTIFY_ZSET,
            incr ? "zincr" : "zadd", key, c->db->id);
    }
}

ZCOUNT命令

統(tǒng)計(jì)score值在一個(gè)范圍內(nèi)的元素?cái)?shù)量, 命令格式: ZCOUNT key min max, zcount操作其實(shí)很簡(jiǎn)單, ziplist存儲(chǔ)結(jié)構(gòu), 只需要依次遍歷然后比較score值是否在范圍內(nèi), 并記錄滿足條件的元素個(gè)數(shù)即可. skiplist可以對(duì)score值進(jìn)行快速檢索, 因此可以找到落入范圍內(nèi)開(kāi)始元素和結(jié)束元素排名, 通過(guò)簡(jiǎn)單運(yùn)算可以得出滿足條件的元素?cái)?shù)量.

void zcountCommand(redisClient *c) {
    robj *key = c->argv[1];
    robj *zobj;
    zrangespec range;
    int count = 0;

    /* 解析min和max參數(shù)值, 并放入range中 */
    if (zslParseRange(c->argv[2],c->argv[3],&range) != REDIS_OK) {
        addReplyError(c,"min or max is not a float");
        return;
    }
    
     /*查找有序集合*/
    if ((zobj = lookupKeyReadOrReply(c, key, shared.czero)) == NULL ||
        checkType(c, zobj, REDIS_ZSET)) return;

    if (zobj->encoding == REDIS_ENCODING_ZIPLIST) {
        unsigned char *zl = zobj->ptr;
        unsigned char *eptr, *sptr;
        double score;

        /* 查找第一個(gè)位于range范圍內(nèi)的元素*/
        eptr = zzlFirstInRange(zl,&range);

        /* 找不到直接返回空 */
        if (eptr == NULL) {
            addReply(c, shared.czero);
            return;
        }

        /* 找到第一個(gè)符號(hào)條件元素, 然后依次遍歷ziplist對(duì)符合條件的元素進(jìn)行計(jì)數(shù)*/
        sptr = ziplistNext(zl,eptr);
        score = zzlGetScore(sptr);
        redisAssertWithInfo(c,zobj,zslValueLteMax(score,&range));
        while (eptr) {
            score = zzlGetScore(sptr);

            /* score必須小于給定返回的最大值max, 否則計(jì)數(shù)結(jié)束 */
            if (!zslValueLteMax(score,&range)) {
                break;
            } else {
                count++;
                zzlNext(zl,&eptr,&sptr);
            }
        }
    } else if (zobj->encoding == REDIS_ENCODING_SKIPLIST) {
        zset *zs = zobj->ptr;
        zskiplist *zsl = zs->zsl;
        zskiplistNode *zn;
        unsigned long rank;

        /* skiplist中查找第一個(gè)落入范圍的元素 */
        zn = zslFirstInRange(zsl, &range);
        if (zn != NULL) {
              /*首先計(jì)算出大于min的元素個(gè)數(shù)count, rank獲取的是大于min值第一個(gè)元素排名*/
            rank = zslGetRank(zsl, zn->score, zn->obj);
            count = (zsl->length - (rank - 1));

            /* skiplist中查找最后一個(gè)落入范圍內(nèi)的元素 */
            zn = zslLastInRange(zsl, &range);
            if (zn != NULL) {
                    /*rank獲取的是最后一個(gè)落入返回內(nèi)的元素排名*/
                rank = zslGetRank(zsl, zn->score, zn->obj);
                    /*(zsl->length-rank)表示所有大于max元素?cái)?shù)量, 與count做減法計(jì)算出結(jié)果*/
                count -= (zsl->length - rank);
            }
        }
    } else {
        redisPanic("Unknown sorted set encoding");
    }
    addReplyLongLong(c, count);
}

ZRANGE命令

獲取一個(gè)位置范圍內(nèi)的元素, 命令格式: ZRANGE key start stop [WITHSCORES], start, stop元素代表位置下標(biāo), 從0開(kāi)始. 這里只對(duì)range操作進(jìn)行講述, 其他的range操作大同小異, 只是對(duì)增加了一些判斷的條件參數(shù), 不在展開(kāi)一一說(shuō)明.

void zrangeCommand(redisClient *c) {
    zrangeGenericCommand(c,0);
}
/*求range范圍內(nèi)元素*/
void zrangeGenericCommand(redisClient *c, int reverse) {
    robj *key = c->argv[1];
    robj *zobj;
    int withscores = 0;
    long start;
    long end;
    int llen;
    int rangelen;
    
     /*取出start和stop值*/
    if ((getLongFromObjectOrReply(c, c->argv[2], &start, NULL) != REDIS_OK) ||
        (getLongFromObjectOrReply(c, c->argv[3], &end, NULL) != REDIS_OK)) return;
     /*設(shè)置withscores標(biāo)志位*/
    if (c->argc == 5 && !strcasecmp(c->argv[4]->ptr,"withscores")) {
        withscores = 1;
    } else if (c->argc >= 5) {
        addReply(c,shared.syntaxerr);
        return;
    }
    if ((zobj = lookupKeyReadOrReply(c,key,shared.emptymultibulk)) == NULL
         || checkType(c,zobj,REDIS_ZSET)) return;

    /*由于start和end可以是負(fù)值, 全部進(jìn)行轉(zhuǎn)換為正值*/
    llen = zsetLength(zobj);
    if (start < 0) start = llen+start;
    if (end < 0) end = llen+end;
    if (start < 0) start = 0;

    /* 判斷range范圍是否符合條件,不合條件直接返回空 */
    if (start > end || start >= llen) {
        addReply(c,shared.emptymultibulk);
        return;
    }
     /*下標(biāo)超出范圍則置為為集合結(jié)尾元素位置*/
    if (end >= llen) end = llen-1;
    rangelen = (end-start)+1;

    /* Return the result in form of a multi-bulk reply */
    addReplyMultiBulkLen(c, withscores ? (rangelen*2) : rangelen);

    if (zobj->encoding == REDIS_ENCODING_ZIPLIST) {
        unsigned char *zl = zobj->ptr;
        unsigned char *eptr, *sptr;
        unsigned char *vstr;
        unsigned int vlen;
        long long vlong;
         
          /* ziplist首先找到start位置的元素, 然后依次遍歷rangelen個(gè)元素, 返回給客戶端*/
        if (reverse)
            eptr = ziplistIndex(zl,-2-(2*start));
        else
            eptr = ziplistIndex(zl,2*start);

        redisAssertWithInfo(c,zobj,eptr != NULL);
        sptr = ziplistNext(zl,eptr);
         
        while (rangelen--) {
            redisAssertWithInfo(c,zobj,eptr != NULL && sptr != NULL);
            redisAssertWithInfo(c,zobj,ziplistGet(eptr,&vstr,&vlen,&vlong));
            if (vstr == NULL)
                addReplyBulkLongLong(c,vlong);
            else
                addReplyBulkCBuffer(c,vstr,vlen);

            if (withscores)
                addReplyDouble(c,zzlGetScore(sptr));

            if (reverse)
                zzlPrev(zl,&eptr,&sptr);
            else
                zzlNext(zl,&eptr,&sptr);
        }

    } else if (zobj->encoding == REDIS_ENCODING_SKIPLIST) {
        zset *zs = zobj->ptr;
        zskiplist *zsl = zs->zsl;
        zskiplistNode *ln;
        robj *ele;

        /* skiplist同樣根據(jù)start位置, 找到相應(yīng)的元素, 遍歷rangelen個(gè)元素返回給客戶端*/
        if (reverse) {
            ln = zsl->tail;
            if (start > 0)
                ln = zslGetElementByRank(zsl,llen-start);
        } else {
            ln = zsl->header->level[0].forward;
            if (start > 0)
                ln = zslGetElementByRank(zsl,start+1);
        }

        while(rangelen--) {
            redisAssertWithInfo(c,zobj,ln != NULL);
            ele = ln->obj;
            addReplyBulk(c,ele);
            if (withscores)
                addReplyDouble(c,ln->score);
            ln = reverse ? ln->backward : ln->level[0].forward;
        }
    } else {
        redisPanic("Unknown sorted set encoding");
    }
}

交集并集命令

求交集zinterstore, 求并集zunionstore, 兩個(gè)命令操作相對(duì)比較復(fù)雜, 操作使用的是同一個(gè)函數(shù), 命令格式如下, 非常類似.

zinterstor命令格式 : ZINTERSTORE destination numkeys key [key ...] [WEIGHTS weight [weight ...]] [AGGREGATE SUM|MIN|MAX]
zunionstore命令格式: ZUNIONSTORE destination numkeys key [key ...] [WEIGHTS weight [weight ...]] [AGGREGATE SUM|MIN|MAX]

/*有序集合求并集入口函數(shù)*/
void zunionstoreCommand(redisClient *c) {
    zunionInterGenericCommand(c,c->argv[1], REDIS_OP_UNION);
}
/*有序集合求交集入口函數(shù)*/
void zinterstoreCommand(redisClient *c) {
    zunionInterGenericCommand(c,c->argv[1], REDIS_OP_INTER);
}

#define REDIS_AGGR_SUM 1  //求和操作
#define REDIS_AGGR_MIN 2  //取最小值
#define REDIS_AGGR_MAX 3  //取最大值
#define zunionInterDictValue(_e) (dictGetVal(_e) == NULL ? 1.0 : *(double*)dictGetVal(_e))

/*聚合操作函數(shù), 比較大小和求和操作*/
inline static void zunionInterAggregate(double *target, double val, int aggregate) {
    if (aggregate == REDIS_AGGR_SUM) {
        *target = *target + val;
        /* The result of adding two doubles is NaN when one variable
         * is +inf and the other is -inf. When these numbers are added,
         * we maintain the convention of the result being 0.0. */
        if (isnan(*target)) *target = 0.0;
    } else if (aggregate == REDIS_AGGR_MIN) {
        *target = val < *target ? val : *target;
    } else if (aggregate == REDIS_AGGR_MAX) {
        *target = val > *target ? val : *target;
    } else {
        /* safety net */
        redisPanic("Unknown ZUNION/INTER aggregate type");
    }
}
/*具體進(jìn)行并集和交集操作的函數(shù)*/
void zunionInterGenericCommand(redisClient *c, robj *dstkey, int op) {
    int i, j;
    long setnum;
    int aggregate = REDIS_AGGR_SUM;
    zsetopsrc *src;
    zsetopval zval;
    robj *tmp;
    unsigned int maxelelen = 0;
    robj *dstobj;
    zset *dstzset;
    zskiplistNode *znode;
    int touched = 0;

    /* 獲取表示key數(shù)量的numkeys字段 */
    if ((getLongFromObjectOrReply(c, c->argv[2], &setnum, NULL) != REDIS_OK))
        return;

    if (setnum < 1) {
        addReplyError(c,
            "at least 1 input key is needed for ZUNIONSTORE/ZINTERSTORE");
        return;
    }

    /* numkeys字段大于實(shí)際輸入的key數(shù)量, 直接返回語(yǔ)法錯(cuò)誤提示 */
    if (setnum > c->argc-3) {
        addReply(c,shared.syntaxerr);
        return;
    }

    /* 讀取所有的key對(duì)應(yīng)的集合 */
    src = zcalloc(sizeof(zsetopsrc) * setnum);
    for (i = 0, j = 3; i < setnum; i++, j++) {
        robj *obj = lookupKeyWrite(c->db,c->argv[j]);
        if (obj != NULL) {
            if (obj->type != REDIS_ZSET && obj->type != REDIS_SET) {
                zfree(src);
                addReply(c,shared.wrongtypeerr);
                return;
            }

            src[i].subject = obj;
            src[i].type = obj->type;
            src[i].encoding = obj->encoding;
        } else {
            src[i].subject = NULL;
        }
        /*weight默認(rèn)為1*/
        src[i].weight = 1.0;
    }

    /* 如果后面還有參數(shù), 解析剩余參數(shù)weights和aggregate字段 */
    if (j < c->argc) {
        int remaining = c->argc - j;

        while (remaining) {
            if (remaining >= (setnum + 1) && !strcasecmp(c->argv[j]->ptr,"weights")) {
                j++; remaining--;
                for (i = 0; i < setnum; i++, j++, remaining--) {
                    if (getDoubleFromObjectOrReply(c,c->argv[j],&src[i].weight,
                            "weight value is not a float") != REDIS_OK)
                    {
                        zfree(src);
                        return;
                    }
                }
            } else if (remaining >= 2 && !strcasecmp(c->argv[j]->ptr,"aggregate")) {
                j++; remaining--;
                if (!strcasecmp(c->argv[j]->ptr,"sum")) {
                    aggregate = REDIS_AGGR_SUM;
                } else if (!strcasecmp(c->argv[j]->ptr,"min")) {
                    aggregate = REDIS_AGGR_MIN;
                } else if (!strcasecmp(c->argv[j]->ptr,"max")) {
                    aggregate = REDIS_AGGR_MAX;
                } else {
                    zfree(src);
                    addReply(c,shared.syntaxerr);
                    return;
                }
                j++; remaining--;
            } else {
                zfree(src);
                addReply(c,shared.syntaxerr);
                return;
            }
        }
    }

    /* 對(duì)集合按集合元素多少進(jìn)行升序排列 */
    qsort(src,setnum,sizeof(zsetopsrc),zuiCompareByCardinality);
    
     /*創(chuàng)建一個(gè)新的集合存放計(jì)算結(jié)果*/
    dstobj = createZsetObject();
    dstzset = dstobj->ptr;
    memset(&zval, 0, sizeof(zval));

    if (op == REDIS_OP_INTER) {
        /* 最少元素集合為空直接跳過(guò)不執(zhí)行 */
        if (zuiLength(&src[0]) > 0) {
            /* 類似于無(wú)序集合求交集, 遍歷第一個(gè)集合, 并在剩余的集合中查找, 查找不到則跳過(guò)該元素, 全部查找到則將該元素放入結(jié)果集合dstzset中*/
            zuiInitIterator(&src[0]);
            while (zuiNext(&src[0],&zval)) {
                double score, value;

                score = src[0].weight * zval.score;
                if (isnan(score)) score = 0;

                for (j = 1; j < setnum; j++) {
                    /* 如果后面集合中有和第一個(gè)集合和第一個(gè)集合是同一個(gè)集合, 則特殊判斷, 因?yàn)榈僮鞑话踩?*/
                    if (src[j].subject == src[0].subject) {
                        value = zval.score*src[j].weight;
                        zunionInterAggregate(&score,value,aggregate);
                    } else if (zuiFind(&src[j],&zval,&value)) {
                              /* 找到元素, 然后score值與weight值做乘積, 最后進(jìn)行聚合操作*/
                        value *= src[j].weight;
                        zunionInterAggregate(&score,value,aggregate);
                    } else {
                        break;
                    }
                }
                   
                    /*只有待查元素在所有集合中都出現(xiàn),才將此元素添加進(jìn)結(jié)果集合中*/
                if (j == setnum) {
                    tmp = zuiObjectFromValue(&zval);
                    znode = zslInsert(dstzset->zsl,score,tmp);
                    incrRefCount(tmp); /* added to skiplist */
                    dictAdd(dstzset->dict,tmp,&znode->score);
                    incrRefCount(tmp); /* added to dictionary */
                         /*判斷并存儲(chǔ)最大元素長(zhǎng)度, 后面判斷是否需要轉(zhuǎn)換數(shù)據(jù)結(jié)構(gòu)*/
                    if (tmp->encoding == REDIS_ENCODING_RAW)
                        if (sdslen(tmp->ptr) > maxelelen)
                            maxelelen = sdslen(tmp->ptr);
                }
            }
            zuiClearIterator(&src[0]);
        }
    } else if (op == REDIS_OP_UNION) {
        dict *accumulator = dictCreate(&setDictType,NULL);
        dictIterator *di;
        dictEntry *de;
        double score;

        if (setnum) {
            /*為了盡可能的減少rehash操作, 擴(kuò)展存放結(jié)果字典空間為最后一個(gè)集合的大小, 上面已經(jīng)排序過(guò), 最后一個(gè)是最大的集合*/
            dictExpand(accumulator,zuiLength(&src[setnum-1]));
        }

        /* 下面開(kāi)始循環(huán)所有集合, 并在accumulator中查找, 如果找到則進(jìn)行相應(yīng)的運(yùn)算, 否則直接插入accumulator中*/
        for (i = 0; i < setnum; i++) {
            if (zuiLength(&src[i]) == 0) continue;

            zuiInitIterator(&src[i]);
            while (zuiNext(&src[i],&zval)) {
                /* Initialize value */
                score = src[i].weight * zval.score;
                if (isnan(score)) score = 0;

                /* 查找元素是否已經(jīng)在accumulator字典中 */
                de = dictFind(accumulator,zuiObjectFromValue(&zval));
                if (de == NULL) {
                    tmp = zuiObjectFromValue(&zval);
                    /* 記錄元素最長(zhǎng)的值, 后面用于判斷是否需要對(duì)集合進(jìn)行轉(zhuǎn)換*/
                    if (tmp->encoding == REDIS_ENCODING_RAW) {
                        if (sdslen(tmp->ptr) > maxelelen)
                            maxelelen = sdslen(tmp->ptr);
                    }
                    /* 直接添加到字典中 */
                    de = dictAddRaw(accumulator,tmp);
                    incrRefCount(tmp);
                    dictSetDoubleVal(de,score);
                } else {
                    /* 元素存在,按照指定的規(guī)則進(jìn)行運(yùn)算 */
                    zunionInterAggregate(&de->v.d,score,aggregate);
                }
            }
            zuiClearIterator(&src[i]);
        }
         
          /*遍歷將accumulator字典轉(zhuǎn)化為有序集合*/
         
        di = dictGetIterator(accumulator);
        dictExpand(dstzset->dict,dictSize(accumulator));
        while((de = dictNext(di)) != NULL) {
            robj *ele = dictGetKey(de);
            score = dictGetDoubleVal(de);
            znode = zslInsert(dstzset->zsl,score,ele);
            incrRefCount(ele); /* added to skiplist */
            dictAdd(dstzset->dict,ele,&znode->score);
            incrRefCount(ele); /* added to dictionary */
        }
        dictReleaseIterator(di);

        /* We can free the accumulator dictionary now. */
        dictRelease(accumulator);
    } else {
        redisPanic("Unknown operator");
    }
    
     /*存儲(chǔ)目標(biāo)key存在,則刪除原來(lái)的集合*/
    if (dbDelete(c->db,dstkey)) {
        signalModifiedKey(c->db,dstkey);
        touched = 1;
        server.dirty++;
    }
    if (dstzset->zsl->length) {
        /* 判斷是否需要將存儲(chǔ)結(jié)構(gòu)轉(zhuǎn)換為ziplist */
        if (dstzset->zsl->length <= server.zset_max_ziplist_entries &&
            maxelelen <= server.zset_max_ziplist_value)
                zsetConvert(dstobj,REDIS_ENCODING_ZIPLIST);

        dbAdd(c->db,dstkey,dstobj);
        addReplyLongLong(c,zsetLength(dstobj));
        if (!touched) signalModifiedKey(c->db,dstkey);
        notifyKeyspaceEvent(REDIS_NOTIFY_ZSET,
            (op == REDIS_OP_UNION) ? "zunionstore" : "zinterstore",
            dstkey,c->db->id);
        server.dirty++;
    } else {
        decrRefCount(dstobj);
        addReply(c,shared.czero);
        if (touched)
            notifyKeyspaceEvent(REDIS_NOTIFY_GENERIC,"del",dstkey,c->db->id);
    }
    zfree(src);
}

總結(jié)

以上是生活随笔為你收集整理的Redis之ZSet命令的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。