Yokozuna ~期待の全文検索機能~

「RiakってKVSなんでしょ？そんなん使いどころ少ないし(ﾟ⊿ﾟ)ｲﾗﾈ」
「結局やっぱ検索が重要だし、mongoじゃないとねー」
そんなふうに思っているアナタに贈るRiak2.0注目の新機能。
みんなでやるRIak Advent Calendar７日目は、全文検索機能Yokozunaの紹介だ。

## Yukozunaの概要
端的に言うと、全文検索エンジンApache Solrの管理をRiakで行うというものだ。
RiakにストアされたデータからSolrのインデックスを作成する。
データの管理もインデックスの管理もRiakが行う。
また、Solrの死活監視もRiakが行う。
これによって実現されるのは、強力な検索機能を持った落ちないDB。
それがYokozuna。

## なんでYokozunaという名前なのか
README曰く、
> Horizontal rope. The top rank in sumo, usually translated Grand Champion. The name comes from the rope a yokozuna wears.
> The goal of the Yokozuna application is to integrate Apache Solr with Riak in order to find the "top rank" documents for a given query.

一番最初が"横の綱"という説明で、外国の人がわかるのだろうか...
字面そのままじゃね...?

という揚げ足取りはさておき、Riak YokozunaにはTop Rankになってほしいものだぜ！！

## セットアップ
YukozunaのREADMEに従えば簡単だ。
Erlang R15B03以上、Java 1.6以上が必要なので注意。
ちなみに、推奨は16B02、Oracle 7u25らしい。
今回はR15B03-1とOpenJDK 1.7なのでどうなんだろ...
クラスタを試してもいいけど、使ってみたいだけなのでとりあえずシングルノードで。
起動前に、設定を書き換えておく。

```
[vagrant@localhost riak]$ sed -e 's/search = off/search = on/' -i.back rel/riak/etc/riak.conf
```
いつものように起動する

```
[vagrant@localhost riak]$ rel/riak/bin/riak start
[vagrant@localhost riak]$ rel/riak/bin/riak ping
pong
```

## とりあえず使ってみよう
Yokozunaを使うには、最初にBucket Typeを作成する必要がある。
これについては二日目にBucket Typesを参考にしてほしい。

```
[vagrant@localhost riak]$ rel/riak/bin/riak-admin bucket-type \ 
> create my_type '{"props":{"search_index":"my_index"}}'
my_type created

[vagrant@localhost riak]$ rel/riak/bin/riak-admin bucket-type \
> activate my_type
my_type has been activated
```
で、次にインデックスを設定する。

```
[vagrant@localhost riak]$ curl -XPUT -i 'http://localhost:8098/search/index/my_index'
HTTP/1.1 204 No Content
Server: MochiWeb/1.1 WebMachine/1.10.5 (jokes are better explained)
Date: Sat, 07 Dec 2013 14:24:22 GMT
Content-Type: application/json
Content-Length: 0
```
あとはデータを入れるだけで、良い感じにインデキシングしてくれる。

```
[vagrant@localhost riak]$ curl -H 'content-type: text/plain' \
> -X PUT 'http://localhost:8098/types/my_type/buckets/my_bucket/keys/name' \
> -d "saisa 6153"
```
クエリを投げるとxmlが帰ってくる。

```
[vagrant@localhost riak]$ curl 'http://localhost:8098/search/my_index?q=text:saisa'
<?xml version="1.0" encoding="UTF-8"?>
<response>
<lst name="responseHeader"><int name="status">0</int><int name="QTime">16</int><lst name="params"><str name="shards">127.0.0.1:8093/solr/my_index</str><str name="q">text:saisa</str><str name="fq">(_yz_node:riak@127.0.0.1 AND (_yz_pn:63 OR (_yz_pn:60 AND (_yz_fpn:60)) OR _yz_pn:59 OR _yz_pn:56 OR _yz_pn:53 OR _yz_pn:50 OR _yz_pn:47 OR _yz_pn:44 OR _yz_pn:41 OR _yz_pn:38 OR _yz_pn:35 OR _yz_pn:32 OR _yz_pn:29 OR _yz_pn:26 OR _yz_pn:23 OR _yz_pn:20 OR _yz_pn:17 OR _yz_pn:14 OR _yz_pn:11 OR _yz_pn:8 OR _yz_pn:5 OR _yz_pn:2))</str></lst></lst><result name="response" numFound="1" start="0" maxScore="0.8784157"><doc><str name="_yz_id">my_type_my_bucket_name_41_2bc30rswtUNBw8YGIg9NWb</str><str name="_yz_rk">name</str><str name="_yz_rt">my_type</str><str name="_yz_rb">my_bucket</str></doc></result>
</response>
```
僕はsolrに不慣れなのでよくわからないが、numFoundを見るとちゃんと機能しているっぽいことがわかる。

