Golang usage

Taking a pause from the theory, let's look at how we can use Redis in Go. At the time of writing this book, there are two main Redis clients in Go:

As an example, we will take a feature where we want to maintain likes about a hotel in Redis. The following struct defines the entity we want to model:

type Hotel struct { 
   Id         string 
   Name       string 
   City       string 
   StarRating int 
   Likes      int 
} 

Here, we will use the Radix client. To install it, use the following command:

go get github.com/mediocregopher/radix.v2 

The first step is, of course, connecting. This can be done as follows:

   conn, err:= redis.Dial("tcp", "localhost:6379") 
   if err != nil { 
         panic(err) 
   } 
   defer conn.Close() 

The code connects to localhost. Of course, in production code, you should take this value as a configuration item.

Next, let's look at how we can save a hotel entity in Redis. The following code takes a hotel and saves it in Redis:

func setHotel(conn *redis.Client, h *Hotel) error { 
   resp:= conn.Cmd("HMSET", 
         "hotels:"+h.Id, 
         "name", h.Name, 
         "city", h.City, 
         "likes", h.Likes, 
         "rating", h.StarRating) 
   if resp.Err != nil { 
         fmt.Println("save err", resp.Err) 
         return resp.Err 
   } 
 
   return nil 
} 

As you can see, we are using the hashes data structure to store likes. This is because we know that the likes attribute will be independently incremented. HMSET is a multiple set for the hash object. Each hotel is identified by the string with the concatenation of "hotels" with the id of the hotel.

The following code gets a hotel with a specific hotel from Redis:

func getHotel(conn *redis.Client, id string) (*Hotel, error) { 
   reply, err:= conn.Cmd("HGETALL", "hotels:"+id).Map() 
   if err != nil { 
         return nil, err 
   } 
 
   h:= new(Hotel) 
   h.Id = id 
   h.Name = reply["name"] 
   h.City = reply["city"] 
   if h.Likes, err = strconv.Atoi(reply["likes"]); err != nil { 
         fmt.Println("likes err", err) 
         return nil, err 
   } 
   if h.StarRating, err = strconv.Atoi(reply["rating"]); err != nil { 
         fmt.Println("ratings err", err) 
         return nil, err 
   } 
 
   return h, nil 
} 

Here, we are using the HGETALL command to get all of the fields of a hash. Then, we use the Map() method of the response object to obtain a map of field names to the values. We then construct a hotel object from the individual fields.

Now, coming to the likes, which is a key method that required is to increment counts of a hotel. Along with maintaining counts, we also have a requirement of determining the most-liked hotels. To enable the latter requirement, we use a sorted-set dataset. The first code snippet implements a like for a hotel:

unc incrementLikes(conn *redis.Client, id string) error { 
 
   //  Sanity check to ensure that the hotel exists! 
   exists, err:= conn.Cmd("EXISTS", "hotels:"+id).Int() 
   if err != nil || exists == 0 { 
         return errors.New("no such hotel") 
   } 
 
   // Use the MULTI command to inform Redis that we are starting a new 
   // transaction. 
   err = conn.Cmd("MULTI").Err 
   if err != nil { 
         return err 
   } 
 
   // Increment the number of likes  for the hotel. in the album hash by 1. 
   // Because we have initiated a  MULTI command, this HINCRBY command is queued NOT executed. 
   // We still check the reply's Err field  to check if there was an error for the queing 
   err = conn.Cmd("HINCRBY", "hotels:"+id, "likes", 1).Err 
   if err != nil { 
         return err 
   } 
 
   // Now we increment the leaderboard sorted set 
   err = conn.Cmd("ZINCRBY", "likes", 1, id).Err 
   if err != nil { 
         return err 
   } 
 
   // Execute both commands in our transaction atomically. 
   // EXEC returns the replies from both commands as an array 
   err = conn.Cmd("EXEC").Err 
   if err != nil { 
         return err 
   } 
   return nil 
} 

This uses the MULTI option of redis to start a transaction and update both the likes for a hotel and the likes sorted set atomically.

The following code snippet gets the top-three liked hotels:

func top3LikedHotels(conn *redis.Client) ([]string, error) { 
   // Use the ZREVRANGE command to fetch the hotels from likes sorted set 
   // with  the highest score first 
   // The start and stop values are zero-based indexes, so we use 0 and 2 
   // respectively to limit the reply to the top three. 
 
   reply, err:= conn.Cmd("ZREVRANGE", "likes", 0, 2).List() 
   if err != nil { 
         return nil, err 
   } 
 
   return reply, nil 
 
} 

The ZREVRANGE command returns the sorted set members in reverse order of rank. Since it returns an array response, we use the List() helper function to convert the response to []string.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset