今更ですが、Riakを使ってみる


以前試しで Redis を使ってたのですが、メモリ上限が気になって本番環境ではどうだろう、とちょっと躊躇してましたが、「Riakとかどうだろう？」って教えてもらったので、さっそく使ってみました。

##インストール
インストールを試みましたが、環境が古くてできませんでした。。。
なので、すでにインストール済みの環境を借りることができたので、それを使います。
\# たぶん apt とかでインストールできるかと。。。
\# version は 2.0.0 でした。


##Rubyから使う
```
gem install 'riak-client'
```
でライブラリをインストールします。

##っとその前に Riak について
Riak は Erlang で記述された Key-Value Store です。
NoSQLは最近流行ってますね。
データの構造とかは特に考えずに、どかーっとデータを格納して利用したい場面で使います(^^;
あとは色々特徴がありますが、公式を参照してみてください。

##基本
Riak は bucket と呼ばれる バケツ にデータを ガーっ と入れます。
バケツ に入れるデータは Key で一意にわかるようなデータで、なんでも入ります。
基本的にはバケツ毎管理なので、バケツが違えば同じ Key でも問題ないみたいです。
ただし、bucket_type というものを使ってくるめることもできるみたいです。


###接続
```
require "riak"

client = Riak::Client.new(:nodes => [{:host => "localhost", :protocol => "pbc", :pb_port => 8087}])
```
ノードを複数設定することも可能です。

###バケツの生成
```
bucket = client.bucket("users")
```
users バケツを作りました。
この中に色々入れていきます。
が、このままでは入れて出すだけしかできないので、検索できるように設定します。

###検索設定
```
client.create_search_index("users")
client.set_bucket_props(bucket, { :search_index => "users" })
```
users に検索インデックスを作成しました。これで検索ができるようになりました。

###データ登録
ポイントは、検索対象の項目には _s とか目印をつけなければならないところです。
検索対象が文字列の場合は、 ```_s (string)``` 
検索対象が数値の場合は、 ```_i (int)、_l (long)、_d (double)``` 
検索対象がブール値の場合は、 ```_b (boolean)``` 
などです。

```
user = bucket.new("Manaka Laala")
user.data = {:birthday_s => "11/20", :bloodtype_s => "O", :favorite_s => "pizza", :charm_s => "lovly", :team_s => "SoLaMiSmile"}
user.store

user = bucket.new("Minami Mirei")
user.data = {:birthday_s => "10/01", :bloodtype_s => "A", :favorite_s => "sweets", :charm_s => "pop", :team_s => "SoLaMiSmile"}
user.store

user = bucket.new("Hojo Sophy")
user.data = {:birthday_s => "07/30", :bloodtype_s => "AB", :favorite_s => "red-flush", :charm_s => "cool", :team_s => "SoLaMiSmile"}

user = bucket.new("Todo Shion")
user.data = {:birthday_s => "01/05", :bloodtype_s => "B", :favorite_s => "daifuku", :charm_s => "cool", :team_s => "DressingPafe"}
user.store

user = bucket.new("Dorothy West")
user.data = {:birthday_s => "02/05", :bloodtype_s => "A", :favorite_s => "monja-yaki", :charm_s => "pop", :team_s => "DressingPafe"}
user.store

user = bucket.new("Reona West")
user.data = {:birthday_s => "02/05", :bloodtype_s => "A", :favorite_s => "strawberry pafe", :charm_s => "pop", :team_s => "DressingPafe"}
user.store
```

bucket.new の引数が キー になります。これが一意の値でないといけません。
同じ場合は、上書きされるので注意しましょう。
\# 実際に使用する場合は、Key は 一意の ID になるのでしょう。

###呼び出し、上書き、削除
```
user = bucket.get("Minami Mirei")
```
Riak::RObject で帰ってきます。
中身は user.data で見ることができます。
キーが無い場合はエラーになります。

```
user = bucket.get("Shiratama Mikan")

#> Expected success from Riak but received not_found. The requested object was not found.(Riak::ProtobuffsFailedRequest)
```

上書きは先ほども触れましたが、同じキーで get して store するだけです。

```
user = bucket.get("Manaka Laala")
user.data[:favorite_s] = "pizza, da-gashi"
user.store
```

削除は delete です。キーを指定して削除します。

```
bucket.delete("Dorothy West")
```

###検索
検索設定をしていれば案外簡単です。

```
result = client.search("users", "charm_s:cool")
```
これで charm_s が cool のものを取ってきます。
上の例では Sophy と Shion が返ってきます。
ヒットした数は result["num_found"] に格納されています。
実際の値は result["docs"] に配列として格納されていますので、取り出して利用します。

```
p result["num_found"]
#> 2

p result["docs"]
#> [{"score"=>"1.83000e+00", "_yz_rb"=>"users", "_yz_rt"=>"default", "_yz_rk"=>"Hojo Sophy", "_yz_id"=>"1*default*users*Hojo Sophy*6", "birthday_s"=>"07/30", "bloodtype_s"=>"AB", "favorite_s"=>"red-flush", "charm_s"=>"cool", "team_s"=>"SoLaMiSmile"}, {...}]
```


が、戻りは普通のハッシュデータなので、キーを取得して、バケツから取り出した方が素直かもしれません。
キーは ```_yz_rk``` で、バケツは ```_yz_rb``` です。

```
result["docs"].each do |doc|
  key = doc["_yz_rk"]
  user = bucket.get(key)
  ...
end
```

###検索文字列
上記の例では ```charm_s:cool``` がこれに該当します。
これは、 ```charm_s が cool のもの``` で SQL文では ```charm_s = 'cool'``` にあたります。
同様に、

```
charm_s like '%c%' は charm_s:*c* になります。
charm_s = 'pop' and team_s like '%So%' の場合は charm_s:pop AND team_s:*So* になります。
```

AND は大文字でないと認識しないので注意しましょう。
数値の場合は

```
age = 10 は age_i:10
age > 10 and age =< 15 は age_i:[11 TO 15]
```

です。

とりあえず、以上な感じですかね。
普通に使う感じではこれくらいあればいけるかなと思います。