1

I'm new to Redis and I have to say I love it till now :)

I'm bumping into an issue I'm not sure how to solve it in the more efficient way. I have a SET of HASH. Each HASH describe a post.

Here is the code to create and store the HASH:

// Create the HASH
$key = 'post:'.$post->getId();
$this->redis->hSet($key, 'created', $post->getCreated());
$this->redis->hSet($key, 'author', $post->getAuthor());
$this->redis->hSet($key, 'message', $post->getMessage());

// Store the HASH in the SET
$this->redis->sAdd('posts', $post->getId());

Now, previously I was storing all the post's attributes in a data field of the HASH (json_encoded) and I was fetching the information like this:

$key = 'posts';
$data = $this->redis->sort($key, array(
    'by' => 'nosort',
    'limit' => array($offset, $limit),
    'get' => 'post:*->data '
));

if (!is_array($data)) {
    return array();
}

foreach ($data as &$post) {
    $post = json_decode($post, true);
}

It was working great, I had all the posts information :)

But I had conflicts when updating the post in Redis (concurrent updates), so I've decided to have all the post's attributes in separated fields of the HASH and it fixed my issue of conflicts.

Now the problem I have is to fetch the HASH from my SET. Do I have to specify every single fields like this:

$key = 'posts';
$data = $this->redis->sort($key, array(
    'by' => 'nosort',
    'limit' => array($offset, $limit),
    'get' => array('post:*->created', 'post:*->author', 'post:*->message')
));

Or is there another way to fetch the full HASH directly within the SET?

I heard about pipeline but I'm not sure it's what I'm looking for and if I can use it with phpredis

Cheers, Maxime


UPDATE

I'm not sure I explained myself clearly. I have some elements in a set (post_id). I want to get the first 10 posts of the SET, which means I want 10 hash (with all their fields and value) in order to build a post object.

I was previously storing all the object information in one field of the hash (data), now I have one field per attribute of the object.

before:

myHash:<id> data

now:

myHash:<id> id "1234" created "2010-01-01" author "John"

Before I was using SORT to fetch the top 10 posts (and paginate easily), like this:

$key = 'posts';
$data = $this->redis->sort($key, array(
    'by' => 'nosort',
    'limit' => array(0, 10),
    'get' => 'post:*->data '
));

Now that I have X members to my hash I'm wondering what is the best solution.

Is it:

$key = 'posts';
$data = $this->redis->sort($key, array(
    'by' => 'nosort',
    'limit' => array($offset, $limit),
    'get' => 'post:*->data '
));

Or maybe:

$key = 'posts';
$data = $this->redis->sort($key, array(
    'by' => 'nosort',
    'limit' => array($offset, $limit),
    'get' => '#'
));

foreach($data as $post_id) {
   $posts[] = $this->redis->hGetAll('post:'.$post_id);
}

Or finally:

$key = 'posts';
$data = $this->redis->sort($key, array(
    'by' => 'nosort',
    'limit' => array($offset, $limit),
    'get' => '#'
));

$pipeline = $this->redis->multi();
foreach ($data as $post_id) {
    $pipeline->hGetAll('post:'.$post_id);
}

return $pipeline->exec();

Or something else that I don't know yet? What is the best, faster way to do this?

maxwell2022
  • 2,818
  • 5
  • 41
  • 60

2 Answers2

0

If you have read redis's source , you'll find that is not possible. There is a workaround that using lua script to combine 'sort' and 'hgetall' commands in a single redis invocation.

The 'get pattern' is processed by function 'lookupKeyByPattern'. https://github.com/antirez/redis/blob/unstable/src/sort.c#L61

yinqiwen
  • 604
  • 6
  • 6
-1

If you start with the redis.io documentation on hashes you'll find there are commands which allow you to get multiple hash members. In particular "HGETALL" for pulling all fields and values, or "HMGET" for pulling a set of fields with their values.

Additionally, for setting them I would recommend setting them in one pass with "HMSET"

The Real Bill
  • 14,884
  • 8
  • 37
  • 39