Riak の 2i を試してみる


Riak の Seconday Index (以後 2i) を試してみる。

## はじめに

1 台のサーバで Riak バージョン 1.3.1 を CentOS 6.4 にインストールした。2i を有効にするために、app.config でバックエンドストレージに ELevelDB を設定している。HTTP プロトコルを扱うクライアントとして curl と [httpie](https://github.com/jkbr/httpie) を使用している。

## インデックスオブジェクト

ひとつのオブジェクトに複数のインデックス項目を設定できる。

```
[on server01]$ ### インデックスを付けたオブジェクトを格納する
[on server01]$ curl -v -X PUT -d 'data1' -H "x-riak-index-field1_bin:val1" -H "x-riak-index-field2_int:1001" http://127.0.0.1:8098/riak/mybucket/mykey1
* About to connect() to 127.0.0.1 port 8098 (#0)
*   Trying 127.0.0.1... connected
* Connected to 127.0.0.1 (127.0.0.1) port 8098 (#0)
> PUT /riak/mybucket/mykey1 HTTP/1.1
> User-Agent: curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.14.0.0 zlib/1.2.3 libidn/1.18 libssh2/1.4.2
> Host: 127.0.0.1:8098
> Accept: */*
> x-riak-index-field1_bin: val1
> x-riak-index-field2_int: 1001
> Content-Length: 5
> Content-Type: application/x-www-form-urlencoded
> 
< HTTP/1.1 204 No Content
< Vary: Accept-Encoding
< Server: MochiWeb/1.1 WebMachine/1.9.2 (someone had painted it blue)
< Date: Thu, 27 Jun 2013 02:30:15 GMT
< Content-Type: application/x-www-form-urlencoded
< Content-Length: 0
< 
* Connection #0 to host 127.0.0.1 left intact
* Closing connection #0

[on server01]$ ### 格納したオブジェクトを主キーで取得する
[on server01]$ http localhost:8098/riak/mybucket/mykey1
HTTP/1.1 200 OK
Content-Encoding: gzip
Content-Length: 25
Content-Type: application/x-www-form-urlencoded
Date: Thu, 27 Jun 2013 02:54:04 GMT
ETag: "2TiABeHgQo586MBaPwmcCp"
Last-Modified: Thu, 27 Jun 2013 02:30:15 GMT
Link: </riak/mybucket>; rel="up"
Server: MochiWeb/1.1 WebMachine/1.9.2 (someone had painted it blue)
Vary: Accept-Encoding
X-Riak-Vclock: a85hYGBgzGDKBVIcXvnPqwNPT16SwZTIk8fKsF3e4TRfFgA=
x-riak-index-field1_bin: val1
x-riak-index-field2_int: 1001

data1
```

インデックスフィールド名に大文字が含まれる場合は小文字に変換される。

```
[on server01]$ ### インデックスフィールド名に大文字を含むオブジェクトを格納する
[on server01]$ curl -v -X PUT -d 'data2' -H "x-riak-index-Field1_bin:val2" -H "x-riak-index-Field2_int:1002" http://127.0.0.1:8098/riak/mybucket/mykey2
* About to connect() to 127.0.0.1 port 8098 (#0)
*   Trying 127.0.0.1... connected
* Connected to 127.0.0.1 (127.0.0.1) port 8098 (#0)
> PUT /riak/mybucket/mykey2 HTTP/1.1
> User-Agent: curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.14.0.0 zlib/1.2.3 libidn/1.18 libssh2/1.4.2
> Host: 127.0.0.1:8098
> Accept: */*
> x-riak-index-Field1_bin:val2
> x-riak-index-Field2_int:1002
> Content-Length: 5
> Content-Type: application/x-www-form-urlencoded
> 
< HTTP/1.1 204 No Content
< Vary: Accept-Encoding
< Server: MochiWeb/1.1 WebMachine/1.9.2 (someone had painted it blue)
< Date: Thu, 27 Jun 2013 02:37:36 GMT
< Content-Type: application/x-www-form-urlencoded
< Content-Length: 0
< 
* Connection #0 to host 127.0.0.1 left intact
* Closing connection #0

[on server01]$ ### 格納したオブジェクトを主キーで取得する
[on server01]$ http localhost:8098/riak/mybucket/mykey2
HTTP/1.1 200 OK
Content-Encoding: gzip
Content-Length: 25
Content-Type: application/x-www-form-urlencoded
Date: Thu, 27 Jun 2013 03:01:36 GMT
ETag: "37HUXH3xjNv5G8AQVWPJPl"
Last-Modified: Thu, 27 Jun 2013 02:37:36 GMT
Link: </riak/mybucket>; rel="up"
Server: MochiWeb/1.1 WebMachine/1.9.2 (someone had painted it blue)
Vary: Accept-Encoding
X-Riak-Vclock: a85hYGBgzGDKBVIcXvnPqwNPT16SwZTIlMfKUKDocJovCwA=
x-riak-index-field1_bin: val2
x-riak-index-field2_int: 1002

data2
```
インデックスフィールド名が大文字のみの場合も小文字に変換される。

```
[on server01]$ ### インデックスフィールド名に大文字を含むオブジェクトを格納する
[on server01]$ curl -v -X PUT -d 'data3' -H "X-RIAK-INDEX-FIELD1_BIN:val3" -H "X-RIAK-INDEX-FIELD2_INT:1003" http://127.0.0.1:8098/riak/mybucket/mykey3
* About to connect() to 127.0.0.1 port 8098 (#0)
*   Trying 127.0.0.1... connected
* Connected to 127.0.0.1 (127.0.0.1) port 8098 (#0)
> PUT /riak/mybucket/mykey3 HTTP/1.1
> User-Agent: curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.14.0.0 zlib/1.2.3 libidn/1.18 libssh2/1.4.2
> Host: 127.0.0.1:8098
> Accept: */*
> X-RIAK-INDEX-FIELD1_BIN:val3
> X-RIAK-INDEX-FIELD2_INT:1003
> Content-Length: 5
> Content-Type: application/x-www-form-urlencoded
> 
< HTTP/1.1 204 No Content
< Vary: Accept-Encoding
< Server: MochiWeb/1.1 WebMachine/1.9.2 (someone had painted it blue)
< Date: Thu, 27 Jun 2013 02:49:08 GMT
< Content-Type: application/x-www-form-urlencoded
< Content-Length: 0
< 
* Connection #0 to host 127.0.0.1 left intact
* Closing connection #0

[on server01]$ ### 格納したオブジェクトを主キーで取得する
[on server01]$ http localhost:8098/riak/mybucket/mykey3
HTTP/1.1 200 OK
Content-Encoding: gzip
Content-Length: 25
Content-Type: application/x-www-form-urlencoded
Date: Thu, 27 Jun 2013 02:51:07 GMT
ETag: "6grLbg0eKBqljxJyH2xZZZ"
Last-Modified: Thu, 27 Jun 2013 02:49:08 GMT
Link: </riak/mybucket>; rel="up"
Server: MochiWeb/1.1 WebMachine/1.9.2 (someone had painted it blue)
Vary: Accept-Encoding
X-Riak-Vclock: a85hYGBgzGDKBVIcXvnPqwNPT16SwZTIlMfKoKLicJovCwA=
x-riak-index-field1_bin: val3
x-riak-index-field2_int: 1003

data3
```

インデックスフィールド値は複数個指定でき、重複した値はユニークになるように取り除かれる。

```
[on server01]$ ### インデックスフィールド値に複数個指定したオブジェクトを格納する
[on server01]$ curl -v -X PUT -d 'data4' -H "x-riak-index-field1_bin:val4, val4, val4a, val4b" -H "x-riak-index-field2_int:1004, 1004, 1005, 1006" -H "x-riak-index-field2_int:1004" -H "x-riak-index-field2_int:1004" -H "x-riak-index-field2_int:1004" -H "x-riak-index-field2_int:1007" http://127.0.0.1:8098/riak/mybucket/mykey4
* About to connect() to 127.0.0.1 port 8098 (#0)
*   Trying 127.0.0.1... connected
* Connected to 127.0.0.1 (127.0.0.1) port 8098 (#0)
> PUT /riak/mybucket/mykey4 HTTP/1.1
> User-Agent: curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.14.0.0 zlib/1.2.3 libidn/1.18 libssh2/1.4.2
> Host: 127.0.0.1:8098
> Accept: */*
> x-riak-index-field1_bin:val4, val4, val4a, val4b
> x-riak-index-field2_int:1004, 1004, 1005, 1006
> x-riak-index-field2_int:1004
> x-riak-index-field2_int:1004
> x-riak-index-field2_int:1004
> x-riak-index-field2_int:1007
> Content-Length: 5
> Content-Type: application/x-www-form-urlencoded
> 
< HTTP/1.1 204 No Content
< Vary: Accept-Encoding
< Server: MochiWeb/1.1 WebMachine/1.9.2 (someone had painted it blue)
< Date: Thu, 27 Jun 2013 02:50:22 GMT
< Content-Type: application/x-www-form-urlencoded
< Content-Length: 0
< 
* Connection #0 to host 127.0.0.1 left intact
* Closing connection #0

[on server01]$ ### 格納したオブジェクトを主キーで取得する
[on server01]$ http localhost:8098/riak/mybucket/mykey4
HTTP/1.1 200 OK
Content-Encoding: gzip
Content-Length: 25
Content-Type: application/x-www-form-urlencoded
Date: Thu, 27 Jun 2013 02:51:08 GMT
ETag: "5XWGgxIagddHHbaInjJ4sk"
Last-Modified: Thu, 27 Jun 2013 02:50:22 GMT
Link: </riak/mybucket>; rel="up"
Server: MochiWeb/1.1 WebMachine/1.9.2 (someone had painted it blue)
Vary: Accept-Encoding
X-Riak-Vclock: a85hYGBgzGDKBVIcXvnPqwNPT16SwZTIlMfKkKficJovCwA=
x-riak-index-field1_bin: val4, val4a, val4b
x-riak-index-field2_int: 1004, 1005, 1006, 1007

data4
```

他のオブジェクトと同じインデックスを付けれる。

```
[on server01]$ ### 他のオブジェクト /mybucket/mykey4 と同じインデックスを付けたオブジェクトを格納する
[on server01]$ curl -v -X PUT -d 'data5' -H "X-RIAK-INDEX-FIELD1_BIN:val5" -H "X-RIAK-INDEX-FIELD2_INT:1005" http://127.0.0.1:8098/riak/mybucket/mykey5
* About to connect() to 127.0.0.1 port 8098 (#0)
*   Trying 127.0.0.1... connected
* Connected to 127.0.0.1 (127.0.0.1) port 8098 (#0)
> PUT /riak/mybucket/mykey5 HTTP/1.1
> User-Agent: curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.14.0.0 zlib/1.2.3 libidn/1.18 libssh2/1.4.2
> Host: 127.0.0.1:8098
> Accept: */*
> x-riak-index-field1_bin:val5
> x-riak-index-field2_int:1005
> Content-Length: 5
> Content-Type: application/x-www-form-urlencoded
> 
< HTTP/1.1 204 No Content
< Vary: Accept-Encoding
< Server: MochiWeb/1.1 WebMachine/1.9.2 (someone had painted it blue)
< Date: Thu, 27 Jun 2013 03:16:26 GMT
< Content-Type: application/x-www-form-urlencoded
< Content-Length: 0
< 
* Connection #0 to host 127.0.0.1 left intact
* Closing connection #0

[on server01]$ ### 格納したオブジェクトを主キーで取得する
[on server01]$ http localhost:8098/buckets/mybucket/index/field1_bin/val5
HTTP/1.1 200 OK
Content-Encoding: gzip
Content-Length: 37
Content-Type: application/json
Date: Thu, 27 Jun 2013 03:16:31 GMT
Server: MochiWeb/1.1 WebMachine/1.9.2 (someone had painted it blue)
Vary: Accept-Encoding

{
    "keys": [
        "mykey5"
    ]
}
```

## Exact Match クエリー

インデックスに一致するオブジェクトの key リストを返す。

```
[on server01]$ ### インデックス field1_bin=val1 の条件に一致するオブジェクトの key リストを取得する
[on server01]$ http localhost:8098/buckets/mybucket/index/field1_bin/val1
HTTP/1.1 200 OK
Content-Encoding: gzip
Content-Length: 37
Content-Type: application/json
Date: Thu, 27 Jun 2013 03:19:47 GMT
Server: MochiWeb/1.1 WebMachine/1.9.2 (someone had painted it blue)
Vary: Accept-Encoding

{
    "keys": [
        "mykey1"
    ]
}

[on server01]$ ### インデックス field2_int=1005 の条件に一致するオブジェクトの key リストを取得する
[on server01]$ http localhost:8098/buckets/mybucket/index/field2_int/1005
HTTP/1.1 200 OK
Content-Encoding: gzip
Content-Length: 42
Content-Type: application/json
Date: Thu, 27 Jun 2013 03:16:41 GMT
Server: MochiWeb/1.1 WebMachine/1.9.2 (someone had painted it blue)
Vary: Accept-Encoding

{
    "keys": [
        "mykey4", 
        "mykey5"
    ]
}
```

## Range クエリー

インデックスの範囲に一致するオブジェクトの key リストを返す。

```
[on server01]$ ### インデックス field1_bin=[val2-val4] の条件に一致するオブジェクトの key リストを取得する
[on server01]$ http localhost:8098/buckets/mybucket/index/field1_bin/val2/val4
HTTP/1.1 200 OK
Content-Encoding: gzip
Content-Length: 45
Content-Type: application/json
Date: Thu, 27 Jun 2013 03:32:58 GMT
Server: MochiWeb/1.1 WebMachine/1.9.2 (someone had painted it blue)
Vary: Accept-Encoding

{
    "keys": [
        "mykey3", 
        "mykey2", 
        "mykey4"
    ]
}

[on server01]$ ### インデックス field2_int=[1002-1007] の条件に一致するオブジェクトの key リストを取得する
[on server01]$ http localhost:8098/buckets/mybucket/index/field2_int/1002/1007
HTTP/1.1 200 OK
Content-Encoding: gzip
Content-Length: 48
Content-Type: application/json
Date: Thu, 27 Jun 2013 03:33:00 GMT
Server: MochiWeb/1.1 WebMachine/1.9.2 (someone had painted it blue)
Vary: Accept-Encoding

{
    "keys": [
        "mykey4", 
        "mykey4", 
        "mykey4", 
        "mykey4", 
        "mykey5", 
        "mykey3", 
        "mykey2"
    ]
}
```

## 特別なインデックスフィールド

インデックスフィールド $key を使用してオブジェクトの key リストを取得できる。

```
[on server01]$ ### インデックス $key=mykey1 の条件に一致するオブジェクトの key リストを取得する
[on server01]$ http localhost:8098/buckets/mybucket/index/\$key/mykey1
HTTP/1.1 200 OK
Content-Encoding: gzip
Content-Length: 37
Content-Type: application/json
Date: Thu, 27 Jun 2013 03:49:05 GMT
Server: MochiWeb/1.1 WebMachine/1.9.2 (someone had painted it blue)
Vary: Accept-Encoding

{
    "keys": [
        "mykey1"
    ]
}

[on server01]$ ### インデックス $key=[mykey3-mykey5] の条件に一致するオブジェクトの key リストを取得する
[on server01]$  http localhost:8098/buckets/mybucket/index/\$key/mykey3/mykey5
HTTP/1.1 200 OK
Content-Encoding: gzip
Content-Length: 45
Content-Type: application/json
Date: Thu, 27 Jun 2013 03:49:13 GMT
Server: MochiWeb/1.1 WebMachine/1.9.2 (someone had painted it blue)
Vary: Accept-Encoding

{
    "keys": [
        "mykey4", 
        "mykey5", 
        "mykey3"
    ]
}
```

インデックスフィールド $bucket を使用して全オブジェクトの key リストを取得できる。

```
[on server01]$ ### 全オブジェクトの key リストを取得する
[on server01]$ http localhost:8098/buckets/mybucket/index/\$bucket/_
HTTP/1.1 200 OK
Content-Encoding: gzip
Content-Length: 50
Content-Type: application/json
Date: Thu, 27 Jun 2013 03:50:52 GMT
Server: MochiWeb/1.1 WebMachine/1.9.2 (someone had painted it blue)
Vary: Accept-Encoding

{
    "keys": [
        "mykey5", 
        "mykey3", 
        "mykey4", 
        "mykey2", 
        "mykey1"
    ]
}
```

## おわり

パフォーマンスが気になるところだけど、2i の全機能を試せた。問い合わせに対する結果のソートされておらず、問い合わせするたびに順番がかわる挙動をしている。ソートが必要だったらクライアント側でやるか、MapReduce 連携を使えってことだね。インデックスの付け方によっては、Range クエリーの結果は重複した項目を含んでいる可能性があるってのは注意しないとな。

## 関連

* [CentOS 6.4 に Riak Cluster を構築する](http://qiita.com/na_ga/items/1abee5a44e2a348e869f)
* [Riak docs の 2i を意訳してみた](http://qiita.com/na_ga/items/2cc047c621da286aca44)
* [Riak docs の Configuring 2i を意訳してみた](http://qiita.com/na_ga/items/d0ca008d87e667a4cc27)
* [Riak docs の 2i Examples を意訳してみた](http://qiita.com/na_ga/items/b9f2e0b98128c6d9cb76)