Droonga チュートリアル: 低レイヤのコマンドの基本的な使い方

チュートリアルのゴール

Droonga の低レイヤのコマンドを用いて、Droonga を使った検索システムを自分で構築できるようになる。

前提条件

概要

Droonga とは

分散データ処理エンジンです。 “distributed-groonga” に由来します。

Droonga は複数のコンポーネントから構成されています。ユーザは、これらのパッケージを組み合わせて利用することで、全文検索をはじめとするスケーラブルな分散データ処理システムを構築することができます。

Droonga を構成するコンポーネント

Droonga Engine

Droonga Engine は Droonga における分散データ処理の要となるコンポーネントです。リクエストに基いて実際のデータ処理を行います。

このコンポーネントはdroonga-engineという名前で開発およびリリースされています。 通信に使用するプロトコルはFluentdと互換性があります。

droonga-engine は検索エンジンとして、オープンソースのカラムストア機能付き全文検索エンジン Groonga を使用しています。

Protocol Adapter

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による検索システムを構築する手順を解説します。 以降の説明は基本的に、DigitalOceanUbuntu 13.10 x64 の仮想マシンのセットアップを完了し、コンソールにアクセスできる状態になった後を前提として進めます。

注意:Droongaが必要とするパッケージをインストールする前に、マシンが2GB以上のメモリを備えていることを確認して下さい。メモリが不足していると、ビルド時にエラーが出て、ビルドに失敗することがあります。

ホストが 192.168.0.10 だと仮定します。

セットアップに必要なパッケージをインストールする

Droonga をセットアップするために必要になるパッケージをインストールします。

# apt-get update
# apt-get -y upgrade
# apt-get install -y ruby ruby-dev build-essential nodejs nodejs-legacy npm

Droonga Engine を構築する

Droonga Engine は、データベースを保持し、実際の検索を担当する部分です。 このセクションでは、 droonga-engine をインストールし、検索対象となるデータを準備します。

droonga-engineとdroonga-clientをインストールする

# gem install droonga-engine droonga-client

Droonga Engine を構築するのに必要なパッケージがセットアップできました。引き続き設定に移ります。

Droonga Engine を起動するための設定ファイルを用意する

まず Droonga Engine 用のディレクトリを作成します。

# mkdir engine
# cd engine

以下の内容で catalog.json を作成します。

catalog.json:

{
  "version": 2,
  "effectiveDate": "2013-09-01T00:00:00Z",
  "datasets": {
    "Default": {
      "nWorkers": 4,
      "plugins": ["groonga", "crud", "search"],
      "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.0.10:10031/droonga.000"
              }
            },
            {
              "volume": {
                "address": "192.168.0.10:10031/droonga.001"
              }
            },
            {
              "volume": {
                "address": "192.168.0.10:10031/droonga.002"
              }
            }
          ]
        },
        {
          "dimension": "_key",
          "slicer": "hash",
          "slices": [
            {
              "volume": {
                "address": "192.168.0.10:10031/droonga.010"
              }
            },
            {
              "volume": {
                "address": "192.168.0.10:10031/droonga.011"
              }
            },
            {
              "volume": {
                "address": "192.168.0.10:10031/droonga.012"
              }
            }
          ]
        }
      ]
    }
  }
}

このcatalog.jsonでは、データセットStarbucksを以下のように定義しています:

これらの6つの、"address"の情報を持つ最小単位のボリュームは、内部的にシングル・ボリュームと呼ばれます。 "address"の情報は、対応する物理的なストレージであるGroongaのデータベースの位置を示していて、それらのデータベースはdroonga-engineによって自動的に作成されます。

catalog.json の詳細については catalog.json を参照してください。

droonga-engine を起動する

以下のようにして droonga-engine を起動します。

# base_path=$PWD
# droonga-engine --host 192.168.0.10 \
                 --log-file=$base_path/droonga-engine.log \
                 --daemon \
                 --pid-file $base_path/droonga-engine.pid

droonga-engine を終了する

最初にdroonga-engineを終了する方法を知っておきましょう。

droonga-engineにSIGTERMを送ります。

# kill $(cat droonga-engine.pid)

これがdroonga-engineを終了する方法です。

再度droonga-engineを起動します。

# base_path=$PWD
# droonga-engine --host 192.168.0.10 \
                 --log-file=$base_path/droonga-engine.log \
                 --daemon \
                 --pid-file $base_path/droonga-engine.pid

