Droonga の低レイヤのコマンドを用いて、Droonga を使った検索システムを自分で構築できるようになる。
分散データ処理エンジンです。 “distributed-groonga” に由来します。
Droonga は複数のコンポーネントから構成されています。ユーザは、これらのパッケージを組み合わせて利用することで、全文検索をはじめとするスケーラブルな分散データ処理システムを構築することができます。
Droonga Engine は Droonga における分散データ処理の要となるコンポーネントです。リクエストに基いて実際のデータ処理を行います。
このコンポーネントはdroonga-engineという名前で開発およびリリースされています。 通信に使用するプロトコルはFluentdと互換性があります。
droonga-engine は検索エンジンとして、オープンソースのカラムストア機能付き全文検索エンジン Groonga を使用しています。
Protocol Adapter は、Droonga を様々なプロトコルで利用できるようにするためのコンポーネントです。
Droonga Engine自体は通信プロトコルとしてfluentdプロトコルにのみ対応しています。 その代わりに、Protocol AdapterがDroonga Engineとクライアントの間に立って、fluentdプロトコルと他の一般的なプロトコル(HTTP、Socket.IOなど)とを翻訳することになります。
現在の所、HTTP用の実装として、Node.js用モジュールパッケージのdroonga-http-serverが存在しています。 言い直すと、droonga-http-serverはDroonga Protocol Adapterの一実装で、言わば「Droonga HTTP Protocol Adapter」であるという事です。
チュートリアルでは、以下の様な構成のシステムを構築します。
+-------------+ +------------------+ +----------------+
| Web Browser | <--------> | Protocol Adapter | <-------> | Droonga Engine |
+-------------+ HTTP +------------------+ Fluent +----------------+
w/droonga-http protocol w/droonga-engine
-server
\--------------------------------------------------/
この部分を構築します
ユーザは Protocol Adapter に、Web ブラウザなどを用いて接続します。Protocol Adapter は Droonga Engine へリクエストを送信します。実際の検索処理は Droonga Engine が行います。検索結果は、Droonga Engine から Protocol Adapter に渡され、最終的にユーザに返ります。
例として、ニューヨークにあるスターバックスの店舗を検索できるデータベースシステムを作成することにします。
まずコンピュータを調達しましょう。このチュートリアルでは、既存のコンピュータにDroongaによる検索システムを構築する手順を解説します。
以降の説明は基本的に、DigitalOceanで Ubuntu 14.04 x64
、CentOS 6.5 x64
、 または CentOS 7 x64
の仮想マシンのセットアップを完了し、コンソールにアクセスできる状態になった後を前提として進めます。
注意:Droongaが必要とするパッケージをインストールする前に、マシンが2GB以上のメモリを備えていることを確認して下さい。メモリが不足していると、パッケージのインストール中にネイティブ拡張のビルドに失敗する場合があります。
ホストが 192.168.100.50
だと仮定します。
Droonga Engine は、データベースを保持し、実際の検索を担当する部分です。 このセクションでは、 droonga-engine をインストールし、検索対象となるデータを準備します。
droonga-engine
をインストールするインストールスクリプトをダウンロードし、root権限でbash
で実行して下さい:
# curl https://raw.githubusercontent.com/droonga/droonga-engine/master/install.sh | \
bash
...
Installing droonga-engine from RubyGems...
...
Preparing the user...
...
Setting up the configuration directory...
This node is configured with a hostname XXXXXXXX.
Registering droonga-engine as a service...
...
Successfully installed droonga-engine.
droonga-engine
を起動するための設定ファイルを用意するすべての設定ファイルと物理的なデータベースは、droonga-engine
サービス用のユーザのホームディレクトリ内にあるdroonga
ディレクトリの下に置かれます:
$ cd ~droonga-engine/droonga
では、以下の内容で設定ファイル catalog.json
を上書きしましょう:
catalog.json:
{
"version": 2,
"effectiveDate": "2013-09-01T00:00:00Z",
"datasets": {
"Default": {
"nWorkers": 4,
"plugins": ["groonga", "crud", "search", "dump", "status"],
"schema": {
"Store": {
"type": "Hash",
"keyType": "ShortText",
"columns": {
"location": {
"type": "Scalar",
"valueType": "WGS84GeoPoint"
}
}
},
"Location": {
"type": "PatriciaTrie",
"keyType": "WGS84GeoPoint",
"columns": {
"store": {
"type": "Index",
"valueType": "Store",
"indexOptions": {
"sources": ["location"]
}
}
}
},
"Term": {
"type": "PatriciaTrie",
"keyType": "ShortText",
"normalizer": "NormalizerAuto",
"tokenizer": "TokenBigram",
"columns": {
"stores__key": {
"type": "Index",
"valueType": "Store",
"indexOptions": {
"position": true,
"sources": ["_key"]
}
}
}
}
},
"replicas": [
{
"dimension": "_key",
"slicer": "hash",
"slices": [
{
"volume": {
"address": "192.168.100.50:10031/droonga.000"
}
},
{
"volume": {
"address": "192.168.100.50:10031/droonga.001"
}
},
{
"volume": {
"address": "192.168.100.50:10031/droonga.002"
}
}
]
},
{
"dimension": "_key",
"slicer": "hash",
"slices": [
{
"volume": {
"address": "192.168.100.50:10031/droonga.010"
}
},
{
"volume": {
"address": "192.168.100.50:10031/droonga.011"
}
},
{
"volume": {
"address": "192.168.100.50:10031/droonga.012"
}
}
]
}
]
}
}
}
このcatalog.json
では、データセットStarbucks
を以下のように定義しています:
これらの6つの、"address"
の情報を持つ最小単位のボリュームは、内部的にシングル・ボリュームと呼ばれます。
"address"
の情報は、対応する物理的なストレージであるGroongaのデータベースの位置を示していて、それらのデータベースはdroonga-engine
によって自動的に作成されます。
catalog.json
の詳細については catalog.json を参照してください。
droonga-engine
サービスの起動と終了droonga-engine
サービスはservice
コマンドを使って起動できます:
# service droonga-engine start
終了する場合も、service
コマンドを使います:
# service droonga-engine stop
確認できたら、再びdroonga-engine
を起動します。
# service droonga-engine start
Dronga Engine が起動したので、データを投入しましょう。
店舗のデータ stores.jsons
を用意します。
stores.jsons:
{
"dataset": "Default",
"type": "add",
"body": {
"table": "Store",
"key": "1st Avenue & 75th St. - New York NY (W)",
"values": {
"location": "40.770262,-73.954798"
}
}
}
{
"dataset": "Default",
"type": "add",
"body": {
"table": "Store",
"key": "76th & Second - New York NY (W)",
"values": {
"location": "40.771056,-73.956757"
}
}
}
{
"dataset": "Default",
"type": "add",
"body": {
"table": "Store",
"key": "2nd Ave. & 9th Street - New York NY",
"values": {
"location": "40.729445,-73.987471"
}
}
}
{
"dataset": "Default",
"type": "add",
"body": {
"table": "Store",
"key": "15th & Third - New York NY (W)",
"values": {
"location": "40.733946,-73.9867"
}
}
}
{
"dataset": "Default",
"type": "add",
"body": {
"table": "Store",
"key": "41st and Broadway - New York NY (W)",
"values": {
"location": "40.755111,-73.986225"
}
}
}
{
"dataset": "Default",
"type": "add",
"body": {
"table": "Store",
"key": "84th & Third Ave - New York NY (W)",
"values": {
"location": "40.777485,-73.954979"
}
}
}
{
"dataset": "Default",
"type": "add",
"body": {
"table": "Store",
"key": "150 E. 42nd Street - New York NY (W)",
"values": {
"location": "40.750784,-73.975582"
}
}
}
{
"dataset": "Default",
"type": "add",
"body": {
"table": "Store",
"key": "West 43rd and Broadway - New York NY (W)",
"values": {
"location": "40.756197,-73.985624"
}
}
}
{
"dataset": "Default",
"type": "add",
"body": {
"table": "Store",
"key": "Macy's 35th Street Balcony - New York NY",
"values": {
"location": "40.750703,-73.989787"
}
}
}
{
"dataset": "Default",
"type": "add",
"body": {
"table": "Store",
"key": "Macy's 6th Floor - Herald Square - New York NY (W)",
"values": {
"location": "40.750703,-73.989787"
}
}
}
{
"dataset": "Default",
"type": "add",
"body": {
"table": "Store",
"key": "Herald Square- Macy's - New York NY",
"values": {
"location": "40.750703,-73.989787"
}
}
}
{
"dataset": "Default",
"type": "add",
"body": {
"table": "Store",
"key": "Macy's 5th Floor - Herald Square - New York NY (W)",
"values": {
"location": "40.750703,-73.989787"
}
}
}
{
"dataset": "Default",
"type": "add",
"body": {
"table": "Store",
"key": "80th & York - New York NY (W)",
"values": {
"location": "40.772204,-73.949862"
}
}
}
{
"dataset": "Default",
"type": "add",
"body": {
"table": "Store",
"key": "Columbus @ 67th - New York NY (W)",
"values": {
"location": "40.774009,-73.981472"
}
}
}
{
"dataset": "Default",
"type": "add",
"body": {
"table": "Store",
"key": "45th & Broadway - New York NY (W)",
"values": {
"location": "40.75766,-73.985719"
}
}
}
{
"dataset": "Default",
"type": "add",
"body": {
"table": "Store",
"key": "Marriott Marquis - Lobby - New York NY",
"values": {
"location": "40.759123,-73.984927"
}
}
}
{
"dataset": "Default",
"type": "add",
"body": {
"table": "Store",
"key": "Second @ 81st - New York NY (W)",
"values": {
"location": "40.77466,-73.954447"
}
}
}
{
"dataset": "Default",
"type": "add",
"body": {
"table": "Store",
"key": "52nd & Seventh - New York NY (W)",
"values": {
"location": "40.761829,-73.981141"
}
}
}
{
"dataset": "Default",
"type": "add",
"body": {
"table": "Store",
"key": "1585 Broadway (47th) - New York NY (W)",
"values": {
"location": "40.759806,-73.985066"
}
}
}
{
"dataset": "Default",
"type": "add",
"body": {
"table": "Store",
"key": "85th & First - New York NY (W)",
"values": {
"location": "40.776101,-73.949971"
}
}
}
{
"dataset": "Default",
"type": "add",
"body": {
"table": "Store",
"key": "92nd & 3rd - New York NY (W)",
"values": {
"location": "40.782606,-73.951235"
}
}
}
{
"dataset": "Default",
"type": "add",
"body": {
"table": "Store",
"key": "165 Broadway - 1 Liberty - New York NY (W)",
"values": {
"location": "40.709727,-74.011395"
}
}
}
{
"dataset": "Default",
"type": "add",
"body": {
"table": "Store",
"key": "1656 Broadway - New York NY (W)",
"values": {
"location": "40.762434,-73.983364"
}
}
}
{
"dataset": "Default",
"type": "add",
"body": {
"table": "Store",
"key": "54th & Broadway - New York NY (W)",
"values": {
"location": "40.764275,-73.982361"
}
}
}
{
"dataset": "Default",
"type": "add",
"body": {
"table": "Store",
"key": "Limited Brands-NYC - New York NY",
"values": {
"location": "40.765219,-73.982025"
}
}
}
{
"dataset": "Default",
"type": "add",
"body": {
"table": "Store",
"key": "19th & 8th - New York NY (W)",
"values": {
"location": "40.743218,-74.000605"
}
}
}
{
"dataset": "Default",
"type": "add",
"body": {
"table": "Store",
"key": "60th & Broadway-II - New York NY (W)",
"values": {
"location": "40.769196,-73.982576"
}
}
}
{
"dataset": "Default",
"type": "add",
"body": {
"table": "Store",
"key": "63rd & Broadway - New York NY (W)",
"values": {
"location": "40.771376,-73.982709"
}
}
}
{
"dataset": "Default",
"type": "add",
"body": {
"table": "Store",
"key": "195 Broadway - New York NY (W)",
"values": {
"location": "40.710703,-74.009485"
}
}
}
{
"dataset": "Default",
"type": "add",
"body": {
"table": "Store",
"key": "2 Broadway - New York NY (W)",
"values": {
"location": "40.704538,-74.01324"
}
}
}
{
"dataset": "Default",
"type": "add",
"body": {
"table": "Store",
"key": "2 Columbus Ave. - New York NY (W)",
"values": {
"location": "40.769262,-73.984764"
}
}
}
{
"dataset": "Default",
"type": "add",
"body": {
"table": "Store",
"key": "NY Plaza - New York NY (W)",
"values": {
"location": "40.702802,-74.012784"
}
}
}
{
"dataset": "Default",
"type": "add",
"body": {
"table": "Store",
"key": "36th and Madison - New York NY (W)",
"values": {
"location": "40.748917,-73.982683"
}
}
}
{
"dataset": "Default",
"type": "add",
"body": {
"table": "Store",
"key": "125th St. btwn Adam Clayton & FDB - New York NY",
"values": {
"location": "40.808952,-73.948229"
}
}
}
{
"dataset": "Default",
"type": "add",
"body": {
"table": "Store",
"key": "70th & Broadway - New York NY (W)",
"values": {
"location": "40.777463,-73.982237"
}
}
}
{
"dataset": "Default",
"type": "add",
"body": {
"table": "Store",
"key": "2138 Broadway - New York NY (W)",
"values": {
"location": "40.781078,-73.981167"
}
}
}
{
"dataset": "Default",
"type": "add",
"body": {
"table": "Store",
"key": "118th & Frederick Douglas Blvd. - New York NY (W)",
"values": {
"location": "40.806176,-73.954109"
}
}
}
{
"dataset": "Default",
"type": "add",
"body": {
"table": "Store",
"key": "42nd & Second - New York NY (W)",
"values": {
"location": "40.750069,-73.973393"
}
}
}
{
"dataset": "Default",
"type": "add",
"body": {
"table": "Store",
"key": "Broadway @ 81st - New York NY (W)",
"values": {
"location": "40.784972,-73.978987"
}
}
}
{
"dataset": "Default",
"type": "add",
"body": {
"table": "Store",
"key": "Fashion Inst of Technology - New York NY",
"values": {
"location": "40.746948,-73.994557"
}
}
}
もう一つターミナルを開いて、jsonをDroonga engineに送信しましょう。
以下のようにしてstores.json
を送信します:
$ droonga-request stores.jsons
Elapsed time: 0.01101195
[
"droonga.message",
1393562553,
{
"inReplyTo": "1393562553.8918273",
"statusCode": 200,
"type": "add.result",
"body": true
}
]
...
Elapsed time: 0.004817463
[
"droonga.message",
1393562554,
{
"inReplyTo": "1393562554.2447524",
"statusCode": 200,
"type": "add.result",
"body": true
}
]
Droonga engineを用いてスターバックスの店舗データベースを検索する準備ができました。
動作を確認してみましょう。クエリを以下のようなJSONファイルとして作成します。
search-all-stores.json:
{
"dataset": "Default",
"type": "search",
"body": {
"queries": {
"stores": {
"source": "Store",
"output": {
"elements": [
"startTime",
"elapsedTime",
"count",
"attributes",
"records"
],
"attributes": ["_key"],
"limit": -1
}
}
}
}
}
Droonga Engine にリクエストを送信します:
$ droonga-request search-all-stores.json
Elapsed time: 0.008286785
[
"droonga.message",
1393562604,
{
"inReplyTo": "1393562604.4970381",
"statusCode": 200,
"type": "search.result",
"body": {
"stores": {
"count": 40,
"records": [
[
"15th & Third - New York NY (W)"
],
[
"41st and Broadway - New York NY (W)"
],
[
"84th & Third Ave - New York NY (W)"
],
[
"Macy's 35th Street Balcony - New York NY"
],
[
"Second @ 81st - New York NY (W)"
],
[
"52nd & Seventh - New York NY (W)"
],
[
"1585 Broadway (47th) - New York NY (W)"
],
[
"54th & Broadway - New York NY (W)"
],
[
"60th & Broadway-II - New York NY (W)"
],
[
"63rd & Broadway - New York NY (W)"
],
[
"2 Columbus Ave. - New York NY (W)"
],
[
"NY Plaza - New York NY (W)"
],
[
"2138 Broadway - New York NY (W)"
],
[
"Broadway @ 81st - New York NY (W)"
],
[
"76th & Second - New York NY (W)"
],
[
"2nd Ave. & 9th Street - New York NY"
],
[
"150 E. 42nd Street - New York NY (W)"
],
[
"Macy's 6th Floor - Herald Square - New York NY (W)"
],
[
"Herald Square- Macy's - New York NY"
],
[
"Macy's 5th Floor - Herald Square - New York NY (W)"
],
[
"Marriott Marquis - Lobby - New York NY"
],
[
"85th & First - New York NY (W)"
],
[
"1656 Broadway - New York NY (W)"
],
[
"Limited Brands-NYC - New York NY"
],
[
"2 Broadway - New York NY (W)"
],
[
"36th and Madison - New York NY (W)"
],
[
"125th St. btwn Adam Clayton & FDB - New York NY"
],
[
"118th & Frederick Douglas Blvd. - New York NY (W)"
],
[
"Fashion Inst of Technology - New York NY"
],
[
"1st Avenue & 75th St. - New York NY (W)"
],
[
"West 43rd and Broadway - New York NY (W)"
],
[
"80th & York - New York NY (W)"
],
[
"Columbus @ 67th - New York NY (W)"
],
[
"45th & Broadway - New York NY (W)"
],
[
"92nd & 3rd - New York NY (W)"
],
[
"165 Broadway - 1 Liberty - New York NY (W)"
],
[
"19th & 8th - New York NY (W)"
],
[
"195 Broadway - New York NY (W)"
],
[
"70th & Broadway - New York NY (W)"
],
[
"42nd & Second - New York NY (W)"
]
]
}
}
}
]
店舗の名前が取得できました。エンジンは正しく動作しているようです。引き続き Protocol Adapter を構築して、検索リクエストをHTTPで受け付けられるようにしましょう。
HTTP Protocol Adapterとしてdroonga-http-server
を使用しましょう。
インストールスクリプトをダウンロードし、root権限でbash
で実行して下さい:
# curl https://raw.githubusercontent.com/droonga/droonga-http-server/master/install.sh | \
bash
...
Installing droonga-http-server from npmjs.org...
...
Preparing the user...
...
Setting up the configuration directory...
The droonga-engine service is detected on this node.
The droonga-http-server is configured to be connected
to this node (XXXXXXXX).
This node is configured with a hostname XXXXXXXX.
Registering droonga-http-server as a service...
...
Successfully installed droonga-http-server.
droonga-http-server
サービスの起動と終了droonga-http-server
サービスはservice
コマンドを使って起動できます:
# service droonga-http-server start
終了する場合も、service
コマンドを使います:
# service droonga-http-server stop
確認できたら、再びdroonga-http-server
を起動します。
# service droonga-engine start
準備が整いました。 Protocol Adapter に向けて HTTP 経由でリクエストを発行し、データベースに問い合わせを行ってみましょう。まずは Shops
テーブルの中身を取得してみます。以下のようなリクエストを用います。(attributes=_key
を指定しているのは「検索結果に _key
値を含めて返してほしい」という意味です。これがないと、records
に何も値がないレコードが返ってきてしまいます。attributes
パラメータには ,
区切りで複数の属性を指定することができます。attributes=_key,location
と指定することで、緯度経度もレスポンスとして受け取ることができます)
$ curl "http://192.168.100.50:10041/tables/Store?attributes=_key&limit=-1"
{
"stores": {
"count": 40,
"records": [
[
"15th & Third - New York NY (W)"
],
[
"41st and Broadway - New York NY (W)"
],
[
"84th & Third Ave - New York NY (W)"
],
[
"Macy's 35th Street Balcony - New York NY"
],
[
"Second @ 81st - New York NY (W)"
],
[
"52nd & Seventh - New York NY (W)"
],
[
"1585 Broadway (47th) - New York NY (W)"
],
[
"54th & Broadway - New York NY (W)"
],
[
"60th & Broadway-II - New York NY (W)"
],
[
"63rd & Broadway - New York NY (W)"
],
[
"2 Columbus Ave. - New York NY (W)"
],
[
"NY Plaza - New York NY (W)"
],
[
"2138 Broadway - New York NY (W)"
],
[
"Broadway @ 81st - New York NY (W)"
],
[
"76th & Second - New York NY (W)"
],
[
"2nd Ave. & 9th Street - New York NY"
],
[
"150 E. 42nd Street - New York NY (W)"
],
[
"Macy's 6th Floor - Herald Square - New York NY (W)"
],
[
"Herald Square- Macy's - New York NY"
],
[
"Macy's 5th Floor - Herald Square - New York NY (W)"
],
[
"Marriott Marquis - Lobby - New York NY"
],
[
"85th & First - New York NY (W)"
],
[
"1656 Broadway - New York NY (W)"
],
[
"Limited Brands-NYC - New York NY"
],
[
"2 Broadway - New York NY (W)"
],
[
"36th and Madison - New York NY (W)"
],
[
"125th St. btwn Adam Clayton & FDB - New York NY"
],
[
"118th & Frederick Douglas Blvd. - New York NY (W)"
],
[
"Fashion Inst of Technology - New York NY"
],
[
"1st Avenue & 75th St. - New York NY (W)"
],
[
"West 43rd and Broadway - New York NY (W)"
],
[
"80th & York - New York NY (W)"
],
[
"Columbus @ 67th - New York NY (W)"
],
[
"45th & Broadway - New York NY (W)"
],
[
"92nd & 3rd - New York NY (W)"
],
[
"165 Broadway - 1 Liberty - New York NY (W)"
],
[
"19th & 8th - New York NY (W)"
],
[
"195 Broadway - New York NY (W)"
],
[
"70th & Broadway - New York NY (W)"
],
[
"42nd & Second - New York NY (W)"
]
]
}
}
count
の値からデータが全部で 36 件あることがわかります。records
に配列として検索結果が入っています。
もう少し複雑なクエリを試してみましょう。例えば、店名に「Columbus」を含む店舗を検索します。query
パラメータにクエリ Columbus
を、match_to
パラメータに検索対象として _key
を指定し、以下のようなリクエストを発行します。
$ curl "http://192.168.100.50:10041/tables/Store?query=Columbus&match_to=_key&attributes=_key&limit=-1"
{
"stores": {
"count": 2,
"records": [
[
"Columbus @ 67th - New York NY (W)"
],
[
"2 Columbus Ave. - New York NY (W)"
]
]
}
}
以上 2 件が検索結果として該当することがわかりました。
Droonga HTTP Serverの詳細についてはリファレンスマニュアルを参照して下さい。
Ubuntu Linux または CentOS 上に Droonga を構成するパッケージである droonga-engine と droonga-http-server をセットアップしました。 これらのパッケージを利用することで、HTTP Protocol Adapter と Droonga Engine からなるシステムを構築し、実際に検索を行いました。