```
[vagrant@localhost riak]$ curl -H 'content-type: text/plain' \
> -X PUT 'http://localhost:8098/types/my_type/buckets/my_bucket/keys/name' \
> -d "saisa 6154"
[vagrant@localhost riak]$ curl -H 'content-type: text/plain' \
> -X PUT 'http://localhost:8098/types/my_type/buckets/my_bucket/keys/name' \
> -d "saisa 6155"
[vagrant@localhost riak]$ curl -H 'content-type: text/plain' \
> -X PUT 'http://localhost:8098/types/my_type/buckets/my_bucket/keys/name' \
> -d "saisa 6156"

[vagrant@localhost riak]$ curl 'http://localhost:8098/search/my_index?q=text:saisa'
<?xml version="1.0" encoding="UTF-8"?>
<response>
<lst name="responseHeader"><int name="status">0</int><int name="QTime">13</int><lst name="params"><str name="shards">127.0.0.1:8093/solr/my_index</str><str name="q">text:saisa</str><str name="fq">(_yz_node:riak@127.0.0.1 AND ((_yz_pn:62 AND (_yz_fpn:62)) OR _yz_pn:61 OR _yz_pn:58 OR _yz_pn:55 OR _yz_pn:52 OR _yz_pn:49 OR _yz_pn:46 OR _yz_pn:43 OR _yz_pn:40 OR _yz_pn:37 OR _yz_pn:34 OR _yz_pn:31 OR _yz_pn:28 OR _yz_pn:25 OR _yz_pn:22 OR _yz_pn:19 OR _yz_pn:16 OR _yz_pn:13 OR _yz_pn:10 OR _yz_pn:7 OR _yz_pn:4 OR _yz_pn:1))</str></lst></lst><result name="response" numFound="4" start="0" maxScore="0.714438"><doc><str name="_yz_id">my_type_my_bucket_name_40_2bc30rswtUNBw8YGIg9NWb</str><str name="_yz_rk">name</str><str name="_yz_rt">my_type</str><str name="_yz_rb">my_bucket</str></doc><doc><str name="_yz_id">my_type_my_bucket_name_40_2aIAVqcBF1ofLErIZ3njhM</str><str name="_yz_rk">name</str><str name="_yz_rt">my_type</str><str name="_yz_rb">my_bucket</str></doc><doc><str name="_yz_id">my_type_my_bucket_name_40_6b1S6KjPezKTQuWLzc86rR</str><str name="_yz_rk">name</str><str name="_yz_rt">my_type</str><str name="_yz_rb">my_bucket</str></doc><doc><str name="_yz_id">my_type_my_bucket_name_40_61ulEKXw5DmxJBlyIE9lPr</str><str name="_yz_rk">name</str><str name="_yz_rt">my_type</str><str name="_yz_rb">my_bucket</str></doc></result>
</response>
```

## 日本語だとどうなるのか
```
[vagrant@localhost riak]$ curl -H 'content-type: text/plain' \
> -X PUT 'http://localhost:8098/types/my_type/buckets/my_bucket/keys/name1’ \
> -d "彼女がほしい"
[vagrant@localhost riak]$ curl -H 'content-type: text/plain' \
> -X PUT 'http://localhost:8098/types/my_type/buckets/my_bucket/keys/name2’ \
> -d "アドベントカレンダー書いてる場合じゃねぇ"
[vagrant@localhost riak]$ curl -H 'content-type: text/plain' \
> -X PUT 'http://localhost:8098/types/my_type/buckets/my_bucket/keys/name3' \
> -d "どこに行けば彼女落ちてますか"

[vagrant@localhost riak]$ curl 'http://localhost:8098/search/my_index?q=text:彼女'
<?xml version="1.0" encoding="UTF-8"?>
<response>
<lst name="responseHeader"><int name="status">0</int><int name="QTime">364</int><lst name="params"><str name="shards">127.0.0.1:8093/solr/my_index</str><str name="q">text:彼女</str><str name="fq">(_yz_node:riak@127.0.0.1 AND (_yz_pn:64 OR (_yz_pn:61 AND (_yz_fpn:61)) OR _yz_pn:60 OR _yz_pn:57 OR _yz_pn:54 OR _yz_pn:51 OR _yz_pn:48 OR _yz_pn:45 OR _yz_pn:42 OR _yz_pn:39 OR _yz_pn:36 OR _yz_pn:33 OR _yz_pn:30 OR _yz_pn:27 OR _yz_pn:24 OR _yz_pn:21 OR _yz_pn:18 OR _yz_pn:15 OR _yz_pn:12 OR _yz_pn:9 OR _yz_pn:6 OR _yz_pn:3))</str></lst></lst><result name="response" numFound="2" start="0" maxScore="0.66360974"><doc><str name="_yz_id">my_type_my_bucket_name1_64</str><str name="_yz_rk">name1</str><str name="_yz_rt">my_type</str><str name="_yz_rb">my_bucket</str></doc><doc><str name="_yz_id">my_type_my_bucket_name3_42</str><str name="_yz_rk">name3</str><str name="_yz_rt">my_type</str><str name="_yz_rb">my_bucket</str></doc></result>
</response>
```
numFoundはしっかり2になっている。
Solrすげぇ！

## まとめ
これまでのRiak Searchは、日本語の検索ができない、インデックスの作成が遅いなどの欠点があったようだ。
しかし来る2.0では、Solrの機能を取り込んだ"実用できる"検索機能が期待できる。
しかもYokozunaの本領は、運用フェーズだ。
データもインデックスも、運用を簡単にしたまま、高度で安定した機能を提供する。
これこそがRiakとSolrを組み合わせたことによる恩恵といえる。

ちなみに、Bashoのドキュメントサイトの検索機能はYokozunaで作られているらしい。

## 参考
http://www.youtube.com/watch?v=nQL2SnqV7Pk
https://github.com/basho/yokozuna
https://github.com/basho/yokozuna/blob/develop/docs/INSTALL.md
http://www.slideshare.net/takashisogabe/riak-meetup2-iijbeta2
https://speakerdeck.com/basho/yokozuna-ricon