【问题标题】:Redis how to store associative array? Set or Hash or List?Redis如何存储关联数组?设置或散列或列表?
【发布时间】:2014-03-26 21:52:48
【问题描述】:

我对 Redis 的所有可用存储选项有点困惑。 我想做一些简单的事情,我不想过度设计它。 我正在使用 phpredisRedis v2.8.6

我有一个需要存储的简单关联数组。我还需要能够通过它的键检索一个项目并遍历所有项目。

$a = array(
    '12345' => array(
        'name' => 'Post A',
        'val2' => 'blah blah',
        'val3' => 'blah blah blah',
    ),
    '54321' => array(
        'name' => 'Post B',
        'val2' => 'blah blah',
        'val3' => 'blah blah blah',
    ),
    '998877' => array(
        'name' => 'Post C',
        'val2' => 'blah blah',
        'val3' => 'blah blah blah',
    )
);

所以到目前为止我所做的是使用hash 类型。像这样存储我的数组:

foreach ($a as $key => $value) {
    $this->redis->hSet('posts', $key, json_encode($value));
}

就像我可以像这样轻松访问密钥:

public function getPost($postId)
{
    return json_decode($this->redis->hGet('posts', $postId), true);
}

// This is returning the information of Post A
$post = getPost(12345);

但是现在我需要遍历所有我不知道该怎么做的帖子,以及我是否可以用我当前的结构来做。我不知道我是否需要将所有post_id 存储在另一个列表中以便能够遍历所有帖子?

所以我的问题是我应该使用哪种数据类型来存储我的帖子列表,允许我通过其 id 获取单个帖子并循环遍历所有帖子?

谢谢, 马克西姆

【问题讨论】:

    标签: redis associative-array phpredis


    【解决方案1】:

    你可以结合使用 SET 和 Hash 和 SORT

    redis 127.0.0.1:6379> HMSET TEST_12345 name "Post A" val2 "Blah Blah" val3 "Blah Blah Blah"
    OK
    redis 127.0.0.1:6379> HMSET TEST_54321 name "Post B" val2 "Blah Blah" val3 "Blah Blah Blah"
    OK
    redis 127.0.0.1:6379> HMSET TEST_998877 name "Post C" val2 "Blah Blah" val3 "Blah Blah Blah"
    OK
    redis 127.0.0.1:6379> SADD All_keys TEST_12345 TEST_54321 TEST_998877
    (integer) 3
    redis 127.0.0.1:6379> HGETALL TEST_12345
    

    获取一个哈希:

    redis 127.0.0.1:6379> HGETALL TEST_12345
    1) "name"
    2) "Post A"
    3) "val2"
    4) "Blah Blah"
    5) "val3"
    6) "Blah Blah Blah"
    

    获取所有哈希

    redis 127.0.0.1:6379> SORT All_keys BY nosort GET *->name GET *->val2 GET *->val3
    1) "Post A"
    2) "Blah Blah"
    3) "Blah Blah Blah"
    4) "Post B"
    5) "Blah Blah"
    6) "Blah Blah Blah"
    7) "Post C"
    8) "Blah Blah"
    9) "Blah Blah Blah"
    

    如果你不想使用排序,你可以使用 Fetch All the key names from SET using SMEMBERS 然后使用 Redis Pipeline 来获取所有的键

    【讨论】:

    • 所以除了将post 的哈希值存储在SET 中之外,没有其他解决方案了吗?如果我在SET 中有数百万个条目,那么SORTSMEMBERS 的最佳选择是什么?
    • 如果你注意到排序我使用的是 nosort 所以实际上它不会排序。另外,根据我的理想结构是 HASH 来保持键值对,我相信你不会一次获取数百万个值,你只会获取几个比如 50 然后你可以使用 Limit 和 sort 。 redis.io/commands/SORT
    • 如果我想从这个集合中删除所有散列怎么办?我是否必须遍历所有这些才能删除它们?
    • 您的意思是要清空 SET 还是要删除 HASH?
    • 两者。我想删除SET 和它包含的所有HASH。我只是在进行计算时使用 Redis 作为缓冲区,计算后我将结果保存在 MySQL 中,我想删除我将不再使用的 Redis 存储对象。
    【解决方案2】:

    对于寻找 PHP 代码的人来说,这是我最终使用的:

    // Create a post hash
    $key = 'post:'.$post->getId();
    $this->redis->hSet($key, 'data', serialize($post->toArray()));
    
    // Add a post in the account posts SET
    $this->redis->sAdd($account->getId().':posts', $post->getId());
    
    // You can execute the above code as many time as you need 
    // to add an object in a SET
    
    // Fetch the first $limit posts for this account
    // SORT <account_id>:posts BY nosort GET <account_id>:post:*->data
    $key = $account->getId().':posts';
    $keys = $this->redis->sort($key, array(
        'by' => 'nosort',
        'limit' => array($offset, $limit),
        'get' => 'post:*->data'
    ));
    
    // All Good !
    var_dump($keys);
    

    我希望这会对你们中的一些人有所帮助;)

    【讨论】:

    • 你应该检查 igbinary:$igbinary = function_exists('igbinary_serialize'); $encoded = $igbinary ? igbinary_serialize($data) : serialize($data); 它应该比常规序列化稍快。
    【解决方案3】:

    在 PHP 中你可以这样做

    $redis->set($key, json_encode($value));
    

    然后

    $value = json_decode($redis->get($key));
    

    或者使用您喜欢的任何序列化技术。 JSON 编码/解码的性能足以让我不在乎。

    【讨论】:

    • 但是当您需要为数千个结果执行此操作时,它可能会使用不必要的资源。使用仅 redis 的解决方案不太可能让您陷入性能问题。
    • @BobKruithof 是的,绝对他妈的。这个答案有点肮脏,我对此感到有些羞耻。不过,它确实对我当时正在做的事情很好。
    猜你喜欢
    • 2012-02-17
    • 1970-01-01
    • 1970-01-01
    • 2021-07-28
    • 2021-02-23
    • 1970-01-01
    • 1970-01-01
    • 2014-05-19
    • 2015-10-09
    相关资源
    最近更新 更多