FuelPHPでElasticaからElasticsearchを使う - 1.導入

# 概要
[FuelPHP](http://fuelphp.com/) 1.7.2から今流行りの「[Elasticsearch・ザ・何でも検索エンジン](http://www.elasticsearch.org/)」を使ってみます。
といってもフツーにPHPからElasticsearchを使うのと特に違いはないです。

Elasticsearchへのアクセス方法はいくつか考えられますが、今回は[Elastica](http://elastica.io/)というライブラリを使ってみます。

Javaのランタイムを用意してElasticsearchをインストールしてcomposerからElasticaをインストールする、というのが大体の流れです。
せっかくなので日本語形態素解析用に[Kuromoji](https://github.com/elasticsearch/elasticsearch-analysis-kuromoji)も入れてみます。

ちなみに環境はCentOS6です。

## Javaのランタイムをインストール
Elasticsearchの動作にはJavaが必要です。
/usr/java/にインストールしてますが、必要なら適宜インストール先を変えてください。

> \$ wget -O jdk-7u67-linux-x64.tar.gz --no-cookies --no-check-certificate --header   "Cookie: gpw_e24=http%3A%2F%2Fwww.oracle.com%2F; oraclelicense=accept-securebackup-cookie" "http://download.oracle.com/otn-pub/java/jdk/7u67-b01/jdk-7u67-linux-x64.tar.gz"
> \$ sudo mkdir /usr/java/
> \$ sudo tar xzf jdk-7u67-linux-x64.tar.gz -C /usr/java/

使うランタイムについて少しだけ補足です。
Java 1.7u25より後、1.7u55より前のJavaではElasticsearch（が使ってるLucene）がうまく動きません。
そのため、少し前までElasticsearchを使う際は1.7u25の使用が推奨されていました。
1.7u55で問題となっていたバグが修正されたため、現在は1.7u25を使う必要はありません。
参考： http://www.elasticsearch.org/blog/java-1-7u55-safe-use-elasticsearch-lucene/

## Elasticsearchのインストール
Elasticaのバージョン番号はElasticsearch本体のバージョンと同期しています。
現在のElasticaの最新安定版は1.3.4なので、Elasticsearchも1.3.4をインストールします。

> \$ wget https://download.elasticsearch.org/elasticsearch/elasticsearch/elasticsearch-1.3.4.noarch.rpm
> \$ sudo yum localinstall elasticsearch-1.3.4.noarch.rpm
> \$ echo "export JAVA_HOME=/usr/java/jdk1.7.0_67" | sudo tee -a /etc/sysconfig/elasticsearch

Elasticsearchを起動し、ちゃんとインストールできてるか確認します

> \$ sudo /etc/init.d/elasticsearch start
> \$ curl -XGET localhost:9200/_cluster/health?pretty

## Kuromojiの導入
日本語形態素解析用にKuromojiを導入します。
Elasticsearchが1.3.4なので、Kuromojiは2.3.0を使います。

> \$ sudo JAVA_HOME=/usr/java/jdk1.7.0_67 /usr/share/elasticsearch/bin/plugin -install elasticsearch/elasticsearch-analysis-kuromoji/2.3.0
> \$ echo "index.analysis.analyzer.default.type: custom" | sudo tee -a /etc/elasticsearch/elasticsearch.yml
> \$ echo "index.analysis.analyzer.default.tokenizer: kuromoji_tokenizer" |  sudo tee -a /etc/elasticsearch/elasticsearch.yml

## Elasticaのインストール
FuelPHPからElasticsearchを叩くライブラリとして、Elasticaをインストールします。
ElasticaはFuelPHP用というわけではないので、命名規則などはFuelPHP本体と異なるものになっていますが、細かいことを気にすると禿げるので無視します。
インストールはcomposerを使えばわりと簡単にできます。
FuelPHPのインストールディレクトリにあるcomposer.jsonへ、requireのところに以下を追記します。

    "ruflin/Elastica": "dev-master"

"require"の部分はたとえばこんな感じになります。

    "require": {
        "php": ">=5.3.3",
        "composer/installers": "~1.0",
        "fuel/docs": "1.7.2",
        "fuel/core": "1.7.2",
        "fuel/auth": "1.7.2",
        "fuel/email": "1.7.2",
        "fuel/oil": "1.7.2",
        "fuel/orm": "1.7.2",
        "fuel/parser": "1.7.2",
        "fuelphp/upload": "2.0.1",
        "monolog/monolog": "1.5.*",
        "michelf/php-markdown": "1.4.0",
        "ruflin/Elastica": "dev-master"
    },

あとはupdateすればインストールされ、FuelPHP側からオートローダでElasticaのクラスが呼べるようになります。
> \$ php composer.phar update

## ちょっとだけ試してみる
[RSS River Plugin](http://www.pilato.fr/rssriver/)を使い、はてブのRSSをインデックスに登録して、検索結果をvar_dumpしてみます。

> \$ sudo JAVA_HOME=/usr/java/jdk1.7.0_67 /usr/share/elasticsearch/bin/plugin -install fr.pilato.elasticsearch.river/rssriver/1.3.0
> \$ sudo /etc/init.d/elasticsearch/restart

    <?php
    
    class Controller_Test extends Controller
    {
        const FEED_INDEX_NAME = 'hatebu';
        const RIVER_TYPE_NAME = 'hatebu';
        const RIVER_FEED_URL = 'http://b.hatena.ne.jp/entrylist/it?sort=hot&threshold=&mode=rss';

        private function get_client()
        {
            return new Elastica\Client(array(
                'host' => 'localhost',
                'port' => 9200
            ));
        }

        public function action_register()
        {
            $elastica_client = $this->get_client();

            $feed_index = $elastica_client->getIndex(self::FEED_INDEX_NAME)
                ->create(array(), false);

            $elastica_client->getIndex('_river')
                ->getType(self::RIVER_TYPE_NAME)
                ->addDocument(
                    new Elastica\Document('_meta', array(
                        'type' => 'rss',
                        'rss' => array(
                            'feeds' => array(
                                array(
                                    'name' => self::FEED_INDEX_NAME,
                                    'url' => self::RIVER_FEED_URL
                                 )
                            )
                        )
                    ))
                );
            echo 'ok';
        }
    
        public function action_search($param)
        {
            $results = $this->get_client()
                ->getIndex(self::FEED_INDEX_NAME)
                ->search($param);
            foreach ($results as $result)
            {
                var_dump($result->getData());
            }
        }
    }