読者です 読者をやめる 読者になる 読者になる

Carpe Diem

備忘録。https://github.com/jun06t

MongoRiverを使う

概要

MongoDBのデータをElasticSearchに流し込むMongoDB River Pluginを扱います。
あるデータに対して検索機能を追加したいけど、MongoDBで全文検索はちょっと。。という時に便利です。

環境

  • Ubuntu 14.04
  • MongoDB 2.6.7
  • Java 1.8.0_31
  • ElasticSearch 1.4.2
  • MongoRiverPlugin 2.0.5
  • MapperAttachmentsPlugin 2.4.2

MongoDBとElasticSearchを別環境で立ち上げて説明します。

サービス IP
MongoDB 192.168.33.10
ElasticSearch 192.168.33.11

注意点

前提知識や、うまく動作しないケースを先にまとめてみました。
これを知ってるだけで随分進めやすくなると思います。

  • MongoDBのレプリのoplogを使うのでレプリ必須
  • 一度oplogのカーソルを見失うと復帰できない。再設定が必要
  • Mongo, ES, プラグインのバージョンが異なると基本的に動かない
  • 大量データを流し込む場合、メモリやulimitが低いとコケる
  • 初回同期時は通常のMongoのレプリと同じくFullSyncしてくれる(oplog関係なく)

特にバージョン違いはよくあるミスなので、現在よりバージョンが上がっている場合は本家の比較表を必ず見てください。

Vagrantの起動

Vagrantfileに以下の設定を追記して複数同時起動します。

  config.vm.define :mongo do |node|
    node.vm.hostname = "mongodb"
    node.vm.network :private_network, ip: "192.168.33.10"
    node.vm.provider "virtualbox" do |vb|
      vb.memory = "1024"
    end
  end

  config.vm.define :es do |node|
    node.vm.hostname = "elasticsearch"
    node.vm.network :private_network, ip: "192.168.33.11"
    node.vm.provider "virtualbox" do |vb|
      vb.memory = "2048"
    end
  end

起動します。

$ vagrant up

各サービスのインストール作業は以下を参考にしてください

MongoDBのレプリ作成

/etc/mongod.confを編集します。レプリカセットの名前はesReplとしましょう。

# bind_ip=127.0.0.1 (コメントアウト)
  :
  :
replSet=esRepl
oplogSize=2048

oplogSizeに関しては

  • 一度に投入するデータ量がこのサイズを超えないこと
  • 一定時間Riverが途切れても、MongoDBに追加されるデータ量がこのサイズ超えないこと

という点に注意して設定すればOKです。設定したら再起動します。

$ sudo service mongodb restart

次にレプリの設定です。1台しかないのでmemberは自分自身のみを設定します。

> config = 
{
    _id: 'esRepl',
    members: [
        {
            _id: 0,
            host: '192.168.33.10: 27017'
        }
    ]
};
> rs.initiate(config);

注意としてhostは他のサーバからも参照できる値(IP, FQDN)にしてください。

問題なければ以下のようにレスポンスがきます。

{
    "info" : "Config now saved locally.  Should come online in about a minute.",
    "ok" : 1
}

プラグインの設定

インストール

Mapper Attachementsのインストール

$ sudo /usr/share/elasticsearch/bin/plugin -install elasticsearch/elasticsearch-mapper-attachments/2.4.2

Mongo Riverのインストール

$ sudo /usr/share/elasticsearch/bin/plugin --install com.github.richardwilly98.elasticsearch/elasticsearch-river-mongodb/2.0.5

インストールが完了したら再起動してください。

$ sudo service elasticsearch restart

マッピング(やってもやらなくてもOK)

設定すればanalyzerを指定できますし、しなければデフォルトのanalyzerでインデックスを作成するようになります。
今回は省略します。

River設定

シンプルなフォーマットとしては以下です。

$ curl -XPUT "localhost:9200/_river/{riverのtype名}/_meta" -d '
{
  "type": "mongodb",
  "mongodb": {
    "db": "{DB名}",
    "collection": "{コレクション名}",
    "servers": [
      { "host": "{レプリカセットのホスト名}", "port": 27017 }
    ]
  },
  "index": {
    "name": "{riverの流し込み先として登録するIndex名}",
    "type": "{上記のIndexのtype名}"
  }
}'

なので今回は以下のように設定します。

$ curl -XPUT "localhost:9200/_river/books/_meta" -d '
{
  "type": "mongodb",
  "mongodb": {
    "db": "library",
    "collection": "books",
    "servers": [
      { "host": "192.168.33.10", "port": 27017 }
    ]
  },
  "index": {
    "name": "books",
    "type": "novels"
  }
}'

詳細は本家を参照してください。
フィールドの指定とかもできます。

設定すると一旦_riverのindexのみ生成されます。

f:id:quoll00:20150211165019p:plain

動作確認

MongoDBにダミーデータを投入します。

esRepl:PRIMARY> use library
esRepl:PRIMARY> db.books.insert({"title": "The Best Short Stories of O. Henry", "auther": "O. Henry"});

f:id:quoll00:20150211165031p:plain

ちゃんと流れ込んでますね。
同じデータを何件も入れて検索してみます。

f:id:quoll00:20150211165100p:plain

大丈夫ですね。

GUIで起動しているかチェック

ちなみに以下のURLがRiverの管理画面として使えます。

http://192.168.33.11:9200/_plugin/river-mongodb/

f:id:quoll00:20150211164918p:plain

riverが動いてないなーと思ったらこの画面から起動することもできます。

実際に動かしてみて気づいたこと

重複データはちゃんと1つのデータとして扱われる

RiverしたままMongoDBのコレクションをDropしてデータを再投入しても、同じデータは1つとして扱われていました。

Riverの設定、データの投入はどちらが先でもいい

今回は先にマッピングを設定しましたが、データを流し込んだあとにマッピングを消して再度River設定をしなおしてもちゃんとデータが入ります。
どちらを先にしたとしても、マッピングしたoplogがある限りデータは流し込まれます。

再起動してもoplogが途切れない限りちゃんと動く

ネットワーク障害耐性はどうなんだろーと思って検証してみましたが、以前は一度途切れると復旧したりしなかったりと怪しい動作でした。
ですが現在(ES 1.4.2以降)は試した限りでは常にRiverし続けてくれてます。対応してくれた開発者さんに感謝です。

oplogSize以上のデータ量でもすべてインデックスに載る

インデックスを再構築したいときにもう一度Riverを設定してみたところ、明らかにoplogSizeを超えているデータ量でも全件インデックスに載りました。
oplogSizeを超えている場合はMongoDBのレプリのようにfullSyncしてくれるみたいです。

ソース