データベースを作成する

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.008872597
[
  "droonga.message",
  1393562553,
  {
    "inReplyTo": "1393562553.9034681",
    "statusCode": 200,
    "type": "add.result",
    "body": true
  }
]
Elapsed time: 0.008392207
[
  "droonga.message",
  1393562553,
  {
    "inReplyTo": "1393562553.9126666",
    "statusCode": 200,
    "type": "add.result",
    "body": true
  }
]
Elapsed time: 0.011983187
[
  "droonga.message",
  1393562553,
  {
    "inReplyTo": "1393562553.9212565",
    "statusCode": 200,
    "type": "add.result",
    "body": true
  }
]
Elapsed time: 0.008101728
[
  "droonga.message",
  1393562553,
  {
    "inReplyTo": "1393562553.9338331",
    "statusCode": 200,
    "type": "add.result",
    "body": true
  }
]
Elapsed time: 0.004175044
[
  "droonga.message",
  1393562553,
  {
    "inReplyTo": "1393562553.9421282",
    "statusCode": 200,
    "type": "add.result",
    "body": true
  }
]
Elapsed time: 0.017018749
[
  "droonga.message",
  1393562553,
  {
    "inReplyTo": "1393562553.946642",
    "statusCode": 200,
    "type": "add.result",
    "body": true
  }
]
Elapsed time: 0.007583209
[
  "droonga.message",
  1393562553,
  {
    "inReplyTo": "1393562553.9639654",
    "statusCode": 200,
    "type": "add.result",
    "body": true
  }
]
Elapsed time: 0.00841723
[
  "droonga.message",
  1393562553,
  {
    "inReplyTo": "1393562553.9719582",
    "statusCode": 200,
    "type": "add.result",
    "body": true
  }
]
Elapsed time: 0.009108127
[
  "droonga.message",
  1393562553,
  {
    "inReplyTo": "1393562553.9804838",
    "statusCode": 200,
    "type": "add.result",
    "body": true
  }
]
Elapsed time: 0.005036642
[
  "droonga.message",
  1393562553,
  {
    "inReplyTo": "1393562553.989766",
    "statusCode": 200,
    "type": "add.result",
    "body": true
  }
]
Elapsed time: 0.004036806
[
  "droonga.message",
  1393562553,
  {
    "inReplyTo": "1393562553.9952037",
    "statusCode": 200,
    "type": "add.result",
    "body": true
  }
]
Elapsed time: 0.012368974
[
  "droonga.message",
  1393562554,
  {
    "inReplyTo": "1393562553.999501",
    "statusCode": 200,
    "type": "add.result",
    "body": true
  }
]
Elapsed time: 0.004099008
[
  "droonga.message",
  1393562554,
  {
    "inReplyTo": "1393562554.0122097",
    "statusCode": 200,
    "type": "add.result",
    "body": true
  }
]
Elapsed time: 0.027017019
[
  "droonga.message",
  1393562554,
  {
    "inReplyTo": "1393562554.016705",
    "statusCode": 200,
    "type": "add.result",
    "body": true
  }
]
Elapsed time: 0.010383751
[
  "droonga.message",
  1393562554,
  {
    "inReplyTo": "1393562554.044215",
    "statusCode": 200,
    "type": "add.result",
    "body": true
  }
]
Elapsed time: 0.004364288
[
  "droonga.message",
  1393562554,
  {
    "inReplyTo": "1393562554.0549927",
    "statusCode": 200,
    "type": "add.result",
    "body": true
  }
]
Elapsed time: 0.003277611
[
  "droonga.message",
  1393562554,
  {
    "inReplyTo": "1393562554.0595262",
    "statusCode": 200,
    "type": "add.result",
    "body": true
  }
]
Elapsed time: 0.007540272
[
  "droonga.message",
  1393562554,
  {
    "inReplyTo": "1393562554.063036",
    "statusCode": 200,
    "type": "add.result",
    "body": true
  }
]
Elapsed time: 0.002973611
[
  "droonga.message",
  1393562554,
  {
    "inReplyTo": "1393562554.0707917",
    "statusCode": 200,
    "type": "add.result",
    "body": true
  }
]
Elapsed time: 0.024142012
[
  "droonga.message",
  1393562554,
  {
    "inReplyTo": "1393562554.0739512",
    "statusCode": 200,
    "type": "add.result",
    "body": true
  }
]
Elapsed time: 0.010329014
[
  "droonga.message",
  1393562554,
  {
    "inReplyTo": "1393562554.098288",
    "statusCode": 200,
    "type": "add.result",
    "body": true
  }
]
Elapsed time: 0.004758853
[
  "droonga.message",
  1393562554,
  {
    "inReplyTo": "1393562554.1089437",
    "statusCode": 200,
    "type": "add.result",
    "body": true
  }
]
Elapsed time: 0.007113416
[
  "droonga.message",
  1393562554,
  {
    "inReplyTo": "1393562554.113922",
    "statusCode": 200,
    "type": "add.result",
    "body": true
  }
]
Elapsed time: 0.007472331
[
  "droonga.message",
  1393562554,
  {
    "inReplyTo": "1393562554.121428",
    "statusCode": 200,
    "type": "add.result",
    "body": true
  }
]
Elapsed time: 0.011560447
[
  "droonga.message",
  1393562554,
  {
    "inReplyTo": "1393562554.1294332",
    "statusCode": 200,
    "type": "add.result",
    "body": true
  }
]
Elapsed time: 0.006053761
[
  "droonga.message",
  1393562554,
  {
    "inReplyTo": "1393562554.1413999",
    "statusCode": 200,
    "type": "add.result",
    "body": true
  }
]
Elapsed time: 0.013611626
[
  "droonga.message",
  1393562554,
  {
    "inReplyTo": "1393562554.1479707",
    "statusCode": 200,
    "type": "add.result",
    "body": true
  }
]
Elapsed time: 0.007455591
[
  "droonga.message",
  1393562554,
  {
    "inReplyTo": "1393562554.1624238",
    "statusCode": 200,
    "type": "add.result",
    "body": true
  }
]
Elapsed time: 0.005440424
[
  "droonga.message",
  1393562554,
  {
    "inReplyTo": "1393562554.1702914",
    "statusCode": 200,
    "type": "add.result",
    "body": true
  }
]
Elapsed time: 0.005610303
[
  "droonga.message",
  1393562554,
  {
    "inReplyTo": "1393562554.1760805",
    "statusCode": 200,
    "type": "add.result",
    "body": true
  }
]
Elapsed time: 0.025479938
[
  "droonga.message",
  1393562554,
  {
    "inReplyTo": "1393562554.1822054",
    "statusCode": 200,
    "type": "add.result",
    "body": true
  }
]
Elapsed time: 0.007125251
[
  "droonga.message",
  1393562554,
  {
    "inReplyTo": "1393562554.2080746",
    "statusCode": 200,
    "type": "add.result",
    "body": true
  }
]
Elapsed time: 0.009454133
[
  "droonga.message",
  1393562554,
  {
    "inReplyTo": "1393562554.2158518",
    "statusCode": 200,
    "type": "add.result",
    "body": true
  }
]
Elapsed time: 0.003632905
[
  "droonga.message",
  1393562554,
  {
    "inReplyTo": "1393562554.2255347",
    "statusCode": 200,
    "type": "add.result",
    "body": true
  }
]
Elapsed time: 0.003653783
[
  "droonga.message",
  1393562554,
  {
    "inReplyTo": "1393562554.2293708",
    "statusCode": 200,
    "type": "add.result",
    "body": true
  }
]
Elapsed time: 0.003643588
[
  "droonga.message",
  1393562554,
  {
    "inReplyTo": "1393562554.2332237",
    "statusCode": 200,
    "type": "add.result",
    "body": true
  }
]
Elapsed time: 0.003703875
[
  "droonga.message",
  1393562554,
  {
    "inReplyTo": "1393562554.237225",
    "statusCode": 200,
    "type": "add.result",
    "body": true
  }
]
Elapsed time: 0.003402826
[
  "droonga.message",
  1393562554,
  {
    "inReplyTo": "1393562554.2411628",
    "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を用いてスターバックスの店舗データベースを検索する準備ができました。

droonga-requestでリクエストを送る

動作を確認してみましょう。クエリを以下のような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 を用意する

HTTP Protocol Adapterとしてdroonga-http-serverを使用します。droonga-http-serverは、Node.js のパッケージです。

droonga-http-serverをインストールする

# npm install -g droonga-http-server

次に、サーバを起動します。

# base_path=$PWD
# droonga-http-server --receive-host-name=192.168.0.10 \
                      --droonga-engine-host-name=192.168.0.10 \
                      --daemon \
                      --pid-file $base_path/droonga-http-server.pid

HTTPでの検索リクエスト

準備が整いました。 Protocol Adapter に向けて HTTP 経由でリクエストを発行し、データベースに問い合わせを行ってみましょう。まずは Shops テーブルの中身を取得してみます。以下のようなリクエストを用います。(attributes=_key を指定しているのは「検索結果に _key 値を含めて返してほしい」という意味です。これがないと、records に何も値がないレコードが返ってきてしまいます。attributes パラメータには , 区切りで複数の属性を指定することができます。attributes=_key,location と指定することで、緯度経度もレスポンスとして受け取ることができます)

# curl "http://192.168.0.10: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.0.10: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 上に Droonga を構成するパッケージである droonga-enginedroonga-http-server をセットアップしました。 これらのパッケージを利用することで、HTTP Protocol Adapter と Droonga Engine からなるシステムを構築し、実際に検索を行いました。