Kouhei Sutou
null+****@clear*****
Mon May 19 16:48:30 JST 2014
Kouhei Sutou 2014-05-19 16:48:30 +0900 (Mon, 19 May 2014) New Revision: 8d2bf44b3260ed165367158c274979cea236e2eb https://github.com/droonga/droonga.org/commit/8d2bf44b3260ed165367158c274979cea236e2eb Message: Add 1.0.3 directory for version 1.0.3 documents 1.0.3 isn't released yet. Added files: _po/ja/reference/1.0.3/catalog/index.po _po/ja/reference/1.0.3/catalog/version1/index.po _po/ja/reference/1.0.3/catalog/version2/index.po _po/ja/reference/1.0.3/commands/add/index.po _po/ja/reference/1.0.3/commands/column-create/index.po _po/ja/reference/1.0.3/commands/index.po _po/ja/reference/1.0.3/commands/search/index.po _po/ja/reference/1.0.3/commands/select/index.po _po/ja/reference/1.0.3/commands/table-create/index.po _po/ja/reference/1.0.3/commands/table-remove/index.po _po/ja/reference/1.0.3/http-server/index.po _po/ja/reference/1.0.3/index.po _po/ja/reference/1.0.3/message/index.po _po/ja/reference/1.0.3/plugin/adapter/index.po _po/ja/reference/1.0.3/plugin/collector/index.po _po/ja/reference/1.0.3/plugin/error/index.po _po/ja/reference/1.0.3/plugin/handler/index.po _po/ja/reference/1.0.3/plugin/index.po _po/ja/reference/1.0.3/plugin/matching-pattern/index.po _po/ja/tutorial/1.0.3/basic/index.po _po/ja/tutorial/1.0.3/groonga/index.po _po/ja/tutorial/1.0.3/index.po _po/ja/tutorial/1.0.3/plugin-development/adapter/index.po _po/ja/tutorial/1.0.3/plugin-development/handler/index.po _po/ja/tutorial/1.0.3/plugin-development/index.po _po/ja/tutorial/1.0.3/watch.po ja/reference/1.0.3/catalog/index.md ja/reference/1.0.3/catalog/version1/index.md ja/reference/1.0.3/catalog/version2/index.md ja/reference/1.0.3/commands/add/index.md ja/reference/1.0.3/commands/column-create/index.md ja/reference/1.0.3/commands/index.md ja/reference/1.0.3/commands/search/index.md ja/reference/1.0.3/commands/select/index.md ja/reference/1.0.3/commands/table-create/index.md ja/reference/1.0.3/commands/table-remove/index.md ja/reference/1.0.3/http-server/index.md ja/reference/1.0.3/index.md ja/reference/1.0.3/message/index.md ja/reference/1.0.3/plugin/adapter/index.md ja/reference/1.0.3/plugin/collector/index.md ja/reference/1.0.3/plugin/error/index.md ja/reference/1.0.3/plugin/handler/index.md ja/reference/1.0.3/plugin/index.md ja/reference/1.0.3/plugin/matching-pattern/index.md ja/tutorial/1.0.3/basic/index.md ja/tutorial/1.0.3/groonga/index.md ja/tutorial/1.0.3/index.md ja/tutorial/1.0.3/plugin-development/adapter/index.md ja/tutorial/1.0.3/plugin-development/handler/index.md ja/tutorial/1.0.3/plugin-development/index.md ja/tutorial/1.0.3/watch.md reference/1.0.3/catalog/index.md reference/1.0.3/catalog/version1/index.md reference/1.0.3/catalog/version2/index.md reference/1.0.3/commands/add/index.md reference/1.0.3/commands/column-create/index.md reference/1.0.3/commands/index.md reference/1.0.3/commands/search/index.md reference/1.0.3/commands/select/index.md reference/1.0.3/commands/table-create/index.md reference/1.0.3/commands/table-remove/index.md reference/1.0.3/http-server/index.md reference/1.0.3/index.md reference/1.0.3/message/index.md reference/1.0.3/plugin/adapter/index.md reference/1.0.3/plugin/collector/index.md reference/1.0.3/plugin/error/index.md reference/1.0.3/plugin/handler/index.md reference/1.0.3/plugin/index.md reference/1.0.3/plugin/matching-pattern/index.md tutorial/1.0.3/basic/index.md tutorial/1.0.3/groonga/index.md tutorial/1.0.3/index.md tutorial/1.0.3/plugin-development/adapter/index.md tutorial/1.0.3/plugin-development/handler/index.md tutorial/1.0.3/plugin-development/index.md tutorial/1.0.3/watch.md Added: _po/ja/reference/1.0.3/catalog/index.po (+36 -0) 100644 =================================================================== --- /dev/null +++ _po/ja/reference/1.0.3/catalog/index.po 2014-05-19 16:48:30 +0900 (da6c573) @@ -0,0 +1,36 @@ +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"PO-Revision-Date: 2014-03-05 12:52+0900\n" +"Language: ja\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" + +msgid "" +"---\n" +"title: Catalog\n" +"layout: en\n" +"---" +msgstr "" +"---\n" +"title: カタログ\n" +"layout: ja\n" +"---" + +msgid "" +"A Droonga network consists of several resources. You need to describe\n" +"them in **catalog**. All the nodes in the network shares the same\n" +"catalog." +msgstr "" +"複数のリソースが集まり、Droongaネットワークを構成します。それらのリソースを **カタログ** に記述しなければいけません。ネットワーク上のすべてのノ" +"ードは同じカタログを共有します。" + +msgid "Catalog specification is versioned. Here are available versions:" +msgstr "カタログの指定はバージョン管理されています。利用可能なバージョンは以下のとおりです:" + +msgid "" +" * [version 2](version2/)\n" +" * [version 1](version1/): (It is deprecated since 1.0.0.)" +msgstr "" Added: _po/ja/reference/1.0.3/catalog/version1/index.po (+483 -0) 100644 =================================================================== --- /dev/null +++ _po/ja/reference/1.0.3/catalog/version1/index.po 2014-05-19 16:48:30 +0900 (f79f002) @@ -0,0 +1,483 @@ +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"PO-Revision-Date: 2014-03-05 12:52+0900\n" +"Language: ja\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" + +msgid "" +"---\n" +"title: Catalog\n" +"layout: en\n" +"---" +msgstr "" +"---\n" +"title: カタログ\n" +"layout: ja\n" +"---" + +msgid "" +"A Droonga network consists of several resources. You need to describe\n" +"them in **catalog**. All the nodes in the network shares the same\n" +"catalog." +msgstr "" +"複数のリソースが集まり、Droongaネットワークを構成します。それらのリソースを **カタログ** に記述しなければいけません。ネットワーク上のすべてのノ" +"ードは同じカタログを共有します。" + +msgid "This documentation describes about catalog." +msgstr "このドキュメントはカタログについて説明します。" + +msgid "" +" * TOC\n" +"{:toc}" +msgstr "" + +msgid "## How to manage" +msgstr "## 管理方法" + +msgid "" +"So far, you need to write catalog and share it to all the nodes\n" +"manually." +msgstr "今のところ、カタログを書くことも書いたカタログをすべてのノードで共有することも手動で行う必要があります。" + +msgid "" +"Some utility programs will generate catalog in near feature.\n" +"Furthermore Droonga network will maintain and share catalog\n" +"automatically." +msgstr "" +"近い将来、カタログを生成するユーティリティープログラムを提供する予定です。さらにその後、Droongaネットワークは自動でカタログの管理やカタログの配布を行" +"うようになる予定です。" + +msgid "## Glossary" +msgstr "## 用語集" + +msgid "This section describes terms in catalog." +msgstr "このセクションではカタログに出てくる用語を説明します。" + +msgid "### Catalog" +msgstr "### カタログ" + +msgid "" +"Catalog is a series of data which represents the resources in the\n" +"network." +msgstr "カタログはネットワーク内のリソースを表現するデータの集まりです。" + +msgid "### Zone" +msgstr "### ゾーン" + +msgid "" +"Zone is a set of farms. Farms in a zone are expected to close to each\n" +"other, like in the same host, in the same switch, in the same network." +msgstr "" +"ゾーンはファームの集まりです。同じゾーン内のファームはお互いに近くに配置することが期待されています。例えば、同じホスト内、同じスイッチ内、同じネットワーク内" +"といった具合です。" + +msgid "### Farm" +msgstr "### ファーム" + +msgid "" +"A farm is a Droonga Engine instance. Droonga Engine is implemented as\n" +"a [Fluentd][] plugin, fluent-plugin-droonga." +msgstr "" +"ファームはDroongaエンジンのインスタンスです。Droongaエンジンは[Fluentd][]のプラグインfluent-plugin-droongaとし" +"て実装されています。" + +msgid "" +"A `fluentd` process can have multiple Droonga Engines. If you add one\n" +"or more `match` entries with type `droonga` into `fluentd.conf`, a\n" +"`fluentd` process instantiates one or more Droonga Engines." +msgstr "" +"1つの `fluentd` プロセスは複数のDroongaエンジンを持てます。 `fluentd.conf` に `droonga` タイプの `match" +"` エントリーを1つ以上追加すると、 `fluentd` プロセスは同じ数のDroongaエンジンのインスタンスを生成します。" + +msgid "" +"A farm has its own workers and a job queue. A farm push request to its\n" +"job queue and workers pull a request from the job queue." +msgstr "ファームは複数のワーカーと1つのジョブキューを持ちます。ファームはリクエストをジョブキューに投入します。ワーカーはジョブキューからリクエストを取り出します。" + +msgid "### Dataset" +msgstr "### データセット" + +msgid "" +"Dataset is a set of logical tables. A logical table must belong to\n" +"only one dataset." +msgstr "データセットは論理テーブルの集まりです。論理テーブルは1つのデータセットに所属しなければいけません。" + +msgid "Each dataset must have an unique name in the same Droonga network." +msgstr "各データセットの名前は同じDroongaネットワーク内で重複してはいけません。" + +msgid "### Logical table" +msgstr "### 論理テーブル" + +msgid "" +"Logical table consists of one or more partitioned physical tables.\n" +"Logical table doesn't have physical records. It returns physical\n" +"records from physical tables." +msgstr "論理テーブルはパーティションされた1つ以上の物理テーブルで構成されます。論理テーブルは物理レコードを持ちません。物理テーブルから物理レコードを返します。" + +msgid "" +"You can custom how to partition a logical table into one or more\n" +"physical tables. For example, you can custom partition key, the\n" +"number of partitions and so on." +msgstr "" +"1つの論理テーブルを1つ以上の物理テーブルにどうやってパーティションするかをカスタマイズできます。例えば、パーティションキーやパーテション数をカスタマイズで" +"きます。" + +msgid "### Physical table" +msgstr "### 物理テーブル" + +msgid "" +"Physical table is a table in Groonga database. It stores physical\n" +"records to the table." +msgstr "物理テーブルはGroongaデータベースのテーブルです。Groongaのテーブルに物理レコードを保存します。" + +msgid "### Ring" +msgstr "### リング" + +msgid "" +"Ring is a series of partition sets. Dataset must have one\n" +"ring. Dataset creates logical tables on the ring." +msgstr "リングはパーティションセットの集まりです。データセットは必ず1つのリングを持ちます。データセットはリング上に論理テーブルを作ります。" + +msgid "" +"Droonga Engine replicates each record in a logical table into one or\n" +"more partition sets." +msgstr "Droongaエンジンは物理テーブル上にあるレコードを1つ以上のパーティションセットに複製します。" + +msgid "### Partition set" +msgstr "### パーティションセット" + +msgid "" +"Partition set is a set of partitions. A partition set stores all\n" +"records in all logical tables in the same Droonga network. In other\n" +"words, dataset is partitioned in a partition set." +msgstr "" +"パーティションセットはパーティションの集まりです。1つのパーティションセットは同じDroongaネットワーク内のすべての論理テーブルのすべてのレコードを保存" +"します。言い換えると、データセットは1つのパーティションセットの中でパーティションされます。" + +msgid "A partition set is a replication of other partition set." +msgstr "1つのパーティションセットは他のパーティションセットの複製です。" + +msgid "" +"Droonga Engine may support partitioning in one or more partition\n" +"sets in the future. It will be useful to use different partition\n" +"size for old data and new data. Normally, old data are smaller and\n" +"new data are bigger. It is reasonable that you use larger partition\n" +"size for bigger data." +msgstr "" +"将来、Droongaエンジンは1つ以上のパーティションセット内でのパーティションをサポートするかもしれません。古いデータと新しいデータで異なるパーティション" +"サイズを使うことができるので便利でしょう。通常、古いデータは小さく、新しいデータは大きくなります。大きなデータに大きなパーティションサイズを使うのは妥当なこ" +"とです。" + +msgid "### Partition" +msgstr "### パーティション" + +msgid "" +"Partition is a Groonga database. It has zero or more physical\n" +"tables." +msgstr "1つのパーティションは1つのGroongaデータベースに対応します。0個以上の物理テーブルを持ちます。" + +msgid "### Plugin" +msgstr "### プラグイン" + +msgid "" +"Droonga Engine can be extended by writing plugin scripts.\n" +"In most cases, a series of plugins work cooperatively to\n" +"achieve required behaviors.\n" +"So, plugins are organized by behaviors.\n" +"Each behavior can be attached to datasets and/or tables by\n" +"adding \"plugins\" section to the corresponding entry in the catalog." +msgstr "" + +msgid "" +"More than one plugin can be assigned in a \"plugins\" section as an array.\n" +"The order in the array controls the execution order of plugins\n" +"when adapting messages.\n" +"When adapting an incoming message, plugins are applied in forward order\n" +"whereas those are applied in reverse order when adapting an outgoing message." +msgstr "" + +msgid "## Example" +msgstr "## 例" + +msgid "Consider the following case:" +msgstr "" + +msgid "" +" * There are two farms.\n" +" * All farms (Droonga Engine instances) works on the same fluentd.\n" +" * Each farm has two partitions.\n" +" * There are two replicas.\n" +" * There are two partitions for each table." +msgstr "" + +msgid "Catalog is written as a JSON file. Its file name is `catalog.json`." +msgstr "" + +msgid "Here is a `catalog.json` for the above case:" +msgstr "" + +msgid "" +"~~~json\n" +"{\n" +" \"version\": 1,\n" +" \"effective_date\": \"2013-06-05T00:05:51Z\",\n" +" \"zones\": [\"localhost:23003/farm0\", \"localhost:23003/farm1\"],\n" +" \"farms\": {\n" +" \"localhost:23003/farm0\": {\n" +" \"device\": \"disk0\",\n" +" \"capacity\": 1024\n" +" },\n" +" \"localhost:23003/farm1\": {\n" +" \"device\": \"disk1\",\n" +" \"capacity\": 1024\n" +" }\n" +" },\n" +" \"datasets\": {\n" +" \"Wiki\": {\n" +" \"workers\": 4,\n" +" \"plugins\": [\"groonga\", \"crud\", \"search\"],\n" +" \"number_of_replicas\": 2,\n" +" \"number_of_partitions\": 2,\n" +" \"partition_key\": \"_key\",\n" +" \"date_range\": \"infinity\",\n" +" \"ring\": {\n" +" \"localhost:23004\": {\n" +" \"weight\": 10,\n" +" \"partitions\": {\n" +" \"2013-07-24\": [\n" +" \"localhost:23003/farm0.000\",\n" +" \"localhost:23003/farm1.000\"\n" +" ]\n" +" }\n" +" },\n" +" \"localhost:23005\": {\n" +" \"weight\": 10,\n" +" \"partitions\": {\n" +" \"2013-07-24\": [\n" +" \"localhost:23003/farm1.001\",\n" +" \"localhost:23003/farm0.001\"\n" +" ]\n" +" }\n" +" }\n" +" }\n" +" }\n" +" }\n" +"}\n" +"~~~" +msgstr "" + +msgid "## Parameters" +msgstr "" + +msgid "Here are descriptions about parameters in `catalog.json`." +msgstr "" + +msgid "### `version` {#version}" +msgstr "" + +msgid "It is a format version of the catalog file." +msgstr "" + +msgid "" +"Droonga Engine will change `catalog.json` format in the\n" +"future. Droonga Engine can provide auto format update feature with the\n" +"information." +msgstr "" + +msgid "The value must be `1`." +msgstr "" + +msgid "This is a required parameter." +msgstr "" + +msgid "Example:" +msgstr "" + +msgid "" +"~~~json\n" +"{\n" +" \"version\": 1\n" +"}\n" +"~~~" +msgstr "" + +msgid "### `effective_date`" +msgstr "" + +msgid "" +"It is a date string representing the day the catalog becomes\n" +"effective." +msgstr "" + +msgid "The date string format must be [W3C-DTF][]." +msgstr "" + +msgid "Note: fluent-plugin-droonga 0.8.0 doesn't use this value yet." +msgstr "" + +msgid "" +"~~~json\n" +"{\n" +" \"effective_date\": \"2013-11-29T11:29:29Z\"\n" +"}\n" +"~~~" +msgstr "" + +msgid "### `zones`" +msgstr "" + +msgid "" +"`Zones` is an array to express proximities between farms.\n" +"Farms are grouped by a zone, and zones can be grouped by another zone recursiv" +"ely.\n" +"Zones make a single tree structure, expressed by nested arrays.\n" +"Farms in a same branch are regarded as relatively closer than other farms." +msgstr "" + +msgid "e.g." +msgstr "" + +msgid "When the value of `zones` is as follows," +msgstr "" + +msgid "" +"```\n" +"[[\"A\", [\"B\", \"C\"]], \"D\"]\n" +"```" +msgstr "" + +msgid "it expresses the following tree." +msgstr "" + +msgid "" +" /\\\n" +" /\\ D\n" +" A /\\\n" +" B C" +msgstr "" + +msgid "" +"This tree means the farm \"B\" and \"C\" are closer than \"A\" or \"D\" to each other." +"\n" +"You should make elements in a `zones` close to each other, like in the\n" +"same host, in the same switch, in the same network." +msgstr "" + +msgid "This is an optional parameter." +msgstr "" + +msgid "" +"~~~json\n" +"{\n" +" \"zones\": [\n" +" [\"localhost:23003/farm0\",\n" +" \"localhost:23003/farm1\"],\n" +" [\"localhost:23004/farm0\",\n" +" \"localhost:23004/farm1\"]\n" +" ]\n" +"}\n" +"~~~" +msgstr "" + +msgid "" +"*TODO: Discuss about the call of this parameter. This seems completely equals " +"to the list of keys of `farms`.*" +msgstr "" + +msgid "### `farms`" +msgstr "" + +msgid "It is an array of Droonga Engine instances." +msgstr "" + +msgid "" +"*TODO: Improve me. For example, we have to describe relations of nested farms," +" ex. `children`.*" +msgstr "" + +msgid "" +"**Farms** correspond with fluent-plugin-droonga instances. A fluentd process m" +"ay have multiple **farms** if more than one **match** entry with type **droong" +"a** appear in the \"fluentd.conf\".\n" +"Each **farm** has its own job queue.\n" +"Each **farm** can attach to a data partition which is a part of a **dataset**." +msgstr "" + +msgid "" +"~~~json\n" +"{\n" +" \"farms\": {\n" +" \"localhost:23003/farm0\": {\n" +" \"device\": \"/disk0\",\n" +" \"capacity\": 1024\n" +" },\n" +" \"localhost:23003/farm1\": {\n" +" \"device\": \"/disk1\",\n" +" \"capacity\": 1024\n" +" }\n" +" }\n" +"}\n" +"~~~" +msgstr "" + +msgid "### `datasets`" +msgstr "" + +msgid "" +"A **dataset** is a set of **tables** which comprise a single logical **table**" +" virtually.\n" +"Each **dataset** must have a unique name in the network." +msgstr "" + +msgid "### `ring`" +msgstr "" + +msgid "" +"`ring` is a series of partitions which comprise a dataset. `replica_count`, `n" +"umber_of_partitons` and **time-slice** factors affect the number of partitions" +" in a `ring`." +msgstr "" + +msgid "### `workers`" +msgstr "" + +msgid "" +"`workers` is an integer number which specifies the number of worker processes " +"to deal with the dataset.\n" +"If `0` is specified, no worker is forked and all operations are done in the ma" +"ster process." +msgstr "" + +msgid "### `number_of_partitions`" +msgstr "" + +msgid "" +"`number_of_partition` is an integer number which represents the number of part" +"itions divided by the hash function. The hash function which determines where " +"each record resides the partition in a dataset is compatible with memcached." +msgstr "" + +msgid "### `date_range`" +msgstr "" + +msgid "" +"`date_range` determines when to split the dataset. If a string \"infinity\" is a" +"ssigned, dataset is never split by time factor." +msgstr "" + +msgid "### `number_of_replicas`" +msgstr "" + +msgid "" +"`number_of_replicas` represents the number of replicas of dataset maintained i" +"n the network." +msgstr "" + +msgid "" +" [Fluentd]: http://fluentd.org/\n" +" [W3C-DTF]: http://www.w3.org/TR/NOTE-datetime \"Date and Time Formats\"" +msgstr "" Added: _po/ja/reference/1.0.3/catalog/version2/index.po (+1138 -0) 100644 =================================================================== --- /dev/null +++ _po/ja/reference/1.0.3/catalog/version2/index.po 2014-05-19 16:48:30 +0900 (65e5c54) @@ -0,0 +1,1138 @@ +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"PO-Revision-Date: 2014-03-05 12:52+0900\n" +"Language: ja\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" + +msgid "" +"---\n" +"title: Catalog\n" +"layout: en\n" +"---" +msgstr "" +"---\n" +"title: カタログ\n" +"layout: ja\n" +"---" + +msgid "" +"* TOC\n" +"{:toc}" +msgstr "" + +msgid "## Abstract {#abstract}" +msgstr "## 概要 {#abstract}" + +msgid "" +"`Catalog` is a JSON data to manage the configuration of a Droonga cluster.\n" +"A Droonga cluster consists of one or more `datasets`, and a `dataset` consists" +" of other portions. They all must be explicitly described in a `catalog` and b" +"e shared with all the hosts in the cluster." +msgstr "" +"`Catalog`はDroongaクラスタの設定を管理するためのJSONデータです。Droongaクラスタは1つ以上の`datasets`からなり、`dat" +"aset`はその他の部分からなります。それらは全て`catalog`に記述し、クラスタ内の全てホストで共有しなければなりません。" + +msgid "## Usage {#usage}" +msgstr "## 使い方 {#usage}" + +msgid "" +"This [`version`](#parameter-version) of `catalog` will be available from Droon" +"ga 1.0.0." +msgstr "この [`version`](#paramter-version) の `catalog` は Droonga 1.0.0 以降で有効です。" + +msgid "## Syntax {#syntax}" +msgstr "## 書式 {#syntax}" + +msgid "" +" {\n" +" \"version\": <Version number>,\n" +" \"effectiveDate\": \"<Effective date>\",\n" +" \"datasets\": {\n" +" \"<Name of the dataset 1>\": {\n" +" \"nWorkers\": <Number of workers>,\n" +" \"plugins\": [\n" +" \"Name of the plugin 1\",\n" +" ...\n" +" ],\n" +" \"schema\": {\n" +" \"<Name of the table 1>\": {\n" +" \"type\" : <\"Array\", \"Hash\", \"PatriciaTrie\" or \"Double" +"ArrayTrie\">\n" +" \"keyType\" : \"<Type of the primary key>\",\n" +" \"tokenizer\" : \"<Tokenizer>\",\n" +" \"normalizer\" : \"<Normalizer>\",\n" +" \"columns\" : {\n" +" \"<Name of the column 1>\": {\n" +" \"type\" : <\"Scalar\", \"Vector\" or \"Index\">,\n" +" \"valueType\" : \"<Type of the value>\",\n" +" \"vectorOptions\": {\n" +" \"weight\" : <Weight>,\n" +" },\n" +" \"indexOptions\" : {\n" +" \"section\" : <Section>,\n" +" \"weight\" : <Weight>,\n" +" \"position\" : <Position>,\n" +" \"sources\" : [\n" +" \"<Name of a column to be indexed>\",\n" +" ...\n" +" ]\n" +" }\n" +" },\n" +" \"<Name of the column 2>\": { ... },\n" +" ...\n" +" }\n" +" },\n" +" \"<Name of the table 2>\": { ... },\n" +" ...\n" +" },\n" +" \"fact\": \"<Name of the fact table>\",\n" +" \"replicas\": [\n" +" {\n" +" \"dimension\": \"<Name of the dimension column>\",\n" +" \"slicer\": \"<Name of the slicer function>\",\n" +" \"slices\": [\n" +" {\n" +" \"label\": \"<Label of the slice>\",\n" +" \"volume\": {\n" +" \"address\": \"<Address string of the volume>\"\n" +" }\n" +" },\n" +" ...\n" +" }\n" +" },\n" +" ...\n" +" ]\n" +" },\n" +" \"<Name of the dataset 2>\": { ... },\n" +" ...\n" +" }\n" +" }" +msgstr "" + +msgid "## Details {#details}" +msgstr "## 詳細 {#details}" + +msgid "### Catalog definition {#catalog}" +msgstr "### Catalog 定義 {#catalog}" + +msgid "" +"Value\n" +": An object with the following key/value pairs." +msgstr "" +"値\n" +": 以下のキーと値のペアを持つオブジェクト。" + +msgid "#### Parameters" +msgstr "#### パラメータ" + +msgid "##### `version` {#parameter-version}" +msgstr "" + +msgid "" +"Abstract\n" +": Version number of the catalog file." +msgstr "" +"概要\n" +": カタログファイルのバージョン番号。" + +msgid "" +"Value\n" +": `2`. (Specification written in this page is valid only when this value is `2" +"`)" +msgstr "" +"値\n" +": `2`. (このページに記述されている仕様はこの値が`2`のときのみ有効です)" + +msgid "" +"Default value\n" +": None. This is a required parameter." +msgstr "" +"既定値\n" +": なし。これは必須のパラメータです。" + +msgid "" +"Inheritable\n" +": False." +msgstr "" +"継承可能性\n" +": 不可。" + +msgid "##### `effectiveDate` {#parameter-effective_date}" +msgstr "" + +msgid "" +"Abstract\n" +": The time when this catalog becomes effective." +msgstr "" +"概要\n" +": このカタログが有効になる時刻。" + +msgid "" +"Value\n" +": A local time string formatted in the [W3C-DTF](http://www.w3.org/TR/NOTE-dat" +"etime \"Date and Time Formats\"), with the time zone." +msgstr "" +"値\n" +": [W3C-DTF](http://www.w3.org/TR/NOTE-datetime \"Date and Time Formats\") でフォーマッ" +"トされたタイムゾーン付きの時刻。" + +msgid "##### `datasets` {#parameter-datasets}" +msgstr "" + +msgid "" +"Abstract\n" +": Definition of datasets." +msgstr "" +"概要\n" +": データセットの定義。" + +msgid "" +"Value\n" +": An object keyed by the name of the dataset with value the [`dataset` definit" +"ion](#dataset)." +msgstr ": データセット名をキーとし、[`dataset` 定義](#dataset) を値とするオブジェクト。" + +msgid "##### `nWorkers` {#parameter-n_workers}" +msgstr "" + +msgid "" +"Abstract\n" +": The number of worker processes spawned for each database instance." +msgstr "" +"概要\n" +": データベースインスタンス毎にspawnされるワーカの数。" + +msgid "" +"Value\n" +": An integer value." +msgstr "" +"値\n" +": 整数。" + +msgid "" +"Default value\n" +": 0 (No worker. All operations are done in the master process)" +msgstr "" +"既定値\n" +": 0 (ワーカー無し。全ての処理がマスタープロセス内で行われます)" + +msgid "" +"Inheritable\n" +": True. Overridable in `dataset` and `volume` definition." +msgstr "" +"継承可能性\n" +": 可。`dataset`と`volume`の定義でオーバライドできます。" + +msgid "#### Example" +msgstr "#### 例" + +msgid "A version 2 catalog effective after `2013-09-01T00:00:00Z`, with no datasets:" +msgstr "" + +msgid "" +"~~~\n" +"{\n" +" \"version\": 2,\n" +" \"effectiveDate\": \"2013-09-01T00:00:00Z\",\n" +" \"datasets\": {\n" +" }\n" +"}\n" +"~~~" +msgstr "" + +msgid "### Dataset definition {#dataset}" +msgstr "### Dataset 定義 {#dataset}" + +msgid "##### `plugins` {#parameter-plugins}" +msgstr "" + +msgid "" +"Abstract\n" +": Name strings of the plugins enabled for the dataset." +msgstr "" +"概要\n" +": このデータセットにおいて有効にするプラグイン名文字列の配列。" + +msgid "" +"Value\n" +": An array of strings." +msgstr "" +"値\n" +": 文字列の配列。" + +msgid "##### `schema` {#parameter-schema}" +msgstr "" + +msgid "" +"Abstract\n" +": Definition of tables and their columns." +msgstr "" +"概要\n" +": テーブルとそのカラムの定義。" + +msgid "" +"Value\n" +": An object keyed by the name of the table with value the [`table` definition]" +"(#table)." +msgstr "" +"値\n" +": テーブル名をキーとし、[`table` 定義](#table)を値とするオブジェクト。" + +msgid "##### `fact` {#parameter-fact}" +msgstr "" + +msgid "" +"Abstract\n" +": The name of the fact table. When a `dataset` is stored as more than one `sli" +"ce`, one [fact table](http://en.wikipedia.org/wiki/Fact_table) must be selecte" +"d from tables defined in [`schema`](#parameter-schema) parameter." +msgstr "" +"概要\n" +": fact テーブルの名前。`dataset`が複数の`slice`に格納される場合、[`schema`](#parameter-schema)パラメータ" +"で定義されたテーブルの中から、1つ[fact table](http://en.wikipedia.org/wiki/Fact_table)を選択する必要が" +"あります。" + +msgid "" +"Value\n" +": A string." +msgstr "" +"値\n" +": 文字列。" + +msgid "" +"Default value\n" +": None." +msgstr "" +"既定値\n" +": なし。" + +msgid "##### `replicas` {#parameter-replicas}" +msgstr "" + +msgid "" +"Abstract\n" +": A collection of volumes which are the copies of each other." +msgstr "" +"概要\n" +": 互いに複製されるボリュームの集合。" + +msgid "" +"Value\n" +": An array of [`volume` definitions](#volume)." +msgstr "" +"値\n" +": [`volume` 定義](#volume)の配列。" + +msgid "" +"A dataset with 4 workers per a database instance, with plugins `groonga`, `cru" +"d` and `search`:" +msgstr "データベースインスタンスに1つにつき4ワーカーを持ち、プラグイン`groonga`、`crud`、`search`を使用するデータセット:" + +msgid "" +"~~~\n" +"{\n" +" \"nWorkers\": 4,\n" +" \"plugins\": [\"groonga\", \"crud\", \"search\"],\n" +" \"schema\": {\n" +" },\n" +" \"replicas\": [\n" +" ]\n" +"}\n" +"~~~" +msgstr "" + +msgid "### Table definition {#table}" +msgstr "### Table 定義 {#table}" + +msgid "##### `type` {#parameter-table-type}" +msgstr "" + +msgid "" +"Abstract\n" +": Specifies which data structure is used for managing keys of the table." +msgstr "" +"概要\n" +": テーブルのキーを管理するためのデータ構造を指定する。" + +msgid "" +"Value\n" +": Any of the following values." +msgstr "" +"値\n" +": 以下のうちいずれかの値。" + +msgid "" +"* `\"Array\"`: for tables which have no keys.\n" +"* `\"Hash\"`: for hash tables.\n" +"* `\"PatriciaTrie\"`: for patricia trie tables.\n" +"* `\"DoubleArrayTrie\"`: for double array trie tables." +msgstr "" +"* `\"Array\"`: キーの無いテーブル\n" +"* `\"Hash\"`: ハッシュテーブル\n" +"* `\"PatriciaTrie\"`: パトリシアトライテーブル\n" +"* `\"DoubleArrayTrie\"`: ダブル配列トライテーブル" + +msgid "" +"Default value\n" +": `\"Hash\"`" +msgstr "" +"既定値\n" +": `\"Hash\"`" + +msgid "##### `keyType` {#parameter-keyType}" +msgstr "" + +msgid "" +"Abstract\n" +": Data type of the key of the table. Mustn't be assigned when the `type` is `\"" +"Array\"`." +msgstr "" +"概要\n" +": テーブルにおけるキーのデータ型。`type`が`\"Array\"`の場合は指定してはいけません。" + +msgid "" +"Value\n" +": Any of the following data types." +msgstr "" +"値\n" +": 以下のデータ型のうちのいずれか。" + +msgid "" +"* `\"Integer\"` : 64bit signed integer.\n" +"* `\"Float\"` : 64bit floating-point number.\n" +"* `\"Time\"` : Time value with microseconds resolution.\n" +"* `\"ShortText\"` : Text value up to 4095 bytes length.\n" +"* `\"TokyoGeoPoint\"` : Tokyo Datum based geometric point value.\n" +"* `\"WGS84GeoPoint\"` : [WGS84](http://en.wikipedia.org/wiki/World_Geodetic_Syst" +"em) based geometric point value." +msgstr "" +"* `\"Integer\"` : 64bit 符号付き整数。\n" +"* `\"Float\"` : 64bit 浮動小数点数。\n" +"* `\"Time\"` : マイクロ秒精度の時刻。\n" +"* `\"ShortText\"` : 4095バイトまでの文字列。\n" +"* `\"TokyoGeoPoint\"` : 旧日本測地系による経緯度。\n" +"* `\"WGS84GeoPoint\"` : [WGS84](http://en.wikipedia.org/wiki/World_Geodetic_Syst" +"em) による経緯度。" + +msgid "" +"Default value\n" +": None. Mandatory for tables with keys." +msgstr "" +"既定値\n" +": なし。キーを持つテーブルでは指定が必須です。" + +msgid "##### `tokenizer` {#parameter-tokenizer}" +msgstr "" + +msgid "" +"Abstract\n" +": Specifies the type of tokenizer used for splitting each text value, when the" +" table is used as a lexicon. Only available when the `keyType` is `\"ShortText\"" +"`." +msgstr "" +"概要\n" +": 語彙表として使われるテーブルにおける、文字列型の値を分割するために使うトークナイザーの種類を指定します。`keyType`が`\"ShortText\"`で" +"ある場合にのみ有効です。" + +msgid "" +"Value\n" +": Any of the following tokenizer names." +msgstr "" +"値\n" +": 以下のトークナイザー名のうちのいずれか。" + +msgid "" +"* `\"TokenDelimit\"`\n" +"* `\"TokenUnigram\"`\n" +"* `\"TokenBigram\"`\n" +"* `\"TokenTrigram\"`\n" +"* `\"TokenBigramSplitSymbol\"`\n" +"* `\"TokenBigramSplitSymbolAlpha\"`\n" +"* `\"TokenBigramSplitSymbolAlphaDigit\"`\n" +"* `\"TokenBigramIgnoreBlank\"`\n" +"* `\"TokenBigramIgnoreBlankSplitSymbol\"`\n" +"* `\"TokenBigramIgnoreBlankSplitSymbolAlpha\"`\n" +"* `\"TokenBigramIgnoreBlankSplitSymbolAlphaDigit\"`\n" +"* `\"TokenDelimitNull\"`" +msgstr "" + +msgid "##### `normalizer` {#parameter-normalizer}" +msgstr "" + +msgid "" +"Abstract\n" +": Specifies the type of normalizer which normalizes and restricts the key valu" +"es. Only available when the `keyType` is `\"ShortText\"`." +msgstr "" +"概要\n" +": キーの値を正規化・制限するノーマライザーの種類を指定します。`keyType`が`\"ShortText\"`である場合にのみ有効です。" + +msgid "" +"Value\n" +": Any of the following normalizer names." +msgstr "" +"値\n" +": 以下のノーマライザー名のうちのいずれか。" + +msgid "" +"* `\"NormalizerAuto\"`\n" +"* `\"NormalizerNFKC51\"`" +msgstr "" + +msgid "##### `columns` {#parameter-columns}" +msgstr "" + +msgid "" +"Abstract\n" +": Column definition for the table." +msgstr "" +"概要\n" +": テーブルのカラムの定義。" + +msgid "" +"Value\n" +": An object keyed by the name of the column with value the [`column` definitio" +"n](#column)." +msgstr "" + +msgid "#### Examples" +msgstr "#### 例" + +msgid "##### Example 1: Hash table" +msgstr "##### 例1: Hashテーブル" + +msgid "A `Hash` table whose key is `ShortText` type, with no columns:" +msgstr "`ShortText`型のキーを持つ`Hash`テーブルで、カラムは無いもの:" + +msgid "" +"~~~\n" +"{\n" +" \"type\": \"Hash\",\n" +" \"keyType\": \"ShortText\",\n" +" \"columns\": {\n" +" }\n" +"}\n" +"~~~" +msgstr "" + +msgid "##### Example 2: PatriciaTrie table" +msgstr "##### 例2: PatriciaTrieテーブル" + +msgid "" +"A `PatriciaTrie` table with `TokenBigram` tokenizer and `NormalizerAuto` norma" +"lizer, with no columns:" +msgstr "`TokenBigram`トークナイザと`NormalizerAuto`ノーマライザを利用する`PatriciaTrie`テーブル" + +msgid "" +"~~~\n" +"{\n" +" \"type\": \"PatriciaTrie\",\n" +" \"keyType\": \"ShortText\",\n" +" \"tokenizer\": \"TokenBigram\",\n" +" \"normalizer\": \"NormalizerAuto\",\n" +" \"columns\": {\n" +" }\n" +"}\n" +"~~~" +msgstr "" + +msgid "### Column definition {#column}" +msgstr "### Column 定義 {#column}" + +msgid "Value" +msgstr "値" + +msgid ": An object with the following key/value pairs." +msgstr "" + +msgid "##### `type` {#parameter-column-type}" +msgstr "" + +msgid "" +"Abstract\n" +": Specifies the quantity of data stored as each column value." +msgstr "" + +msgid "" +"Value\n" +": Any of the followings." +msgstr "" + +msgid "" +"* `\"Scalar\"`: A single value.\n" +"* `\"Vector\"`: A list of values.\n" +"* `\"Index\"` : A set of unique values with additional properties respectively. " +"Properties can be specified in [`indexOptions`](#parameter-indexOptions)." +msgstr "" + +msgid "" +"Default value\n" +": `\"Scalar\"`" +msgstr "" + +msgid "##### `valueType` {#parameter-valueType}" +msgstr "" + +msgid "" +"Abstract\n" +": Data type of the column value." +msgstr "" + +msgid "" +"Value\n" +": Any of the following data types or the name of another table defined in the " +"same dataset. When a table name is assigned, the column acts as a foreign key " +"references the table." +msgstr "" + +msgid "" +"* `\"Bool\"` : `true` or `false`.\n" +"* `\"Integer\"` : 64bit signed integer.\n" +"* `\"Float\"` : 64bit floating-point number.\n" +"* `\"Time\"` : Time value with microseconds resolution.\n" +"* `\"ShortText\"` : Text value up to 4,095 bytes length.\n" +"* `\"Text\"` : Text value up to 2,147,483,647 bytes length.\n" +"* `\"TokyoGeoPoint\"` : Tokyo Datum based geometric point value.\n" +"* `\"WGS84GeoPoint\"` : [WGS84](http://en.wikipedia.org/wiki/World_Geodetic_Syst" +"em) based geometric point value." +msgstr "" + +msgid "##### `vectorOptions` {#parameter-vectorOptions}" +msgstr "" + +msgid "" +"Abstract\n" +": Specifies the optional properties of a \"Vector\" column." +msgstr "" +"概要\n" +": データベースインスタンスの場所を指定します。" + +msgid "" +"Value\n" +": An object which is a [`vectorOptions` definition](#vectorOptions)" +msgstr "" + +msgid "" +"Default value\n" +": `{}` (Void object)." +msgstr "" + +msgid "##### `indexOptions` {#parameter-indexOptions}" +msgstr "" + +msgid "" +"Abstract\n" +": Specifies the optional properties of an \"Index\" column." +msgstr "" +"概要\n" +": データベースインスタンスの場所を指定します。" + +msgid "" +"Value\n" +": An object which is an [`indexOptions` definition](#indexOptions)" +msgstr "" + +msgid "##### Example 1: Scalar column" +msgstr "##### 例1: スカラー型カラム" + +msgid "A scaler column to store `ShortText` values:" +msgstr "`ShortText`を格納するスカラー型のカラム:" + +msgid "" +"~~~\n" +"{\n" +" \"type\": \"Scalar\",\n" +" \"valueType\": \"ShortText\"\n" +"}\n" +"~~~" +msgstr "" + +msgid "##### Example 2: Vector column" +msgstr "##### 例1: スカラー型カラム" + +msgid "A vector column to store `ShortText` values with weight:" +msgstr "" + +msgid "" +"~~~\n" +"{\n" +" \"type\": \"Scalar\",\n" +" \"valueType\": \"ShortText\",\n" +" \"vectorOptions\": {\n" +" \"weight\": true\n" +" }\n" +"}\n" +"~~~" +msgstr "" + +msgid "##### Example 3: Index column" +msgstr "##### 例2: インデクスカラム" + +msgid "A column to index `address` column on `Store` table:" +msgstr "`Store`テーブルの`address`カラムをインデクスするカラム:" + +msgid "" +"~~~\n" +"{\n" +" \"type\": \"Index\",\n" +" \"valueType\": \"Store\",\n" +" \"indexOptions\": {\n" +" \"sources\": [\n" +" \"address\"\n" +" ]\n" +" }\n" +"}\n" +"~~~" +msgstr "" + +msgid "### vectorOptions definition {#vectorOptions}" +msgstr "### vectorOptions 定義 {#vectorOptions}" + +msgid "##### `weight` {#parameter-vectorOptions-weight}" +msgstr "" + +msgid "" +"Abstract\n" +": Specifies whether the vector column stores the weight data or not. Weight da" +"ta is used for indicating the importance of the value." +msgstr "" + +msgid "" +"Value\n" +": A boolean value (`true` or `false`)." +msgstr "" + +msgid "" +"Default value\n" +": `false`." +msgstr "" + +msgid "Store the weight data." +msgstr "" + +msgid "" +"~~~\n" +"{\n" +" \"weight\": true\n" +"}\n" +"~~~" +msgstr "" + +msgid "### indexOptions definition {#indexOptions}" +msgstr "### indexOptions 定義 {#indexOptions}" + +msgid "##### `section` {#parameter-indexOptions-section}" +msgstr "" + +msgid "" +"Abstract\n" +": Specifies whether the index column stores the section data or not. Section d" +"ata is typically used for distinguishing in which part of the sources the valu" +"e appears." +msgstr "" + +msgid "##### `weight` {#parameter-indexOptions-weight}" +msgstr "" + +msgid "" +"Abstract\n" +": Specifies whether the index column stores the weight data or not. Weight dat" +"a is used for indicating the importance of the value in the sources." +msgstr "" + +msgid "##### `position` {#parameter-indexOptions-position}" +msgstr "" + +msgid "" +"Abstract\n" +": Specifies whether the index column stores the position data or not. Position" +" data is used for specifying the position where the value appears in the sourc" +"es. It is indispensable for fast and accurate phrase-search." +msgstr "" + +msgid "##### `sources` {#parameter-indexOptions-sources}" +msgstr "" + +msgid "" +"Abstract\n" +": Makes the column an inverted index of the referencing table's columns." +msgstr "" + +msgid "" +"Value\n" +": An array of column names of the referencing table assigned as [`valueType`](" +"#parameter-valueType)." +msgstr "" + +msgid "" +"Store the section data, the weight data and the position data.\n" +"Index `name` and `address` on the referencing table." +msgstr "" + +msgid "" +"~~~\n" +"{\n" +" \"section\": true,\n" +" \"weight\": true,\n" +" \"position\": true\n" +" \"sources\": [\n" +" \"name\",\n" +" \"address\"\n" +" ]\n" +"}\n" +"~~~" +msgstr "" + +msgid "### Volume definition {#volume}" +msgstr "### Volume 定義 {#volume}" + +msgid "" +"Abstract\n" +": A unit to compose a dataset. A dataset consists of one or more volumes. A vo" +"lume consists of either a single instance of database or a collection of `slic" +"es`. When a volume consists of a single database instance, `address` parameter" +" must be assigned and the other parameters must not be assigned. Otherwise, `d" +"imension`, `slicer` and `slices` are required, and vice versa." +msgstr "" +"概要\n" +": データセットを構成する単位。データセットは1つ、もしくは複数のボリュームからなります。ボリュームは単一のデータベースインスタンスか、`slices` の" +"集合で構成されます。ボリュームが単一のデータベースインスタンスから構成される場合は、`address`パラメータを指定しなければなりません。このとき、それ以" +"外のパラメータを指定してはいけません。そうでない場合は、`dimension`と`slicer`と`slices`が必須で、他は指定してはいけません。" + +msgid "##### `address` {#parameter-address}" +msgstr "" + +msgid "" +"Abstract\n" +": Specifies the location of the database instance." +msgstr "" +"概要\n" +": データベースインスタンスの場所を指定します。" + +msgid "" +"Value\n" +": A string in the following format." +msgstr "" +"値\n" +": 以下の書式の文字列。" + +msgid "\"[database_type:]hostname[:port_number]/localpath/to/the/database\"" +msgstr "" + +msgid "" +"* database_type: Optional. Default value is \"groonga\".\n" +"* port_number: Optional. Default value is 10047." +msgstr "" +"* database_type: 省略可能。既定値は\"groonga\"。\n" +"* port_number: 省略可能。既定値は 10047。" + +msgid "##### `dimension` {#parameter-dimension}" +msgstr "" + +msgid "" +"Abstract\n" +": Specifies the dimension to slice the records in the fact table. Either '_key" +"\" or a scalar type column can be selected from [`columns`](#parameter-columns)" +" parameter of the fact table. See [dimension](http://en.wikipedia.org/wiki/Dim" +"ension_%28data_warehouse%29)." +msgstr "" +"概要\n" +": fact表の中でレコードをスライスする次元を指定します。fact表の'_key'または[`columns`](#parameter-columns)から" +"スカラー型のカラムを選択します。[dimension](http://en.wikipedia.org/wiki/Dimension_%28data_war" +"ehouse%29)を参照してください。" + +msgid "" +"Default value\n" +": `\"_key\"`" +msgstr "" +"既定値\n" +": `\"_key\"`" + +msgid "##### `slicer` {#parameter-slicer}" +msgstr "" + +msgid "" +"Abstract\n" +": Function to slice the value of dimension column." +msgstr "" +"概要\n" +": dimensionカラムをsliceする関数。" + +msgid "" +"Value\n" +": Name of slicer function." +msgstr "" +"値\n" +": スライサー関数の名前。" + +msgid "" +"Default value\n" +": `\"hash\"`" +msgstr "" +"既定値\n" +": `\"hash\"`" + +msgid "" +"In order to define a volume which consists of a collection of `slices`,\n" +"the way how slice records into slices must be decided." +msgstr "`slices`の集合からなるボリュームを定義するためには、レコードを複数のスライスに振り分けるための方法を決める必要があります。" + +msgid "" +"The slicer function that specified as `slicer` and\n" +"the column (or key) specified as `dimension`,\n" +"which is input for the slicer function, defines that." +msgstr "" +"`slice`で指定されたスライサー関数と、スライサー関数への入力として与えられる`dimension`で指定されたカラム(またはキー)によって、それが決ま" +"ります。" + +msgid "Slicers are categorized into three types. Here are three types of slicers:" +msgstr "スライサーは以下の3種類に分けられます:" + +msgid "" +"Ratio-scaled\n" +": *Ratio-scaled slicers* slice datapoints in the specified ratio,\n" +" e.g. hash function of _key.\n" +" Slicers of this type are:" +msgstr "" +"比率尺度\n" +": *比率尺度スライサー*は、個々のデータを指定された比率で、_keyのハッシュ値などに基づいて振り分けます。\n" +" この種類のスライサー:" + +msgid " * `hash`" +msgstr "" + +msgid "" +"Ordinal-scaled\n" +": *Ordinal-scaled slicers* slice datapoints with ordinal values;\n" +" the values have some ranking, e.g. time, integer,\n" +" element of `{High, Middle, Low}`.\n" +" Slicers of this type are:" +msgstr "" +"順序尺度\n" +": *順序尺度スライサー*は、個々のデータを順序のある値(時間、整数、`{High, Middle, Low}`など)に基づいて振り分けます。\n" +" この種類のスライサー:" + +msgid " * (not implemented yet)" +msgstr " * (未実装)" + +msgid "" +"Nominal-scaled\n" +": *Nominal-scaled slicers* slice datapoints with nominal values;\n" +" the values denotes categories,which have no order,\n" +" e.g. country, zip code, color.\n" +" Slicers of this type are:" +msgstr "" +"名義尺度\n" +": *名義尺度スライサー*は、個々のデータをカテゴリを示す名義(国名、郵便番号、色など)で振り分けます。\n" +" この種類のスライサー:" + +msgid "##### `slices` {#parameter-slices}" +msgstr "" + +msgid "" +"Abstract\n" +": Definition of slices which store the contents of the data." +msgstr "" +"概要\n" +": データを格納するスライスの定義。" + +msgid "" +"Value\n" +": An array of [`slice` definitions](#slice)." +msgstr "" +"値\n" +": [`slice` 定義](#slice)の配列。" + +msgid "##### Example 1: Single instance" +msgstr "##### 例1: 単一のインスタンス" + +msgid "A volume at \"localhost:24224/volume.000\":" +msgstr "\"localhost:24224/volume.000\"にあるボリューム:" + +msgid "" +"~~~\n" +"{\n" +" \"address\": \"localhost:24224/volume.000\"\n" +"}\n" +"~~~" +msgstr "" + +msgid "##### Example 2: Slices" +msgstr "##### Example 2: 複数のスライス" + +msgid "" +"A volume that consists of three slices, records are to be distributed accordin" +"g to `hash`,\n" +"which is ratio-scaled slicer function, of `_key`." +msgstr "3つのスライスから構成され、`_key`に対してratio-scaledなスライサー関数`hash`を適用してレコードを分散させるボリューム" + +msgid "" +"~~~\n" +"{\n" +" \"dimension\": \"_key\",\n" +" \"slicer\": \"hash\",\n" +" \"slices\": [\n" +" {\n" +" \"volume\": {\n" +" \"address\": \"localhost:24224/volume.000\"\n" +" }\n" +" },\n" +" {\n" +" \"volume\": {\n" +" \"address\": \"localhost:24224/volume.001\"\n" +" }\n" +" },\n" +" {\n" +" \"volume\": {\n" +" \"address\": \"localhost:24224/volume.002\"\n" +" }\n" +" }\n" +" ]\n" +"~~~" +msgstr "" + +msgid "### Slice definition {#slice}" +msgstr "### Slice 定義 {#slice}" + +msgid "" +"Abstract\n" +": Definition of each slice. Specifies the range of sliced data and the volume " +"to store the data." +msgstr "" +"概要\n" +": スライスの定義。スライスされたデータの範囲と、それを保存するボリュームを指定する。" + +msgid "##### `weight` {#parameter-slice-weight}" +msgstr "" + +msgid "" +"Abstract\n" +": Specifies the share in the slices. Only available when the `slicer` is ratio" +"-scaled." +msgstr "" +"概要\n" +": スライス内での割り当て量を指定します。`slicer`が atio-scaledの場合のみ有効。" + +msgid "" +"Value\n" +": A numeric value." +msgstr "" +"値\n" +": 数値。" + +msgid "" +"Default value\n" +": `1`." +msgstr "" +"既定値\n" +": `1`" + +msgid "##### `label` {#parameter-label}" +msgstr "" + +msgid "" +"Abstract\n" +": Specifies the concrete value that slicer may return. Only available when the" +" slicer is nominal-scaled." +msgstr "" +"概要\n" +": slicer が返す具体的な値。 slicerがnominal-scaledの場合のみ有効。" + +msgid "" +"Value\n" +": A value of the dimension column data type. When the value is not provided, t" +"his slice is regarded as *else*; matched only if all other labels are not matc" +"hed. Therefore, only one slice without `label` is allowed in slices." +msgstr "" + +msgid "##### `boundary` {#parameter-boundary}" +msgstr "" + +msgid "" +"Abstract\n" +": Specifies the concrete value that can compare with `slicer`'s return value. " +"Only available when the `slicer` is ordinal-scaled." +msgstr "" +"概要\n" +": `slicer`の返す値と比較可能な具体的な値。`slicer`がordinal-scaledの場合のみ有効。" + +msgid "" +"Value\n" +": A value of the dimension column data type. When the value is not provided, t" +"his slice is regarded as *else*; this means the slice is open-ended. Therefore" +", only one slice without `boundary` is allowed in a slices." +msgstr "" + +msgid "##### `volume` {#parameter-volume}" +msgstr "" + +msgid "" +"Abstract\n" +": A volume to store the data which corresponds to the slice." +msgstr "" +"概要\n" +": スライスに対応するデータを格納するボリューム。" + +msgid ": An object which is a [`volume` definition](#volume)" +msgstr ": [`volume` 定義](#volume)オブジェクト" + +msgid "##### Example 1: Ratio-scaled" +msgstr "##### 例1: Ratio-scaled" + +msgid "Slice for a ratio-scaled slicer, with the weight `1`:" +msgstr "ratio-scaledなスライサーのためのスライス、重みは`1`" + +msgid "" +"~~~\n" +"{\n" +" \"weight\": 1,\n" +" \"volume\": {\n" +" }\n" +"}\n" +"~~~" +msgstr "" + +msgid "##### Example 2: Nominal-scaled" +msgstr "##### 例2: Nominal-scaled" + +msgid "Slice for a nominal-scaled slicer, with the label `\"1\"`:" +msgstr "nominal-scaledなスライサーのためのスライス、ラベルは `\"1\"`" + +msgid "" +"~~~\n" +"{\n" +" \"label\": \"1\",\n" +" \"volume\": {\n" +" }\n" +"}\n" +"~~~" +msgstr "" + +msgid "##### Example 3: Ordinal-scaled" +msgstr "##### 例3: Ordinal-scaled" + +msgid "Slice for a ordinal-scaled slicer, with the boundary `100`:" +msgstr "ordinal-scaledなスライサーに対するスライス、境界値は`100`:" + +msgid "" +"~~~\n" +"{\n" +" \"boundary\": 100,\n" +" \"volume\": {\n" +" }\n" +"}\n" +"~~~" +msgstr "" + +msgid "## Realworld example" +msgstr "## 実際の例" + +msgid "See the catalog of [basic tutorial]." +msgstr "[基本的な使い方のチュートリアル][basic tutorial]に登場するカタログを参照してください。" + +msgid " [basic tutorial]: ../../../tutorial/basic" +msgstr "" Added: _po/ja/reference/1.0.3/commands/add/index.po (+411 -0) 100644 =================================================================== --- /dev/null +++ _po/ja/reference/1.0.3/commands/add/index.po 2014-05-19 16:48:30 +0900 (8b9f52e) @@ -0,0 +1,411 @@ +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"PO-Revision-Date: 2014-03-05 12:52+0900\n" +"Language: ja\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" + +msgid "" +"---\n" +"title: add\n" +"layout: en\n" +"---" +msgstr "" +"---\n" +"title: add\n" +"layout: ja\n" +"---" + +msgid "" +"* TOC\n" +"{:toc}" +msgstr "" + +msgid "## Abstract {#abstract}" +msgstr "## 概要 {#abstract}" + +msgid "" +"The `add` command adds a new record to the specified table. Column values of t" +"he existing record are updated by given values, if the table has a primary key" +" and there is existing record with the specified key." +msgstr "" +"`add` は、テーブルにレコードを登録します。対象のテーブルが主キーを持っており、同じキーのレコードが既に存在している場合には、既存レコードのカラムの値を" +"更新します。" + +msgid "" +"Style\n" +": Request-Response. One response message is always returned per one request." +msgstr "" +"形式\n" +": Request-Response型。コマンドに対しては必ず対応するレスポンスが返されます。" + +msgid "" +"`type` of the request\n" +": `add`" +msgstr "" +"リクエストの `type`\n" +": `add`" + +msgid "" +"`body` of the request\n" +": A hash of parameters." +msgstr "" +"リクエストの `body`\n" +": パラメータのハッシュ。" + +msgid "" +"`type` of the response\n" +": `add.result`" +msgstr "" +"レスポンスの `type`\n" +": `add.result`" + +msgid "## Parameter syntax {#syntax}" +msgstr "## パラメータの構文 {#syntax}" + +msgid "If the table has a primary key column:" +msgstr "対象のテーブルが主キーを持つ場合:" + +msgid "" +" {\n" +" \"table\" : \"<Name of the table>\",\n" +" \"key\" : \"<The primary key of the record>\",\n" +" \"values\" : {\n" +" \"<Name of the column 1>\" : <value 1>,\n" +" \"<Name of the column 2>\" : <value 2>,\n" +" ...\n" +" }\n" +" }" +msgstr "" +" {\n" +" \"table\" : \"<テーブル名>\",\n" +" \"key\" : \"<レコードの主キー>\",\n" +" \"values\" : {\n" +" \"<カラム1の名前>\" : <値1>,\n" +" \"<カラム2の名前>\" : <値2>,\n" +" ...\n" +" }\n" +" }" + +msgid "If the table has no primary key column:" +msgstr "対象のテーブルが主キーを持たない場合:" + +msgid "" +" {\n" +" \"table\" : \"<Name of the table>\",\n" +" \"values\" : {\n" +" \"<Name of the column 1>\" : <value 1>,\n" +" \"<Name of the column 2>\" : <value 2>,\n" +" ...\n" +" }\n" +" }" +msgstr "" +" {\n" +" \"table\" : \"<テーブル名>\",\n" +" \"values\" : {\n" +" \"<カラム1の名前>\" : <値1>,\n" +" \"<カラム2の名前>\" : <値2>,\n" +" ...\n" +" }\n" +" }" + +msgid "## Usage {#usage}" +msgstr "## 使い方 {#usage}" + +msgid "" +"This section describes how to use the `add` command, via a typical usage with " +"following two tables:" +msgstr "本項の説明では以下のような2つのテーブルが存在している事を前提として、典型的な使い方を通じて `add` コマンドの使い方を説明します。" + +msgid "Person table (without primary key):" +msgstr "Personテーブル(主キー無し):" + +msgid "" +"|name|job (referring the Job table)|\n" +"|Alice Arnold|announcer|\n" +"|Alice Cooper|musician|" +msgstr "" +"|name|job (Jobテーブルを参照)|\n" +"|Alice Arnold|announcer|\n" +"|Alice Cooper|musician|" + +msgid "Job table (with primary key)" +msgstr "Jobテーブル(主キー有り):" + +msgid "" +"|_key|label|\n" +"|announcer|announcer|\n" +"|musician|musician|" +msgstr "" + +msgid "" +"### Adding a new record to a table without primary key {#adding-record-to-tabl" +"e-without-key}" +msgstr "### 主キーを持たないテーブルにレコードを追加する {#adding-record-to-table-without-key}" + +msgid "" +"Specify only `table` and `values`, without `key`, if the table has no primary " +"key." +msgstr "主キーを持たないテーブルにレコードを追加する場合は、 `key` を指定せずに `table` と `values` だけを指定します。" + +msgid "" +" {\n" +" \"type\" : \"add\",\n" +" \"body\" : {\n" +" \"table\" : \"Person\",\n" +" \"values\" : {\n" +" \"name\" : \"Bob Dylan\",\n" +" \"job\" : \"musician\"\n" +" }\n" +" }\n" +" }" +msgstr "" + +msgid "" +" => {\n" +" \"type\" : \"add.result\",\n" +" \"body\" : true\n" +" }" +msgstr "" + +msgid "" +"The `add` command works recursively. If there is no existing record with the k" +"ey in the referred table, then it is also automatically added silently so you'" +"ll see no error response. For example this will add a new Person record with a" +" new Job record named `doctor`." +msgstr "" +"`add` は再帰的に動作します。別のテーブルを参照しているカラムについて、参照先のテーブルに存在しない値を指定した場合、エラーにはならず、参照先のテーブル" +"にも同時に新しいレコードが追加されます。例えば、以下は テーブルに存在しない主キー `doctor` を伴って Person テーブルにレコードを追加しま" +"す。" + +msgid "" +" {\n" +" \"type\" : \"add\",\n" +" \"body\" : {\n" +" \"table\" : \"Person\",\n" +" \"values\" : {\n" +" \"name\" : \"Alice Miller\",\n" +" \"job\" : \"doctor\"\n" +" }\n" +" }\n" +" }" +msgstr "" + +msgid "" +"By the command above, a new record will be automatically added to the Job tabl" +"e like;" +msgstr "この時、Jobテーブルには主キーだけが指定された新しいレコードが自動的に追加されます。" + +msgid "" +"|_key|label|\n" +"|announcer|announcer|\n" +"|musician|musician|\n" +"|doctor|(blank)|" +msgstr "" +"|_key|label|\n" +"|announcer|announcer|\n" +"|musician|musician|\n" +"|doctor|(空文字)|" + +msgid "" +"### Adding a new record to a table with primary key {#adding-record-to-table-w" +"ith-key}" +msgstr "### 主キーを持つテーブルにレコードを追加する {#adding-record-to-table-with-key}" + +msgid "" +"Specify all parameters `table`, `values` and `key`, if the table has a primary" +" key column." +msgstr "主キーを持つテーブルにレコードを追加する場合は、 `table`、`key`、`values` のすべてを指定します。" + +msgid "" +" {\n" +" \"type\" : \"add\",\n" +" \"body\" : {\n" +" \"table\" : \"Job\",\n" +" \"key\" : \"writer\",\n" +" \"values\" : {\n" +" \"label\" : \"writer\"\n" +" }\n" +" }\n" +" }" +msgstr "" + +msgid "### Updating column values of an existing record {#updating}" +msgstr "### 既存レコードのカラムの値を更新する {#updating}" + +msgid "" +"This command works as \"updating\" operation, if the table has a primary key col" +"umn and there is an existing record for the specified key." +msgstr "主キーを持つテーブルに対する、既存レコードの主キーを伴う `add` コマンドは、既存レコードのカラムの値の更新操作と見なされます。" + +msgid "" +" {\n" +" \"type\" : \"add\",\n" +" \"body\" : {\n" +" \"table\" : \"Job\",\n" +" \"key\" : \"doctor\",\n" +" \"values\" : {\n" +" \"label\" : \"doctor\"\n" +" }\n" +" }\n" +" }" +msgstr "" + +msgid "" +"You cannot update column values of existing records, if the table has no prima" +"ry key column. Then this command will always work as \"adding\" operation for th" +"e table." +msgstr "主キーを持たないテーブルのレコードに対しては、値の更新操作はできません(常にレコードの追加と見なされます)。" + +msgid "## Parameter details {#parameters}" +msgstr "## パラメータの詳細 {#parameters}" + +msgid "### `table` {#parameter-table}" +msgstr "" + +msgid "" +"Abstract\n" +": The name of a table which a record is going to be added to." +msgstr "" +"概要\n" +": レコードを登録するテーブルの名前を指定します。" + +msgid "" +"Value\n" +": A name string of an existing table." +msgstr "" +"値\n" +": テーブル名の文字列。" + +msgid "" +"Default value\n" +": Nothing. This is a required parameter." +msgstr "" +"省略時の既定値\n" +": なし。このパラメータは必須です。" + +msgid "### `key` {#parameter-key}" +msgstr "" + +msgid "" +"Abstract\n" +": The primary key for the record going to be added." +msgstr "" +"概要\n" +": レコードの主キーを指定します。" + +msgid "" +"Value\n" +": A primary key string." +msgstr "" +"値\n" +": 主キーとなる文字列。" + +msgid "" +"Default value\n" +": Nothing. This is required if the table has a primary key column. Otherwise, " +"this is ignored." +msgstr "" +"省略時の初期値\n" +": Nなし。対象のテーブルが主キーを持つ場合、このパラメータは必須です。主キーがない場合、このパラメータは無視されます。" + +msgid "" +"Existing column values will be updated, if there is an existing record for the" +" key." +msgstr "既に同じ主キーを持つレコードが存在している場合は、レコードの各カラムの値を更新します。" + +msgid "This parameter will be ignored if the table has no primary key column." +msgstr "対象のテーブルが主キーを持たない場合は、指定しても単に無視されます。" + +msgid "### `values` {#parameter-values}" +msgstr "" + +msgid "" +"Abstract\n" +": New values for columns of the record." +msgstr "" +"概要\n" +": レコードの各カラムの値を指定します。" + +msgid "" +"Value\n" +": A hash. Keys of the hash are column names, values of the hash are new values" +" for each column." +msgstr "" +"値\n" +": カラム名をキー、カラムの値を値としたハッシュ。" + +msgid "" +"Default value\n" +": `null`" +msgstr "" +"省略時の初期値\n" +": `null`" + +msgid "Value of unspecified columns will not be changed." +msgstr "指定されなかったカラムの値は登録・更新されません。" + +msgid "## Responses {#response}" +msgstr "## レスポンス {#response}" + +msgid "" +"This returns a boolean value `true` like following as the response's `body`, w" +"ith `200` as its `statusCode`, if a record is successfully added or updated." +msgstr "" +"このコマンドは、レコードを正常に追加または更新できた場合、真偽値 `true` を`body` 、`200` を `statusCode` としたレスポンス" +"を返します。以下はレスポンスの `body` の例です。" + +msgid " true" +msgstr "" + +msgid "## Error types {#errors}" +msgstr "## エラーの種類 {#errors}" + +msgid "" +"This command reports errors not only [general errors](/reference/message/#erro" +"r) but also followings." +msgstr "このコマンドは[一般的なエラー](/ja/reference/message/#error)に加えて、以下のエラーを場合に応じて返します。" + +msgid "### `MissingTableParameter`" +msgstr "" + +msgid "" +"Means you've forgotten to specify the `table` parameter. The status code is `4" +"00`." +msgstr "`table` パラメータの指定を忘れていることを示します。ステータスコードは `400` です。" + +msgid "### `MissingPrimaryKeyParameter`" +msgstr "" + +msgid "" +"Means you've forgotten to specify the `key` parameter, for a table with the pr" +"imary key column. The status code is `400`." +msgstr "主キーが存在するテーブルに対して、`key` パラメータの指定を忘れていることを示します。ステータスコードは `400` です。" + +msgid "### `InvalidValue`" +msgstr "" + +msgid "" +"Means you've specified an invalid value for a column. For example, a string fo" +"r a geolocation column, a string for an integer column, etc. The status code i" +"s `400`." +msgstr "カラムに設定しようとした値が不正である(例:位置情報型や整数型のカラムに通常の文字列を指定した、など)事を示します。ステータスコードは `400` です。" + +msgid "### `UnknownTable`" +msgstr "" + +msgid "" +"Means you've specified a table which is not existing in the specified dataset." +" The status code is `404`." +msgstr "指定されたデータセット内に、指定されたレコードが存在していない事を示します。ステータスコードは `404` です。" + +msgid "### `UnknownColumn`" +msgstr "" + +msgid "" +"Means you've specified any column which is not existing in the specified table" +". The status code is `404`." +msgstr "指定されたカラムがテーブルに存在しない未知のカラムである事を示します。ステータスコードは `400` です。" Added: _po/ja/reference/1.0.3/commands/column-create/index.po (+182 -0) 100644 =================================================================== --- /dev/null +++ _po/ja/reference/1.0.3/commands/column-create/index.po 2014-05-19 16:48:30 +0900 (9ceaba9) @@ -0,0 +1,182 @@ +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"PO-Revision-Date: 2014-03-05 12:52+0900\n" +"Language: ja\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" + +msgid "" +"---\n" +"title: column_create\n" +"layout: en\n" +"---" +msgstr "" +"---\n" +"title: column_create\n" +"layout: ja\n" +"---" + +msgid "" +"* TOC\n" +"{:toc}" +msgstr "" + +msgid "## Abstract {#abstract}" +msgstr "## 概要 {#abstract}" + +msgid "The `column_create` command creates a new column into the specified table." +msgstr "`column_create` は、指定したテーブルに新しいカラムを作成します。" + +msgid "" +"This is compatible to [the `column_create` command of the Groonga](http://groo" +"nga.org/docs/reference/commands/column_create.html)." +msgstr "" +"このコマンドは[Groonga の `column_create` コマンド](http://groonga.org/ja/docs/reference/c" +"ommands/column_create.html)と互換性があります。" + +msgid "" +"Style\n" +": Request-Response. One response message is always returned per one request." +msgstr "" +"形式\n" +": Request-Response型。コマンドに対しては必ず対応するレスポンスが返されます。" + +msgid "" +"`type` of the request\n" +": `column_create`" +msgstr "" +"リクエストの `type`\n" +": `column_create`" + +msgid "" +"`body` of the request\n" +": A hash of parameters." +msgstr "" +"リクエストの `body`\n" +": パラメータのハッシュ。" + +msgid "" +"`type` of the response\n" +": `column_create.result`" +msgstr "" +"レスポンスの `type`\n" +": `column_create.result`" + +msgid "## Parameter syntax {#syntax}" +msgstr "## パラメータの構文 {#syntax}" + +msgid "" +" {\n" +" \"table\" : \"<Name of the table>\",\n" +" \"name\" : \"<Name of the column>\",\n" +" \"flags\" : \"<Flags for the column>\",\n" +" \"type\" : \"<Type of the value>\",\n" +" \"source\" : \"<Name of a column to be indexed>\"\n" +" }" +msgstr "" +" {\n" +" \"table\" : \"<テーブル名>\",\n" +" \"name\" : \"<カラム名>\",\n" +" \"flags\" : \"<カラムの属性>\",\n" +" \"type\" : \"<値の型>\",\n" +" \"source\" : \"<インデックス対象のカラム名>\"\n" +" }" + +msgid "## Parameter details {#parameters}" +msgstr "## パラメータの詳細 {#parameters}" + +msgid "All parameters except `table` and `name` are optional." +msgstr "`table`, `name` 以外のパラメータはすべて省略可能です。" + +msgid "" +"They are compatible to [the parameters of the `column_create` command of the G" +"roonga](http://groonga.org/docs/reference/commands/column_create.html#paramete" +"rs). See the linked document for more details." +msgstr "" +"すべてのパラメータは[Groonga の `column_create` コマンドの引数](http://groonga.org/ja/docs/refer" +"ence/commands/column_create.html#parameters)と共通です。詳細はGroongaのコマンドリファレンスを参照して下さ" +"い。" + +msgid "## Responses {#response}" +msgstr "## レスポンス {#response}" + +msgid "This returns an array meaning the result of the operation, as the `body`." +msgstr "このコマンドは、レスポンスの `body` としてコマンドの実行結果に関する情報を格納した配列を返却します。" + +msgid "" +" [\n" +" [\n" +" <Groonga's status code>,\n" +" <Start time>,\n" +" <Elapsed time>\n" +" ],\n" +" <Column is successfully created or not>\n" +" ]" +msgstr "" +" [\n" +" [\n" +" <Groongaのステータスコード>,\n" +" <開始時刻>,\n" +" <処理に要した時間>\n" +" ],\n" +" <カラムが作成されたかどうか>\n" +" ]" + +msgid "" +"This command always returns a response with `200` as its `statusCode`, because" +" this is a Groonga compatible command and errors of this command must be handl" +"ed in the way same to Groonga's one." +msgstr "" +"このコマンドはレスポンスの `statusCode` として常に `200` を返します。これは、Groonga互換コマンドのエラー情報はGroongaのそ" +"れと同じ形で処理される必要があるためです。" + +msgid "Response body's details:" +msgstr "レスポンスの `body` の詳細:" + +msgid "" +"Status code\n" +": An integer meaning the operation's result. Possible values are:" +msgstr "" +"ステータスコード\n" +": コマンドが正常に受け付けられたかどうかを示す整数値です。以下のいずれかの値をとります。" + +msgid "" +" * `0` (`Droonga::GroongaHandler::Status::SUCCESS`) : Successfully processed" +".\n" +" * `-22` (`Droonga::GroongaHandler::Status::INVALID_ARGUMENT`) : There is an" +"y invalid argument." +msgstr "" +" * `0` (`Droonga::GroongaHandler::Status::SUCCESS`) : 正常に処理された。.\n" +" * `-22` (`Droonga::GroongaHandler::Status::INVALID_ARGUMENT`) : 引数が不正である。" + +msgid "" +"Start time\n" +": An UNIX time which the operation was started on." +msgstr "" +"開始時刻\n" +": 処理を開始した時刻を示す数値(UNIX秒)。" + +msgid "" +"Elapsed time\n" +": A decimal of seconds meaning the elapsed time for the operation." +msgstr "" +"処理に要した時間\n" +": 処理を開始してから完了までの間にかかった時間を示す数値。" + +msgid "" +"Column is successfully created or not\n" +": A boolean value meaning the column was successfully created or not. Possible" +" values are:" +msgstr "" +"カラムが作成されたかどうか\n" +": カラムが作成されたかどうかを示す真偽値です。以下のいずれかの値をとります。" + +msgid "" +" * `true`:The column was successfully created.\n" +" * `false`:The column was not created." +msgstr "" +" * `true`:カラムを作成した。\n" +" * `false`:カラムを作成しなかった。" Added: _po/ja/reference/1.0.3/commands/index.po (+49 -0) 100644 =================================================================== --- /dev/null +++ _po/ja/reference/1.0.3/commands/index.po 2014-05-19 16:48:30 +0900 (f9babb6) @@ -0,0 +1,49 @@ +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"PO-Revision-Date: 2014-03-05 12:52+0900\n" +"Language: ja\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" + +msgid "" +"---\n" +"title: Commands\n" +"layout: en\n" +"---" +msgstr "" +"---\n" +"title: コマンドリファレンス\n" +"layout: ja\n" +"---" + +msgid "Here are available commands" +msgstr "以下のコマンドを利用できます。" + +msgid "## Built-in commands" +msgstr "## ビルトインのコマンド" + +msgid "" +" * [search](search/): Searches data\n" +" * [add](add/): Adds a record" +msgstr "" +" * [search](search/): データの検索\n" +" * [add](add/): レコードの追加" + +msgid "## Groonga compatible commands" +msgstr "## Groonga互換コマンド" + +msgid "" +" * [column_create](column-create/)\n" +" * [column_list](column-list/)\n" +" * [column_remove](column-remove/)\n" +" * [column_rename](column-rename/)\n" +" * [delete](delete/)\n" +" * [load](load/)\n" +" * [select](select/)\n" +" * [table_create](table-create/)\n" +" * [table_list](table-list/)\n" +" * [table_remove](table-remove/)" +msgstr "" Added: _po/ja/reference/1.0.3/commands/search/index.po (+2283 -0) 100644 =================================================================== --- /dev/null +++ _po/ja/reference/1.0.3/commands/search/index.po 2014-05-19 16:48:30 +0900 (196e6ae) @@ -0,0 +1,2283 @@ +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"PO-Revision-Date: 2014-03-05 12:52+0900\n" +"Language: ja\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" + +msgid "" +"---\n" +"title: search\n" +"layout: en\n" +"---" +msgstr "" +"---\n" +"title: search\n" +"layout: ja\n" +"---" + +msgid "" +"* TOC\n" +"{:toc}" +msgstr "" + +msgid "## Abstract {#abstract}" +msgstr "## 概要 {#abstract}" + +msgid "" +"The `search` command finds records from the specified table based on given con" +"ditions, and returns found records and/or related information." +msgstr "`search` は、1つ以上のテーブルから指定された条件にマッチするレコードを検索し、見つかったレコードに関する情報を返却します。" + +msgid "" +"This is designed as the most basic (low layer) command on Droonga, to search i" +"nformation from a database. When you want to add a new plugin including \"searc" +"h\" feature, you should develop it as just a wrapper of this command, instead o" +"f developing something based on more low level technologies." +msgstr "" +"これは、Droonga において検索機能を提供する最も低レベルのコマンドです。\n" +"検索用のコマンドをプラグインとして実装する際は、内部的にこのコマンドを使用して検索を行うという用途が想定されます。" + +msgid "" +"Style\n" +": Request-Response. One response message is always returned per one request." +msgstr "" +"形式\n" +": Request-Response型。コマンドに対しては必ず対応するレスポンスが返されます。" + +msgid "" +"`type` of the request\n" +": `search`" +msgstr "" +"リクエストの `type`\n" +": `search`" + +msgid "" +"`body` of the request\n" +": A hash of parameters." +msgstr "" +"リクエストの `body`\n" +": パラメータのハッシュ。" + +msgid "" +"`type` of the response\n" +": `search.result`" +msgstr "" +"レスポンスの `type`\n" +": `search.result`" + +msgid "## Parameter syntax {#syntax}" +msgstr "## パラメータの構文 {#syntax}" + +msgid "" +" {\n" +" \"timeout\" : <Seconds to be timed out>,\n" +" \"queries\" : {\n" +" \"<Name of the query 1>\" : {\n" +" \"source\" : \"<Name of a table or another query>\",\n" +" \"condition\" : <Search conditions>,\n" +" \"sortBy\" : <Sort conditions>,\n" +" \"groupBy\" : <Group conditions>,\n" +" \"output\" : <Output conditions>\n" +" },\n" +" \"<Name of the query 2>\" : { ... },\n" +" ...\n" +" }\n" +" }" +msgstr "" +" {\n" +" \"timeout\" : <タイムアウトするまでの秒数>,\n" +" \"queries\" : {\n" +" \"<クエリ1の名前>\" : {\n" +" \"source\" : \"<検索対象のテーブル名、または別の検索クエリの名前>\",\n" +" \"condition\" : <検索条件>,\n" +" \"sortBy\" : <ソートの条件>,\n" +" \"groupBy\" : <集約の条件>,\n" +" \"output\" : <出力の指定>\n" +" },\n" +" \"<クエリ2の名前>\" : { ... },\n" +" ...\n" +" }\n" +" }" + +msgid "## Usage {#usage}" +msgstr "## 使い方 {#usage}" + +msgid "" +"This section describes how to use this command, via a typical usage with follo" +"wing table:" +msgstr "この項では、以下のテーブルが存在する状態を前提として、典型的な使い方を通じて `search` コマンドの使い方を説明します。" + +msgid "Person table (with primary key):" +msgstr "Personテーブル(主キーあり):" + +msgid "" +"|_key|name|age|sex|job|note|\n" +"|Alice Arnold|Alice Arnold|20|female|announcer||\n" +"|Alice Cooper|Alice Cooper|30|male|musician||\n" +"|Alice Miller|Alice Miller|25|female|doctor||\n" +"|Bob Dole|Bob Dole|42|male|lawer||\n" +"|Bob Cousy|Bob Cousy|38|male|basketball player||\n" +"|Bob Wolcott|Bob Wolcott|36|male|baseball player||\n" +"|Bob Evans|Bob Evans|31|male|driver||\n" +"|Bob Ross|Bob Ross|54|male|painter||\n" +"|Lewis Carroll|Lewis Carroll|66|male|writer|the author of Alice's Adventures i" +"n Wonderland|" +msgstr "" + +msgid "Note: `name` and `note` are indexed with `TokensBigram`." +msgstr "※`name`、`note` には `TokensBigram` を使用したインデックスが用意されていると仮定します。" + +msgid "### Basic usage {#usage-basic}" +msgstr "### 基本的な使い方 {#usage-basic}" + +msgid "This is a simple example to output all records of the Person table:" +msgstr "最も単純な例として、Person テーブルのすべてのレコードを出力する例を示します。" + +msgid "" +" {\n" +" \"type\" : \"search\",\n" +" \"body\" : {\n" +" \"queries\" : {\n" +" \"people\" : {\n" +" \"source\" : \"Person\",\n" +" \"output\" : {\n" +" \"elements\" : [\"count\", \"records\"],\n" +" \"attributes\" : [\"_key\", \"name\", \"age\", \"sex\", \"job\", \"note\"],\n" +" \"limit\" : -1\n" +" }\n" +" }\n" +" }\n" +" }\n" +" }" +msgstr "" + +msgid "" +" => {\n" +" \"type\" : \"search.result\",\n" +" \"body\" : {\n" +" \"people\" : {\n" +" \"count\" : 9,\n" +" \"records\" : [\n" +" [\"Alice Arnold\", \"Alice Arnold\", 20, \"female\", \"announcer\", \"\"]" +",\n" +" [\"Alice Cooper\", \"Alice Cooper\", 30, \"male\", \"musician\", \"\"],\n" +" [\"Alice Miller\", \"Alice Miller\", 25, \"male\", \"doctor\", \"\"],\n" +" [\"Bob Dole\", \"Bob Dole\", 42, \"male\", \"lawer\", \"\"],\n" +" [\"Bob Cousy\", \"Bob Cousy\", 38, \"male\", \"basketball player\", \"\"]" +",\n" +" [\"Bob Wolcott\", \"Bob Wolcott\", 36, \"male\", \"baseball player\", \"" +"\"],\n" +" [\"Bob Evans\", \"Bob Evans\", 31, \"male\", \"driver\", \"\"],\n" +" [\"Bob Ross\", \"Bob Ross\", 54, \"male\", \"painter\", \"\"],\n" +" [\"Lewis Carroll\", \"Lewis Carroll\", 66, \"male\", \"writer\",\n" +" \"the author of Alice's Adventures in Wonderland\"]\n" +" ]\n" +" }\n" +" }\n" +" }" +msgstr "" + +msgid "" +"The name `people` is a temporary name for the search query and its result.\n" +"A response of a `search` command will be returned as a hash, and the keys are " +"same to keys of the given `queries`.\n" +"So, this means: \"name the search result of the query as `people`\"." +msgstr "" +"`people` は、この検索クエリおよびその処理結果に対して付けた一時的な名前です。\n" +"`search` のレスポンスは、検索クエリに付けた名前を伴って返されます。\n" +"よって、これは「この検索クエリの結果を `people` と呼ぶ」というような意味合いになります。" + +msgid "Why the command above returns all informations of the table? Because:" +msgstr "どうしてこのコマンドが全レコードのすべての情報を出力するのでしょうか? これは以下の理由に依ります。" + +msgid "" +" * There is no search condition. This command matches all records in the speci" +"fied table, if no condition is specified.\n" +" * [`output`](#query-output)'s `elements` contains `records` (and `count`) col" +"umn(s). The parameter `elements` controls the returned information. Matched re" +"cords are returned as `records`, the total number of matched records are retur" +"ned as `count`.\n" +" * [`output`](#query-output)'s `limit` is `-1`. The parameter `limit` controls" +" the number of returned records, and `-1` means \"return all records\".\n" +" * [`output`](#query-output)'s `attributes` contains all columns of the Person" +" table. The parameter `attributes` controls which columns' value are returned." +msgstr "" +" * 検索条件を何も指定していないため。検索条件を指定しないとすべてのレコードがマッチします。\n" +" * [`output`](#query-output) の `elements` パラメータに `records` (および `count`)が指定されて" +"いるため。 `elements` は結果に出力する情報を制御します。マッチしたレコードの情報は `records` に、マッチしたレコードの総数は `cou" +"nt` に出力されます。\n" +" * [`output`](#query-output) の `limit` パラメータに `-1` が指定されているため。 `limit` は出力するレコ" +"ードの最大数の指定ですが、 `-1` を指定するとすべてのレコードが出力されます。\n" +" * [`output`](#query-output) の `attributes` パラメータに Person テーブルのすべてのカラムの名前が列挙され" +"ているため。 `attributes` は個々のレコードに出力するカラムを制御します。" + +msgid "#### Search conditions {#usage-condition}" +msgstr "#### 検索条件 {#usage-condition}" + +msgid "" +"Search conditions are specified via the `condition` parameter. There are two s" +"tyles of search conditions: \"script syntax\" and \"query syntax\". See [`conditio" +"n` parameter](#query-condition) for more details." +msgstr "" +"検索条件は `condition` パラメータで指定します。指定方法は、大きく分けて「スクリプト構文形式」と「クエリー構文形式」の2通りがあります。詳細は " +"[`condition` パラメータの仕様](#query-condition) を参照して下さい。" + +msgid "##### Search conditions in Script syntax {#usage-condition-script-syntax}" +msgstr "##### スクリプト構文形式の検索条件 {#usage-condition-script-syntax}" + +msgid "" +"Search conditions in script syntax are similar to ECMAScript. For example, fol" +"lowing query means \"find records that `name` contains `Alice` and `age` is lar" +"ger than or equal to `25`\":" +msgstr "" +"スクリプト構文形式は、ECMAScriptの書式に似ています。「`name` に `Alice` を含み、且つ`age` が `25` 以上である」という検" +"索条件は、スクリプト構文形式で以下のように表現できます。" + +msgid "" +" {\n" +" \"type\" : \"search\",\n" +" \"body\" : {\n" +" \"queries\" : {\n" +" \"people\" : {\n" +" \"source\" : \"Person\",\n" +" \"condition\" : \"name @ 'Alice' && age >= 25\"\n" +" \"output\" : {\n" +" \"elements\" : [\"count\", \"records\"],\n" +" \"attributes\" : [\"name\", \"age\"],\n" +" \"limit\" : -1\n" +" }\n" +" }\n" +" }\n" +" }\n" +" }" +msgstr "" + +msgid "" +" => {\n" +" \"type\" : \"search.result\",\n" +" \"body\" : {\n" +" \"people\" : {\n" +" \"count\" : 2,\n" +" \"records\" : [\n" +" [\"Alice Arnold\", 20],\n" +" [\"Alice Cooper\", 30],\n" +" [\"Alice Miller\", 25]\n" +" ]\n" +" }\n" +" }\n" +" }" +msgstr "" + +msgid "" +"[Script syntax is compatible to Groonga's one](http://groonga.org/docs/referen" +"ce/grn_expr/script_syntax.html). See the linked document for more details." +msgstr "" +"スクリプト構文の詳細な仕様は[Groonga のスクリプト構文のリファレンス](http://groonga.org/ja/docs/reference/g" +"rn_expr/script_syntax.html)を参照して下さい。" + +msgid "##### Search conditions in Query syntax {#usage-condition-query-syntax}" +msgstr "##### クエリー構文形式の検索条件 {#usage-condition-query-syntax}" + +msgid "" +"The query syntax is mainly designed for search boxes in webpages. For example," +" following query means \"find records that `name` or `note` contain the given w" +"ord, and the word is `Alice`\":" +msgstr "" +"クエリー構文形式は、主にWebページなどに組み込む検索ボックス向けに用意されています。例えば「検索ボックスに入力された語句を `name` または `not" +"e` に含むレコードを検索する」という場面において、検索ボックスに入力された語句が `Alice` であった場合の検索条件は、クエリー構文形式で以下のように" +"表現できます。" + +msgid "" +" {\n" +" \"type\" : \"search\",\n" +" \"body\" : {\n" +" \"queries\" : {\n" +" \"people\" : {\n" +" \"source\" : \"Person\",\n" +" \"condition\" : {\n" +" \"query\" : \"Alice\",\n" +" \"matchTo\" : [\"name\", \"note\"]\n" +" },\n" +" \"output\" : {\n" +" \"elements\" : [\"count\", \"records\"],\n" +" \"attributes\" : [\"name\", \"note\"],\n" +" \"limit\" : -1\n" +" }\n" +" }\n" +" }\n" +" }\n" +" }" +msgstr "" + +msgid "" +" => {\n" +" \"type\" : \"search.result\",\n" +" \"body\" : {\n" +" \"people\" : {\n" +" \"count\" : 4,\n" +" \"records\" : [\n" +" [\"Alice Arnold\", \"\"],\n" +" [\"Alice Cooper\", \"\"],\n" +" [\"Alice Miller\", \"\"],\n" +" [\"Lewis Carroll\",\n" +" \"the author of Alice's Adventures in Wonderland\"]\n" +" ]\n" +" }\n" +" }\n" +" }" +msgstr "" + +msgid "" +"[Query syntax is compatible to Groonga's one](http://groonga.org/docs/referenc" +"e/grn_expr/query_syntax.html). See the linked document for more details." +msgstr "" +"クエリー構文の詳細な仕様は[Groonga のクエリー構文のリファレンス](http://groonga.org/ja/docs/reference/grn" +"_expr/query_syntax.html)を参照して下さい。" + +msgid "#### Sorting of search results {#usage-sort}" +msgstr "#### 検索結果のソート {#usage-sort}" + +msgid "" +"Returned records can be sorted by conditions specified as the `sortBy` paramet" +"er. For example, following query means \"sort results by their `age`, in ascend" +"ing order\":" +msgstr "出力するレコードのソート条件は `sortBy` パラメータで指定します。以下は、結果を `age` カラムの値の昇順でソートする場合の例です。" + +msgid "" +" {\n" +" \"type\" : \"search\",\n" +" \"body\" : {\n" +" \"queries\" : {\n" +" \"people\" : {\n" +" \"source\" : \"Person\",\n" +" \"condition\" : \"name @ 'Alice'\"\n" +" \"sortBy\" : [\"age\"],\n" +" \"output\" : {\n" +" \"elements\" : [\"count\", \"records\"],\n" +" \"attributes\" : [\"name\", \"age\"],\n" +" \"limit\" : -1\n" +" }\n" +" }\n" +" }\n" +" }\n" +" }" +msgstr "" + +msgid "" +" => {\n" +" \"type\" : \"search.result\",\n" +" \"body\" : {\n" +" \"people\" : {\n" +" \"count\" : 8,\n" +" \"records\" : [\n" +" [\"Alice Arnold\", 20],\n" +" [\"Alice Miller\", 25],\n" +" [\"Alice Cooper\", 30]\n" +" ]\n" +" }\n" +" }\n" +" }" +msgstr "" + +msgid "" +"If you add `-` before name of columns, then search results are returned in des" +"cending order. For example:" +msgstr "ソートするカラム名の前に `-` を付けると、降順でのソートになります。以下は `age` の降順でソートする場合の例です。" + +msgid "" +" {\n" +" \"type\" : \"search\",\n" +" \"body\" : {\n" +" \"queries\" : {\n" +" \"people\" : {\n" +" \"source\" : \"Person\",\n" +" \"condition\" : \"name @ 'Alice'\"\n" +" \"sortBy\" : [\"-age\"],\n" +" \"output\" : {\n" +" \"elements\" : [\"count\", \"records\"],\n" +" \"attributes\" : [\"name\", \"age\"],\n" +" \"limit\" : -1\n" +" }\n" +" }\n" +" }\n" +" }\n" +" }" +msgstr "" + +msgid "" +" => {\n" +" \"type\" : \"search.result\",\n" +" \"body\" : {\n" +" \"people\" : {\n" +" \"count\" : 8,\n" +" \"records\" : [\n" +" [\"Alice Cooper\", 30],\n" +" [\"Alice Miller\", 25],\n" +" [\"Alice Arnold\", 20]\n" +" ]\n" +" }\n" +" }\n" +" }" +msgstr "" + +msgid "See [`sortBy` parameter](#query-sortBy) for more details." +msgstr "詳細は [`sortBy` パラメータの仕様](#query-sortBy) を参照して下さい。" + +msgid "#### Paging of search results {#usage-paging}" +msgstr "#### 検索結果のページング {#usage-paging}" + +msgid "" +"Search results can be retuned partially via `offset` and `limit` under the [`o" +"utput`](#query-output) parameter. For example, following queries will return 2" +"0 or more search results by 10's." +msgstr "" +"[`output`](#query-output) パラメータの `offset` と `limit` を指定することで、出力されるレコードの範囲を指定でき" +"ます。以下は、20件以上ある結果を先頭から順に10件ずつ取得する場合の例です。" + +msgid "" +" {\n" +" \"type\" : \"search\",\n" +" \"body\" : {\n" +" \"queries\" : {\n" +" \"people\" : {\n" +" \"source\" : \"Person\",\n" +" \"output\" : {\n" +" \"elements\" : [\"count\", \"records\"],\n" +" \"attributes\" : [\"name\"],\n" +" \"offset\" : 0,\n" +" \"limit\" : 10\n" +" }\n" +" }\n" +" }\n" +" }\n" +" }" +msgstr "" + +msgid " => returns 10 results from the 1st to the 10th." +msgstr " => 0件目から9件目までの10件が返される。" + +msgid "" +" {\n" +" \"type\" : \"search\",\n" +" \"body\" : {\n" +" \"queries\" : {\n" +" \"people\" : {\n" +" \"source\" : \"Person\",\n" +" \"output\" : {\n" +" \"elements\" : [\"count\", \"records\"],\n" +" \"attributes\" : [\"name\"],\n" +" \"offset\" : 10,\n" +" \"limit\" : 10\n" +" }\n" +" }\n" +" }\n" +" }\n" +" }" +msgstr "" + +msgid " => returns 10 results from the 11th to the 20th." +msgstr " => 10件目から19件目までの10件が返される。" + +msgid "" +" {\n" +" \"type\" : \"search\",\n" +" \"body\" : {\n" +" \"queries\" : {\n" +" \"people\" : {\n" +" \"source\" : \"Person\",\n" +" \"output\" : {\n" +" \"elements\" : [\"count\", \"records\"],\n" +" \"attributes\" : [\"name\"],\n" +" \"offset\" : 20,\n" +" \"limit\" : 10\n" +" }\n" +" }\n" +" }\n" +" }\n" +" }" +msgstr "" + +msgid " => returns 10 results from the 21st to the 30th." +msgstr " => 20件目から29件目までの10件が返される。" + +msgid "" +"The value `-1` is not recommended for the `limit` parameter, in regular use. " +"It will return too much results and increase traffic loads. Instead `100` or l" +"ess value is recommended for the `limit` parameter. Then you should do paging " +"by the `offset` parameter." +msgstr "" +"`limit` の指定 `-1` は、実際の運用では推奨されません。膨大な量のレコードがマッチした場合、出力のための処理にリソースを使いすぎてしまいますし、" +"ネットワークの帯域も浪費してしまいます。コンピュータの性能にもよりますが、`limit` には `100` 程度までの値を上限として指定し、それ以上のレコー" +"ドは適宜ページングで取得するようにして下さい。" + +msgid "See [`output` parameter](#query-output) for more details." +msgstr "詳細は [`output` パラメータの仕様](#query-output) を参照して下さい。" + +msgid "" +"Moreover, you can do paging via [the `sortBy` parameter](#query-sortBy-hash) a" +"nd it will work faster than the paging by the `output` parameter. You should d" +"o paging via the `sortBy` parameter instead of `output` as much as possible." +msgstr "" +"また、ページングは [`sortBy` パラメータの機能](#query-sortBy-hash)でも行う事ができ、一般的にはそちらの方が高速に動作します。" +"\n" +"よって、可能な限り `output` でのページングよりも `sortBy` でのページングの方を使う事が推奨されます。" + +msgid "#### Output format {#usage-format}" +msgstr "#### 出力形式 {#usage-format}" + +msgid "" +"Search result records in examples above are shown as arrays of arrays, but the" +"y can be returned as arrays of hashes by the [`output`](#query-output)'s `form" +"at` parameter. If you specify `complex` for the `format`, then results are ret" +"urned like:" +msgstr "" +"ここまでの例では、レコードの一覧はすべて配列の配列として出力されていました。[`output`](#query-output) パラメータの `format" +"` を指定すると、出力されるレコードの形式を変える事ができます。以下は、`format` に `complex` を指定した場合の例です。" + +msgid "" +" {\n" +" \"type\" : \"search\",\n" +" \"body\" : {\n" +" \"queries\" : {\n" +" \"people\" : {\n" +" \"source\" : \"Person\",\n" +" \"output\" : {\n" +" \"elements\" : [\"count\", \"records\"],\n" +" \"attributes\" : [\"_key\", \"name\", \"age\", \"sex\", \"job\", \"note\"],\n" +" \"limit\" : 3,\n" +" \"format\" : \"complex\"\n" +" }\n" +" }\n" +" }\n" +" }\n" +" }" +msgstr "" + +msgid "" +" => {\n" +" \"type\" : \"search.result\",\n" +" \"body\" : {\n" +" \"people\" : {\n" +" \"count\" : 9,\n" +" \"records\" : [\n" +" { \"_key\" : \"Alice Arnold\",\n" +" \"name\" : \"Alice Arnold\",\n" +" \"age\" : 20,\n" +" \"sex\" : \"female\",\n" +" \"job\" : \"announcer\",\n" +" \"note\" : \"\" },\n" +" { \"_key\" : \"Alice Cooper\",\n" +" \"name\" : \"Alice Cooper\",\n" +" \"age\" : 30,\n" +" \"sex\" : \"male\",\n" +" \"job\" : \"musician\",\n" +" \"note\" : \"\" },\n" +" { \"_key\" : \"Alice Miller\",\n" +" \"name\" : \"Alice Miller\",\n" +" \"age\" : 25,\n" +" \"sex\" : \"female\",\n" +" \"job\" : \"doctor\",\n" +" \"note\" : \"\" }\n" +" ]\n" +" }\n" +" }\n" +" }" +msgstr "" + +msgid "" +"Search result records will be returned as an array of hashes, when you specify" +" `complex` as the value of the `format` parameter.\n" +"Otherwise - `simple` or nothing is specified -, records are returned as an arr" +"ay of arrays." +msgstr "" +"`format` に `complex` を指定した場合、レコードの一覧はこの例のようにカラム名をキーとしたハッシュの配列として出力されます。\n" +"`format` に `simple` を指定した場合、または `format` の指定を省略した場合、レコードの一覧は配列の配列として出力されます。" + +msgid "" +"See [`output` parameters](#query-output) and [responses](#response) for more d" +"etails." +msgstr "詳細は [`output` パラメータの仕様](#query-output) および [レスポンスの仕様](#response) を参照して下さい。" + +msgid "### Advanced usage {#usage-advanced}" +msgstr "### 高度な使い方 {#usage-advanced}" + +msgid "#### Grouping {#usage-group}" +msgstr "#### 検索結果の集約 {#usage-group}" + +msgid "" +"You can group search results by a column, via the [`groupBy`](#query-groupBy) " +"parameters. For example, following query returns a result grouped by the `sex`" +" column, with the count of original search results:" +msgstr "" +"[`groupBy`](#query-groupBy) パラメータを指定することで、レコードを指定カラムの値で集約した結果を取得することができます。以下は、" +"テーブルの内容を `sex` カラムの値で集約した結果と、集約前のレコードがそれぞれ何件あったかを取得する例です。" + +msgid "" +" {\n" +" \"type\" : \"search\",\n" +" \"body\" : {\n" +" \"queries\" : {\n" +" \"sexuality\" : {\n" +" \"source\" : \"Person\",\n" +" \"groupBy\" : \"sex\",\n" +" \"output\" : {\n" +" \"elements\" : [\"count\", \"records\"],\n" +" \"attributes\" : [\"_key\", \"_nsubrecs\"],\n" +" \"limit\" : -1\n" +" }\n" +" }\n" +" }\n" +" }\n" +" }" +msgstr "" + +msgid "" +" => {\n" +" \"type\" : \"search.result\",\n" +" \"body\" : {\n" +" \"sexuality\" : {\n" +" \"count\" : 2,\n" +" \"records\" :\n" +" [\"female\", 2],\n" +" [\"male\", 7]\n" +" ]\n" +" }\n" +" }\n" +" }" +msgstr "" + +msgid "" +"The result means: \"There are two `female` records and seven `male` records, mo" +"reover there are two types for the column `sex`." +msgstr "" +"上記の結果は、 `sex` の値が `female` であるレコードが2件、`male` であるレコードが7件存在していて、`sex` の値の種類としては2" +"通りが登録されている事を示しています。" + +msgid "" +"You can also extract the ungrouped record by the `maxNSubRecords` parameter an" +"d the `_subrecs` virtual column. For example, following query returns the resu" +"lt grouped by `sex` and extract two ungrouped records:" +msgstr "" +"また、集約前のレコードを代表値として取得する事もできます。以下は、`sex` カラムの値で集約した結果と、それぞれの集約前のレコードを2件ずつ取得する例です" +"。" + +msgid "" +" {\n" +" \"type\" : \"search\",\n" +" \"body\" : {\n" +" \"queries\" : {\n" +" \"sexuality\" : {\n" +" \"source\" : \"Person\",\n" +" \"groupBy\" : {\n" +" \"keys\" : \"sex\",\n" +" \"maxNSubRecords\" : 2\n" +" },\n" +" \"output\" : {\n" +" \"elements\" : [\"count\", \"records\"],\n" +" \"attributes\" : [\n" +" \"_key\",\n" +" \"_nsubrecs\",\n" +" { \"label\" : \"subrecords\",\n" +" \"source\" : \"_subrecs\",\n" +" \"attributes\" : [\"name\"] }\n" +" ],\n" +" \"limit\" : -1\n" +" }\n" +" }\n" +" }\n" +" }\n" +" }" +msgstr "" + +msgid "" +" => {\n" +" \"type\" : \"search.result\",\n" +" \"body\" : {\n" +" \"sexuality\" : {\n" +" \"count\" : 2,\n" +" \"records\" :\n" +" [\"female\", 2, [[\"Alice Arnold\"], [\"Alice Miller\"]]],\n" +" [\"male\", 7, [[\"Alice Cooper\"], [\"Bob Dole\"]]]\n" +" ]\n" +" }\n" +" }\n" +" }" +msgstr "" + +msgid "See [`groupBy` parameters](#query-groupBy) for more details." +msgstr "詳細は [`groupBy` パラメータの仕様](#query-groupBy) を参照して下さい。" + +msgid "#### Multiple search queries in one request {#usage-multiple-queries}" +msgstr "#### 複数の検索クエリの列挙 {#usage-multiple-queries}" + +msgid "" +"Multiple queries can be appear in one `search` command. For example, following" +" query searches people younger than 25 or older than 40:" +msgstr "" +"`search` は、一度に複数の検索クエリを受け付ける事ができます。以下は、`age` が `25` 以下のレコードと `age` が `40` 以上のレ" +"コードを同時に検索する例です。" + +msgid "" +" {\n" +" \"type\" : \"search\",\n" +" \"body\" : {\n" +" \"queries\" : {\n" +" \"junior\" : {\n" +" \"source\" : \"Person\",\n" +" \"condition\" : \"age <= 25\",\n" +" \"output\" : {\n" +" \"elements\" : [\"count\", \"records\"],\n" +" \"attributes\" : [\"name\", \"age\"],\n" +" \"limit\" : -1\n" +" }\n" +" },\n" +" \"senior\" : {\n" +" \"source\" : \"Person\",\n" +" \"condition\" : \"age >= 40\",\n" +" \"output\" : {\n" +" \"elements\" : [\"count\", \"records\"],\n" +" \"attributes\" : [\"name\", \"age\"],\n" +" \"limit\" : -1\n" +" }\n" +" }\n" +" }\n" +" }\n" +" }" +msgstr "" + +msgid "" +" => {\n" +" \"type\" : \"search.result\",\n" +" \"body\" : {\n" +" \"junior\" : {\n" +" \"count\" : 2,\n" +" \"records\" : [\n" +" [\"Alice Arnold\", 20],\n" +" [\"Alice Miller\", 25]\n" +" ]\n" +" },\n" +" \"senior\" : {\n" +" \"count\" : 3,\n" +" \"records\" : [\n" +" [\"Bob Dole\", 42],\n" +" [\"Bob Ross\", 54],\n" +" [\"Lewis Carroll\", 66]\n" +" ]\n" +" }\n" +" }\n" +" }" +msgstr "" + +msgid "" +"Each search result can be identified by the temporary name given for each quer" +"y." +msgstr "レスポンスに含まれる検索結果は、各クエリに付けた一時的な名前で識別することになります。" + +msgid "#### Chained search queries {#usage-chain}" +msgstr "#### 検索のチェーン {#usage-chain}" + +msgid "" +"You can specify not only an existing table, but search result of another query" +" also, as the value of the \"source\" parameter. Chained search queries can do f" +"lexible search in just one request." +msgstr "" +"検索クエリを列挙する際は、`source` パラメータの値として実在するテーブルの名前だけでなく、別の検索クエリに付けた一時的な名前を指定する事ができます。" +"これにより、1つの検索クエリでは表現できない複雑な検索を行う事ができます。" + +msgid "" +"For example, the following query returns two results: records that their `name" +"` contains `Alice`, and results grouped by their `sex` column:" +msgstr "" +"以下は、Personテーブルについて `name` カラムが `Alice` を含んでいるレコードを検索た結果と、それをさらに `sex` カラムの値で集約" +"した結果を同時に取得する例です。" + +msgid "" +" {\n" +" \"type\" : \"search\",\n" +" \"body\" : {\n" +" \"queries\" : {\n" +" \"people\" : {\n" +" \"source\" : \"Person\",\n" +" \"condition\" : \"name @ 'Alice'\"\n" +" \"output\" : {\n" +" \"elements\" : [\"count\", \"records\"],\n" +" \"attributes\" : [\"name\", \"age\"],\n" +" \"limit\" : -1\n" +" }\n" +" },\n" +" \"sexuality\" : {\n" +" \"source\" : \"people\",\n" +" \"groupBy\" : \"sex\",\n" +" \"output\" : {\n" +" \"elements\" : [\"count\", \"records\"],\n" +" \"attributes\" : [\"_key\", \"_nsubrecs\"],\n" +" \"limit\" : -1\n" +" }\n" +" }\n" +" }\n" +" }\n" +" }" +msgstr "" + +msgid "" +" => {\n" +" \"type\" : \"search.result\",\n" +" \"body\" : {\n" +" \"people\" : {\n" +" \"count\" : 8,\n" +" \"records\" : [\n" +" [\"Alice Cooper\", 30],\n" +" [\"Alice Miller\", 25],\n" +" [\"Alice Arnold\", 20]\n" +" ]\n" +" },\n" +" \"sexuality\" : {\n" +" \"count\" : 2,\n" +" \"records\" :\n" +" [\"female\", 2],\n" +" [\"male\", 1]\n" +" ]\n" +" }\n" +" }\n" +" }" +msgstr "" + +msgid "" +"You can use search queries just internally, without output. For example, the f" +"ollowing query does: 1) group records of the Person table by their `job` colum" +"n, and 2) extract grouped results which have the text `player` in their `job`." +" (*Note: The second query will be done without indexes, so it can be slow.)" +msgstr "" +"個々の検索クエリの結果は出力しない(中間テーブルとしてのみ使う)事もできます。\n" +"以下は、Personテーブルについて `job` カラムの値で集約した結果をまず求め、そこからさらに `player` という語句を含んでいる項目に絞り込む" +"例です。\n" +"(※この場合の2つ目の検索ではインデックスが使用されないため、検索処理が遅くなる可能性があります。)" + +msgid "" +" {\n" +" \"type\" : \"search\",\n" +" \"body\" : {\n" +" \"queries\" : {\n" +" \"allJob\" : {\n" +" \"source\" : \"Person\",\n" +" \"groupBy\" : \"job\"\n" +" },\n" +" \"playerJob\" : {\n" +" \"source\" : \"allJob\",\n" +" \"condition\" : \"_key @ `player`\",\n" +" \"output\" : {\n" +" \"elements\" : [\"count\", \"records\"],\n" +" \"attributes\" : [\"_key\", \"_nsubrecs\"],\n" +" \"limit\" : -1\n" +" }\n" +" }\n" +" }\n" +" }\n" +" }" +msgstr "" + +msgid "" +" => {\n" +" \"type\" : \"search.result\",\n" +" \"body\" : {\n" +" \"playerJob\" : {\n" +" \"count\" : 2,\n" +" \"records\" : [\n" +" [\"basketball player\", 1],\n" +" [\"baseball player\", 1]\n" +" ]\n" +" }\n" +" }\n" +" }" +msgstr "" + +msgid "## Parameter details {#parameters}" +msgstr "## パラメータの詳細 {#parameters}" + +msgid "### Container parameters {#container-parameters}" +msgstr "### 全体のパラメータ {#container-parameters}" + +msgid "#### `timeout` {#parameter-timeout}" +msgstr "" + +msgid "" +"*Note: This parameter is not implemented yet on the version {{ site.droonga_ve" +"rsion }}." +msgstr "※註:このパラメータはバージョン {{ site.droonga_version }} では未実装です。指定しても機能しません。" + +msgid "" +"Abstract\n" +": Threshold to time out for the request." +msgstr "" +"概要\n" +": 検索処理がタイムアウトするまでの時間を指定します。" + +msgid "" +"Value\n" +": An integer in milliseconds." +msgstr "" +"値\n" +": タイムアウトするまでの時間の数値(単位:ミリ秒)。" + +msgid "" +"Default value\n" +": `10000` (10 seconds)" +msgstr "" +"省略時の初期値\n" +": 10000(10秒)" + +msgid "" +"Droonga Engine will return an error response instead of a search result, if th" +"e search operation take too much time, longer than the given `timeout`.\n" +"Clients may free resources for the search operation after the timeout." +msgstr "" +"指定した時間以内に Droonga Engine が検索の処理を完了できなかった場合、Droonga はその時点で検索処理を打ち切り、エラーを返却します。\n" +"クライアントは、この時間を過ぎた後は検索処理に関するリソースを解放して問題ありません。" + +msgid "#### `queries` {#parameter-queries}" +msgstr "" + +msgid "" +"Abstract\n" +": Search queries." +msgstr "" +"概要\n" +": 検索クエリとして、検索の条件と出力の形式を指定します。" + +msgid "" +"Value\n" +": A hash. Keys of the hash are query names, values of the hash are [queries (h" +"ashes of query parameters)](#query-parameters)." +msgstr "" +"値\n" +": 個々の検索クエリの名前をキー、[個々の検索クエリ](#query-parameters)の内容を値としたハッシュ。" + +msgid "" +"Default value\n" +": Nothing. This is a required parameter." +msgstr "" +"省略時の既定値\n" +": なし。このパラメータは必須です。" + +msgid "You can put multiple search queries in a `search` request." +msgstr "`search` は、複数の検索クエリを一度に受け取る事ができます。" + +msgid "" +"On the {{ site.droonga_version }}, all search results for a request are return" +"ed in one time. In the future, as an optional behaviour, each result can be re" +"turned as separated messages progressively." +msgstr "" +"バージョン {{ site.droonga_version }} ではすべての検索クエリの結果を一度にレスポンスとして返却する動作のみ対応していますが、将来" +"的には、それぞれの検索クエリの結果を分割して受け取る(結果が出た物からバラバラに受け取る)動作にも対応する予定です。" + +msgid "### Parameters of each query {#query-parameters}" +msgstr "### 個々の検索クエリのパラメータ {#query-parameters}" + +msgid "#### `source` {#query-source}" +msgstr "" + +msgid "" +"Abstract\n" +": A source of a search operation." +msgstr "" +"概要\n" +": 検索対象とするデータソースを指定します。" + +msgid "" +"Value\n" +": A name string of an existing table, or a name of another query." +msgstr "" +"値\n" +": テーブル名の文字列、または結果を参照する別の検索クエリの名前の文字列。" + +msgid "" +"You can do a facet search, specifying a name of another search query as its so" +"urce." +msgstr "別の検索クエリの処理結果をデータソースとして指定する事により、ファセット検索などを行う事ができます。" + +msgid "" +"The order of operations is automatically resolved by Droonga itself.\n" +"You don't have to write queries in the order they should be operated in." +msgstr "" +"なお、その場合の各検索クエリの実行順(依存関係)は Droonga が自動的に解決します。\n" +"依存関係の順番通りに各検索クエリを並べて記述する必要はありません。" + +msgid "#### `condition` {#query-condition}" +msgstr "" + +msgid "" +"Abstract\n" +": Conditions to search records from the given source." +msgstr "" +"概要\n" +": 検索の条件を指定します。" + +msgid "" +"Value\n" +": Possible patterns:" +msgstr "" +"値\n" +": 以下のパターンのいずれかをとります。" + +msgid "" +" 1. A [script syntax](http://groonga.org/docs/reference/grn_expr/script_synta" +"x.html) string.\n" +" 2. A hash including [script syntax](http://groonga.org/docs/reference/grn_ex" +"pr/script_syntax.html) string.\n" +" 3. A hash including [query syntax](http://groonga.org/docs/reference/grn_exp" +"r/query_syntax.html) string.\n" +" 4. An array of conditions from 1 to 3 and an operator." +msgstr "" +" 1. [スクリプト構文](http://groonga.org/ja/docs/reference/grn_expr/script_syntax.htm" +"l)形式の文字列。\n" +" 2. [スクリプト構文](http://groonga.org/ja/docs/reference/grn_expr/script_syntax.htm" +"l)形式の文字列を含むハッシュ。\n" +" 3. [クエリー構文](http://groonga.org/ja/docs/reference/grn_expr/query_syntax.html)" +"形式の文字列を含むハッシュ。\n" +" 4. 1〜3および演算子の文字列の配列。 " + +msgid "" +"Default value\n" +": Nothing." +msgstr "" +"省略時の既定値\n" +": なし。" + +msgid "" +"If no condition is given, then all records in the source will appear as the se" +"arch result, for following operations and the output." +msgstr "検索条件を指定しなかった場合、データソースに含まれるすべてのレコードが検索結果として取り出され、その後の処理に使われます。" + +msgid "" +"##### Search condition in a Script syntax string {#query-condition-script-synt" +"ax-string}" +msgstr "##### スクリプト構文形式の文字列による検索条件 {#query-condition-script-syntax-string}" + +msgid "This is a sample condition in the script syntax:" +msgstr "以下のような形式の文字列で検索条件を指定します。" + +msgid " \"name == 'Alice' && age >= 20\"" +msgstr "" + +msgid "" +"It means \"the value of the `name` column equals to `\"Alice\"`, and the value of" +" the `age` column is `20` or more\"." +msgstr "上記の例は「 `name` カラムの値が `\"Alice\"` と等しく、且つ `age` カラムの値が20以上である」という意味になります。" + +msgid "" +"See [the reference document of the script syntax on Groonga](http://groonga.or" +"g/docs/reference/grn_expr/script_syntax.html) for more details." +msgstr "" +"詳細は[Groonga のスクリプト構文のリファレンス](http://groonga.org/ja/docs/reference/grn_expr/scr" +"ipt_syntax.html)を参照して下さい。" + +msgid "" +"##### Search condition in a hash based on the Script syntax {#query-condition-" +"script-syntax-hash}" +msgstr "##### スクリプト構文形式の文字列を含むハッシュによる検索条件 {#query-condition-script-syntax-hash}" + +msgid "" +"In this pattern, you'll specify a search condition as a hash based on a \n" +"[script syntax string](#query-condition-script-syntax-string), like:" +msgstr "" +"[スクリプト構文形式の文字列による検索条件](#query-condition-script-syntax-string)をベースとした、以下のような形式の" +"ハッシュで検索条件を指定します。" + +msgid "" +" {\n" +" \"script\" : \"name == 'Alice' && age >= 20\",\n" +" \"allowUpdate\" : true\n" +" }" +msgstr "" + +msgid "" +"(*Note: under construction because the specification of the `allowUpdate` para" +"meter is not defined yet.)" +msgstr "(詳細未稿:仕様が未確定、動作が不明、未実装のため)" + +msgid "" +"##### Search condition in a hash based on the Query syntax {#query-condition-q" +"uery-syntax-hash}" +msgstr "##### クエリー構文形式の文字列を含むハッシュ {#query-condition-query-syntax-hash}" + +msgid "In this pattern, you'll specify a search condition as a hash like:" +msgstr "以下のような形式のハッシュで検索条件を指定します。" + +msgid "" +" {\n" +" \"query\" : \"Alice\",\n" +" \"matchTo\" : [\"name * 2\", \"job * 1\"],\n" +" \"defaultOperator\" : \"&&\",\n" +" \"allowPragma\" : true,\n" +" \"allowColumn\" : true,\n" +" \"matchEscalationThreshold\" : 10\n" +" }" +msgstr "" + +msgid "" +"`query`\n" +": A string to specify the main search query. In most cases, a text posted via " +"a search box in a webpage will be given.\n" +" See [the document of the query syntax in Groonga](http://groonga.org/docs/re" +"ference/grn_expr/query_syntax.html) for more details.\n" +" This parameter is always required." +msgstr "" +"`query`\n" +": クエリを文字列で指定します。\n" +" 詳細は[Groonga のクエリー構文の仕様](http://groonga.org/ja/docs/reference/grn_expr/query_" +"syntax.html)を参照して下さい。\n" +" このパラメータは省略できません。\n" + +msgid "" +"`matchTo`\n" +": An array of strings, meaning the list of column names to be searched by defa" +"ult. If you specify no column name in the `query`, it will work as a search qu" +"ery for columns specified by this parameter.\n" +" You can apply weighting for each column, like `name * 2`.\n" +" This parameter is optional." +msgstr "" +": 検索対象のカラムを、カラム名の文字列またはその配列で指定します。\n" +" カラム名の後に `name * 2` のような指定を加える事で、重み付けができます。\n" +" このパラメータは省略可能で、省略時の初期値は `\"_key\"` です。" + +msgid "" +"`defaultOperator`\n" +": A string to specify the default logical operator for multiple queries listed" +" in the `query`. Possible values:" +msgstr "" +"`defaultOperator`: `query` に複数のクエリが列挙されている場合の既定の論理演算の条件を指定します。\n" +" 以下のいずれかの文字列を指定します。" + +msgid "" +" * `\"&&\"` : means \"AND\" condition.\n" +" * `\"||\"` : means \"OR\" condition.\n" +" * `\"-\"` : means [\"NOT\" condition](http://groonga.org/docs/reference/grn_ex" +"pr/query_syntax.html#logical-not)." +msgstr "" +" * `\"&&\"` : AND条件と見なす。\n" +" * `\"||\"` : OR条件と見なす。\n" +" * `\"-\"` : [論理否定](http://groonga.org/ja/docs/reference/grn_expr/query_synta" +"x.html#logical-not)条件と見なす。" + +msgid " This parameter is optional, the default value is `\"&&\"`." +msgstr " このパラメータは省略可能で、省略時の初期値は `\"&&\"` です。" + +msgid "" +"`allowPragma`\n" +": A boolean value to allow (`true`) or disallow (`false`) to use \"pragma\" like" +" `*E-1`, on the head of the `query`.\n" +" This parameter is optional, the default value is `true`." +msgstr "" +"`allowPragma`\n" +": `query` の先頭において、`*E-1` のようなプラグマの指定を許容するかどうかを真偽値で指定します。\n" +" このパラメータは省略可能で、省略時の初期値は `true` (プラグマの指定を許容する)です。" + +msgid "" +"`allowColumn`\n" +": A boolean value to allow (`true`) or disallow (`false`) to specify column na" +"me for each query in the `query`, like `name:Alice`.\n" +" This parameter is optional, the default value is `true`." +msgstr "" +"`allowColumn`\n" +": `query` において、カラム名を指定した `name:Alice` のような書き方を許容するかどうかを真偽値で指定します。\n" +" このパラメータは省略可能で、省略時の初期値は `true` (カラム名の指定を許容する)です。" + +msgid "" +"`matchEscalationThreshold`\n" +": An integer to specify the threshold to escalate search methods.\n" +" When the number of search results by indexes is smaller than this value, the" +"n Droonga does the search based on partial matching, etc.\n" +" See also [the specification of the search behavior of Groonga](http://groong" +"a.org/docs/spec/search.html) for more details.\n" +" This parameter is optional, the default value is `0`." +msgstr "" +"`matchEscalationThreshold`\n" +": 検索方法をエスカレーションするかどうかを決定するための閾値を指定します。\n" +" インデックスを用いた全文検索のヒット件数がこの閾値以下であった場合は、非分かち書き検索、部分一致検索へエスカレーションします。\n" +" 詳細は [Groonga の検索の仕様の説明](http://groonga.org/ja/docs/spec/search.html)を参照して下さい" +"。\n" +" このパラメータは省略可能で、省略時の初期値は `0` です。" + +msgid "##### Complex search condition as an array {#query-condition-array}" +msgstr "##### 配列による検索条件 {#query-condition-array}" + +msgid "In this pattern, you'll specify a search condition as an array like:" +msgstr "以下のような形式の配列で検索条件を指定します。" + +msgid "" +" [\n" +" \"&&\",\n" +" <search condition 1>,\n" +" <search condition 2>,\n" +" ...\n" +" ]" +msgstr "" +" [\n" +" \"&&\",\n" +" <検索条件1>,\n" +" <検索条件2>,\n" +" ...\n" +" ]" + +msgid "The fist element of the array is an operator string. Possible values:" +msgstr "配列の最初の要素は、論理演算子を以下のいずれかの文字列で指定します。" + +msgid "" +" * `\"&&\"` : means \"AND\" condition.\n" +" * `\"||\"` : means \"OR\" condition.\n" +" * `\"-\"` : means [\"NOT\" condition](http://groonga.org/docs/reference/grn_expr" +"/query_syntax.html#logical-not)." +msgstr "" +" * `\"&&\"` : AND条件と見なす。\n" +" * `\"||\"` : OR条件と見なす。\n" +" * `\"-\"` : [論理否定](http://groonga.org/ja/docs/reference/grn_expr/query_syntax." +"html#logical-not)条件と見なす。" + +msgid "" +"Rest elements are logically operated based on the operator.\n" +"For example this is an \"AND\" operated condition based on two conditions, means" +" \"the value of the `name` equals to `\"Alice\"`, and, the value of the `age` is " +"`20` or more\":" +msgstr "" +"配列の2番目以降の要素で示された検索条件について、1番目の要素で指定した論理演算子による論理演算を行います。\n" +"例えば以下は、スクリプト構文形式の文字列による検索条件2つによるAND条件であると見なされ、「 `name` カラムの値が `\"Alice\"` と等しく、且" +"つ `age` カラムの値が20以上である」という意味になります。" + +msgid " [\"&&\", \"name == 'Alice'\", \"age >= 20\"]" +msgstr "" + +msgid "" +"Nested array means more complex conditions. For example, this means \"`name` eq" +"uals to `\"Alice\"` and `age` is `20` or more, but `job` does not equal to `\"eng" +"ineer\"`\":" +msgstr "" +"配列を入れ子にする事により、より複雑な検索条件を指定する事もできます。\n" +"例えば以下は、「 `name` カラムの値が `\"Alice\"` と等しく、且つ `age` カラムの値が20以上であるが、 `job` カラムの値が `\"" +"engineer\"` ではない」という意味になります。" + +msgid "" +" [\n" +" \"-\",\n" +" [\"&&\", \"name == 'Alice'\", \"age >= 20\"],\n" +" \"job == 'engineer'\"\n" +" ]" +msgstr "" + +msgid "#### `sortBy` {#query-sortBy}" +msgstr "" + +msgid "" +"Abstract\n" +": Conditions for sorting and paging." +msgstr "" +"概要\n" +": ソートの条件および取り出すレコードの範囲を指定します。" + +msgid "" +" 1. An array of column name strings.\n" +" 2. A hash including an array of sort column name strings and paging conditio" +"ns." +msgstr "" +" 1. カラム名の文字列の配列。\n" +" 2. ソート条件と取り出すレコードの範囲を指定するハッシュ。 " + +msgid "" +"If sort conditions are not specified, then all results will appear as-is, for " +"following operations and the output." +msgstr "ソート条件が指定されなかった場合、すべての検索結果がそのままの並び順でソート結果として取り出され、その後の処理に使われます。" + +msgid "##### Basic sort condition {#query-sortBy-array}" +msgstr "##### 基本的なソート条件の指定 {#query-sortBy-array}" + +msgid "Sort condition is given as an array of column name strings." +msgstr "ソート条件はカラム名の文字列の配列として指定します。" + +msgid "" +"At first Droonga tries to sort records by the value of the first given sort co" +"lumn. After that, if there are multiple records which have same value for the " +"column, then Droonga tries to sort them by the secondary given sort column. Th" +"ese processes are repeated for all given sort columns." +msgstr "" +"Droongaはまず最初に指定したカラムの値でレコードをソートし、カラムの値が同じレコードが複数あった場合は2番目に指定したカラムの値でさらにソートする、と" +"いう形で、すべての指定カラムの値に基づいてソートを行います。" + +msgid "You must specify sort columns as an array, even if there is only one column." +msgstr "ソート対象のカラムを1つだけ指定する場合であっても、必ず配列として指定する必要があります。" + +msgid "" +"Records are sorted by the value of the column value, in an ascending order. Re" +"sults can be sorted in descending order if sort column name has a prefix `-`." +msgstr "ソート順序は指定したカラムの値での昇順となります。カラム名の前に `-` を加えると降順となります。" + +msgid "" +"For example, this condition means \"sort records by the `name` at first in an a" +"scending order, and sort them by their `age~ column in the descending order\":" +msgstr "例えば以下は、「 `name` の値で昇順にソートし、同じ値のレコードはさらに `age` の値で降順にソートする」という意味になります。" + +msgid " [\"name\", \"-age\"]" +msgstr "" + +msgid "##### Paging of sorted results {#query-sortBy-hash}" +msgstr "##### ソート結果から取り出すレコードの範囲の指定 {#query-sortBy-hash}" + +msgid "Paging conditions can be specified as a part of a sort condition hash, like:" +msgstr "ソートの指定において、以下の形式でソート結果から取り出すレコードの範囲を指定する事ができます。" + +msgid "" +" {\n" +" \"keys\" : [<Sort columns>],\n" +" \"offset\" : <Offset of paging>,\n" +" \"limit\" : <Number of results to be extracted>\n" +" }" +msgstr "" +" {\n" +" \"keys\" : [<ソート対象のカラム>],\n" +" \"offset\" : <ページングの起点>,\n" +" \"limit\" : <取り出すレコード数>\n" +" }" + +msgid "" +"`keys`\n" +": Sort conditions same to [the basic sort condition](#query-sortBy-array).\n" +" This parameter is always required." +msgstr "" +"`keys`\n" +": ソート条件を[基本的なソート条件の指定](#query-sortBy-array)の形式で指定します。\n" +" このパラメータは省略できません。" + +msgid "" +"`offset`\n" +": An integer meaning the offset to the paging of sorted results. Possible valu" +"es are `0` or larger integers." +msgstr "" +"`offset`\n" +": 取り出すレコードのページングの起点を示す `0` または正の整数。" + +msgid " This parameter is optional and the default value is `0`." +msgstr " このパラメータは省略可能で、省略時の既定値は `0` です。" + +msgid "" +"`limit`\n" +": An integer meaning the number of sorted results to be extracted. Possible va" +"lues are `-1`, `0`, or larger integers. The value `-1` means \"return all resul" +"ts\"." +msgstr "" +"`limit`\n" +": 取り出すレコード数を示す `-1` 、 `0` 、または正の整数。\n" +" `-1`を指定すると、すべてのレコードを取り出します。" + +msgid " This parameter is optional and the default value is `-1`." +msgstr " このパラメータは省略可能で、省略時の既定値は `-1` です。" + +msgid "For example, this condition extracts 10 sorted results from 11th to 20th:" +msgstr "例えば以下は、ソート結果の10番目から19番目までの10件のレコードを取り出すという意味になります。" + +msgid "" +" {\n" +" \"keys\" : [\"name\", \"-age\"],\n" +" \"offset\" : 10,\n" +" \"limit\" : 10\n" +" }" +msgstr "" + +msgid "" +"In most cases, paging by a sort condition is faster than paging by `output`'s " +"`limit` and `output`, because this operation reduces the number of records." +msgstr "" +"これらの指定を行った場合、取り出されたレコードのみがその後の処理の対象となります。\n" +"そのため、 `output` における `offset` および `limit` の指定よりも高速に動作します。" + +msgid "#### `groupBy` {#query-groupBy}" +msgstr "" + +msgid "" +"Abstract\n" +": A condition for grouping of (sorted) search results." +msgstr "" +"概要\n" +": 処理対象のレコード群を集約する条件を指定します。" + +msgid "" +" 1. A condition string to do grouping. (a column name or an expression)\n" +" 2. A hash to specify a condition for grouping with details." +msgstr "" +" 1. 基本的な集約条件(カラム名または式)の文字列。\n" +" 2. 複雑な集約条件を指定するハッシュ。 " + +msgid "" +"If a condition for grouping is given, then grouped result records will appear " +"as the result, for following operations and the output." +msgstr "集約条件を指定した場合、指定に基づいてレコードを集約した結果がレコードとして取り出され、その後の処理に使われます。" + +msgid "##### Basic condition of grouping {#query-groupBy-string}" +msgstr "##### 基本的な集約条件の指定 {#query-groupBy-string}" + +msgid "" +"A condition of grouping is given as a string of a column name or an expression" +"." +msgstr "基本的な集約条件では、処理対象のレコード群が持つカラムの名前を文字列として指定します。" + +msgid "" +"Droonga groups (sorted) search result records, based on the value of the speci" +"fied column. Then the result of the grouping will appear instead of search res" +"ults from the `source`. Result records of a grouping will have following colum" +"ns:" +msgstr "" +"Droongaはそのカラムの値が同じであるレコードを集約し、カラムの値をキーとした新しいレコード群を結果として出力します。\n" +"集約結果のレコードは以下のカラムを持ちます。" + +msgid "" +"`_key`\n" +": A value of the grouped column." +msgstr "" +"`_key`\n" +": 集約前のレコード群における、集約対象のカラムの値です。" + +msgid "" +"`_nsubrecs`\n" +": An integer meaning the number of grouped records." +msgstr "" +"`_nsubrecs`\n" +": 集約前のレコード群における、集約対象のカラムの値が一致するレコードの総数を示す数値です。" + +msgid "" +"For example, this condition means \"group records by their `job` column's value" +", with the number of grouped records for each value\":" +msgstr "" +"例えば以下は、`job` カラムの値でレコードを集約し、`job` カラムの値としてどれだけの種類が存在しているのか、および、各 `job` の値を持つレコ" +"ードが何件存在しているのかを集約結果として取り出すという意味になります。" + +msgid " \"job\"" +msgstr "" + +msgid "##### Condition of grouping with details {#query-groupBy-hash}" +msgstr "##### 複雑な集約条件の指定 {#query-groupBy-hash}" + +msgid "A condition of grouping can include more options, like:" +msgstr "集約の指定において、集約結果の一部として出力する集約前のレコードの数を、以下の形式で指定する事ができます。" + +msgid "" +" {\n" +" \"key\" : \"<Basic condition for grouping>\",\n" +" \"maxNSubRecords\" : <Number of sample records included into each grouped " +"result>\n" +" }" +msgstr "" +" {\n" +" \"key\" : \"<基本的な集約条件>\",\n" +" \"maxNSubRecords\" : <集約結果の一部として出力する集約前のレコードの数>\n" +" }" + +msgid "" +"`key`\n" +": A string meaning [a basic condition of grouping](#query-groupBy-string).\n" +" This parameter is always required." +msgstr "" +"`key`\n" +": [基本的な集約条件の指定](#query-groupBy-string)の形式による、集約条件を指定する文字列。\n" +" このパラメータは省略できません。" + +msgid "" +"`maxNSubRecords`\n" +": An integer, meaning maximum number of sample records included into each grou" +"ped result. Possible values are `0` or larger. `-1` is not acceptable." +msgstr "" +"`maxNSubRecords`\n" +": 集約結果の一部として出力する集約前のレコードの最大数を示す `0` または正の整数。\n" +" `-1` は指定できません。" + +msgid " This parameter is optional, the default value is `0`." +msgstr " このパラメータは省略可能で、省略時の既定値は `0` です。" + +msgid "" +"For example, this condition will return results grouped by their `job` column " +"with one sample record per a grouped result:" +msgstr "" +"例えば以下は、`job` カラムの値でレコードを集約した結果について、各 `job` カラムの値を含んでいるレコードを代表として1件ずつ取り出すという意味に" +"なります。" + +msgid "" +" {\n" +" \"key\" : \"job\",\n" +" \"maxNSubRecords\" : 1\n" +" }" +msgstr "" + +msgid "" +"Grouped results will have all columns of [the result of the basic conditions f" +"or grouping](#query-groupBy-string), and following extra columns:" +msgstr "" +"集約結果のレコードは、[基本的な集約条件の指定](#query-groupBy-string)の集約結果のレコード群が持つすべてのカラムに加えて、以下のカラ" +"ムを持ちます。" + +msgid "" +"`_subrecs`\n" +": An array of sample records which have the value in its grouped column." +msgstr "" +"`_subrecs`\n" +": 集約前のレコード群における、集約対象のカラムの値が一致するレコードの配列。" + +msgid "" +"*Note: On the version {{ site.droonga_version }}, too many records can be retu" +"rned larger than the specified `maxNSubRecords`, if the dataset has multiple v" +"olumes. This is a known problem and to be fixed in a future version." +msgstr "" +"※バージョン {{ site.droonga_version }} では、データセットが複数のボリュームに別れている場合、集約前のレコードの代表が `max" +"NSubRecords` で指定した数よりも多く返される場合があります。これは既知の問題で、将来のバージョンで修正される予定です。" + +msgid "#### `output` {#query-output}" +msgstr "" + +msgid "" +"Abstract\n" +": A output definition for a search result" +msgstr "" +"概要\n" +": 処理結果の出力形式を指定します。" + +msgid "" +"Value\n" +": A hash including information to control output format." +msgstr "" +"値\n" +": 出力形式を指定するハッシュ。 " + +msgid "" +"If no `output` is given, then search results of the query won't be exported to" +" the returned message.\n" +"You can reduce processing time and traffic via omitting of `output` for tempor" +"ary tables which are used only for grouping and so on." +msgstr "" +"指定を省略した場合、その検索クエリの検索結果はレスポンスには出力されません。\n" +"集約操作などのために必要な中間テーブルにあたる検索結果を求めるだけの検索クエリにおいては、 `output` を省略して処理時間や転送するデータ量を減らすこ" +"とができます。" + +msgid "An output definition is given as a hash like:" +msgstr "出力形式は、以下の形式のハッシュで指定します。" + +msgid "" +" {\n" +" \"elements\" : [<Names of elements to be exported>],\n" +" \"format\" : \"<Format of each record>\",\n" +" \"offset\" : <Offset of paging>,\n" +" \"limit\" : <Number of records to be exported>,\n" +" \"attributes\" : <Definition of columnst to be exported for each record>\n" +" }" +msgstr "" +" {\n" +" \"elements\" : [<出力する情報の名前の配列>],\n" +" \"format\" : \"<検索結果のレコードの出力スタイル>\",\n" +" \"offset\" : <ページングの起点>,\n" +" \"limit\" : <出力するレコード数>,\n" +" \"attributes\" : <レコードのカラムの出力指定の配列>\n" +" }" + +msgid "" +"`elements`\n" +": An array of strings, meaning the list of elements exported to the result of " +"the search query in a [search response](#response).\n" +" Possible values are following, and you must specify it as an array even if y" +"ou export just one element:" +msgstr "" +"`elements`\n" +": その検索クエリの結果として[レスポンス](#response)に出力する情報を、プロパティ名の文字列の配列で指定します。\n" +" 以下の項目を指定できます。項目は1つだけ指定する場合であっても必ず配列で指定します。" + +msgid "" +" * `\"startTime\"` *Note: This will be ignored because it is not implemented o" +"n the version {{ site.droonga_version }} yet.\n" +" * `\"elapsedTime\"` *Note: This will be ignored because it is not implemented" +" on the version {{ site.droonga_version }} yet.\n" +" * `\"count\"`\n" +" * `\"attributes\"`\n" +" * `\"records\"`" +msgstr "" +" * `\"startTime\"` ※バージョン {{ site.droonga_version }} では未実装です。指定しても機能しません。\n" +" * `\"elapsedTime\"` ※バージョン {{ site.droonga_version }} では未実装です。指定しても機能しません。\n" +" * `\"count\"`\n" +" * `\"attributes\"`\n" +" * `\"records\"`" + +msgid "" +" This parameter is optional, there is not default value. Nothing will be expo" +"rted if no element is specified." +msgstr " このパラメータは省略可能で、省略時の初期値はありません(結果を何も出力しません)。" + +msgid "" +"`format`\n" +": A string meaning the format of exported each record.\n" +" Possible values:" +msgstr "" +"`format`\n" +": 検索結果のレコードの出力スタイルを指定します。\n" +" 以下のいずれかの値(文字列)を取ります。" + +msgid "" +" * `\"simple\"` : Each record will be exported as an array of column values.\n" +" * `\"complex\"` : Each record will be exported as a hash." +msgstr "" +" * `\"simple\"` : 個々のレコードを配列として出力します。\n" +" * `\"complex\"` : 個々のレコードをハッシュとして出力します。" + +msgid " This parameter is optional, the default value is `\"simple\"`." +msgstr " このパラメータは省略可能で、省略時の初期値は `\"simple\"` です。" + +msgid "" +"`offset`\n" +": An integer meaning the offset to the paging of exported records. Possible va" +"lues are `0` or larger integers." +msgstr "" +"`offset`\n" +": 出力するレコードのページングの起点を示す `0` または正の整数。" + +msgid "" +"`limit`\n" +": An integer meaning the number of exported records. Possible values are `-1`," +" `0`, or larger integers. The value `-1` means \"export all records\"." +msgstr "" +"`limit`\n" +": 出力するレコード数を示す `-1` 、 `0` 、または正の整数。\n" +" `-1`を指定すると、すべてのレコードを出力します。" + +msgid "" +"`attributes`\n" +": Definition of columns to be exported for each record.\n" +" Possible patterns:" +msgstr "" +"`attributes`\n" +": レコードのカラムの値について、出力形式を配列で指定します。\n" +" 個々のカラムの値の出力形式は以下のいずれかで指定します。" + +msgid "" +" 1. An array of column definitions.\n" +" 2. A hash of column definitions." +msgstr "" +" 1. カラムの定義の配列。\n" +" 2. カラムの定義を値としたハッシュ" + +msgid " Each column can be defined in one of following styles:" +msgstr " 各カラムは以下の形式のいずれかで指定します。" + +msgid "" +" * A name string of a column.\n" +" * `\"name\"` : Exports the value of the `name` column, as is.\n" +" * `\"age\"` : Exports the value of the `age` column, as is.\n" +" * A hash with details:\n" +" * This exports the value of the `name` column as a column with different " +"name `realName`." +msgstr "" +" * カラム名の文字列。例は以下の通りです。\n" +" * `\"name\"` : `name` カラムの値をそのまま `name` カラムとして出力します。\n" +" * `\"age\"` : `age` カラムの値をそのまま `age` カラムとして出力します。\n" +" * 詳細な出力形式指定のハッシュ。例は以下の通りです。\n" +" * 以下の例は、 `name` カラムの値を `realName` カラムとして出力します。" + +msgid " { \"label\" : \"realName\", \"source\" : \"name\" }" +msgstr "" + +msgid "" +" * This exports the snippet in HTML fragment as a column with the name `ht" +"ml`." +msgstr "" +" * 以下の例は、 `name` カラムの値について、全文検索にヒットした位置を強調したHTMLコード片の文字列を `html` カラムとして出力し" +"ます。" + +msgid " { \"label\" : \"html\", \"source\": \"snippet_html(name)\" }" +msgstr "" + +msgid "" +" * This exports a static value `\"Japan\"` for the `country` column of all r" +"ecords.\n" +" (This will be useful for debugging, or a use case to try modification o" +"f APIs.)" +msgstr "" +" * 以下の例は、`country` カラムについて、すべてのレコードの当該カラムの値が文字列 `\"Japan\"` であるものとして出力します。\n" +" (存在しないカラムを実際に作成する前にクライアント側の挙動を確認したい場合などに、この機能が利用できます。)" + +msgid " { \"label\" : \"country\", \"source\" : \"'Japan'\" }" +msgstr "" + +msgid "" +" * This exports a number of grouped records as the `\"itemsCount\"` column o" +"f each record (grouped result)." +msgstr " * 以下の例は、集約前の元のレコードの総数を、集約後のレコードの `\"itemsCount\"` カラムの値として出力します。" + +msgid " { \"label\" : \"itemsCount\", \"source\" : \"_nsubrecs\", }" +msgstr "" + +msgid "" +" * This exports samples of the source records of grouped records, as the `" +"\"items\"` column of grouped records.\n" +" The format of the `\"attributes\"` is just same to this section." +msgstr "" +" * 以下の例は、集約前の元のレコードの配列を、集約後のレコードの `\"items\"` カラムの値として出力します。\n" +" `\"attributes\"` は、この項の説明と同じ形式で指定します。" + +msgid "" +" { \"label\" : \"items\", \"source\" : \"_subrecs\",\n" +" \"attributes\": [\"name\", \"price\"] }" +msgstr "" + +msgid "" +" An array of column definitions can contain any type definition described abo" +"ve, like:" +msgstr " カラムの定義の配列には、上記の形式で示されたカラムの定義を0個以上含めることができます。例:" + +msgid "" +" [\n" +" \"name\",\n" +" \"age\",\n" +" { \"label\" : \"realName\", \"source\" : \"name\" }\n" +" ]" +msgstr "" + +msgid "" +" A hash of column definitions can contain any type definition described above" +" except `label` of hashes, because keys of the hash means `label` of each colu" +"mn, like:" +msgstr " カラムの定義を値としたハッシュでは、カラムの出力名をキー、上記の形式で示されたカラムの定義を値として、カラムの定義を0個以上含めることができます。例:" + +msgid "" +" {\n" +" \"name\" : \"name\",\n" +" \"age\" : \"age\",\n" +" \"realName\" : { \"source\" : \"name\" },\n" +" \"country\" : { \"source\" : \"'Japan'\" }\n" +" }" +msgstr "" + +msgid "" +" This parameter is optional, there is no default value. No column will be exp" +"orted if no column is specified." +msgstr " このパラメータは省略可能で、省略時の既定値はありません。カラムの指定がない場合、カラムの値は一切出力されません。" + +msgid "## Responses {#response}" +msgstr "## レスポンス {#response}" + +msgid "" +"This command returns a hash as the result as the `body`, with `200` as the `st" +"atusCode`." +msgstr "このコマンドは、検索結果を`body` 、ステータスコード `200` を `statusCode` の値としたレスポンスを返します。" + +msgid "" +"Keys of the result hash is the name of each query (a result of a search query)" +", values of the hash is the result of each [search query](#query-parameters), " +"like:" +msgstr "" +"検索結果のハッシュは、個々の検索クエリの名前をキー、対応する[個々の検索クエリ](#query-parameters)の処理結果を値とした、以下のような形式" +"を取ります。" + +msgid "" +" {\n" +" \"<Name of the query 1>\" : {\n" +" \"startTime\" : \"<Time to start the operation>\",\n" +" \"elapsedTime\" : <Elapsed time to process the query, in milliseconds),\n" +" \"count\" : <Number of records searched by the given conditions>,\n" +" \"attributes\" : <Array or hash of exported columns>,\n" +" \"records\" : [<Array of search result records>]\n" +" },\n" +" \"<Name of the query 2>\" : { ... },\n" +" ...\n" +" }" +msgstr "" +" {\n" +" \"<クエリ1の名前>\" : {\n" +" \"startTime\" : \"<検索を開始した時刻>\",\n" +" \"elapsedTime\" : <検索にかかった時間(単位:ミリ秒)),\n" +" \"count\" : <指定された検索条件に該当するレコードの総数>,\n" +" \"attributes\" : <出力されたレコードのカラムの情報の配列またはハッシュ>,\n" +" \"records\" : [<出力されたレコードの配列>]\n" +" },\n" +" \"<クエリ2の名前>\" : { ... },\n" +" ...\n" +" }" + +msgid "" +"A hash of a search query's result can have following elements, but only some e" +"lements specified in the `elements` of the [`output` parameter](#query-output)" +" will appear in the response." +msgstr "" +"検索クエリの処理結果のハッシュは以下の項目を持つことができ、[検索クエリの `output`](#query-output) の `elements` で明" +"示的に指定された項目のみが出力されます。" + +msgid "### `startTime` {#response-query-startTime}" +msgstr "" + +msgid "A local time string meaning the search operation is started." +msgstr "検索を開始した時刻(ローカル時刻)の文字列です。" + +msgid "" +"It is formatted in the [W3C-DTF](http://www.w3.org/TR/NOTE-datetime \"Date and " +"Time Formats\"), with the time zone like:" +msgstr "" +"形式は、[W3C-DTF](http://www.w3.org/TR/NOTE-datetime \"Date and Time Formats\")のタイムゾ" +"ーンを含む形式となります。\n" +"例えば以下の要領です。" + +msgid " 2013-11-29T08:15:30+09:00" +msgstr "" + +msgid "### `elapsedTime` {#response-query-elapsedTime}" +msgstr "" + +msgid "An integer meaning the elapsed time of the search operation, in milliseconds." +msgstr "検索にかかった時間の数値(単位:ミリ秒)です。" + +msgid "### `count` {#response-query-count}" +msgstr "" + +msgid "" +"An integer meaning the total number of search result records.\n" +"Paging options `offset` and `limit` in [`sortBy`](#query-sortBy) or [`output`]" +"(#query-output) will not affect to this count." +msgstr "" +"検索条件に該当するレコードの総数の数値です。\n" +"この値は、検索クエリの [`sortBy`](#query-sortBy) や [`output`](#query-output) における `offset" +"` および `limit` の指定の影響を受けません。" + +msgid "### `attributes` and `records` {#response-query-attributes-and-records}" +msgstr "### `attributes` および `records` {#response-query-attributes-and-records}" + +msgid "" +" * `attributes` is an array or a hash including information of exported column" +"s for each record.\n" +" * `records` is an array of search result records." +msgstr "" +" * `attributes` は出力されたレコードのカラムの情報を示す配列またはハッシュです。\n" +" * `records` は出力されたレコードの配列です。" + +msgid "" +"There are two possible patterns of `attributes` and `records`, based on the [`" +"output`](#query-output)'s `format` parameter." +msgstr "" +"`attributes` および `records` の出力形式は[検索クエリの `output`](#query-output) の `format` の" +"指定に従って以下の2通りに別れます。" + +msgid "#### Simple format result {#response-query-simple-attributes-and-records}" +msgstr "#### 単純な形式のレスポンス {#response-query-simple-attributes-and-records}" + +msgid "" +"A search result with `\"simple\"` as the value of `output`'s `format` will be re" +"turned as a hash like:" +msgstr "`format` が `\"simple\"` の場合、個々の検索クエリの結果は以下の形を取ります。" + +msgid "" +" {\n" +" \"startTime\" : \"<Time to start the operation>\",\n" +" \"elapsedTime\" : <Elapsed time to process the query),\n" +" \"count\" : <Total number of search result records>,\n" +" \"attributes\" : [\n" +" { \"name\" : \"<Name of the column 1>\",\n" +" \"type\" : \"<Type of the column 1>\",\n" +" \"vector\" : <It this column is a vector column?> },\n" +" { \"name\" : \"<Name of the column 2>\",\n" +" \"type\" : \"<Type of the column 2>\",\n" +" \"vector\" : <It this column is a vector column?> },\n" +" { \"name\" : \"<Name of the column 3 (with subrecords)>\"\n" +" \"attributes\" : [\n" +" { \"name\" : \"<Name of the column 3-1>\",\n" +" \"type\" : \"<Type of the column 3-1>\",\n" +" \"vector\" : <It this column is a vector column?> },\n" +" { \"name\" : \"<Name of the the column 3-2>\",\n" +" \"type\" : \"<Type of the the column 3-2>\",\n" +" \"vector\" : <It this column is a vector column?> },\n" +" ],\n" +" ...\n" +" },\n" +" ...\n" +" ],\n" +" \"records\" : [\n" +" [<Value of the column 1 of the record 1>,\n" +" <Value of the column 2 of the record 1>,\n" +" [\n" +" [<Value of the column of 3-1 of the subrecord 1 of the record 1>,\n" +" <Value of the column of 3-2 of the subrecord 2 of the record 1>,\n" +" ...],\n" +" [<Value of the column of 3-1 of the subrecord 1 of the record 1>,\n" +" <Value of the column of 3-2 of the subrecord 2 of the record 1>,\n" +" ...],\n" +" ...],\n" +" ...],\n" +" [<Value of the column 1 of the record 2>,\n" +" <Value of the column 2 of the record 2>,\n" +" [\n" +" [<Value of the column of 3-1 of the subrecord 1 of the record 2>,\n" +" <Value of the column of 3-2 of the subrecord 2 of the record 2>,\n" +" ...],\n" +" [<Value of the column of 3-1 of the subrecord 1 of the record 2>,\n" +" <Value of the column of 3-2 of the subrecord 2 of the record 2>,\n" +" ...],\n" +" ...],\n" +" ...],\n" +" ...\n" +" ]\n" +" }" +msgstr "" +" {\n" +" \"startTime\" : \"<検索を開始した時刻>\",\n" +" \"elapsedTime\" : <検索にかかった時間),\n" +" \"count\" : <検索結果のレコードの総数>,\n" +" \"attributes\" : [\n" +" { \"name\" : \"<カラム1の名前>\",\n" +" \"type\" : \"<カラム1の型>\",\n" +" \"vector\" : <カラム1がベクターカラムかどうか> },\n" +" { \"name\" : \"<カラム2の名前>\",\n" +" \"type\" : \"<カラム2の型>\",\n" +" \"vector\" : <カラム2がベクターカラムかどうか> },\n" +" { \"name\" : \"<カラム3(サブレコードが存在する場合)の名前>\"\n" +" \"attributes\" : [\n" +" { \"name\" : \"<カラム3-1のカラムの名前>\",\n" +" \"type\" : \"<カラム3-1のカラムの型>\",\n" +" \"vector\" : <カラム3-1がベクターカラムかどうか> },\n" +" { \"name\" : \"<カラム3-2のカラムの名前>\",\n" +" \"type\" : \"<カラム3-2のカラムの型>\",\n" +" \"vector\" : <カラム3-2がベクターカラムかどうか> },\n" +" ],\n" +" ...\n" +" },\n" +" ...\n" +" ],\n" +" \"records\" : [\n" +" [<レコード1のカラム1の値>,\n" +" <レコード1のカラム2の値>,\n" +" [\n" +" [<レコード1のサブレコード1のカラム3-1の値>,\n" +" <レコード1のサブレコード1のカラム3-2の値>,\n" +" ...],\n" +" [<レコード1のサブレコード2のカラム3-1の値>,\n" +" <レコード1のサブレコード2のカラム3-2の値>,\n" +" ...],\n" +" ...],\n" +" ...],\n" +" [<レコード2のカラム1の値>,\n" +" <レコード2のカラム2の値>,\n" +" [\n" +" [<レコード2のサブレコード1のカラム3-1の値>,\n" +" <レコード2のサブレコード1のカラム3-2の値>,\n" +" ...],\n" +" [<レコード2のサブレコード2のカラム3-1の値>,\n" +" <レコード2のサブレコード2のカラム3-2の値>,\n" +" ...],\n" +" ...],\n" +" ...],\n" +" ...\n" +" ]\n" +" }" + +msgid "" +"This format is designed to reduce traffic with small responses, instead of use" +"ful rich data format.\n" +"Recommended for cases when the response can include too much records, or the s" +"ervice can accept too much requests." +msgstr "" +"これは、受け取ったデータの扱いやすさよりも、データの転送量を小さく抑える事を優先する出力形式です。\n" +"大量のレコードを検索結果として受け取る場合や、多量のアクセスが想定される場合などに適しています。" + +msgid "##### `attributes` {#response-query-simple-attributes}" +msgstr "" + +msgid "" +"An array of column informations for each exported search result, ordered by [t" +"he `output` parameter](#query-output)'s `attributes`." +msgstr "" +"出力されたレコードのカラムについての情報の配列で、[検索クエリの `output`](#query-output) における `attributes` で指" +"定された順番で個々のカラムの情報を含みます。" + +msgid "" +"Each column information is returned as a hash in the form of one of these thre" +"e variations corresponding to the kind of values. The hash will have the follo" +"wing keys respectively:" +msgstr "個々のカラムの情報はハッシュの形をとり、その形式はレコードの値に応じて以下の3種類で与えられます。ハッシュのキーと値は以下のとおりです。" + +msgid "###### For ordinal columns" +msgstr "###### 通常のカラム" + +msgid "" +"`name`\n" +": A string meaning the name (label) of the exported column. It is just same to" +" labels defined in [the `output` parameter](#query-output)'s `attributes`." +msgstr "" +"`name`\n" +": カラムの出力名の文字列です。[検索クエリの `output`](#query-output) における `attributes` の指定内容に基づきます" +"。" + +msgid "" +"`type`\n" +": A string meaning the value type of the column.\n" +" The type is indicated as one of [Groonga's primitive data formats](http://gr" +"oonga.org/docs/reference/types.html), or a name of an existing table for refer" +"ring columns." +msgstr "" +"`type`\n" +": カラムの値の型を示す文字列です。\n" +" 値は[Groonga のプリミティブなデータ型](http://groonga.org/ja/docs/reference/types.html)の名前" +"か、もしくはテーブル名です。" + +msgid "" +"`vector`\n" +": A boolean value meaning it is a [vector column](http://groonga.org/docs/tuto" +"rial/data.html#vector-types) or not.\n" +" Possible values:" +msgstr "" +"`vector`\n" +": カラムが[ベクター型](http://groonga.org/ja/docs/tutorial/data.html#vector-types)かどうかを" +"示す真偽値です。\n" +" 以下のいずれかの値をとります。" + +msgid "" +" * `true` : It is a vector column.\n" +" * `false` : It is not a vector column, but a scalar column." +msgstr "" +" * `true` : カラムはベクター型である。\n" +" * `false` : カラムはベクター型ではない(スカラー型である)。" + +msgid "###### For columns corresponding to subrecords" +msgstr "###### サブレコードに対応するカラム" + +msgid "" +"`attributes`\n" +": An array including information about columns of subrecords. The form is the " +"same as `attributes` for (main) records. This means `attributes` has recursive" +" structure." +msgstr "" +"サブレコードのカラム情報を含む配列です。この形式は主レコードの `attributes` と同様です。つまり `attribuets` は再帰的な構造になっ" +"ています。" + +msgid "###### For expressions" +msgstr "###### 式" + +msgid "##### `records` {#response-query-simple-records}" +msgstr "" + +msgid "An array of exported search result records." +msgstr "出力されたレコードの配列です。" + +msgid "" +"Each record is exported as an array of column values, ordered by the [`output`" +" parameter](#query-output)'s `attributes`." +msgstr "" +"個々のレコードは配列の形をとり、[検索クエリの `output`](#query-output) における `attributes` で指定された各カラムの" +"値を同じ順番で含みます。" + +msgid "" +"A value of [date time type](http://groonga.org/docs/tutorial/data.html#date-an" +"d-time-type) column will be returned as a string formatted in the [W3C-DTF](ht" +"tp://www.w3.org/TR/NOTE-datetime \"Date and Time Formats\"), with the time zone." +msgstr "" +"[日時型](http://groonga.org/ja/docs/tutorial/data.html#date-and-time-type)のカラムの値は" +"、[W3C-DTF](http://www.w3.org/TR/NOTE-datetime \"Date and Time Formats\")のタイムゾーンを" +"含む形式の文字列として出力されます。" + +msgid "#### Complex format result {#response-query-complex-attributes-and-records}" +msgstr "#### 複雑な形式のレスポンス {#response-query-complex-attributes-and-records}" + +msgid "" +"A search result with `\"complex\"` as the value of `output`'s `format` will be r" +"eturned as a hash like:" +msgstr "`format` が `\"complex\"` の場合、個々の検索クエリの結果は以下の形を取ります。" + +msgid "" +" {\n" +" \"startTime\" : \"<Time to start the operation>\",\n" +" \"elapsedTime\" : <Elapsed time to process the query),\n" +" \"count\" : <Total number of search result records>,\n" +" \"attributes\" : {\n" +" \"<Name of the column 1>\" : { \"type\" : \"<Type of the column 1>\",\n" +" \"vector\" : <It this column is a vector co" +"lumn?> },\n" +" \"<Name of the column 2>\" : { \"type\" : \"<Type of the column 2>\",\n" +" \"vector\" : <It this column is a vector co" +"lumn?> },\n" +" \"<Name of the column 3 (with subrecords)>\" : {\n" +" \"attributes\" : {\n" +" \"<Name of the column 3-1>\" : { \"type\" : \"<Type of the column 3-1" +">\",\n" +" \"vector\" : <It this column is a vec" +"tor column?> },\n" +" \"<Name of the column 3-2>\" : { \"type\" : \"<Type of the column 3-2" +">\",\n" +" \"vector\" : <It this column is a vec" +"tor column?> },\n" +" ...\n" +" }\n" +" },\n" +" ...\n" +" ],\n" +" \"records\" : [\n" +" { \"<Name of the column 1>\" : <Value of the column 1 of the record 1>,\n" +" \"<Name of the column 2>\" : <Value of the column 2 of the record 1>,\n" +" \"<Name of the column 3 (with subrecords)>\" : [\n" +" { \"<Name of the column 3-1>\" : <Value of the column 3-1 of the sub" +"record 1 of record 1>,\n" +" \"<Name of the column 3-2>\" : <Value of the column 3-2 of the sub" +"record 1 of record 1>,\n" +" ... },\n" +" { \"<Name of the column 3-1>\" : <Value of the column 3-1 of the sub" +"record 2 of record 1>,\n" +" \"<Name of the column 3-2>\" : <Value of the column 3-2 of the sub" +"record 2 of record 1>,\n" +" ... },\n" +" ...\n" +" ],\n" +" ... }" +",\n" +" { \"<Name of the column 1>\" : <Value of the column 1 of the record 2>,\n" +" \"<Name of the column 2>\" : <Value of the column 2 of the record 2>,\n" +" \"<Name of the column 3 (with subrecords)>\" : [\n" +" { \"<Name of the column 3-1>\" : <Value of the column 3-1 of the sub" +"record 1 of record 2>,\n" +" \"<Name of the column 3-2>\" : <Value of the column 3-2 of the sub" +"record 1 of record 2>,\n" +" ... },\n" +" { \"<Name of the column 3-1>\" : <Value of the column 3-1 of the sub" +"record 2 of record 2>,\n" +" \"<Name of the column 3-2>\" : <Value of the column 3-2 of the sub" +"record 2 of record 2>,\n" +" ... },\n" +" ...\n" +" ],\n" +" ... }" +",\n" +" ...\n" +" ]\n" +" }" +msgstr "" +" {\n" +" \"startTime\" : \"<検索を開始した時刻>\",\n" +" \"elapsedTime\" : <検索にかかった時間),\n" +" \"count\" : <検索結果のレコードの総数>,\n" +" \"attributes\" : {\n" +" \"<カラム1の名前>\" : { \"type\" : \"<カラム1の型>\",\n" +" \"vector\" : <カラム1がベクターカラムかどうか> },\n" +" \"<カラム2の名前>\" : { \"type\" : \"<カラム2の型>\",\n" +" \"vector\" : <カラム2がベクターカラムかどうか> },\n" +" \"<カラム3(サブレコードが存在する場合)の名前>\" : {\n" +" \"attributes\" : {\n" +" \"<カラム3-1の名前>\" : { \"type\" : \"<カラム3-1の型>\",\n" +" \"vector\" : <カラム3-1がベクターカラムかどうか> },\n" +" \"<カラム3-2の名前>\" : { \"type\" : \"<カラム3-2の型>\",\n" +" \"vector\" : <カラム3-2がベクターカラムかどうか> },\n" +" ...\n" +" }\n" +" },\n" +" ...\n" +" ],\n" +" \"records\" : [\n" +" { \"<カラム1の名前>\" : <レコード1のカラム1の値>,\n" +" \"<カラム2の名前>\" : <レコード1のカラム2の値>,\n" +" \"<カラム3の名前(サブレコードが存在する場合)>\" : [\n" +" { \"<カラム3-1の名前>\" : <レコード1のサブレコード1のカラム3-1の値>,\n" +" \"<カラム3-2の名前>\" : <レコード1のサブレコード1のカラム3-2の値>,\n" +" ... },\n" +" { \"<カラム3-1の名前>\" : <レコード1のサブレコード2のカラム3-1の値>,\n" +" \"<カラム3-2の名前>\" : <レコード1のサブレコード2のカラム3-2の値>,\n" +" ... },\n" +" ...\n" +" ],\n" +" ... }" +",\n" +" { \"<カラム1の名前>\" : <レコード2のカラム1の値>,\n" +" \"<カラム2の名前>\" : <レコード2のカラム2の値>,\n" +" \"<カラム3の名前(サブレコードが存在する場合)>\" : [\n" +" { \"<カラム3-1の名前>\" : <レコード2のサブレコード1のカラム3-1の値>,\n" +" \"<カラム3-2の名前>\" : <レコード2のサブレコード1のカラム3-2の値>,\n" +" ... },\n" +" { \"<カラム3-1の名前>\" : <レコード2のサブレコード2のカラム3-1の値>,\n" +" \"<カラム3-2の名前>\" : <レコード2のサブレコード2のカラム3-2の値>,\n" +" ... },\n" +" ...\n" +" ],\n" +" ... }" +",\n" +" ...\n" +" ]\n" +" }" + +msgid "" +"This format is designed to keep human readability, instead of less traffic.\n" +"Recommended for small traffic cases like development, debugging, features only" +" for administrators, and so on." +msgstr "" +"これは、データの転送量を小さく抑える事よりも、受け取ったデータの扱いやすさを優先する出力形式です。\n" +"検索結果の件数が小さい事があらかじめ分かっている場合や、管理機能などのそれほど多量のアクセスが見込まれない場合などに適しています。" + +msgid "##### `attributes` {#response-query-complex-attributes}" +msgstr "" + +msgid "" +"A hash of column informations for each exported search result. Keys of the has" +"h are column names defined by [the `output` parameter](#query-output)'s `attri" +"butes`, values are informations of each column." +msgstr "" +"出力されたレコードのカラムについての情報を含むハッシュで、[検索クエリの `output`](#query-output) における `attributes" +"` で指定された出力カラム名がキー、カラムの情報が値となります。" + +msgid "" +"`type`\n" +": A string meaning the value type of the column.\n" +" The type is indicated as one of [Groonga's primitive data formats](http://gr" +"oonga.org/docs/reference/types.html), or a name for an existing table for refe" +"rring columns." +msgstr "" +"`type`\n" +": カラムの値の型を示す文字列です。\n" +" 値は[Groonga のプリミティブなデータ型](http://groonga.org/ja/docs/reference/types.html)の名前" +"か、もしくはテーブル名です。" + +msgid "Has no key. Just a empty hash `{}` will be returned." +msgstr "キーはありません。空のハッシュ `{}` です。" + +msgid "##### `records` {#response-query-complex-records}" +msgstr "" + +msgid "" +"Each record is exported as a hash. Keys of the hash are column names defined b" +"y [`output` parameter](#query-output)'s `attributes`, values are column values" +"." +msgstr "" +"個々のレコードは、[検索クエリの `output`](#query-output) における `attributes` で指定された出力カラム名をキー、カラ" +"ムの値を値としたハッシュとなります。" + +msgid "## Error types {#errors}" +msgstr "## エラーの種類 {#errors}" + +msgid "" +"This command reports errors not only [general errors](/reference/message/#erro" +"r) but also followings." +msgstr "このコマンドは[一般的なエラー](/ja/reference/message/#error)に加えて、以下のエラーを場合に応じて返します。" + +msgid "### `MissingSourceParameter`" +msgstr "" + +msgid "" +"Means you've forgotten to specify the `source` parameter. The status code is `" +"400`." +msgstr "`source` の指定がないクエリがあることを示します。ステータスコードは `400` です。" + +msgid "### `UnknownSource`" +msgstr "" + +msgid "" +"Means there is no existing table and no other query with the name, for a `sour" +"ce` of a query. The status code is `404`." +msgstr "" +"`source` の値として、他のクエリの名前ではない、実際には存在しないテーブルの名前が指定されていることを示します。ステータスコードは `404` です" +"。" + +msgid "### `CyclicSource`" +msgstr "" + +msgid "Means there is any circular reference of sources. The status code is `400`." +msgstr "`source` の循環参照があることを示します。ステータスコードは `400` です。" + +msgid "### `SearchTimeout`" +msgstr "" + +msgid "" +"Means the engine couldn't finish to process the request in the time specified " +"as `timeout`. The status code is `500`." +msgstr "`timeout` で指定された時間内に検索処理が完了しなかったことを示します。ステータスコードは `500` です。" Added: _po/ja/reference/1.0.3/commands/select/index.po (+179 -0) 100644 =================================================================== --- /dev/null +++ _po/ja/reference/1.0.3/commands/select/index.po 2014-05-19 16:48:30 +0900 (88a1ecc) @@ -0,0 +1,179 @@ +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"PO-Revision-Date: 2014-03-05 12:52+0900\n" +"Language: ja\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" + +msgid "" +"---\n" +"title: select\n" +"layout: en\n" +"---" +msgstr "" +"---\n" +"title: select\n" +"layout: ja\n" +"---" + +msgid "" +"* TOC\n" +"{:toc}" +msgstr "" + +msgid "## Abstract {#abstract}" +msgstr "## 概要 {#abstract}" + +msgid "" +"The `select` command finds records from the specified table based on given con" +"ditions, and returns found records." +msgstr "`select` は、テーブルから指定された条件にマッチするレコードを検索し、見つかったレコードを返却します。" + +msgid "" +"This is compatible to [the `select` command of the Groonga](http://groonga.org" +"/docs/reference/commands/select.html)." +msgstr "" +"このコマンドは[Groonga の `select` コマンド](http://groonga.org/ja/docs/reference/commands" +"/select.html)と互換性があります。" + +msgid "" +"Style\n" +": Request-Response. One response message is always returned per one request." +msgstr "" +"形式\n" +": Request-Response型。コマンドに対しては必ず対応するレスポンスが返されます。" + +msgid "" +"`type` of the request\n" +": `select`" +msgstr "" +"リクエストの `type`\n" +": `select`" + +msgid "" +"`body` of the request\n" +": A hash of parameters." +msgstr "" +"リクエストの `body`\n" +": パラメータのハッシュ。" + +msgid "" +"`type` of the response\n" +": `select.result`" +msgstr "" +"レスポンスの `type`\n" +": `select.result`" + +msgid "## Parameter syntax {#syntax}" +msgstr "## パラメータの構文 {#syntax}" + +msgid "" +" {\n" +" \"table\" : \"<Name of the table>\",\n" +" \"match_columns\" : \"<List of matching columns, separated by '||'>\",\n" +" \"query\" : \"<Simple search conditions>\",\n" +" \"filter\" : \"<Complex search conditions>\",\n" +" \"scorer\" : \"<An expression to be applied to matched records>\"," +"\n" +" \"sortby\" : \"<List of sorting columns, separated by ','>\",\n" +" \"output_columns\" : \"<List of returned columns, separated by ','>\",\n" +" \"offset\" : <Offset of paging>,\n" +" \"limit\" : <Number of records to be returned>,\n" +" \"drilldown\" : \"<Column name to be drilldown-ed>\",\n" +" \"drilldown_sortby\" : \"List of sorting columns for drilldown's result, se" +"parated by ','>\",\n" +" \"drilldown_output_columns\" :\n" +" \"List of returned columns for drilldown's result, s" +"eparated by ','>\",\n" +" \"drilldown_offset\" : <Offset of drilldown's paging>,\n" +" \"drilldown_limit\" : <Number of drilldown results to be returned>,\n" +" \"cache\" : \"<Query cache option>\",\n" +" \"match_escalation_threshold\":\n" +" <Threshold to escalate search methods>,\n" +" \"query_flags\" : \"<Flags to customize query parameters>\",\n" +" \"query_expander\" : \"<Arguments to expanding queries>\"\n" +" }" +msgstr "" +" {\n" +" \"table\" : \"<テーブル名>\",\n" +" \"match_columns\" : \"<検索対象のカラム名のリストを'||'区切りで指定>\",\n" +" \"query\" : \"<単純な検索条件>\",\n" +" \"filter\" : \"<複雑な検索条件>\",\n" +" \"scorer\" : \"<見つかったすべてのレコードに適用する式>\",\n" +" \"sortby\" : \"<ソートキーにするカラム名のリストをカンマ(',')区切りで指定>\",\n" +" \"output_columns\" : \"<L返却するカラム名のリストをカンマ(',')区切りで指定>\",\n" +" \"offset\" : <ページングの起点>,\n" +" \"limit\" : <返却するレコード数>,\n" +" \"drilldown\" : \"<ドリルダウンするカラム名>\",\n" +" \"drilldown_sortby\" : \"ドリルダウン結果のソートキーにするカラム名のリストをカンマ(',')区切りで指定>\",\n" +" \"drilldown_output_columns\" :\n" +" \"ドリルダウン結果として返却するカラム名のリストをカンマ(',')区切りで指定>\",\n" +" \"drilldown_offset\" : <ドリルダウン結果のページングの起点>,\n" +" \"drilldown_limit\" : <返却するドリルダウン結果のレコード数>,\n" +" \"cache\" : \"<クエリキャッシュの指定>\",\n" +" \"match_escalation_threshold\":\n" +" <検索方法をエスカレーションする閾値>,\n" +" \"query_flags\" : \"<queryパラメーターのカスタマイズ用フラグ>\",\n" +" \"query_expander\" : \"<クエリー展開用の引数>\"\n" +" }" + +msgid "## Parameter details {#parameters}" +msgstr "## パラメータの詳細 {#parameters}" + +msgid "All parameters except `table` are optional." +msgstr "`table` 以外のパラメータはすべて省略可能です。" + +msgid "" +"On the version {{ site.droonga_version }}, only following parameters are avail" +"able. Others are simply ignored because they are not implemented." +msgstr "" +"また、バージョン {{ site.droonga_version }} の時点では以下のパラメータのみが動作します。\n" +"これら以外のパラメータは未実装のため無視されます。" + +msgid "" +" * `table`\n" +" * `match_columns`\n" +" * `query`\n" +" * `filter`\n" +" * `output_columns`\n" +" * `offset`\n" +" * `limit`\n" +" * `drilldown`\n" +" * `drilldown_output_columns`\n" +" * `drilldown_sortby`\n" +" * `drilldown_offset`\n" +" * `drilldown_limit`" +msgstr "" + +msgid "" +"All parameters are compatible to [parameters for `select` command of the Groon" +"ga](http://groonga.org/docs/reference/commands/select.html#parameters). See th" +"e linked document for more details." +msgstr "" +"すべてのパラメータの意味は[Groonga の `select` コマンドの引数](http://groonga.org/ja/docs/reference" +"/commands/select.html#parameters)と共通です。詳細はGroongaのコマンドリファレンスを参照して下さい。" + +msgid "## Responses {#response}" +msgstr "## レスポンス {#response}" + +msgid "This returns an array including search results as the response's `body`." +msgstr "このコマンドは、レスポンスの `body` として検索結果の配列を返却します。" + +msgid "" +"The structure of the returned array is compatible to [the returned value of th" +"e Groonga's `select` command](http://groonga.org/docs/reference/commands/selec" +"t.html#id6). See the linked document for more details." +msgstr "" +"検索結果の配列の構造は[Groonga の `select` コマンドの返り値](http://groonga.org/ja/docs/reference/" +"commands/select.html#id6)と共通です。詳細はGroongaのコマンドリファレンスを参照して下さい。" + +msgid "" +"This command always returns a response with `200` as its `statusCode`, because" +" this is a Groonga compatible command and errors of this command must be handl" +"ed in the way same to Groonga's one." +msgstr "" +"このコマンドはレスポンスの `statusCode` として常に `200` を返します。これは、Groonga互換コマンドのエラー情報はGroongaのそ" +"れと同じ形で処理される必要があるためです。" Added: _po/ja/reference/1.0.3/commands/table-create/index.po (+183 -0) 100644 =================================================================== --- /dev/null +++ _po/ja/reference/1.0.3/commands/table-create/index.po 2014-05-19 16:48:30 +0900 (0da1e15) @@ -0,0 +1,183 @@ +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"PO-Revision-Date: 2014-03-05 12:52+0900\n" +"Language: ja\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" + +msgid "" +"---\n" +"title: table_create\n" +"layout: en\n" +"---" +msgstr "" +"---\n" +"title: table_create\n" +"layout: ja\n" +"---" + +msgid "" +"* TOC\n" +"{:toc}" +msgstr "" + +msgid "## Abstract {#abstract}" +msgstr "## 概要 {#abstract}" + +msgid "The `table_create` command creates a new table." +msgstr "`table_create` は、新しいテーブルを作成します。" + +msgid "" +"This is compatible to [the `table_create` command of the Groonga](http://groon" +"ga.org/docs/reference/commands/table_create.html)." +msgstr "" +"このコマンドは[Groonga の `table_create` コマンド](http://groonga.org/ja/docs/reference/co" +"mmands/table_create.html)と互換性があります。" + +msgid "" +"Style\n" +": Request-Response. One response message is always returned per one request." +msgstr "" +"形式\n" +": Request-Response型。コマンドに対しては必ず対応するレスポンスが返されます。" + +msgid "" +"`type` of the request\n" +": `table_create`" +msgstr "" +"リクエストの `type`\n" +": `table_create`" + +msgid "" +"`body` of the request\n" +": A hash of parameters." +msgstr "" +"リクエストの `body`\n" +": パラメータのハッシュ。" + +msgid "" +"`type` of the response\n" +": `table_create.result`" +msgstr "" +"レスポンスの `type`\n" +": `table_create.result`" + +msgid "## Parameter syntax {#syntax}" +msgstr "## パラメータの構文 {#syntax}" + +msgid "" +" {\n" +" \"name\" : \"<Name of the table>\",\n" +" \"flags\" : \"<Flags for the table>\",\n" +" \"key_type\" : \"<Type of the primary key>\",\n" +" \"value_type\" : \"<Type of the value>\",\n" +" \"default_tokenizer\" : \"<Default tokenizer>\",\n" +" \"normalizer\" : \"<Normalizer>\"\n" +" }" +msgstr "" +" {\n" +" \"name\" : \"<テーブル名>\",\n" +" \"flags\" : \"<テーブルの属性>\",\n" +" \"key_type\" : \"<主キーの型>\",\n" +" \"value_type\" : \"<値の型>\",\n" +" \"default_tokenizer\" : \"<既定のトークナイザー>\",\n" +" \"normalizer\" : \"<ノーマライザー>\"\n" +" }" + +msgid "## Parameter details {#parameters}" +msgstr "## パラメータの詳細 {#parameters}" + +msgid "All parameters except `name` are optional." +msgstr "`name` 以外のパラメータはすべて省略可能です。" + +msgid "" +"They are compatible to [the parameters of the `table_create` command of the Gr" +"oonga](http://groonga.org/docs/reference/commands/table_create.html#parameters" +"). See the linked document for more details." +msgstr "" +"すべてのパラメータは[Groonga の `table_create` コマンドの引数](http://groonga.org/ja/docs/refere" +"nce/commands/table_create.html#parameters)と共通です。詳細はGroongaのコマンドリファレンスを参照して下さい。" + +msgid "## Responses {#response}" +msgstr "## レスポンス {#response}" + +msgid "This returns an array meaning the result of the operation, as the `body`." +msgstr "このコマンドは、レスポンスの `body` としてコマンドの実行結果に関する情報を格納した配列を返却します。" + +msgid "" +" [\n" +" [\n" +" <Groonga's status code>,\n" +" <Start time>,\n" +" <Elapsed time>\n" +" ],\n" +" <Table is successfully created or not>\n" +" ]" +msgstr "" +" [\n" +" [\n" +" <Groongaのステータスコード>,\n" +" <開始時刻>,\n" +" <処理に要した時間>\n" +" ],\n" +" <テーブルが作成されたかどうか>\n" +" ]" + +msgid "" +"This command always returns a response with `200` as its `statusCode`, because" +" this is a Groonga compatible command and errors of this command must be handl" +"ed in the way same to Groonga's one." +msgstr "" +"このコマンドはレスポンスの `statusCode` として常に `200` を返します。これは、Groonga互換コマンドのエラー情報はGroongaのそ" +"れと同じ形で処理される必要があるためです。" + +msgid "Response body's details:" +msgstr "レスポンスの `body` の詳細:" + +msgid "" +"Status code\n" +": An integer which means the operation's result. Possible values are:" +msgstr "" +"ステータスコード\n" +": コマンドが正常に受け付けられたかどうかを示す整数値です。以下のいずれかの値をとります。" + +msgid "" +" * `0` (`Droonga::GroongaHandler::Status::SUCCESS`) : Successfully processed" +".\n" +" * `-22` (`Droonga::GroongaHandler::Status::INVALID_ARGUMENT`) : There is an" +"y invalid argument." +msgstr "" +" * `0` (`Droonga::GroongaHandler::Status::SUCCESS`) : 正常に処理された。.\n" +" * `-22` (`Droonga::GroongaHandler::Status::INVALID_ARGUMENT`) : 引数が不正である。" + +msgid "" +"Start time\n" +": An UNIX time which the operation was started on." +msgstr "" +"開始時刻\n" +": 処理を開始した時刻を示す数値(UNIX秒)。" + +msgid "" +"Elapsed time\n" +": A decimal of seconds meaning the elapsed time for the operation." +msgstr "" +"処理に要した時間\n" +": 処理を開始してから完了までの間にかかった時間を示す数値。" + +msgid "" +"Table is successfully created or not\n" +": A boolean value meaning the table was successfully created or not. Possible " +"values are:" +msgstr "" +"テーブルが作成されたかどうか\n" +": テーブルが作成されたかどうかを示す真偽値です。以下のいずれかの値をとります。" + +msgid "" +" * `true`:The table was successfully created.\n" +" * `false`:The table was not created." +msgstr "" +" * `true`:テーブルを作成した。\n" +" * `false`:テーブルを作成しなかった。" Added: _po/ja/reference/1.0.3/commands/table-remove/index.po (+169 -0) 100644 =================================================================== --- /dev/null +++ _po/ja/reference/1.0.3/commands/table-remove/index.po 2014-05-19 16:48:30 +0900 (6ca6f86) @@ -0,0 +1,169 @@ +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"PO-Revision-Date: 2014-03-05 12:52+0900\n" +"Language: ja\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" + +msgid "" +"---\n" +"title: table_remove\n" +"layout: en\n" +"---" +msgstr "" + +msgid "" +"* TOC\n" +"{:toc}" +msgstr "" + +msgid "## Abstract {#abstract}" +msgstr "## 概要 {#abstract}" + +msgid "The `table_remove` command removes an existing table." +msgstr "`table_remove` は、既存のテーブルを1つ削除します。" + +msgid "" +"This is compatible to [the `table_remove` command of the Groonga](http://groon" +"ga.org/docs/reference/commands/table_remove.html)." +msgstr "" +"このコマンドは[Groonga の `table_remove` コマンド](http://groonga.org/ja/docs/reference/co" +"mmands/table_remove.html)と互換性があります。" + +msgid "" +"Style\n" +": Request-Response. One response message is always returned per one request." +msgstr "" +"形式\n" +": Request-Response型。コマンドに対しては必ず対応するレスポンスが返されます。" + +msgid "" +"`type` of the request\n" +": `table_remove`" +msgstr "" +"リクエストの `type`\n" +": `table_remove`" + +msgid "" +"`body` of the request\n" +": A hash of parameters." +msgstr "" +"リクエストの `body`\n" +": パラメータのハッシュ。" + +msgid "" +"`type` of the response\n" +": `table_remove.result`" +msgstr "" +"レスポンスの `type`\n" +": `table_remove.result`" + +msgid "## Parameter syntax {#syntax}" +msgstr "## パラメータの構文 {#syntax}" + +msgid "" +" {\n" +" \"name\" : \"<Name of the table>\"\n" +" }" +msgstr "" +" {\n" +" \"name\" : \"<テーブル名>\"\n" +" }" + +msgid "## Parameter details {#parameters}" +msgstr "## パラメータの詳細 {#parameters}" + +msgid "The only one parameter `name` is required." +msgstr "唯一のパラメータとなる `name` は省略不可能です。" + +msgid "" +"They are compatible to [the parameters of the `table_remove` command of the Gr" +"oonga](http://groonga.org/docs/reference/commands/table_remove.html#parameters" +"). See the linked document for more details." +msgstr "" +"すべてのパラメータは[Groonga の `table_remove` コマンドの引数](http://groonga.org/ja/docs/refere" +"nce/commands/table_remove.html#parameters)と共通です。詳細はGroongaのコマンドリファレンスを参照して下さい。" + +msgid "## Responses {#response}" +msgstr "## レスポンス {#response}" + +msgid "This returns an array meaning the result of the operation, as the `body`." +msgstr "このコマンドは、レスポンスの `body` としてコマンドの実行結果に関する情報を格納した配列を返却します。" + +msgid "" +" [\n" +" [\n" +" <Groonga's status code>,\n" +" <Start time>,\n" +" <Elapsed time>\n" +" ],\n" +" <Table is successfully removed or not>\n" +" ]" +msgstr "" +" [\n" +" [\n" +" <Groongaのステータスコード>,\n" +" <開始時刻>,\n" +" <処理に要した時間>\n" +" ],\n" +" <テーブルが削除されたかどうか>\n" +" ]" + +msgid "" +"This command always returns a response with `200` as its `statusCode`, because" +" this is a Groonga compatible command and errors of this command must be handl" +"ed in the way same to Groonga's one." +msgstr "" +"このコマンドはレスポンスの `statusCode` として常に `200` を返します。これは、Groonga互換コマンドのエラー情報はGroongaのそ" +"れと同じ形で処理される必要があるためです。" + +msgid "Response body's details:" +msgstr "レスポンスの `body` の詳細:" + +msgid "" +"Status code\n" +": An integer which means the operation's result. Possible values are:" +msgstr "" +"ステータスコード\n" +": コマンドが正常に受け付けられたかどうかを示す整数値です。以下のいずれかの値をとります。" + +msgid "" +" * `0` (`Droonga::GroongaHandler::Status::SUCCESS`) : Successfully processed" +".\n" +" * `-22` (`Droonga::GroongaHandler::Status::INVALID_ARGUMENT`) : There is an" +"y invalid argument." +msgstr "" +" * `0` (`Droonga::GroongaHandler::Status::SUCCESS`) : 正常に処理された。.\n" +" * `-22` (`Droonga::GroongaHandler::Status::INVALID_ARGUMENT`) : 引数が不正である。" + +msgid "" +"Start time\n" +": An UNIX time which the operation was started on." +msgstr "" +"開始時刻\n" +": 処理を開始した時刻を示す数値(UNIX秒)。" + +msgid "" +"Elapsed time\n" +": A decimal of seconds meaning the elapsed time for the operation." +msgstr "" +"処理に要した時間\n" +": 処理を開始してから完了までの間にかかった時間を示す数値。" + +msgid "" +"Table is successfully removed or not\n" +": A boolean value meaning the table was successfully removed or not. Possible " +"values are:" +msgstr "" +"テーブルが削除されたかどうか\n" +": テーブルが削除されたかどうかを示す真偽値です。以下のいずれかの値をとります。" + +msgid "" +" * `true`:The table was successfully removed.\n" +" * `false`:The table was not removed." +msgstr "" +" * `true`:テーブルを削除した。\n" +" * `false`:テーブルを削除しなかった。" Added: _po/ja/reference/1.0.3/http-server/index.po (+327 -0) 100644 =================================================================== --- /dev/null +++ _po/ja/reference/1.0.3/http-server/index.po 2014-05-19 16:48:30 +0900 (cb45833) @@ -0,0 +1,327 @@ +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"PO-Revision-Date: 2014-03-05 12:52+0900\n" +"Language: ja\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" + +msgid "" +"---\n" +"title: HTTP Server\n" +"layout: en\n" +"---" +msgstr "" +"---\n" +"title: HTTPサーバ\n" +"layout: ja\n" +"---" + +msgid "" +"* TOC\n" +"{:toc}" +msgstr "" + +msgid "## Abstract {#abstract}" +msgstr "## 概要 {#abstract}" + +msgid "" +"The [Droonga HTTP Server][droonga-http-server] is as an HTTP protocol adapter " +"for the Droonga Engine." +msgstr "" +"[Droonga HTTP Server][droonga-http-server]は、Droonga Engine用のHTTP Protocol Adap" +"terです。" + +msgid "" +"The Droonga Engine supports only the fluentd protocol, so you have to use `flu" +"ent-cat` or something, to communicate with the Drooga Engine.\n" +"This application provides ability to communicate with the Droonga Engine via H" +"TTP." +msgstr "" +"Droonga Engineはfluentdプロトコルにのみ対応しているため、Droonga Engineとの通信には`fluent-cat`などを使う必要" +"があります。\n" +"このアプリケーションは、Droonga EngineとHTTP経由で通信するための機能を提供します。" + +msgid "## Install {#install}" +msgstr "## インストール {#install}" + +msgid "" +"It is released as the [droonga-http-server npm module][], a [Node.js][] module" +" package.\n" +"You can install it via the `npm` command, like:" +msgstr "" +"Droonga HTTP Serverは、[Node.js][] 用の[droonga-http-server npmモジュール][droonga-http" +"-server npm module]として提供されています。\n" +"以下のように、`npm`コマンドでインストールすることができます:" + +msgid " # npm install -g droonga-http-server" +msgstr "" + +msgid "## Usage {#usage}" +msgstr "## 使い方 {#usage}" + +msgid "### Command line options {#usage-command}" +msgstr "### コマンドラインオプション {#usage-command}" + +msgid "" +"It includes a command `droonga-http-server` to start an HTTP server.\n" +"You can start it with command line options, like:" +msgstr "" +"Droonga HTTP Serverは、HTTPサーバを起動するための`droonga-http-server`コマンドを含んでいます。\n" +"以下のようにコマンドラインオプションを指定して起動できます:" + +msgid " # droonga-http-server --port 3003" +msgstr "" + +msgid "Available options and their default values are:" +msgstr "指定可能なオプションと既定値は以下の通りです:" + +msgid "" +"`--port <13000>`\n" +": The port number which the server receives HTTP requests at." +msgstr "" +"`--port <13000>`\n" +": HTTPリクエストを受け付けるポート番号。" + +msgid "" +"`--receive-host-name <127.0.0.1>`\n" +": The host name (or the IP address) of the computer itself which the server is" +" running.\n" +" It is used by the Droonga Engine, to send response messages to the protocol " +"adapter." +msgstr "" +"`--receive-host-name <127.0.0.1>`\n" +": HTTPサーバが動作するコンピュータ自身のホスト名(またはIPアドレス)。\n" +" Droonga EngineからProtocol Adapterへレスポンスのメッセージを送出する際の宛先に使われます。" + +msgid "" +"`--droonga-engine-host-name <127.0.0.1>`\n" +": The host name (or the IP address) of the computer which the Droonga Engine i" +"s running on." +msgstr "" +"`--droonga-engine-host-name <127.0.0.1>`\n" +": Droonga Engineが動作するコンピュータのホスト名(またはIPアドレス)。" + +msgid "" +"`--droonga-engine-port <24224>`\n" +": The port number which the Droonga Engine receives messages at." +msgstr "" +"`--droonga-engine-port <24224>`\n" +": Droonga Engineがメッセージを受け付けるポートの番号。" + +msgid "" +"`--default-dataset <Droonga>`\n" +": The name of the default dataset.\n" +" It is used for requests triggered via built-in HTTP APIs." +msgstr "" +"`--default-dataset <Droonga>`\n" +": 既定のデータセット名。\n" +" 組み込みのHTTP APIから発行されるリクエストに使われます。" + +msgid "" +"`--tag <droonga>`\n" +": The tag used for fluentd messages sent to the Droonga Engine." +msgstr "" +"`--tag <droonga>`\n" +": Droonga Engineに送るfluentdメッセージに使われます。" + +msgid "" +"`--enable-logging`\n" +": If you specify this option, log messages are printed to the standard output." +msgstr "" +"`--enable-logging`\n" +": このオプションを指定した場合、ログが標準出力に出力されるようになります。" + +msgid "" +"`--cache-size <100>`\n" +": The maximum size of the LRU response cache.\n" +" Droonga HTTP server caches all responses for GET requests on the RAM, unthil" +" this size." +msgstr "" +"`--cache-size <100>`\n" +": LRUレスポンスキャッシュの最大サイズ。\n" +" Droonga HTTP ServerはすべてのGETリクエストについて、レスポンスをここで指定した件数までメモリ上にキャッシュします。" + +msgid "" +"You have to specify appropriate values for your Droonga Engine. For example, i" +"f the HTTP server is running on the host 192.168.10.90 and the Droonga engine " +"is running on the host 192.168.10.100 with following configurations:" +msgstr "" +"コマンドラインオプションには、組み合わせるDroonga Engineに合わせた値を適切に指定する必要があります。例えば、HTTPサーバが192.168.1" +"0.90のコンピュータ上で動作し、Droonga Engineが192.168.10.100のコンピュータ上で以下の設定を伴って動作する時:" + +msgid "fluentd.conf:" +msgstr "" + +msgid "" +" <source>\n" +" type forward\n" +" port 24324\n" +" </source>\n" +" <match books.message>\n" +" name localhost:24224/books\n" +" type droonga\n" +" </match>\n" +" <match output.message>\n" +" type stdout\n" +" </match>" +msgstr "" + +msgid "catalog.json:" +msgstr "" + +msgid "" +" {\n" +" \"version\": 2,\n" +" \"effectiveDate\": \"2013-09-01T00:00:00Z\",\n" +" \"datasets\": {\n" +" \"Books\": {\n" +" ...\n" +" }\n" +" }\n" +" }" +msgstr "" + +msgid "" +"Then, you'll start the HTTP server on the host 192.168.10.90, with options lik" +"e:" +msgstr "この時、192.168.10.90のコンピュータ上でHTTPサーバを起動する際のコマンドラインオプションは以下のようになります:" + +msgid "" +" # droonga-http-server --receive-host-name 192.168.10.90 \\\n" +" --droonga-engine-host-name 192.168.10.100 \\\n" +" --droonga-engine-port 24324 \\\n" +" --default-dataset Books \\\n" +" --tag books" +msgstr "" + +msgid "See also the [basic tutorial][]." +msgstr "[基本のチュートリアル][basic tutorial]も併せて参照して下さい。" + +msgid "## Built-in APIs {#usage-api}" +msgstr "## 組み込みのAPI {#usage-api}" + +msgid "The Droonga HTTP Server includes following APIs:" +msgstr "Droonga HTTP Serverは以下のAPIを含んでいます:" + +msgid "### REST API {#usage-rest}" +msgstr "" + +msgid "#### `GET /tables/<table name>` {#usage-rest-get-tables-table}" +msgstr "#### `GET /tables/<テーブル名>` {#usage-rest-get-tables-table}" + +msgid "" +"This emits a simple [search request](../commands/search/).\n" +"The [`source`](../commands/search/#query-source) is filled by the table name i" +"n the path.\n" +"Available query parameters are:" +msgstr "" +"単純な[検索リクエスト](../commands/search/)を発行します。\n" +"リクエストの[`source`](../commands/search/#query-source)は、パス中で指定されたテーブル名となります。\n" +"指定できるクエリパラメータは以下の通りです:" + +msgid "" +"`attributes`\n" +": Corresponds to [`output.attributes`](../commands/search/#query-output).\n" +" The value is a comma-separated list, like: `attributes=_key,name,age`." +msgstr "" +"`attributes`\n" +": [`output.attributes`](../commands/search/#query-output)に対応。\n" +" 値はカンマ区切りのリストです。例:`attributes=_key,name,age`." + +msgid "" +"`query`\n" +": Corresponds to [`condition.*.query`](../commands/search/#query-condition-que" +"ry-syntax-hash).\n" +" The vlaue is a query string." +msgstr "" +"`query`\n" +": [`condition.*.query`](../commands/search/#query-condition-query-syntax-hash)" +"に対応。\n" +" 値はクエリ文字列です。" + +msgid "" +"`match_to`\n" +": Corresponds to [`condition.*.matchTo`](../commands/search/#query-condition-q" +"uery-syntax-hash).\n" +" The vlaue is an comma-separated list, like: `match_to=_key,name`." +msgstr "" +"`match_to`\n" +": [`condition.*.matchTo`](../commands/search/#query-condition-query-syntax-has" +"h)に対応。\n" +" 値はカンマ区切りのリストです。例:`match_to=_key,name`." + +msgid "" +"`match_escalation_threshold`\n" +": Corresponds to [`condition.*.matchEscalationThreshold`](../commands/search/#" +"query-condition-query-syntax-hash).\n" +" The vlaue is an integer." +msgstr "" +"`match_escalation_threshold`\n" +": [`condition.*.matchEscalationThreshold`](../commands/search/#query-condition" +"-query-syntax-hash)に対応。\n" +" 値は整数です。" + +msgid "" +"`script`\n" +": Corresponds to [`condition`](../commands/search/#query-condition-query-synta" +"x-hash) in the script syntax.\n" +" If you specity both `query` and `script`, then they work with an `and` logic" +"al condition." +msgstr "" +"`script`\n" +": [`condition`](../commands/search/#query-condition-query-syntax-hash)におけるスクリプ" +"ト形式の指定に対応。もし`query`と両方同時に指定した場合には、両者の`and`条件と見なされます。" + +msgid "" +"`adjusters`\n" +": Corresponds to `adjusters`." +msgstr "" +"`adjusters`\n" +": `adjusters`に対応します。" + +msgid "" +"`sort_by`\n" +": Corresponds to [`sortBy`](../commands/search/#query-sortBy).\n" +" The value is a column name string." +msgstr "" +"`sort_by`\n" +": [`sortBy`](../commands/search/#query-sortBy)に対応します。\n" +" 値はカラム名の文字列です。" + +msgid "" +"`limit`\n" +": Corresponds to [`output.limit`](../commands/search/#query-output).\n" +" The value is an integer." +msgstr "" +"`limit`\n" +": [`output.limit`](../commands/search/#query-output)に対応。\n" +" 値は整数です。" + +msgid "" +"`offset`\n" +": Corresponds to [`output.offset`](../commands/search/#query-output).\n" +" The value is an integer." +msgstr "" +"`offset`\n" +": [`output.offset`](../commands/search/#query-output)に対応。\n" +" 値は整数です。" + +msgid "### Groonga HTTP server compatible API {#usage-groonga}" +msgstr "### Groonga HTTPサーバ互換API {#usage-groonga}" + +msgid "#### `GET /d/<command name>` {#usage-groonga-d}" +msgstr "#### `GET /d/<コマンド名>` {#usage-groonga-d}" + +msgid "(TBD)" +msgstr "(未稿)" + +msgid "" +" [basic tutorial]: ../../tutorial/basic/\n" +" [droonga-http-server]: https://github.com/droonga/droonga-http-server\n" +" [droonga-http-server npm module]: https://npmjs.org/package/droonga-http-ser" +"ver\n" +" [Node.js]: http://nodejs.org/" +msgstr "" Added: _po/ja/reference/1.0.3/index.po (+58 -0) 100644 =================================================================== --- /dev/null +++ _po/ja/reference/1.0.3/index.po 2014-05-19 16:48:30 +0900 (172b047) @@ -0,0 +1,58 @@ +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"PO-Revision-Date: 2014-03-05 12:52+0900\n" +"Language: ja\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" + +msgid "" +"---\n" +"title: Reference manuals\n" +"layout: en\n" +"---" +msgstr "" +"---\n" +"title: リファレンスマニュアル\n" +"layout: ja\n" +"---" + +msgid "" +"[Catalog](catalog/)\n" +": Describes details of `catalog.json` which defines behavior of the Droonga En" +"gine." +msgstr "" +"[カタログの仕様](catalog/)\n" +": Droonga Engineの振る舞いを定義する`catalog.json`の詳細。" + +msgid "" +"[Message format](message/)\n" +": Describes details of message format flowing in the Droonga Engines." +msgstr "" +"[メッセージの形式](message/)\n" +": Droonga Engine内を流れるメッセージの形式の詳細。" + +msgid "" +"[Commands](commands/)\n" +": Describes details of built-in commands available on the Droonga Engines." +msgstr "" +"[コマンドリファレンス](commands/)\n" +": Droonga Engineで利用可能な組み込みのコマンドの詳細。" + +msgid "" +"[HTTP Server](http-server/)\n" +": Describes usage of the [droonga-http-server](https://github.com/droonga/droo" +"nga-http-server)." +msgstr "" +"[HTTPサーバ](http-server/)\n" +": [droonga-http-server](https://github.com/droonga/droonga-http-server)の使用方法。" + +msgid "" +"[Plugin development](plugin/)\n" +": Describes details of public APIs to develop custom plugins for the Droonga E" +"ngine." +msgstr "" +"[プラグイン開発](plugin/)\n" +": Droonga Engine用の独自のプラグインを開発するための公開APIの詳細。" Added: _po/ja/reference/1.0.3/message/index.po (+398 -0) 100644 =================================================================== --- /dev/null +++ _po/ja/reference/1.0.3/message/index.po 2014-05-19 16:48:30 +0900 (d28d3bc) @@ -0,0 +1,398 @@ +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"PO-Revision-Date: 2014-03-05 12:52+0900\n" +"Language: ja\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" + +msgid "" +"---\n" +"title: Message format\n" +"layout: en\n" +"---" +msgstr "" +"---\n" +"title: メッセージ形式\n" +"layout: ja\n" +"---" + +msgid "" +"* TOC\n" +"{:toc}" +msgstr "" + +msgid "## Request {#request}" +msgstr "## リクエスト {#request}" + +msgid "The basic format of a request message is like following:" +msgstr "リクエストのメッセージの基本的な形式は以下の通りです。" + +msgid "" +" {\n" +" \"id\" : \"<ID of the message>\",\n" +" \"type\" : \"<Type of the message>\",\n" +" \"replyTo\" : \"<Route to the receiver>\",\n" +" \"dataset\" : \"<Name of the target dataset>\",\n" +" \"body\" : <Body of the message>\n" +" }" +msgstr "" +" {\n" +" \"id\" : \"<メッセージの識別子>\",\n" +" \"type\" : \"<メッセージの種類>\",\n" +" \"replyTo\" : \"<レスポンスの受信者へのパス>\",\n" +" \"dataset\" : \"<対象データセット名>\",\n" +" \"body\" : <メッセージ本文>\n" +" }" + +msgid "### `id` {#request-id}" +msgstr "" + +msgid "" +"Abstract\n" +": The unique identifier for the message." +msgstr "" +"概要\n" +": そのメッセージの一意な識別子。" + +msgid "" +"Value\n" +": An identifier string. You can use any string with any format as you like, if" +" only it is unique. The given id of a request message will be used for the ['i" +"nReplyTo`](#response-inReplyTo) information of its response." +msgstr "" +"値\n" +": 識別子となる文字列。一意でさえあれば、どんな形式のどんな文字列でも指定できます。値は対応するレスポンスの['inReplyTo`](#response-" +"inReplyTo)に使われます。" + +msgid "" +"Default value\n" +": Nothing. This is required information." +msgstr "" +"省略時の既定値\n" +": なし。この情報は省略できません。" + +msgid "### `type` {#request-type}" +msgstr "" + +msgid "" +"Abstract\n" +": The type of the message." +msgstr "" +"概要\n" +": そのメッセージの種類。" + +msgid "" +"Value\n" +": A type string of [a command](/reference/commands/)." +msgstr "" +"値\n" +": [コマンド](/ja/reference/commands/)の名前の文字列" + +msgid "### `replyTo` {#request-replyTo}" +msgstr "" + +msgid "" +"Abstract\n" +": The route to the response receiver." +msgstr "" +"概要\n" +": レスポンスの受信者へのパス。" + +msgid "" +"Value\n" +": An path string in the format: `<hostname>:<port>/<tag>`, for example: `local" +"host:24224/output`." +msgstr "" +"値\n" +": `<ホスト>:<ポート番号>/<タグ名>` で示されたパス文字列。例:`localhost:24224/output`." + +msgid "" +"Default value\n" +": Nothing. This is optional. If you specify no `replyTo`, then the response me" +"ssage will be thrown away." +msgstr "" +"省略時の既定値\n" +": なし。この情報は省略可能で、省略した場合はレスポンスのメッセージは単に捨てられます。" + +msgid "### `dataset` {#request-dataset}" +msgstr "" + +msgid "" +"Abstract\n" +": The target dataset." +msgstr "" +"概要\n" +": 対象となるデータセット。" + +msgid "" +"Value\n" +": A name string of a dataset." +msgstr "" +"値\n" +": データセット名の文字列。" + +msgid "### `body` {#request-body}" +msgstr "" + +msgid "" +"Abstract\n" +": The body of the message." +msgstr "" +"概要\n" +": メッセージの本文。" + +msgid "" +"Value\n" +": Object, string, number, boolean, or `null`." +msgstr "" +"値\n" +": オブジェクト、文字列、数値、真偽値、または `null`。" + +msgid "" +"Default value\n" +": Nothing. This is optional." +msgstr "" +"省略時の既定値\n" +": なし。この情報は省略可能です。" + +msgid "## Response {#response}" +msgstr "## レスポンス {#response}" + +msgid "The basic format of a response message is like following:" +msgstr "レスポンスのメッセージの基本的な形式は以下の通りです。" + +msgid "" +" {\n" +" \"type\" : \"<Type of the message>\",\n" +" \"inReplyTo\" : \"<ID of the related request message>\",\n" +" \"statusCode\" : <Status code>,\n" +" \"body\" : <Body of the message>,\n" +" \"errors\" : <Errors from nodes>\n" +" }" +msgstr "" +" {\n" +" \"type\" : \"<メッセージの種類>\",\n" +" \"inReplyTo\" : \"<対応するリクエストメッセージの識別子>\",\n" +" \"statusCode\" : <ステータスコード>,\n" +" \"body\" : <メッセージの本文>,\n" +" \"errors\" : <ノードから返されたエラー>\n" +" }" + +msgid "### `type` {#response-type}" +msgstr "" + +msgid "" +"Value\n" +": A type string. Generally it is a suffixed version of the type string of the " +"request message, with the suffix \".result\"." +msgstr "" +"値\n" +": メッセージの種類を示す文字列。多くの場合は、元のリクエストメッセージの `type` の値に `.result` という接尾辞を伴った文字列です。" + +msgid "### `inReplyTo` {#response-inReplyTo}" +msgstr "" + +msgid "" +"Abstract\n" +": The identifier of the related request message." +msgstr "" +"概要\n" +": 対応するリクエストメッセージの識別子。" + +msgid "" +"Value\n" +": An identifier string of the related request message." +msgstr "" +"値\n" +": 対応するリクエストメッセージの識別子の文字列 related request message." + +msgid "### `statusCode` {#response-statusCode}" +msgstr "" + +msgid "" +"Abstract\n" +": The result status for the request message." +msgstr "" +"概要\n" +": そのメッセージの種類。" + +msgid "" +"Value\n" +": A status code integer." +msgstr "" +"値\n" +": ステータスコードを示す整数。" + +msgid "Status codes of responses are similar to HTTP's one. Possible values:" +msgstr "レスポンスのステータスコードはHTTPのステータスコードに似ています。" + +msgid "" +"`200` and other `2xx` statuses\n" +": The command is successfully processed." +msgstr "" +"`200` およびその他の `2xx` のステータス\n" +": コマンドが正常に処理されたことを示します。" + +msgid "### `body` {#response-body}" +msgstr "" + +msgid "" +"Abstract\n" +": The result information for the request message." +msgstr "" +"概要\n" +": そのリクエストメッセージの処理結果の情報。" + +msgid "### `errors` {#response-errors}" +msgstr "" + +msgid "" +"Abstract\n" +": All errors from nodes." +msgstr "" +"概要\n" +": 各ノードから返されたすべてのエラー。" + +msgid "" +"Value\n" +": Object." +msgstr "" +"値\n" +": オブジェクト。" + +msgid "" +"This information will appear only when the command is distributed to multiple " +"volumes and they returned errors. Otherwise, the response message will have no" +" `errors` field. For more details, see [the \"Error response\" section](#error)." +msgstr "" +"この情報は、コマンドが複数のボリュームに分散して処理された時にのみ現れます。それ以外の場合、レスポンスメッセージは `errors` フィールドを含みません" +"。詳細は[エラーレスポンスの説明](#error)を参照して下さい。" + +msgid "## Error response {#error}" +msgstr "## エラーレスポンス {#error}" + +msgid "Some commands can return an error response." +msgstr "コマンドの中にはエラーを返す物があります。" + +msgid "" +"An error response has the `type` same to a regular response, but it has differ" +"ent `statusCode` and `body`. General type of the error is indicated by the `st" +"atusCode`, and details are reported as the `body`." +msgstr "" +"エラーレスポンスは通常のレスポンスと同じ `type` を伴って返されますが、通常のレスポンスとは異なる `statusCode` と `body` を持ち" +"ます。大まかなエラーの種類は `statusCode` で示され、詳細な情報は `body` の内容として返されます。" + +msgid "" +"If a command is distributed to multiple volumes and they return errors, then t" +"he response message will have an `error` field. All errors from all nodes are " +"stored to the field, like:" +msgstr "" +"コマンドが複数のボリュームに分散して処理されて、各ボリュームがエラーを返した場合、レスポンスメッセージは `errors` フィールドを持ちます。各ボリュー" +"ムから返されたエラーは以下のように保持されます:" + +msgid "" +" {\n" +" \"type\" : \"add.result\",\n" +" \"inReplyTo\" : \"...\",\n" +" \"statusCode\" : 400,\n" +" \"body\" : {\n" +" \"name\": \"UnknownTable\",\n" +" \"message\": ...\n" +" },\n" +" \"errors\" : {\n" +" \"/path/to/the/node1\" : {\n" +" \"statusCode\" : 400,\n" +" \"body\" : {\n" +" \"name\": \"UnknownTable\",\n" +" \"message\": ...\n" +" }\n" +" },\n" +" \"/path/to/the/node2\" : {\n" +" \"statusCode\" : 400,\n" +" \"body\" : {\n" +" \"name\": \"UnknownTable\",\n" +" \"message\": ...\n" +" }\n" +" }\n" +" }\n" +" }" +msgstr "" + +msgid "" +"In this case, one of all errors will be exported as the main message `body`, a" +"s a representative." +msgstr "このような場合、すべてのエラーの中で代表的な1つがメッセージの `body` に出力されます。" + +msgid "### Status codes of error responses {#error-status}" +msgstr "### エラーレスポンスのステータスコード {#error-status}" + +msgid "Status codes of error responses are similar to HTTP's one. Possible values:" +msgstr "エラーレスポンスのステータスコードはHTTPのステータスコードに似ています。" + +msgid "" +"`400` and other `4xx` statuses\n" +": An error of the request message." +msgstr "" +"`400` およびその他の `4xx` のステータス\n" +": リクエストのメッセージが原因でのエラーであることを示します。" + +msgid "" +"`500` and other `5xx` statuses\n" +": An internal error of the Droonga Engine." +msgstr "" +"`500` およびその他の `5xx` のステータス\n" +": Droonga Engine内部のエラーであることを示します。" + +msgid "### Body of error responses {#error-body}" +msgstr "### エラーレスポンスの `body` {#error-body}" + +msgid "The basic format of the body of an error response is like following:" +msgstr "エラーレスポンスの `body` の基本的な形式は以下の通りです。" + +msgid "" +" {\n" +" \"name\" : \"<Type of the error>\",\n" +" \"message\" : \"<Human readable details of the error>\",\n" +" \"detail\" : <Other extra information for the error, in various formats>\n" +" }" +msgstr "" +" {\n" +" \"name\" : \"<エラーの種類>\",\n" +" \"message\" : \"<人間が読みやすい形式で示されたエラーの詳細>\",\n" +" \"detail\" : <任意の形式の、追加のエラー情報>\n" +" }" + +msgid "If there is no detail, `detial` can be missing." +msgstr "追加の情報がない場合、 `detail` は出力されないことがあります。" + +msgid "#### Error types {#error-type}" +msgstr "#### エラーの種類 {#error-type}" + +msgid "There are some general error types for any command." +msgstr "すべてのコマンドに共通するエラーとして、以下の物があります。" + +msgid "" +"`MissingDatasetParameter`\n" +": Means you've forgotten to specify the `dataset`. The status code is `400`." +msgstr "" +"`MissingDatasetParameter`\n" +": `dataset` の指定がないことを示します。ステータスコードは `400` です。" + +msgid "" +"`UnknownDataset`\n" +": Means you've specified a dataset which is not existing. The status code is `" +"404`." +msgstr "" +"`UnknownDataset`\n" +": 指定されたデータセットが存在しないことを示します。ステータスコードは `404` です。" + +msgid "" +"`UnknownType`\n" +": Means there is no handler for the command given as the `type`. The status co" +"de is `400`." +msgstr "" +"`UnknownType`\n" +": `type` に指定されたコマンドを処理するハンドラが存在しない、未知のコマンドであることを示します。ステータスコードは `400` です。" Added: _po/ja/reference/1.0.3/plugin/adapter/index.po (+599 -0) 100644 =================================================================== --- /dev/null +++ _po/ja/reference/1.0.3/plugin/adapter/index.po 2014-05-19 16:48:30 +0900 (2fcd6fe) @@ -0,0 +1,599 @@ +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"PO-Revision-Date: 2014-03-05 12:52+0900\n" +"Language: ja\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" + +msgid "" +"---\n" +"title: API set for plugins on the adaption phase\n" +"layout: en\n" +"---" +msgstr "" +"---\n" +"title: アダプション・フェーズでのプラグインAPI\n" +"layout: ja\n" +"---" + +msgid "" +"* TOC\n" +"{:toc}" +msgstr "" + +msgid "## Abstract {#abstract}" +msgstr "## 概要 {#abstract}" + +msgid "" +"Each Droonga Engine plugin can have its *adapter*. On the adaption phase, adap" +"ters can modify both incoming messages (from the Protocol Adapter to the Droon" +"ga Engine, in other words, they are \"request\"s) and outgoing messages (from th" +"e Droonga Engine to the Protocol Adapter, in other words, they are \"response\"s" +")." +msgstr "" +"各々のDroonga Engineプラグインは、それ自身のための*アダプター*を持つことができます。アダプション・フェーズでは、アダプターは入力メッセージ(" +"Protocol AdapterからDroonga Engineへ送られてきたリクエストに相当)と出力メッセージ(Droonga EngineからProto" +"col Adapterへ送られるレスポンスに相当)の両方について変更を加えることができます。" + +msgid "### How to define an adapter? {#howto-define}" +msgstr "### アダプターの定義の仕方 {#howto-define}" + +msgid "For example, here is a sample plugin named \"foo\" with an adapter:" +msgstr "例えば、「foo」という名前のプラグインにアダプターを定義する場合は以下のようにします:" + +msgid "" +"~~~ruby\n" +"require \"droonga/plugin\"" +msgstr "" + +msgid "" +"module Droonga::Plugins::FooPlugin\n" +" extend Plugin\n" +" register(\"foo\")" +msgstr "" + +msgid "" +" class Adapter < Droonga::Adapter\n" +" # operations to configure this adapter\n" +" XXXXXX = XXXXXX" +msgstr "" +" class Adapter < Droonga::Adapter\n" +" # このアダプターを設定するための操作\n" +" XXXXXX = XXXXXX" + +msgid "" +" def adapt_input(input_message)\n" +" # operations to modify incoming messages\n" +" input_message.XXXXXX = XXXXXX\n" +" end" +msgstr "" +" def adapt_input(input_message)\n" +" # 入力メッセージを変更するための操作\n" +" input_message.XXXXXX = XXXXXX\n" +" end" + +msgid "" +" def adapt_output(output_message)\n" +" # operations to modify outgoing messages\n" +" output_message.XXXXXX = XXXXXX\n" +" end\n" +" end\n" +"end\n" +"~~~" +msgstr "" +" def adapt_output(output_message)\n" +" # 出力メッセージを変更するための操作\n" +" output_message.XXXXXX = XXXXXX\n" +" end\n" +" end\n" +"end\n" +"~~~" + +msgid "Steps to define an adapter:" +msgstr "アダプターを定義するための手順は以下の通りです:" + +msgid "" +" 1. Define a module for your plugin (ex. `Droonga::Plugins::FooPlugin`) and re" +"gister it as a plugin. (required)\n" +" 2. Define an adapter class (ex. `Droonga::Plugins::FooPlugin::Adapter`) inher" +"iting [`Droonga::Adapter`](#classes-Droonga-Adapter). (required)\n" +" 3. [Configure conditions to apply the adapter](#howto-configure). (required)\n" +" 4. Define adaption logic for incoming messages as [`#adapt_input`](#classes-D" +"roonga-Adapter-adapt_input). (optional)\n" +" 5. Define adaption logic for outgoing messages as [`#adapt_output`](#classes-" +"Droonga-Adapter-adapt_output). (optional)" +msgstr "" +" 1. プラグイン用のモジュール(例:`Droonga::Plugins::FooPlugin`)を定義し、プラグインとして登録する。(必須)\n" +" 2. [`Droonga::Adapter`](#classes-Droonga-Adapter)を継承したアダプタークラス(例:`Droonga::Pl" +"ugins::FooPlugin::Adapter`)を定義する。(必須)\n" +" 3. [アダプターを適用する条件を設定する](#howto-configure)。(必須)\n" +" 4. 入力メッセージに対する変更操作を[`#adapt_input`](#classes-Droonga-Adapter-adapt_input)として定" +"義する。(任意)\n" +" 5. 出力メッセージに対する変更操作を[`#adapt_output`](#classes-Droonga-Adapter-adapt_output)とし" +"て定義する。(任意)" + +msgid "" +"See also the [plugin development tutorial](../../../tutorial/plugin-developmen" +"t/adapter/)." +msgstr "[プラグイン開発のチュートリアル](../../../tutorial/plugin-development/adapter/)も参照して下さい。" + +msgid "### How an adapter works? {#how-works}" +msgstr "### アダプターはどのように操作するか {#how-works}" + +msgid "An adapter works like following:" +msgstr "アダプターは以下のように動作します:" + +msgid "" +" 1. The Droonga Engine starts.\n" +" * A global instance of the adapter class (ex. `Droonga::Plugins::FooPlugin" +"::Adapter`) is created and it is registered.\n" +" * The input pattern and the output pattern are registered.\n" +" * The Droonga Engine starts to wait for incoming messages.\n" +" 2. An incoming message is transferred from the Protocol Adapter to the Droong" +"a Engine.\n" +" Then, the adaption phase (for an incoming message) starts.\n" +" * The adapter's [`#adapt_input`](#classes-Droonga-Adapter-adapt_input) is " +"called, if the message matches to the [input matching pattern](#config) of the" +" adapter.\n" +" * The method can modify the given incoming message, via [its methods](#cla" +"sses-Droonga-InputMessage).\n" +" 3. After all adapters are applied, the adaption phase for an incoming message" +" ends, and the message is transferred to the next \"planning\" phase.\n" +" 4. An outgoing message returns from the previous \"collection\" phase.\n" +" Then, the adaption phase (for an outgoing message) starts.\n" +" * The adapter's [`#adapt_output`](#classes-Droonga-Adapter-adapt_output) i" +"s called, if the message meets following both requirements:\n" +" - It is originated from an incoming message which was processed by the a" +"dapter itself.\n" +" - It matches to the [output matching pattern](#config) of the adapter.\n" +" * The method can modify the given outgoing message, via [its methods](#cla" +"sses-Droonga-OutputMessage).\n" +" 5. After all adapters are applied, the adaption phase for an outgoing message" +" ends, and the outgoing message is transferred to the Protocol Adapter." +msgstr "" +" 1. Droonga Engineが起動する。\n" +" * アダプタークラス(例:`Droonga::Plugins::FooPlugin::Adapter`)の唯一のインスタンスが作られ、登録される。\n" +" * 入力のマッチングパターンおよび出力のマッチングパターンが登録される。\n" +" * Droonga Engineが起動し、入力メッセージを待ち受ける。\n" +" 2. 入力メッセージがProtocol AdapterからDroonga Engineへ送られてくる。\n" +" この時点で(入力メッセージ用の)アダプション・フェーズが開始される。\n" +" * そのメッセージが[入力のマッチングパターン](#config)にマッチするアダプターについて、アダプターの[`#adapt_input`](#c" +"lasses-Droonga-Adapter-adapt_input)が呼ばれる。\n" +" * このメソッドは、[入力メッセージ自身が持つメソッド](#classes-Droonga-InputMessage)を通じて入力メッセージを変更す" +"ることができる。\n" +" 3. すべてのアダプターが適用された時点で、入力メッセージ用のアダプション・フェーズが終了し、メッセージが次のプランニング・フェーズに送られる。\n" +" 4. 出力メッセージが前のコレクション・フェーズから送られてくる。\n" +" この時点で(出力メッセージ用の)アダプション・フェーズが開始される。\n" +" * そのメッセージ外貨の両方の条件を満たす場合に、アダプターの[`#adapt_output`](#classes-Droonga-Adapter-" +"adapt_output)が呼ばれる:\n" +" - そのメッセージが、そのアダプター自身によって処理された入力メッセージに起因した物である。\n" +" - そのメッセージが、アダプターの[出力のマッチングパターン](#config)にマッチする。\n" +" * このメソッドは、[出力メッセージ自身が持つメソッド](#classes-Droonga-OutputMessage)を通じて出力メッセージを変更" +"することができる。\n" +" 5. すべてのアダプターが適用された時点で、出力メッセージ用のアダプション・フェーズが終了し、メッセージがProtocol Adapterに送られる。" + +msgid "" +"As described above, the Droonga Engine creates only one global instance of the" +" adapter class for each plugin.\n" +"You should not keep stateful information for a pair of incoming and outgoing m" +"essages as instance variables of the adapter itself.\n" +"Instead, you should give stateful information as a part of the incoming messag" +"e body, and receive it from the body of the corresponding outgoing message." +msgstr "" +"上記の通り、Droonga Engineは各プラグインのアダプタークラスについて、インスタンスを全体で1つだけ生成します。\n" +"対になった入力メッセージと出力メッセージのための状態を示す情報をアダプター自身のインスタンス変数として保持してはいけません。\n" +"代わりに、状態を示す情報を入力メッセージのbodyの一部として埋め込み、対応する出力メッセージのbodyから取り出すようにして下さい。" + +msgid "" +"Any error raised from the adapter is handled by the Droonga Engine itself. See" +" also [error handling][]." +msgstr "" +"アダプター内で発生したすべてのエラーは、Droonga Engine自身によって処理されます。[エラー処理][error handling]も併せて参照して" +"下さい。" + +msgid "## Configurations {#config}" +msgstr "## 設定 {#config}" + +msgid "" +"`input_message.pattern` ([matching pattern][], optional, default=`nil`)\n" +": A [matching pattern][] for incoming messages.\n" +" If no pattern (`nil`) is given, any message is regarded as \"matched\"." +msgstr "" +"`input_message.pattern` ([マッチングパターン][matching pattern], 省略可能, 初期値=`nil`)\n" +": 入力メッセージに対する[マッチングパターン][matching pattern]。\n" +" パターンが指定されていない(もしくは`nil`が指定された)場合は、すべてのメッセージがマッチします。" + +msgid "" +"`output_message.pattern` ([matching pattern][], optional, default=`nil`)\n" +": A [matching pattern][] for outgoing messages.\n" +" If no pattern (`nil`) is given, any message is regarded as \"matched\"." +msgstr "" +"`output_message.pattern` ([マッチングパターン][matching pattern], 省略可能, 初期値=`nil`)\n" +": 出力メッセージに対する[マッチングパターン][matching pattern]。\n" +" パターンが指定されていない(もしくは`nil`が指定された)場合は、すべてのメッセージがマッチします。" + +msgid "## Classes and methods {#classes}" +msgstr "## クラスとメソッド {#classes}" + +msgid "### `Droonga::Adapter` {#classes-Droonga-Adapter}" +msgstr "" + +msgid "" +"This is the common base class of any adapter. Your plugin's adapter class must" +" inherit this." +msgstr "これはすべてのアダプターに共通の基底クラスです。独自プラグインのアダプタークラスは、このクラスを継承する必要があります。" + +msgid "#### `#adapt_input(input_message)` {#classes-Droonga-Adapter-adapt_input}" +msgstr "" + +msgid "" +"This method receives a [`Droonga::InputMessage`](#classes-Droonga-InputMessage" +") wrapped incoming message.\n" +"You can modify the incoming message via its methods." +msgstr "" +"このメソッドは、[`Droonga::InputMessage`](#classes-Droonga-InputMessage)でラップされた入力メッセージ" +"を受け取ります。\n" +"入力メッセージは、メソッドを通じて内容を変更することができます。" + +msgid "" +"In this base class, this method is defined as just a placeholder and it does n" +"othing.\n" +"To modify incoming messages, you have to override it by yours, like following:" +msgstr "" +"この基底クラスにおいて、このメソッドは何もしない単なるプレースホルダとして定義されています。\n" +"入力メッセージを変更するには、以下のようにメソッドを再定義して下さい:" + +msgid "" +"~~~ruby\n" +"module Droonga::Plugins::QueryFixer\n" +" class Adapter < Droonga::Adapter\n" +" def adapt_input(input_message)\n" +" input_message.body[\"query\"] = \"fixed query\"\n" +" end\n" +" end\n" +"end\n" +"~~~" +msgstr "" + +msgid "#### `#adapt_output(output_message)` {#classes-Droonga-Adapter-adapt_output}" +msgstr "" + +msgid "" +"This method receives a [`Droonga::OutputMessage`](#classes-Droonga-OutputMessa" +"ge) wrapped outgoing message.\n" +"You can modify the outgoing message via its methods." +msgstr "" +"このメソッドは、[`Droonga::OutputMessage`](#classes-Droonga-OutputMessage)でラップされた出力メッセ" +"ージを受け取ります。\n" +"出力メッセージは、メソッドを通じて内容を変更することができます。" + +msgid "" +"In this base class, this method is defined as just a placeholder and it does n" +"othing.\n" +"To modify outgoing messages, you have to override it by yours, like following:" +msgstr "" +"この基底クラスにおいて、このメソッドは何もしない単なるプレースホルダとして定義されています。\n" +"出力メッセージを変更するには、以下のようにメソッドを再定義して下さい:" + +msgid "" +"~~~ruby\n" +"module Droonga::Plugins::ErrorConcealer\n" +" class Adapter < Droonga::Adapter\n" +" def adapt_output(output_message)\n" +" output_message.status_code = Droonga::StatusCode::OK\n" +" end\n" +" end\n" +"end\n" +"~~~" +msgstr "" + +msgid "### `Droonga::InputMessage` {#classes-Droonga-InputMessage}" +msgstr "" + +msgid "#### `#type`, `#type=(type)` {#classes-Droonga-InputMessage-type}" +msgstr "" + +msgid "This returns the `\"type\"` of the incoming message." +msgstr "入力メッセージの`\"type\"`の値を返します。" + +msgid "You can override it by assigning a new string value, like:" +msgstr "以下のように、新しい文字列値を代入することで値を変更できます:" + +msgid "" +"~~~ruby\n" +"module Droonga::Plugins::MySearch\n" +" class Adapter < Droonga::Adapter\n" +" input_message.pattern = [\"type\", :equal, \"my-search\"]" +msgstr "" + +msgid "" +" def adapt_input(input_message)\n" +" p input_message.type\n" +" # => \"my-search\"\n" +" # This message will be handled by a plugin\n" +" # for the custom \"my-search\" type." +msgstr "" +" def adapt_input(input_message)\n" +" p input_message.type\n" +" # => \"my-search\"\n" +" # このメッセージは「my-search」というメッセージタイプに\n" +" # 対応したプラグインによって処理される。" + +msgid " input_message.type = \"search\"" +msgstr "" + +msgid "" +" p input_message.type\n" +" # => \"search\"\n" +" # The messge type (type) is changed.\n" +" # This message will be handled by the \"search\" plugin,\n" +" # as a regular search request.\n" +" end\n" +" end\n" +"end\n" +"~~~" +msgstr "" +" p input_message.type\n" +" # => \"search\"\n" +" # メッセージタイプが変更された。\n" +" # このメッセージはsearchプラグインによって、\n" +" # 通常の検索リクエストとして処理される。\n" +" end\n" +" end\n" +"end\n" +"~~~" + +msgid "#### `#body`, `#body=(body)` {#classes-Droonga-InputMessage-body}" +msgstr "" + +msgid "This returns the `\"body\"` of the incoming message." +msgstr "入力メッセージの`\"body\"`の値を返します。" + +msgid "You can override it by assigning a new value, partially or fully. For example:" +msgstr "以下のように、新しい値を代入したり部分的に値を代入したりすることで、値を変更することができます:" + +msgid "" +"~~~ruby\n" +"module Droonga::Plugins::MinimumLimit\n" +" class Adapter < Droonga::Adapter\n" +" input_message.pattern = [\"type\", :equal, \"search\"]" +msgstr "" + +msgid " MAXIMUM_LIMIT = 10" +msgstr "" + +msgid "" +" def adapt_input(input_message)\n" +" input_message.body[\"queries\"].each do |name, query|\n" +" query[\"output\"] ||= {}\n" +" query[\"output\"][\"limit\"] ||= MAXIMUM_LIMIT\n" +" query[\"output\"][\"limit\"] = [query[\"output\"][\"limit\"], MAXIMUM_LIMIT].m" +"in\n" +" end\n" +" # Now, all queries have \"output.limit=10\".\n" +" end\n" +" end\n" +"end\n" +"~~~" +msgstr "" +" def adapt_input(input_message)\n" +" input_message.body[\"queries\"].each do |name, query|\n" +" query[\"output\"] ||= {}\n" +" query[\"output\"][\"limit\"] ||= MAXIMUM_LIMIT\n" +" query[\"output\"][\"limit\"] = [query[\"output\"][\"limit\"], MAXIMUM_LIMIT].m" +"in\n" +" end\n" +" # この時点で、すべての検索クエリが\"output.limit=10\"の指定を持っている。\n" +" end\n" +" end\n" +"end\n" +"~~~" + +msgid "Another case:" +msgstr "別の例:" + +msgid "" +" def adapt_input(input_message)\n" +" # Extract the query string from the custom type message.\n" +" query_string = input_message[\"body\"][\"query\"]" +msgstr "" +" def adapt_input(input_message)\n" +" # 独自形式のメッセージからクエリ文字列を取り出す。\n" +" query_string = input_message[\"body\"][\"query\"]" + +msgid "" +" # Construct internal search request for the \"search\" type.\n" +" input_message.type = \"search\"\n" +" input_message.body = {\n" +" \"queries\" => {\n" +" \"source\" => \"Store\",\n" +" \"condition\" => {\n" +" \"query\" => query_string,\n" +" \"matchTo\" => [\"name\"],\n" +" },\n" +" \"output\" => {\n" +" \"elements\" => [\"records\"],\n" +" \"limit\" => 10,\n" +" },\n" +" },\n" +" }\n" +" # Now, both \"type\" and \"body\" are completely replaced.\n" +" end\n" +" end\n" +"end\n" +"~~~" +msgstr "" +" # \"search\"型の内部的な検索リクエストを組み立てる。\n" +" input_message.type = \"search\"\n" +" input_message.body = {\n" +" \"queries\" => {\n" +" \"source\" => \"Store\",\n" +" \"condition\" => {\n" +" \"query\" => query_string,\n" +" \"matchTo\" => [\"name\"],\n" +" },\n" +" \"output\" => {\n" +" \"elements\" => [\"records\"],\n" +" \"limit\" => 10,\n" +" },\n" +" },\n" +" }\n" +" # この時点で、\"type\"と\"body\"は両方とも完全に置き換えられている。\n" +" end\n" +" end\n" +"end\n" +"~~~" + +msgid "### `Droonga::OutputMessage` {#classes-Droonga-OutputMessage}" +msgstr "" + +msgid "" +"#### `#status_code`, `#status_code=(status_code)` {#classes-Droonga-OutputMess" +"age-status_code}" +msgstr "" + +msgid "This returns the `\"statusCode\"` of the outgoing message." +msgstr "出力メッセージの`\"statusCode\"`の値を返します。" + +msgid "You can override it by assigning a new status code. For example:" +msgstr "以下のように、新しいステータスコードを代入することで値を変更できます:" + +msgid "" +"~~~ruby\n" +"module Droonga::Plugins::ErrorConcealer\n" +" class Adapter < Droonga::Adapter\n" +" input_message.pattern = [\"type\", :equal, \"search\"]" +msgstr "" + +msgid "" +" def adapt_output(output_message)\n" +" unless output_message.status_code == StatusCode::InternalServerError\n" +" output_message.status_code = Droonga::StatusCode::OK\n" +" output_message.body = {}\n" +" output_message.errors = nil\n" +" # Now any internal server error is ignored and clients\n" +" # receive regular responses.\n" +" end\n" +" end\n" +" end\n" +"end\n" +"~~~" +msgstr "" +" def adapt_output(output_message)\n" +" unless output_message.status_code == StatusCode::InternalServerError\n" +" output_message.status_code = Droonga::StatusCode::OK\n" +" output_message.body = {}\n" +" output_message.errors = nil\n" +" # この時点で、内部的なサーバーエラーはすべて無視されるため\n" +" # クライアントは通常のレスポンスを受け取る事になる。\n" +" end\n" +" end\n" +" end\n" +"end\n" +"~~~" + +msgid "#### `#errors`, `#errors=(errors)` {#classes-Droonga-OutputMessage-errors}" +msgstr "" + +msgid "This returns the `\"errors\"` of the outgoing message." +msgstr "出力メッセージの`\"errors\"`の値を返します。" + +msgid "" +"You can override it by assigning new error information, partially or fully. Fo" +"r example:" +msgstr "以下のように、新しいエラー情報を代入したり値を部分的に書き換えたりする事ができます:" + +msgid "" +"~~~ruby\n" +"module Droonga::Plugins::ErrorExporter\n" +" class Adapter < Droonga::Adapter\n" +" input_message.pattern = [\"type\", :equal, \"search\"]" +msgstr "" + +msgid "" +" def adapt_output(output_message)\n" +" output_message.errors.delete(secret_database)\n" +" # Delete error information from secret database" +msgstr "" +" def adapt_output(output_message)\n" +" output_message.errors.delete(secret_database)\n" +" # 秘密のデータベースからのエラー情報を削除する。" + +msgid "" +" output_message.body[\"errors\"] = {\n" +" \"records\" => output_message.errors.collect do |database, error|\n" +" {\n" +" \"database\" => database,\n" +" \"error\" => error\n" +" }\n" +" end,\n" +" }\n" +" # Convert error informations to a fake search result named \"errors\".\n" +" end\n" +" end\n" +"end\n" +"~~~" +msgstr "" +" output_message.body[\"errors\"] = {\n" +" \"records\" => output_message.errors.collect do |database, error|\n" +" {\n" +" \"database\" => database,\n" +" \"error\" => error\n" +" }\n" +" end,\n" +" }\n" +" # エラー情報を、\"error\"という名前の擬似的な検索結果に変換する。\n" +" end\n" +" end\n" +"end\n" +"~~~" + +msgid "#### `#body`, `#body=(body)` {#classes-Droonga-OutputMessage-body}" +msgstr "" + +msgid "This returns the `\"body\"` of the outgoing message." +msgstr "出力メッセージの`\"body\"`の値を返します。" + +msgid "" +"~~~ruby\n" +"module Droonga::Plugins::SponsoredSearch\n" +" class Adapter < Droonga::Adapter\n" +" input_message.pattern = [\"type\", :equal, \"search\"]" +msgstr "" + +msgid "" +" def adapt_output(output_message)\n" +" output_message.body.each do |name, result|\n" +" next unless result[\"records\"]\n" +" result[\"records\"].unshift(sponsored_entry)\n" +" end\n" +" # Now all search results include sponsored entry.\n" +" end" +msgstr "" +" def adapt_output(output_message)\n" +" output_message.body.each do |name, result|\n" +" next unless result[\"records\"]\n" +" result[\"records\"].unshift(sponsored_entry)\n" +" end\n" +" # これにより、すべての検索結果が広告エントリを含むようになる。\n" +" end" + +msgid "" +" def sponsored_entry\n" +" {\n" +" \"title\"=> \"SALE!\",\n" +" \"url\"=> \"http://...\"\n" +" }\n" +" end\n" +" end\n" +"end\n" +"~~~" +msgstr "" + +msgid "" +" [matching pattern]: ../matching-pattern/\n" +" [error handling]: ../error/" +msgstr "" Added: _po/ja/reference/1.0.3/plugin/collector/index.po (+106 -0) 100644 =================================================================== --- /dev/null +++ _po/ja/reference/1.0.3/plugin/collector/index.po 2014-05-19 16:48:30 +0900 (311afb0) @@ -0,0 +1,106 @@ +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"PO-Revision-Date: 2014-03-05 12:52+0900\n" +"Language: ja\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" + +msgid "" +"---\n" +"title: Collector\n" +"layout: en\n" +"---" +msgstr "" +"---\n" +"title: コレクター\n" +"layout: ja\n" +"---" + +msgid "" +"* TOC\n" +"{:toc}" +msgstr "" + +msgid "## Abstract {#abstract}" +msgstr "## 概要 {#abstract}" + +msgid "" +"A collector merges two input values to single value.\n" +"The Droonga Engine tries to collect three or more values by applying the speci" +"fied collector for two of them again and again." +msgstr "" +"コレクターは、2つの入力値を1つの値に結合します。\n" +"Droonga Engineは3つ以上の値に対しても、指定されたコレクターを繰り返し適用することによって、それらを1つの値にします。" + +msgid "## Built-in collector classes {#builtin-collectors}" +msgstr "## 組み込みのコレクタークラス {#builtin-collectors}" + +msgid "" +"There are some pre-defined collector classes used by built-in plugins.\n" +"Of course they are available for your custom plugins." +msgstr "" +"組み込みのプラグインによって使われている、定義済みのコレクタークラスがいくつかあります。\n" +"これらは当然ですが、自作プラグインからも利用することができます。" + +msgid "### `Droonga::Collectors::And`" +msgstr "" + +msgid "" +"Returns a result from comparison of two values by the `and` logical operator.\n" +"If both values are logically equal to `true`, then one of them (it is indeterm" +"inate) becomes the result." +msgstr "" +"`and` 論理演算子によって2つの値を比較した結果を返します。\n" +"両方の値が論理的に真である場合、どちらかの値が返されます(どちらが返されるかは不定です)。" + +msgid "" +"Values `null` (`nil`) and `false` are treated as `false`.\n" +"Otherwise `true`." +msgstr "`null` (`nil`) および `false` は論理的に偽として扱われ、それ以外の場合はすべて真として扱われます。" + +msgid "### `Droonga::Collectors::Or`" +msgstr "" + +msgid "" +"Returns a result from comparison of two values by the `or` logical operator.\n" +"If only one of them is logically equal to `true`, then the value becomes the r" +"esult.\n" +"Otherwise, if values are logically same, one of them (it is indeterminate) bec" +"omes the result." +msgstr "" +"`or` 論理演算子によって2つの値を比較した結果を返します。\n" +"片方の値だけが論理的に真である場合、その値が返り値となります。\n" +"そうでなく2つの値が論理的に等しい場合は、どちらかの値が返されます(どちらが返されるかは不定です)。" + +msgid "### `Droonga::Collectors::Sum`" +msgstr "" + +msgid "Returns a summarized value of two input values." +msgstr "2つの値のまとめた結果を返します。" + +msgid "This collector works a little complicatedly." +msgstr "このコレクターは若干複雑な動作をします。" + +msgid "" +" * If one of values is equal to `null` (`nil`), then the other value becomes t" +"he result.\n" +" * If both values are hash, then a merged hash becomes the result.\n" +" * The result hash has all keys of two hashes.\n" +" If both have same keys, then one of their values appears as the value of " +"the key in the reuslt hash.\n" +" * It is indeterminate which value becomes the base.\n" +" * Otherwise the result of `a + b` becomes the result.\n" +" * If they are arrays or strings, a concatenated value becomes the result.\n" +" It is indeterminate which value becomes the lefthand." +msgstr "" +" * 片方の値が `null` (`nil`) である場合、もう片方の値を返します。\n" +" * 両方の値がハッシュである場合、ハッシュの結合結果を値として返します。\n" +" * 結果のハッシュは、2つのハッシュが持つキーのすべてを持ちます。\n" +" 両方のハッシュでキーが重複した場合、重複したキーの値はどちらかのハッシュの値となります。\n" +" * 重複するキーの値についてどちらのハッシュの値が使われるかは不定です。\n" +" * それ以外の場合は、 `a + b` の結果を値として返します。\n" +" * 両方ともの値が配列または文字列であった場合、それらを連結した結果を値として返します。\n" +" どちらの値が左辺になるかは不定です。" Added: _po/ja/reference/1.0.3/plugin/error/index.po (+148 -0) 100644 =================================================================== --- /dev/null +++ _po/ja/reference/1.0.3/plugin/error/index.po 2014-05-19 16:48:30 +0900 (bdf364a) @@ -0,0 +1,148 @@ +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"PO-Revision-Date: 2014-03-05 12:52+0900\n" +"Language: ja\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" + +msgid "" +"---\n" +"title: Error handling in plugins\n" +"layout: en\n" +"---" +msgstr "" +"---\n" +"title: プラグインでのエラーの扱い\n" +"layout: ja\n" +"---" + +msgid "" +"* TOC\n" +"{:toc}" +msgstr "" + +msgid "## Abstract {#abstract}" +msgstr "## 概要 {#abstract}" + +msgid "" +"Any unhandled error raised from a plugin is returned as an [error response][] " +"for the corresponding incoming message, with the status code `500` (means \"int" +"ernal error\")." +msgstr "" +"プラグイン内部で発生した例外のうち、そのプラグイン自身によって補足されなかった物は、すべて、入力メッセージに対する[エラーレスポンス][error resp" +"onse]として返されます。この時のエラーレスポンスのステータスコードは`500`(Internal Errorを意味する)です。" + +msgid "" +"If you want formatted error information to be returned, then rescue errors and" +" raise your custom errors inheriting `Droonga::ErrorMessage::BadRequest` or `D" +"roonga::ErrorMessage::InternalServerError` instead of raw errors.\n" +"(By the way, they are already included to the base class of plugins so you can" +" define your custom errors easily like: `class CustomError < BadRequest`)" +msgstr "" +"整形されたエラー情報を返したい場合は、低レベルのエラーを捕捉した上で、`Droonga::ErrorMessage::BadRequest`または`Droo" +"nga::ErrorMessage::InternalServerError`を継承したカスタムエラークラスでラップして再度`raise`して下さい。\n" +"(ちなみに、これらの基底クラスはプラグインの名前空間に初期状態で`include`されているため、エラークラスの定義時には単に`class CustomEr" +"ror < BadRequest`などと書くだけで参照できます。)" + +msgid "## Built-in error classes {#builtin-errors}" +msgstr "## 組み込みのエラークラス {#builtin-errors}" + +msgid "" +"There are some pre-defined error classes used by built-in plugins and the Droo" +"nga Engine itself." +msgstr "組み込みのプラグインやDroonga Engine自身によってあらかじめ定義されているエラークラスとしては、以下の物があります。" + +msgid "### `Droonga::ErrorMessage::NotFound`" +msgstr "" + +msgid "" +"Means an error which the specified resource is not found in the dataset or any" +" source. For example:" +msgstr "データセットまたは指定された情報ソースの中に、探している情報が見つからなかったことを示す。例:" + +msgid "" +" # the second argument means \"details\" of the error. (optional)\n" +" raise Droonga::NotFound.new(\"#{name} is not found!\", :elapsed_time => elap" +"sed_time)" +msgstr "" +" # 第2引数はエラーの詳細な情報。(省略可能)\n" +" raise Droonga::NotFound.new(\"#{name} is not found!\", :elapsed_time => elap" +"sed_time)" + +msgid "### `Droonga::ErrorMessage::BadRequest`" +msgstr "" + +msgid "" +"Means any error originated from the incoming message itself, ex. syntax error," +" validation error, and so on. For example:" +msgstr "文法エラーやバリデーションエラーなど、入力メッセージ自体にエラーが含まれていたことを示す。例:" + +msgid "" +" # the second argument means \"details\" of the error. (optional)\n" +" raise Droonga::NotFound.new(\"Syntax error in #{query}!\", :detail => detail" +")" +msgstr "" +" # 第2引数はエラーの詳細な情報。(省略可能)\n" +" raise Droonga::NotFound.new(\"Syntax error in #{query}!\", :detail => detail" +")" + +msgid "### `Droonga::ErrorMessage::InternalServerError`" +msgstr "" + +msgid "" +"Means other unknown error, ex. timed out, file I/O error, and so on. For examp" +"le:" +msgstr "タイムアウト、ファイル入出力のエラーなど、その他の未知のエラーであることを示す。例:" + +msgid "" +" # the second argument means \"details\" of the error. (optional)\n" +" raise Droonga::MessageProcessingError.new(\"busy!\", :elapsed_time => elapse" +"d_time)" +msgstr "" +" # 第2引数はエラーの詳細な情報。(省略可能)\n" +" raise Droonga::MessageProcessingError.new(\"busy!\", :elapsed_time => elapse" +"d_time)" + +msgid "## Built-in status codes {#builtin-status-codes}" +msgstr "## 組み込みのステータスコード {#builtin-status-codes}" + +msgid "" +"You should use following or other status codes as [a matter of principle](../." +"./message/#error-status)." +msgstr "" +"エラーのステータスコードとしては、以下のステータスコードか、もしくは[慣習に従ったステータスコード](../../message/#error-status" +")を使用します。" + +msgid "" +"`Droonga::StatusCode::OK`\n" +": Equals to `200`." +msgstr "" +"`Droonga::StatusCode::OK`\n" +": `200`と等価。" + +msgid "" +"`Droonga::StatusCode::NOT_FOUND`\n" +": Equals to `404`." +msgstr "" +"`Droonga::StatusCode::NOT_FOUND`\n" +": `404`と等価。" + +msgid "" +"`Droonga::StatusCode::BAD_REQUEST`\n" +": Equals to `400`." +msgstr "" +"`Droonga::StatusCode::BAD_REQUEST`\n" +": `400`と等価。" + +msgid "" +"`Droonga::StatusCode::INTERNAL_ERROR`\n" +": Equals to `500`." +msgstr "" +"`Droonga::StatusCode::INTERNAL_ERROR`\n" +": `500`と等価。" + +msgid " [error response]: ../../message/#error" +msgstr "" Added: _po/ja/reference/1.0.3/plugin/handler/index.po (+457 -0) 100644 =================================================================== --- /dev/null +++ _po/ja/reference/1.0.3/plugin/handler/index.po 2014-05-19 16:48:30 +0900 (4dc95d2) @@ -0,0 +1,457 @@ +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"PO-Revision-Date: 2014-03-05 12:52+0900\n" +"Language: ja\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" + +msgid "" +"---\n" +"title: API set for plugins on the handling phase\n" +"layout: en\n" +"---" +msgstr "" +"---\n" +"title: ハンドリング・フェーズでのプラグインAPI\n" +"layout: ja\n" +"---" + +msgid "" +"* TOC\n" +"{:toc}" +msgstr "" + +msgid "## Abstract {#abstract}" +msgstr "## 概要 {#abstract}" + +msgid "" +"Each Droonga Engine plugin can have its *handler*.\n" +"On the handling phase, handlers can process a request and return a result." +msgstr "" +"各々のDroonga Engineプラグインは、それ自身のための*ハンドラー*を持つことができます。ハンドリング・フェーズでは、ハンドラーはリクエストを処理" +"して結果を返すことができます。" + +msgid "### How to define a handler? {#howto-define}" +msgstr "### ハンドラーの定義の仕方 {#howto-define}" + +msgid "For example, here is a sample plugin named \"foo\" with a handler:" +msgstr "例えば、「foo」という名前のプラグインにハンドラーを定義する場合は以下のようにします:" + +msgid "" +"~~~ruby\n" +"require \"droonga/plugin\"" +msgstr "" + +msgid "" +"module Droonga::Plugins::FooPlugin\n" +" extend Plugin\n" +" register(\"foo\")" +msgstr "" + +msgid "" +" define_single_step do |step|\n" +" step.name = \"foo\"\n" +" step.handler = :Handler\n" +" step.collector = Collectors::And\n" +" end" +msgstr "" + +msgid "" +" class Handler < Droonga::Handler\n" +" def handle(message)\n" +" # operations to process a request\n" +" end\n" +" end\n" +"end\n" +"~~~" +msgstr "" +" class Handler < Droonga::Handler\n" +" def handle(message)\n" +" # リクエストを処理するための操作\n" +" end\n" +" end\n" +"end\n" +"~~~" + +msgid "Steps to define a handler:" +msgstr "ハンドラーを定義するための手順は以下の通りです:" + +msgid "" +" 1. Define a module for your plugin (ex. `Droonga::Plugins::FooPlugin`) and re" +"gister it as a plugin. (required)\n" +" 2. Define a \"single step\" corresponding to the handler you are going to imple" +"ment, via [`Droonga::SingleStepDefinition`](#class-Droonga-SingleStepDefinitio" +"n). (required)\n" +" 3. Define a handler class (ex. `Droonga::Plugins::FooPlugin::Handler`) inheri" +"ting [`Droonga::Handler`](#classes-Droonga-Handler). (required)\n" +" 4. Define handling logic for requests as [`#handle`](#classes-Droonga-Handler" +"-handle). (optional)" +msgstr "" +" 1. プラグイン用のモジュール(例:`Droonga::Plugins::FooPlugin`)を定義し、プラグインとして登録する。(必須)\n" +" 2. [`Droonga::SingleStepDefinition`](#class-Droonga-SingleStepDefinition)を使い、" +"実装しようとしているハンドラーに対応する「single step」を定義する。(必須)\n" +" 3. [`Droonga::Handler`](#classes-Droonga-Handler)を継承したハンドラークラス(例:`Droonga::Pl" +"ugins::FooPlugin::Handler`)を定義する。(必須)\n" +" 4. リクエストを処理する操作を[`#handle`](#classes-Droonga-Handler-handle)として定義する。(任意)\n" + +msgid "" +"See also the [plugin development tutorial](../../../tutorial/plugin-developmen" +"t/handler/)." +msgstr "[プラグイン開発チュートリアル](../../../tutorial/plugin-development/handler/)も併せて参照して下さい。" + +msgid "### How a handler works? {#how-works}" +msgstr "### ハンドラーはどのように操作するか {#how-works}" + +msgid "A handler works like following:" +msgstr "ハンドラーは以下のように動作します:" + +msgid "" +" 1. The Droonga Engine starts.\n" +" * Your custom steps are registered.\n" +" Your custom handler classes also.\n" +" * Then the Droonga Engine starts to wait for request messages.\n" +" 2. A request message is transferred from the adaption phase.\n" +" Then, the processing phase starts.\n" +" * The Droonga Engine finds a step definition from the message type.\n" +" * The Droonga Engine builds a \"single step\" based on the registered defini" +"tion.\n" +" * A \"single step\" creates an instance of the registered handler class.\n" +" Then the Droonga Engine enters to the handling phase.\n" +" * The handler's [`#handle`](#classes-Droonga-Handler-handle) is called w" +"ith a task massage including the request.\n" +" * The method can process the given incoming message as you like.\n" +" * The method returns a result value, as the output.\n" +" * After the handler finishes, the handling phase for the task message (a" +"nd the request) ends.\n" +" * If no \"step\" is found for the type, nothing happens.\n" +" * All \"step\"s finish their task, the processing phase for the request ends" +"." +msgstr "" +" 1. Droonga Engineが起動する。\n" +" * stepとハンドラークラスが登録される。\n" +" * Droonga Engineが起動し、入力メッセージを待ち受ける。\n" +" 2. アダプション・フェーズからメッセージが転送されてくる。\n" +" この時点でプロセッシング・フェーズが開始される。\n" +" * Droonga Engineが、メッセージタイプからstepの定義を見つける。\n" +" * Droonga Engineが、登録済みの定義に従ってsingle stepを作成する。\n" +" * single stepが、登録済みのハンドラークラスのインスタンスを作成する。\n" +" この時点でハンドリング・フェーズが開始される。\n" +" * ハンドラーの[`#handle`](#classes-Droonga-Handler-handle)メソッドが、リクエストの情報を含むタスク" +"メッセージを伴って呼ばれる。\n" +" * このメソッドにより、入力メッセージを任意に処理することができる。\n" +" * このメソッドは、処理結果の出力を戻り値として返す。\n" +" * ハンドラーの処理が完了した時点で、そのタスクメッセージ(およびリクエスト)のハンドリング・フェーズが終了する。\n" +" * メッセージタイプからstepが見つからなかった場合は、何も処理されない。\n" +" * すべてのstepが処理を終えた時点で、そのリクエストに対するプロセッシング・フェーズが終了する。" + +msgid "" +"As described above, the Droonga Engine creates an instance of the handler clas" +"s for each request." +msgstr "上記の通り、Droonga Engineは各リクエストに対してその都度ハンドラークラスのインスタンスを生成します。" + +msgid "" +"Any error raised from the handler is handled by the Droonga Engine itself. See" +" also [error handling][]." +msgstr "" +"ハンドラー内で発生したすべてのエラーは、Droonga Engine自身によって処理されます。[エラー処理][error handling]も併せて参照して" +"下さい。" + +msgid "## Configurations {#config}" +msgstr "## 設定 {#config}" + +msgid "" +"`action.synchronous` (boolean, optional, default=`false`)\n" +": Indicates that the request must be processed synchronously.\n" +" For example, a request to define a new column in a table must be processed a" +"fter a request to define the table itself, if the table does not exist yet.\n" +" Then handlers for these requests have the configuration `action.synchronous " +"= true`." +msgstr "" +"`action.synchronous` (真偽値, 省略可能, 初期値=`false`)\n" +": リクエストを同期的に処理する必要があるかどうかを示す。\n" +" 例えば、テーブル内に新しいカラムを追加するリクエストは、テーブルが存在しない場合には必ず、テーブル作成用のリクエストの後で処理する必要がある。このような" +"場合のハンドラーは、 `action.synchronous = true` の指定を伴うことになる。" + +msgid "## Classes and methods {#classes}" +msgstr "## クラスとメソッド {#classes}" + +msgid "### `Droonga::SingleStepDefinition` {#classes-Droonga-SingleStepDefinition}" +msgstr "" + +msgid "This provides methods to describe the \"step\" corresponding to the handler." +msgstr "このクラスは、ハンドラーに対応するstepの詳細を記述する機能を提供します。" + +msgid "#### `#name`, `#name=(name)` {#classes-Droonga-SingleStepDefinition-name}" +msgstr "" + +msgid "" +"Describes the name of the step itself.\n" +"Possible value is a string." +msgstr "step自身の名前を記述します。値は文字列です。" + +msgid "" +"The Droonga Engine treats an incoming message as a request of a \"command\", if " +"there is any step with the `name` which equals to the message's `type`.\n" +"In other words, this defines the name of the command corresponding to the step" +" itself." +msgstr "" +"Droonga Engineは、メッセージの`type`に一致する`name`を持つstepが存在する場合に、入力メッセージをコマンドのリクエストとして扱い" +"ます。\n" +"言い換えると、このメソッドはstepに対応するコマンドの名前を定義します。" + +msgid "" +"#### `#handler`, `#handler=(handler)` {#classes-Droonga-SingleStepDefinition-h" +"andler}" +msgstr "" + +msgid "" +"Associates a specific handler class to the step itself.\n" +"You can specify the class as any one of following choices:" +msgstr "" +"特定のハンドラークラスをstepに紐付けます。\n" +"ハンドラークラスは以下のいずれかの方法で指定します:" + +msgid "" +" * A reference to a handler class itself, like `Handler` or `Droonga::Plugins:" +":FooPlugin::Handler`.\n" +" Of course, the class have to be already defined at the time.\n" +" * A symbol which refers the name of a handler class in the current namespace," +" like `:Handler`.\n" +" This is useful if you want to describe the step at first and define the act" +"ual class after that.\n" +" * A class path string of a handler class, like `\"Droonga::Plugins::FooPlugin:" +":Handler\"`.\n" +" This is also useful to define the class itself after the description." +msgstr "" +" * `Handler` や `Droonga::Plugins::FooPlugin::Handler` のような、ハンドラークラス自体への参照。\n" +" 当然ながら、参照先のクラスはその時点で定義済みでなければなりません。\n" +" * `:Handler`のような、その名前空間で定義されているハンドラークラスのクラス名のシンボル。\n" +" この記法は、stepを先に記述して後からハンドラークラスを定義する場合に有用です。\n" +" * `\"Droonga::Plugins::FooPlugin::Handler\"` のような、ハンドラークラスのクラスパス文字列。\n" +" この記法もまた、stepの後でハンドラークラスを定義する場合に有用です。" + +msgid "" +"You must define the referenced class by the time the Droonga Engine actually p" +"rocesses the step, if you specify the name of the handler class as a symbol or" +" a string.\n" +"If the Droonga Engine fails to find out the actual handler class, or no handle" +"r is specified, then the Droonga Engine does nothing for the request." +msgstr "" +"ハンドラークラスをシンボルまたは文字列で指定した場合、参照先のクラスは、Droonga Engineが実際にそのstepを処理する時点までの間に定義しておく" +"必要があります。\n" +"Droonga Engineがハンドラークラスの実体を見つけられなかった場合、またはハンドラークラスが未指定の場合には、Droonga Engineはそのリ" +"クエストに対して何も処理を行いません。" + +msgid "" +"#### `#collector`, `#collector=(collector)` {#classes-Droonga-SingleStepDefini" +"tion-collector}" +msgstr "" + +msgid "" +"Associates a specific collector class to the step itself.\n" +"You can specify the class as any one of following choices:" +msgstr "" +"特定のコレクタークラスをstepに紐付けます。\n" +"コレクタークラスは以下のいずれかの方法で指定します:" + +msgid "" +" * A reference to a collector class itself, like `Collectors::Something` or `D" +"roonga::Plugins::FooPlugin::MyCollector`.\n" +" Of course, the class have to be already defined at the time.\n" +" * A symbol which refers the name of a collector class in the current namespac" +"e, like `:MyCollector`.\n" +" This is useful if you want to describe the step at first and define the act" +"ual class after that.\n" +" * A class path string of a collector class, like `\"Droonga::Plugins::FooPlugi" +"n::MyCollector\"`.\n" +" This is also useful to define the class itself after the description." +msgstr "" +" * `Collectors::Something` や `Droonga::Plugins::FooPlugin::MyCollector` のような、コ" +"レクタークラス自体への参照。\n" +" 当然ながら、参照先のクラスはその時点で定義済みでなければなりません。\n" +" * `:MyCollector`のような、その名前空間で定義されているコレクタークラスのクラス名のシンボル。\n" +" この記法は、stepを先に記述して後からコレクタークラスを定義する場合に有用です。\n" +" * `\"Droonga::Plugins::FooPlugin::MyCollector\"` のような、コレクタークラスのクラスパス文字列。\n" +" この記法もまた、stepの後でコレクタークラスを定義する場合に有用です。" + +msgid "" +"You must define the referenced class by the time the Droonga Engine actually c" +"ollects results, if you specify the name of the collector class as a symbol or" +" a string.\n" +"If the Droonga Engine fails to find out the actual collector class, or no coll" +"ector is specified, then the Droonga Engine doesn't collect results and return" +"s multiple messages as results." +msgstr "" +"コレクタークラスをシンボルまたは文字列で指定した場合、参照先のクラスは、Droonga Engineが実際にそのstepの結果を集約する時点までの間に定義し" +"ておく必要があります。\n" +"Droonga Engineがコレクタークラスの実体を見つけられなかった場合、またはコレクタークラスが未指定の場合には、Droonga Engineは処理結" +"果を集約せず、複数のメッセージとして返します。" + +msgid "See also [descriptions of collectors][collector]." +msgstr "[コレクターの説明][collector]も併せて参照して下さい。" + +msgid "#### `#write`, `#write=(write)` {#classes-Droonga-SingleStepDefinition-write}" +msgstr "" + +msgid "" +"Describes whether the step modifies any data in the storage or don't.\n" +"If a request aims to modify some data in the storage, the request must be proc" +"essed for all replicas.\n" +"Otherwise the Droonga Engine can optimize handling of the step.\n" +"For example, caching of results, reducing of CPU/memory usage, and so on." +msgstr "" +"stepがストレージ内の情報を変更し得るかどうかを記述します。\n" +"リクエストがストレージ内のデータを変更することを意図する物である場合、そのリクエストはすべてのreplicaで処理される必要があります。\n" +"それ以外の場合、Droonga Engineは結果をキャッシュしたり、CPUやメモリの使用量を削減するなどして、処理を最適化することができます。" + +msgid "Possible values are:" +msgstr "取り得る値:" + +msgid "" +" * `true`, means \"this step can modify the storage.\"\n" +" * `false`, means \"this step never modifies the storage.\" (default)" +msgstr "" +" * `true`: そのstepではストレージの内容が変更される可能性がある事を示す。\n" +" * `false`: そのstepではストレージの内容が変更される可能性はない事を示す。(初期値)\"" + +msgid "" +"#### `#inputs`, `#inputs=(inputs)` {#classes-Droonga-SingleStepDefinition-inpu" +"ts}" +msgstr "" + +msgid "(TBD)" +msgstr "(未稿)" + +msgid "" +"#### `#output`, `#output=(output)` {#classes-Droonga-SingleStepDefinition-outp" +"ut}" +msgstr "" + +msgid "### `Droonga::Handler` {#classes-Droonga-Handler}" +msgstr "" + +msgid "" +"This is the common base class of any handler.\n" +"Your plugin's handler class must inherit this." +msgstr "これはすべてのハンドラーに共通の基底クラスです。独自プラグインのハンドラークラスは、このクラスを継承する必要があります。" + +msgid "#### `#handle(message)` {#classes-Droonga-Handler-handle}" +msgstr "" + +msgid "" +"This method receives a [`Droonga::HandlerMessage`](#classes-Droonga-HandlerMes" +"sage) wrapped task message.\n" +"You can read the request information via its methods." +msgstr "" +"このメソッドは、[`Droonga::HandlerMessage`](#classes-Droonga-HandlerMessage)でラップされたタスク" +"メッセージを受け取ります。\n" +"プラグインは、このタスクメッセージのメソッドからリクエストの情報を読み取る事ができます。" + +msgid "" +"In this base class, this method is defined as just a placeholder and it does n" +"othing.\n" +"To process messages, you have to override it by yours, like following:" +msgstr "" +"この基底クラスにおいて、このメソッドは何もしない単なるプレースホルダとして定義されています。\n" +"メッセージを処理するには、以下のようにメソッドを再定義して下さい:" + +msgid "" +"~~~ruby\n" +"module Droonga::Plugins::MySearch\n" +" class Handler < Droonga::Handler\n" +" def handle(message)\n" +" search_query = message.request[\"body\"][\"query\"]\n" +" ...\n" +" { ... } # the result\n" +" end\n" +" end\n" +"end\n" +"~~~" +msgstr "" + +msgid "" +"The Droonga Engine uses the returned value of this method as the result of the" +" handling.\n" +"It will be used to build the body of the unified response, and delivered to th" +"e Protocol Adapter." +msgstr "" +"Droonga Engineは、このメソッドの戻り値を処理の結果として扱います。\n" +"結果の値は、レスポンスのbodyの組み立てに使われ、Protocol Adapterに送られます。" + +msgid "### `Droonga::HandlerMessage` {#classes-Droonga-HandlerMessage}" +msgstr "" + +msgid "This is a wrapper for a task message." +msgstr "このクラスはタスクメッセージに対するラッパーとして働きます。" + +msgid "" +"The Droonga Engine analyzes a transferred request message, and build multiple " +"task massages to process the request.\n" +"A task massage has some information: a request, a step, descendant tasks, and " +"so on." +msgstr "" +"Droonga Engineは送られてきたリクエストのメッセージを解析し、そのリクエストを処理するための複数のタスクメッセージを作成します。\n" +"1つのタスクメッセージは、リクエストの実体、step、後続するタスクの一覧などの情報を持ちます。" + +msgid "#### `#request` {#classes-Droonga-HandlerMessage-request}" +msgstr "" + +msgid "" +"This returns the request message.\n" +"You can read request body via this method. For example:" +msgstr "このメソッドはリクエストメッセージを返します。例:" + +msgid "" +"~~~ruby\n" +"module Droonga::Plugins::MySearch\n" +" class Handler < Droonga::Handler\n" +" def handle(message)\n" +" request = message.request\n" +" search_query = request[\"body\"][\"query\"]\n" +" ...\n" +" end\n" +" end\n" +"end\n" +"~~~" +msgstr "" + +msgid "#### `@context` {#classes-Droonga-HandlerMessage-context}" +msgstr "" + +msgid "" +"This is a reference to the `Groonga::Context` instance for the storage of the " +"corresponding volume.\n" +"See the [class reference of Rroonga][Groonga::Context]." +msgstr "" +"対応するボリュームのストレージを示す、`Groonga::Context`のインスタンスへの参照。\n" +"[Rroongaのクラスリファレンス][Groonga::Context]も併せて参照して下さい" + +msgid "" +"You can use any feature of Rroonga via `@context`.\n" +"For example, this code returns the number of records in the specified table:" +msgstr "" +"`@context`を経由して、Rroongaのすべての機能を利用できます。\n" +"例えば、以下は指定されたテーブルのすべてのレコードの数を返す例です:" + +msgid "" +"~~~ruby\n" +"module Droonga::Plugins::CountRecords\n" +" class Handler < Droonga::Handler\n" +" def handle(message)\n" +" request = message.request\n" +" table_name = request[\"body\"][\"table\"]\n" +" count = @context[table_name].size\n" +" end\n" +" end\n" +"end\n" +"~~~" +msgstr "" + +msgid "" +" [error handling]: ../error/\n" +" [collector]: ../collector/\n" +" [Groonga::Context]: http://ranguba.org/rroonga/en/Groonga/Context.html" +msgstr "" Added: _po/ja/reference/1.0.3/plugin/index.po (+41 -0) 100644 =================================================================== --- /dev/null +++ _po/ja/reference/1.0.3/plugin/index.po 2014-05-19 16:48:30 +0900 (31c64a5) @@ -0,0 +1,41 @@ +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"PO-Revision-Date: 2014-03-05 12:52+0900\n" +"Language: ja\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" + +msgid "" +"---\n" +"title: Plugin development\n" +"layout: en\n" +"---" +msgstr "" +"---\n" +"title: プラグイン開発\n" +"layout: ja\n" +"---" + +msgid "" +"Droonga Engine has different API sets for plugins, on each phase.\n" +"See also the [plugin development tutorial](../../tutorial/plugin-development/)" +"." +msgstr "" +"Droonga Engineはプラグインに対して、処理の各段階ごとに異なるAPIセットを提供します。[プラグイン開発のチュートリアル](../../tuto" +"rial/plugin-development/)も参照してください。" + +msgid "" +" * [API set for the adaption phase](adapter/)\n" +" * [API set for the handling phase](handler/)\n" +" * [Matching pattern for messages](matching-pattern/)\n" +" * [Collector](collector/)\n" +" * [Error handling](error/)" +msgstr "" +" * [アダプション・フェーズでのAPI](adapter/)\n" +" * [ハンドリング・フェーズでのAPI](handler/)\n" +" * [メッセージのためのマッチングパターン](matching-pattern/)\n" +" * [コレクター](collector/)\n" +" * [エラー処理](error/)" Added: _po/ja/reference/1.0.3/plugin/matching-pattern/index.po (+365 -0) 100644 =================================================================== --- /dev/null +++ _po/ja/reference/1.0.3/plugin/matching-pattern/index.po 2014-05-19 16:48:30 +0900 (766ddd2) @@ -0,0 +1,365 @@ +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"PO-Revision-Date: 2014-03-05 12:52+0900\n" +"Language: ja\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" + +msgid "" +"---\n" +"title: Matching pattern for messages\n" +"layout: en\n" +"---" +msgstr "" +"---\n" +"title: メッセージのマッチングパターン\n" +"layout: ja\n" +"---" + +msgid "" +"* TOC\n" +"{:toc}" +msgstr "" + +msgid "## Abstract {#abstract}" +msgstr "## 概要 {#abstract}" + +msgid "" +"The Droonga Engine provides a tiny language to specify patterns of messages, c" +"alled *matching pattern*.\n" +"It is used to specify target messages of various operations, ex. plugins." +msgstr "" +"Droonga Engineはメッセージのパターンを指定するための小規模な言語を実装しています。これを*マッチングパターン*と呼びます。\n" +"マッチングパターンは、プラグインなどの様々な場所で処理対象のメッセージを指定するために使われます。" + +msgid "## Examples {#examples}" +msgstr "## 例 {#examples}" + +msgid "### Simple matching" +msgstr "### 単純なマッチング" + +msgid " pattern = [\"type\", :equal, \"search\"]" +msgstr "" + +msgid "This matches to messages like:" +msgstr "これは以下のようなメッセージにマッチします:" + +msgid "" +" {\n" +" \"type\": \"search\",\n" +" ...\n" +" }" +msgstr "" + +msgid "### Matching for a deep target" +msgstr "### 深い位置にある対象へのマッチング" + +msgid " pattern = [\"body.success\", :equal, true]" +msgstr "" + +msgid "" +" {\n" +" \"type\": \"add.result\",\n" +" \"body\": {\n" +" \"success\": true\n" +" }\n" +" }" +msgstr "" + +msgid "Doesn't match to:" +msgstr "以下にはマッチしません:" + +msgid "" +" {\n" +" \"type\": \"add.result\",\n" +" \"body\": {\n" +" \"success\": false\n" +" }\n" +" }" +msgstr "" + +msgid "### Nested patterns" +msgstr "### パターン自体のネスト" + +msgid "" +" pattern = [\n" +" [\"type\", :equal, \"table_create\"],\n" +" :or,\n" +" [\"body.success\", :equal, true]\n" +" ]" +msgstr "" + +msgid "This matches to both:" +msgstr "これは以下の両方にマッチします:" + +msgid "" +" {\n" +" \"type\": \"table_create\",\n" +" ...\n" +" }" +msgstr "" + +msgid "and:" +msgstr "および:" + +msgid "" +" {\n" +" \"type\": \"column_create\",\n" +" ...\n" +" \"body\": {\n" +" \"success\": true\n" +" }\n" +" }" +msgstr "" + +msgid "## Syntax {#syntax}" +msgstr "## 書式 {#syntax}" + +msgid "" +"There are two typeos of matching patterns: \"basic pattern\" and \"nested pattern" +"\"." +msgstr "マッチングパターンには「基本パターン」と「ネストしたパターン」の2種類があります。" + +msgid "### Basic pattern {#syntax-basic}" +msgstr "### 基本パターン {#syntax-basic}" + +msgid "#### Structure {#syntax-basic-structure}" +msgstr "#### 構造 {#syntax-basic-structure}" + +msgid "" +"A basic pattern is described as an array including 2 or more elements, like fo" +"llowing:" +msgstr "基本パターンは以下のように、2つ以上の要素を含む配列として表現されます:" + +msgid " [\"type\", :equal, \"search\"]" +msgstr "" + +msgid "" +" * The first element is a *target path*. It means the location of the informat" +"ion to be checked, in the [message][].\n" +" * The second element is an *operator*. It means how the information specified" +" by the target path should be checked.\n" +" * The third element is an *argument for the oeprator*. It is a primitive valu" +"e (string, numeric, or boolean) or an array of values. Some operators require " +"no argument." +msgstr "" +" * 最初の要素は *ターゲットパス* です。これは、[メッセージ][message]の中でチェックされる情報の位置を示します。\n" +" * 2番目の要素は *演算子* です。これは、ターゲットパスで示された情報をどのようにチェックするかを示します。\n" +" * 3番目の要素は *演算子のための引数* です。これは、プリミティブ値(文字列、数値、または真偽値)、もしくはそれらの値の配列です。ただし、いくつかの演" +"算子は引数を取りません。" + +msgid "#### Target path {#syntax-basic-target-path}" +msgstr "#### ターゲットパス {#syntax-basic-target-path}" + +msgid "The target path is specified as a string, like:" +msgstr "ターゲットパスは以下の文字列のような形で示します:" + +msgid " \"body.success\"" +msgstr "" + +msgid "" +"The matching mechanism of the Droonga Engine interprets it as a dot-separated " +"list of *path components*.\n" +"A path component represents the property in the message with same name.\n" +"So, the example above means the location:" +msgstr "" +"Droonga Engineのマッチング機構は、これをドットで区切られた *パスコンポーネント* のリストとして解釈します。\n" +"1つのパスコンポーネントはメッセージ中の同名のプロパティを表します。\n" +"よって、上記の例は以下の位置を示します:" + +msgid "" +" {\n" +" \"body\": {\n" +" \"success\": <target>\n" +" }\n" +" }" +msgstr "" + +msgid "#### Avialable operators {#syntax-basic-operators}" +msgstr "#### 利用可能な演算子 {#syntax-basic-operators}" + +msgid "The operator is specified as a symbol." +msgstr "演算子はシンボルとして指定します。" + +msgid "" +"`:equal`\n" +": Returns `true`, if the target value is equal to the given value. Otherwise `" +"false`.\n" +" For example," +msgstr "" +"`:equal`\n" +": ターゲットの値が与えられた値と等しい場合に `true` を返します。それ以外の場合は `false` を返します。\n" +" 例えば、" + +msgid " [\"type\", :equal, \"search\"]" +msgstr "" + +msgid " The pattern above matches to a message like following:" +msgstr " 上記のパターンは以下のようなメッセージにマッチします:" + +msgid "" +" {\n" +" \"type\": \"search\",\n" +" ...\n" +" }" +msgstr "" + +msgid "" +"`:in`\n" +": Returns `true`, if the target value is in the given array of values. Otherwi" +"se `false`.\n" +" For example," +msgstr "" +"`:in`\n" +": ターゲットの値が与えられた配列の中に含まれている場合に `true` を返します。それ以外の場合は `false` を返します。\n" +" 例えば、" + +msgid " [\"type\", :in, [\"search\", \"select\"]]" +msgstr "" + +msgid "" +" {\n" +" \"type\": \"select\",\n" +" ...\n" +" }" +msgstr "" + +msgid " But it doesn't match to:" +msgstr " 以下にはマッチしません:" + +msgid "" +" {\n" +" \"type\": \"find\",\n" +" ...\n" +" }" +msgstr "" + +msgid "" +"`:include`\n" +": Returns `true` if the target array of values includes the given value. Other" +"wise `false`.\n" +" In other words, this is the opposite of the `:in` operator.\n" +" For example," +msgstr "" +"`:include`\n" +": ターゲットの値の配列の中に指定された値が含まれている場合に `true` を返します。それ以外の場合は `false` を返します。\n" +" 言い換えると、これは `:in` 演算子の反対の働きをします。\n" +" 例えば、" + +msgid " [\"body.tags\", :include, \"News\"]" +msgstr "" + +msgid "" +" {\n" +" \"type\": \"my.notification\",\n" +" \"body\": {\n" +" \"tags\": [\"News\", \"Groonga\", \"Droonga\", \"Fluentd\"]\n" +" }\n" +" }" +msgstr "" + +msgid "" +"`:exist`\n" +": Returns `true` if the target exists. Otherwise `false`.\n" +" For example," +msgstr "" +"`:exist`\n" +": ターゲットに指定された情報が存在する場合は `true` を返します。それ以外の場合は `false` を返します。\n" +" 例えば、" + +msgid " [\"body.comments\", :exist, \"News\"]" +msgstr "" + +msgid "" +" {\n" +" \"type\": \"my.notification\",\n" +" \"body\": {\n" +" \"title\": \"Hello!\",\n" +" \"comments\": []\n" +" }\n" +" }" +msgstr "" + +msgid "" +" {\n" +" \"type\": \"my.notification\",\n" +" \"body\": {\n" +" \"title\": \"Hello!\"\n" +" }\n" +" }" +msgstr "" + +msgid "" +"`:start_with`\n" +": Returns `true` if the target string value starts with the given string. Othe" +"rwise `false`.\n" +" For example," +msgstr "" +"`:start_with`\n" +": ターゲットの文字列が指定された文字列で始まる場合に `true` を返します。それ以外の場合は `false` を返します。\n" +" 例えば、" + +msgid " [\"body.path\", :start_with, \"/archive/\"]" +msgstr "" + +msgid "" +" {\n" +" \"type\": \"my.notification\",\n" +" \"body\": {\n" +" \"path\": \"/archive/2014/02/28.html\"\n" +" }\n" +" }" +msgstr "" + +msgid "### Nested pattern {#syntax-nested}" +msgstr "### ネストしたパターン {#syntax-nested}" + +msgid "#### Structure {#syntax-nested-structure}" +msgstr "#### 構造 {#syntax-nested-structure}" + +msgid "" +"A nested pattern is described as an array including 3 elements, like following" +":" +msgstr "ネストしたパターンは、以下のような3つの要素を持つ配列として表現されます:" + +msgid "" +" [\n" +" [\"type\", :equal, \"table_create\"],\n" +" :or,\n" +" [\"type\", :equal, \"column_create\"]\n" +" ]" +msgstr "" + +msgid "" +" * The first and the third elements are patterns, basic or nested. (In other w" +"ords, you can nest patterns recursively.)\n" +" * The second element is a *logical operator*." +msgstr "" +" * 最初の要素と最後の要素は基本パターンまたはネストしたパターンです。(言い換えると、ネストしたパターンは再帰的に書くことができます。)\n" +" * 2番目の要素は *論理演算子* です。" + +msgid "#### Avialable operators {#syntax-nested-operators}" +msgstr "#### 利用可能な演算子 {#syntax-nested-operators}" + +msgid "" +"`:and`\n" +": Returns `true` if both given patterns are evaluated as `true`. Otherwise `fa" +"lse`." +msgstr "" +"`:and`\n" +": 与えられた両方のパターンが `true` を返す場合に、`true` を返します。それ以外の場合は `false` を返します。" + +msgid "" +"`:or`\n" +": Returns `true` if one of given patterns (the first or the third element) is " +"evaluated as `true`. Otherwise `false`." +msgstr "" +"`:or`\n" +": 与えられたパターン(1番目または3番目の要素)のいずれかまたは両方が `true` を返す場合に `true` を返します。それ以外の場合は `fals" +"e` を返します。" + +msgid " [message]:../../message/" +msgstr "" Added: _po/ja/tutorial/1.0.3/basic/index.po (+1745 -0) 100644 =================================================================== --- /dev/null +++ _po/ja/tutorial/1.0.3/basic/index.po 2014-05-19 16:48:30 +0900 (361a605) @@ -0,0 +1,1745 @@ +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"PO-Revision-Date: 2014-03-05 12:52+0900\n" +"Language: ja\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" + +msgid "" +"---\n" +"title: \"Droonga tutorial: basic usage\"\n" +"layout: en\n" +"---" +msgstr "" +"---\n" +"title: \"Droonga チュートリアル: 基本的な使い方\"\n" +"layout: ja\n" +"---" + +msgid "" +"* TOC\n" +"{:toc}" +msgstr "" + +msgid "## The goal of this tutorial" +msgstr "## チュートリアルのゴール" + +msgid "Learning steps to setup a Droonga based search system by yourself." +msgstr "Droonga を使った検索システムを自分で構築できるようになる。" + +msgid "## Precondition" +msgstr "## 前提条件" + +msgid "" +"* You must have basic knowledge and experiences to setup and operate an [Ubunt" +"u][] Server.\n" +"* You must have basic knowledge and experiences to develop applications based " +"on the [Ruby][] and the [Node.js][]." +msgstr "" +"* [Ubuntu][] Server を自分でセットアップしたり、基本的な操作ができること\n" +"* [Ruby][] と [Node.js][] の基本的な知識があること" + +msgid "## Abstract" +msgstr "## 概要" + +msgid "### What is the Droonga?" +msgstr "### Droonga とは" + +msgid "" +"It is a data processing engine based on a distributed architecture, named afte" +"r the terms \"distributed-Groonga\"." +msgstr "分散データ処理エンジンです。 \"distributed-groonga\" に由来します。" + +msgid "" +"The Droonga is built on some components which are made as separated packages. " +"You can develop various data processing systems (for example, a fulltext searc" +"h engine) with high scalability from a distributed architecture, with those pa" +"ckages." +msgstr "" +"Droonga は複数のコンポーネントから構成されています。ユーザは、これらのパッケージを組み合わせて利用することで、全文検索をはじめとするスケーラブルな分" +"散データ処理システムを構築することができます。" + +msgid "### Components of the Droonga" +msgstr "### Droonga を構成するコンポーネント" + +msgid "#### Droonga Engine" +msgstr "" + +msgid "" +"The component \"Droonga Engine\" is the main part to process data with a distrib" +"uted architecture. It is triggered by requests and processes various data." +msgstr "Droonga Engine は Droonga における分散データ処理の要となるコンポーネントです。リクエストに基いて実際のデータ処理を行います。" + +msgid "" +"This component is developed and released as the [droonga-engine][].\n" +"The protocol is compatible to [Fluentd]." +msgstr "" +"このコンポーネントは[droonga-engine][]という名前で開発およびリリースされています。\n" +"通信に使用するプロトコルは[Fluentd]と互換性があります。" + +msgid "" +"It internally uses [Groonga][] as its search engine.\n" +"Groonga is an open source, fulltext search engine, including a column-store fe" +"ature." +msgstr "[droonga-engine][] は検索エンジンとして、オープンソースのカラムストア機能付き全文検索エンジン [Groonga][] を使用しています。" + +msgid "#### Protocol Adapter" +msgstr "" + +msgid "" +"The component \"Protocol Adapter\" provides ability for clients to communicate w" +"ith a Droonga engine, using various protocols." +msgstr "Protocol Adapter は、Droonga を様々なプロトコルで利用できるようにするためのコンポーネントです。" + +msgid "" +"The only one available protocol of a Droonga engine is the fluentd protocol.\n" +"Instead, protocol adapters translate it to other common protocols (like HTTP, " +"Socket.OP, etc.) between the Droonga Engine and clients." +msgstr "" +"Droonga Engine自体は通信プロトコルとしてfluentdプロトコルにのみ対応しています。\n" +"その代わりに、Protocol AdapterがDroonga Engineとクライアントの間に立って、fluentdプロトコルと他の一般的なプロトコル(H" +"TTP、Socket.IOなど)とを翻訳することになります。" + +msgid "" +"Currently, there is an implementation for the HTTP: [droonga-http-server][], a" +" [Node.js][] module package.\n" +"In other words, the droonga-http-server is one of Droonga Progocol Adapters, a" +"nd it's a \"Droonga HTTP Protocol Adapter\"." +msgstr "" +"現在の所、HTTP用の実装として、[Node.js][]用モジュールパッケージの[droonga-http-server][]が存在しています。\n" +"言い直すと、droonga-http-serverはDroonga Protocol Adapterの一実装で、言わば「Droonga HTTP Proto" +"col Adapter」であるという事です。" + +msgid "## Abstract of the system described in this tutorial" +msgstr "## チュートリアルでつくるシステムの全体像" + +msgid "This tutorial describes steps to build a system like following:" +msgstr "チュートリアルでは、以下の様な構成のシステムを構築します。" + +msgid "" +" +-------------+ +------------------+ +-----------" +"-----+\n" +" | Web Browser | <--------> | Protocol Adapter | <-------> | Droonga En" +"gine |\n" +" +-------------+ HTTP +------------------+ Fluent +-----------" +"-----+\n" +" w/droonga-http protocol w/droonga-en" +"gine\n" +" -server" +msgstr "" + +msgid "" +" \\--------------------------------------------" +"------/\n" +" This tutorial describes about this part" +"." +msgstr "" +" \\--------------------------------------------" +"------/\n" +" この部分を構築します" + +msgid "" +"User agents (ex. a Web browser) send search requests to a protocol adapter. Th" +"e adapter receives them, and sends internal (translated) search requests to a " +"Droonga engine. The engine processes them actually. Search results are sent fr" +"om the engine to the protocol adapter, and finally delivered to the user agent" +"s." +msgstr "" +"ユーザは Protocol Adapter に、Web ブラウザなどを用いて接続します。Protocol Adapter は Droonga Engine " +"へリクエストを送信します。実際の検索処理は Droonga Engine が行います。検索結果は、Droonga Engine から Protocol Ad" +"apter に渡され、最終的にユーザに返ります。" + +msgid "" +"For example, let's try to build a database system to find [Starbucks stores in" +" New York](http://geocommons.com/overlays/430038)." +msgstr "" +"例として、[ニューヨークにあるスターバックスの店舗](http://geocommons.com/overlays/430038)を検索できるデータベースシ" +"ステムを作成することにします。" + +msgid "## Prepare an environment for experiments" +msgstr "## 実験用のマシンを用意する" + +msgid "" +"Prepare a computer at first. This tutorial describes steps to develop a search" +" service based on the Droonga, on an existing computer.\n" +"Following instructions are basically written for a successfully prepared virtu" +"al machine of the `Ubuntu 13.10 x64` on the service [DigitalOcean](https://www" +".digitalocean.com/), with an available console." +msgstr "" +"まずコンピュータを調達しましょう。このチュートリアルでは、既存のコンピュータにDroongaによる検索システムを構築する手順を解説します。\n" +"以降の説明は基本的に、[DigitalOcean](https://www.digitalocean.com/)で `Ubuntu 13.10 x64` の" +"仮想マシンのセットアップを完了し、コンソールにアクセスできる状態になった後を前提として進めます。" + +msgid "" +"NOTE: Make sure to use instances with >= 2GB memory equipped, at least during " +"installation of required packages for Droonga. Otherwise, you may experience a" +" strange build error." +msgstr "" +"注意:Droongaが必要とするパッケージをインストールする前に、マシンが2GB以上のメモリを備えていることを確認して下さい。メモリが不足していると、ビルド" +"時にエラーが出て、ビルドに失敗することがあります。" + +msgid "Assume that the host is `192.168.0.10`." +msgstr "ホストが `192.168.0.10` だと仮定します。" + +msgid "## Install packages required for the setup process" +msgstr "## セットアップに必要なパッケージをインストールする" + +msgid "Install packages required to setup a Droonga engine." +msgstr "Droonga をセットアップするために必要になるパッケージをインストールします。" + +msgid "" +" # apt-get update\n" +" # apt-get -y upgrade\n" +" # apt-get install -y ruby ruby-dev build-essential nodejs npm" +msgstr "" + +msgid "## Build a Droonga engine" +msgstr "## Droonga Engine を構築する" + +msgid "" +"The part \"Droonga engine\" stores the database and provides the search feature " +"actually.\n" +"In this section we install a droonga-engine and load searchable data to the da" +"tabase." +msgstr "" +"Droonga Engine は、データベースを保持し、実際の検索を担当する部分です。\n" +"このセクションでは、 droonga-engine をインストールし、検索対象となるデータを準備します。" + +msgid "### Install a droonga-engine and droonga-client" +msgstr "### droonga-engineとdroonga-clientをインストールする" + +msgid " # gem install droonga-engine droonga-client" +msgstr "" + +msgid "" +"Required packages are prepared by the command above. Let's continue to the con" +"figuration step." +msgstr "Droonga Engine を構築するのに必要なパッケージがセットアップできました。引き続き設定に移ります。" + +msgid "### Prepare configuration files to start a Droonga engine" +msgstr "### Droonga Engine を起動するための設定ファイルを用意する" + +msgid "Create a directory for a Droonga engine:" +msgstr "まず Droonga Engine 用のディレクトリを作成します。" + +msgid "" +" # mkdir engine\n" +" # cd engine" +msgstr "" + +msgid "" +"Next, put a configuration file `catalog.json` like following, into the directo" +"ry:" +msgstr "以下の内容で `catalog.json` を作成します。" + +msgid "catalog.json:" +msgstr "" + +msgid "" +" {\n" +" \"version\": 2,\n" +" \"effectiveDate\": \"2013-09-01T00:00:00Z\",\n" +" \"datasets\": {\n" +" \"Starbucks\": {\n" +" \"nWorkers\": 4,\n" +" \"plugins\": [\"groonga\", \"crud\", \"search\"],\n" +" \"schema\": {\n" +" \"Store\": {\n" +" \"type\": \"Hash\",\n" +" \"keyType\": \"ShortText\",\n" +" \"columns\": {\n" +" \"location\": {\n" +" \"type\": \"Scalar\",\n" +" \"valueType\": \"WGS84GeoPoint\"\n" +" }\n" +" }\n" +" },\n" +" \"Location\": {\n" +" \"type\": \"PatriciaTrie\",\n" +" \"keyType\": \"WGS84GeoPoint\",\n" +" \"columns\": {\n" +" \"store\": {\n" +" \"type\": \"Index\",\n" +" \"valueType\": \"Store\",\n" +" \"indexOptions\": {\n" +" \"sources\": [\"location\"]\n" +" }\n" +" }\n" +" }\n" +" },\n" +" \"Term\": {\n" +" \"type\": \"PatriciaTrie\",\n" +" \"keyType\": \"ShortText\",\n" +" \"normalizer\": \"NormalizerAuto\",\n" +" \"tokenizer\": \"TokenBigram\",\n" +" \"columns\": {\n" +" \"stores__key\": {\n" +" \"type\": \"Index\",\n" +" \"valueType\": \"Store\",\n" +" \"indexOptions\": {\n" +" \"position\": true,\n" +" \"sources\": [\"_key\"]\n" +" }\n" +" }\n" +" }\n" +" }\n" +" },\n" +" \"replicas\": [\n" +" {\n" +" \"dimension\": \"_key\",\n" +" \"slicer\": \"hash\",\n" +" \"slices\": [\n" +" {\n" +" \"volume\": {\n" +" \"address\": \"192.168.0.10:10031/droonga.000\"\n" +" }\n" +" },\n" +" {\n" +" \"volume\": {\n" +" \"address\": \"192.168.0.10:10031/droonga.001\"\n" +" }\n" +" },\n" +" {\n" +" \"volume\": {\n" +" \"address\": \"192.168.0.10:10031/droonga.002\"\n" +" }\n" +" }\n" +" ]\n" +" },\n" +" {\n" +" \"dimension\": \"_key\",\n" +" \"slicer\": \"hash\",\n" +" \"slices\": [\n" +" {\n" +" \"volume\": {\n" +" \"address\": \"192.168.0.10:10031/droonga.010\"\n" +" }\n" +" },\n" +" {\n" +" \"volume\": {\n" +" \"address\": \"192.168.0.10:10031/droonga.011\"\n" +" }\n" +" },\n" +" {\n" +" \"volume\": {\n" +" \"address\": \"192.168.0.10:10031/droonga.012\"\n" +" }\n" +" }\n" +" ]\n" +" }\n" +" ]\n" +" }\n" +" }\n" +" }" +msgstr "" + +msgid "This `catalog.json` defines a dataset `Starbucks` as:" +msgstr "この`catalog.json`では、データセット`Starbucks`を以下のように定義しています:" + +msgid "" +" * At the top level, there is one volume based on two sub volumes, called \"rep" +"licas\".\n" +" * At the next lower level, one replica volume is based on three sub volumes, " +"called \"slices\".\n" +" They are minimum elements constructing a Droonga's dataset." +msgstr "" +" * 最上位には1つのボリュームがあり、このボリュームには「レプリカ」と名付けられた2つのサブボリュームが含まれる。\n" +" * 1段階下がった次のレベルには、1つのレプリカ・ボリュームごとに「スライス」と名付けられた3つのサブボリュームが含まれる。\n" +" これらはDroongaのデータセットの最小の構成要素である。" + +msgid "" +"These six atomic volumes having `\"address\"` information are internally called " +"as *single volume*s.\n" +"The `\"address\"` indicates the location of the corresponding physical storage w" +"hich is a database for Groonga, they are managed by `droonga-engine` instances" +" automatically." +msgstr "" +"これらの6つの、`\"address\"`の情報を持つ最小単位のボリュームは、内部的に*シングル・ボリューム*と呼ばれます。\n" +"`\"address\"`の情報は、対応する物理的なストレージであるGroongaのデータベースの位置を示していて、それらのデータベースは`droonga-en" +"gine`によって自動的に作成されます。" + +msgid "" +"For more details of the configuration file `catalog.json`, see [the reference " +"manual of catalog.json](/reference/catalog)." +msgstr "`catalog.json` の詳細については [catalog.json](/ja/reference/catalog) を参照してください。" + +msgid "### Start an instance of droonga-engine" +msgstr "### droonga-engine を起動する" + +msgid "" +"Start a Droonga engine, you can start it with the command `droonga-engine`, li" +"ke:" +msgstr "以下のようにして droonga-engine を起動します。" + +msgid "" +" # droonga-engine --host 192.168.0.10 --log-file=$PWD/droonga-engine.log --" +"daemon --pid-file $PWD/droonga-engine.pid" +msgstr "" + +msgid "### Stop an instance of droonga-engine" +msgstr "### droonga-engine を終了する" + +msgid "First, you need to know how to stop droonga-engine." +msgstr "最初にdroonga-engineを終了する方法を知っておきましょう。" + +msgid "Send SIGTERM to droonga-engine:" +msgstr "droonga-engineにSIGTERMを送ります。" + +msgid " # kill $(cat droonga-engine.pid)" +msgstr "" + +msgid "This is the way to stop droonga-engine." +msgstr "これがdroonga-engineを終了する方法です。" + +msgid "Start droonga-engine again:" +msgstr "再度droonga-engineを起動します。" + +msgid "### Create a database" +msgstr "### データベースを作成する" + +msgid "" +"After a Droonga engine is started, let's load data.\n" +"Prepare `stores.jsons` including location data of stores." +msgstr "" +"Dronga Engine が起動したので、データを投入しましょう。\n" +"店舗のデータ `stores.jsons` を用意します。" + +msgid "stores.jsons:" +msgstr "" + +msgid "" +"~~~\n" +"{\n" +" \"dataset\": \"Starbucks\",\n" +" \"type\": \"add\",\n" +" \"body\": {\n" +" \"table\": \"Store\",\n" +" \"key\": \"1st Avenue & 75th St. - New York NY (W)\",\n" +" \"values\": {\n" +" \"location\": \"40.770262,-73.954798\"\n" +" }\n" +" }\n" +"}\n" +"{\n" +" \"dataset\": \"Starbucks\",\n" +" \"type\": \"add\",\n" +" \"body\": {\n" +" \"table\": \"Store\",\n" +" \"key\": \"76th & Second - New York NY (W)\",\n" +" \"values\": {\n" +" \"location\": \"40.771056,-73.956757\"\n" +" }\n" +" }\n" +"}\n" +"{\n" +" \"dataset\": \"Starbucks\",\n" +" \"type\": \"add\",\n" +" \"body\": {\n" +" \"table\": \"Store\",\n" +" \"key\": \"2nd Ave. & 9th Street - New York NY\",\n" +" \"values\": {\n" +" \"location\": \"40.729445,-73.987471\"\n" +" }\n" +" }\n" +"}\n" +"{\n" +" \"dataset\": \"Starbucks\",\n" +" \"type\": \"add\",\n" +" \"body\": {\n" +" \"table\": \"Store\",\n" +" \"key\": \"15th & Third - New York NY (W)\",\n" +" \"values\": {\n" +" \"location\": \"40.733946,-73.9867\"\n" +" }\n" +" }\n" +"}\n" +"{\n" +" \"dataset\": \"Starbucks\",\n" +" \"type\": \"add\",\n" +" \"body\": {\n" +" \"table\": \"Store\",\n" +" \"key\": \"41st and Broadway - New York NY (W)\",\n" +" \"values\": {\n" +" \"location\": \"40.755111,-73.986225\"\n" +" }\n" +" }\n" +"}\n" +"{\n" +" \"dataset\": \"Starbucks\",\n" +" \"type\": \"add\",\n" +" \"body\": {\n" +" \"table\": \"Store\",\n" +" \"key\": \"84th & Third Ave - New York NY (W)\",\n" +" \"values\": {\n" +" \"location\": \"40.777485,-73.954979\"\n" +" }\n" +" }\n" +"}\n" +"{\n" +" \"dataset\": \"Starbucks\",\n" +" \"type\": \"add\",\n" +" \"body\": {\n" +" \"table\": \"Store\",\n" +" \"key\": \"150 E. 42nd Street - New York NY (W)\",\n" +" \"values\": {\n" +" \"location\": \"40.750784,-73.975582\"\n" +" }\n" +" }\n" +"}\n" +"{\n" +" \"dataset\": \"Starbucks\",\n" +" \"type\": \"add\",\n" +" \"body\": {\n" +" \"table\": \"Store\",\n" +" \"key\": \"West 43rd and Broadway - New York NY (W)\",\n" +" \"values\": {\n" +" \"location\": \"40.756197,-73.985624\"\n" +" }\n" +" }\n" +"}\n" +"{\n" +" \"dataset\": \"Starbucks\",\n" +" \"type\": \"add\",\n" +" \"body\": {\n" +" \"table\": \"Store\",\n" +" \"key\": \"Macy's 35th Street Balcony - New York NY\",\n" +" \"values\": {\n" +" \"location\": \"40.750703,-73.989787\"\n" +" }\n" +" }\n" +"}\n" +"{\n" +" \"dataset\": \"Starbucks\",\n" +" \"type\": \"add\",\n" +" \"body\": {\n" +" \"table\": \"Store\",\n" +" \"key\": \"Macy's 6th Floor - Herald Square - New York NY (W)\",\n" +" \"values\": {\n" +" \"location\": \"40.750703,-73.989787\"\n" +" }\n" +" }\n" +"}\n" +"{\n" +" \"dataset\": \"Starbucks\",\n" +" \"type\": \"add\",\n" +" \"body\": {\n" +" \"table\": \"Store\",\n" +" \"key\": \"Herald Square- Macy's - New York NY\",\n" +" \"values\": {\n" +" \"location\": \"40.750703,-73.989787\"\n" +" }\n" +" }\n" +"}\n" +"{\n" +" \"dataset\": \"Starbucks\",\n" +" \"type\": \"add\",\n" +" \"body\": {\n" +" \"table\": \"Store\",\n" +" \"key\": \"Macy's 5th Floor - Herald Square - New York NY (W)\",\n" +" \"values\": {\n" +" \"location\": \"40.750703,-73.989787\"\n" +" }\n" +" }\n" +"}\n" +"{\n" +" \"dataset\": \"Starbucks\",\n" +" \"type\": \"add\",\n" +" \"body\": {\n" +" \"table\": \"Store\",\n" +" \"key\": \"80th & York - New York NY (W)\",\n" +" \"values\": {\n" +" \"location\": \"40.772204,-73.949862\"\n" +" }\n" +" }\n" +"}\n" +"{\n" +" \"dataset\": \"Starbucks\",\n" +" \"type\": \"add\",\n" +" \"body\": {\n" +" \"table\": \"Store\",\n" +" \"key\": \"Columbus @ 67th - New York NY (W)\",\n" +" \"values\": {\n" +" \"location\": \"40.774009,-73.981472\"\n" +" }\n" +" }\n" +"}\n" +"{\n" +" \"dataset\": \"Starbucks\",\n" +" \"type\": \"add\",\n" +" \"body\": {\n" +" \"table\": \"Store\",\n" +" \"key\": \"45th & Broadway - New York NY (W)\",\n" +" \"values\": {\n" +" \"location\": \"40.75766,-73.985719\"\n" +" }\n" +" }\n" +"}\n" +"{\n" +" \"dataset\": \"Starbucks\",\n" +" \"type\": \"add\",\n" +" \"body\": {\n" +" \"table\": \"Store\",\n" +" \"key\": \"Marriott Marquis - Lobby - New York NY\",\n" +" \"values\": {\n" +" \"location\": \"40.759123,-73.984927\"\n" +" }\n" +" }\n" +"}\n" +"{\n" +" \"dataset\": \"Starbucks\",\n" +" \"type\": \"add\",\n" +" \"body\": {\n" +" \"table\": \"Store\",\n" +" \"key\": \"Second @ 81st - New York NY (W)\",\n" +" \"values\": {\n" +" \"location\": \"40.77466,-73.954447\"\n" +" }\n" +" }\n" +"}\n" +"{\n" +" \"dataset\": \"Starbucks\",\n" +" \"type\": \"add\",\n" +" \"body\": {\n" +" \"table\": \"Store\",\n" +" \"key\": \"52nd & Seventh - New York NY (W)\",\n" +" \"values\": {\n" +" \"location\": \"40.761829,-73.981141\"\n" +" }\n" +" }\n" +"}\n" +"{\n" +" \"dataset\": \"Starbucks\",\n" +" \"type\": \"add\",\n" +" \"body\": {\n" +" \"table\": \"Store\",\n" +" \"key\": \"1585 Broadway (47th) - New York NY (W)\",\n" +" \"values\": {\n" +" \"location\": \"40.759806,-73.985066\"\n" +" }\n" +" }\n" +"}\n" +"{\n" +" \"dataset\": \"Starbucks\",\n" +" \"type\": \"add\",\n" +" \"body\": {\n" +" \"table\": \"Store\",\n" +" \"key\": \"85th & First - New York NY (W)\",\n" +" \"values\": {\n" +" \"location\": \"40.776101,-73.949971\"\n" +" }\n" +" }\n" +"}\n" +"{\n" +" \"dataset\": \"Starbucks\",\n" +" \"type\": \"add\",\n" +" \"body\": {\n" +" \"table\": \"Store\",\n" +" \"key\": \"92nd & 3rd - New York NY (W)\",\n" +" \"values\": {\n" +" \"location\": \"40.782606,-73.951235\"\n" +" }\n" +" }\n" +"}\n" +"{\n" +" \"dataset\": \"Starbucks\",\n" +" \"type\": \"add\",\n" +" \"body\": {\n" +" \"table\": \"Store\",\n" +" \"key\": \"165 Broadway - 1 Liberty - New York NY (W)\",\n" +" \"values\": {\n" +" \"location\": \"40.709727,-74.011395\"\n" +" }\n" +" }\n" +"}\n" +"{\n" +" \"dataset\": \"Starbucks\",\n" +" \"type\": \"add\",\n" +" \"body\": {\n" +" \"table\": \"Store\",\n" +" \"key\": \"1656 Broadway - New York NY (W)\",\n" +" \"values\": {\n" +" \"location\": \"40.762434,-73.983364\"\n" +" }\n" +" }\n" +"}\n" +"{\n" +" \"dataset\": \"Starbucks\",\n" +" \"type\": \"add\",\n" +" \"body\": {\n" +" \"table\": \"Store\",\n" +" \"key\": \"54th & Broadway - New York NY (W)\",\n" +" \"values\": {\n" +" \"location\": \"40.764275,-73.982361\"\n" +" }\n" +" }\n" +"}\n" +"{\n" +" \"dataset\": \"Starbucks\",\n" +" \"type\": \"add\",\n" +" \"body\": {\n" +" \"table\": \"Store\",\n" +" \"key\": \"Limited Brands-NYC - New York NY\",\n" +" \"values\": {\n" +" \"location\": \"40.765219,-73.982025\"\n" +" }\n" +" }\n" +"}\n" +"{\n" +" \"dataset\": \"Starbucks\",\n" +" \"type\": \"add\",\n" +" \"body\": {\n" +" \"table\": \"Store\",\n" +" \"key\": \"19th & 8th - New York NY (W)\",\n" +" \"values\": {\n" +" \"location\": \"40.743218,-74.000605\"\n" +" }\n" +" }\n" +"}\n" +"{\n" +" \"dataset\": \"Starbucks\",\n" +" \"type\": \"add\",\n" +" \"body\": {\n" +" \"table\": \"Store\",\n" +" \"key\": \"60th & Broadway-II - New York NY (W)\",\n" +" \"values\": {\n" +" \"location\": \"40.769196,-73.982576\"\n" +" }\n" +" }\n" +"}\n" +"{\n" +" \"dataset\": \"Starbucks\",\n" +" \"type\": \"add\",\n" +" \"body\": {\n" +" \"table\": \"Store\",\n" +" \"key\": \"63rd & Broadway - New York NY (W)\",\n" +" \"values\": {\n" +" \"location\": \"40.771376,-73.982709\"\n" +" }\n" +" }\n" +"}\n" +"{\n" +" \"dataset\": \"Starbucks\",\n" +" \"type\": \"add\",\n" +" \"body\": {\n" +" \"table\": \"Store\",\n" +" \"key\": \"195 Broadway - New York NY (W)\",\n" +" \"values\": {\n" +" \"location\": \"40.710703,-74.009485\"\n" +" }\n" +" }\n" +"}\n" +"{\n" +" \"dataset\": \"Starbucks\",\n" +" \"type\": \"add\",\n" +" \"body\": {\n" +" \"table\": \"Store\",\n" +" \"key\": \"2 Broadway - New York NY (W)\",\n" +" \"values\": {\n" +" \"location\": \"40.704538,-74.01324\"\n" +" }\n" +" }\n" +"}\n" +"{\n" +" \"dataset\": \"Starbucks\",\n" +" \"type\": \"add\",\n" +" \"body\": {\n" +" \"table\": \"Store\",\n" +" \"key\": \"2 Columbus Ave. - New York NY (W)\",\n" +" \"values\": {\n" +" \"location\": \"40.769262,-73.984764\"\n" +" }\n" +" }\n" +"}\n" +"{\n" +" \"dataset\": \"Starbucks\",\n" +" \"type\": \"add\",\n" +" \"body\": {\n" +" \"table\": \"Store\",\n" +" \"key\": \"NY Plaza - New York NY (W)\",\n" +" \"values\": {\n" +" \"location\": \"40.702802,-74.012784\"\n" +" }\n" +" }\n" +"}\n" +"{\n" +" \"dataset\": \"Starbucks\",\n" +" \"type\": \"add\",\n" +" \"body\": {\n" +" \"table\": \"Store\",\n" +" \"key\": \"36th and Madison - New York NY (W)\",\n" +" \"values\": {\n" +" \"location\": \"40.748917,-73.982683\"\n" +" }\n" +" }\n" +"}\n" +"{\n" +" \"dataset\": \"Starbucks\",\n" +" \"type\": \"add\",\n" +" \"body\": {\n" +" \"table\": \"Store\",\n" +" \"key\": \"125th St. btwn Adam Clayton & FDB - New York NY\",\n" +" \"values\": {\n" +" \"location\": \"40.808952,-73.948229\"\n" +" }\n" +" }\n" +"}\n" +"{\n" +" \"dataset\": \"Starbucks\",\n" +" \"type\": \"add\",\n" +" \"body\": {\n" +" \"table\": \"Store\",\n" +" \"key\": \"70th & Broadway - New York NY (W)\",\n" +" \"values\": {\n" +" \"location\": \"40.777463,-73.982237\"\n" +" }\n" +" }\n" +"}\n" +"{\n" +" \"dataset\": \"Starbucks\",\n" +" \"type\": \"add\",\n" +" \"body\": {\n" +" \"table\": \"Store\",\n" +" \"key\": \"2138 Broadway - New York NY (W)\",\n" +" \"values\": {\n" +" \"location\": \"40.781078,-73.981167\"\n" +" }\n" +" }\n" +"}\n" +"{\n" +" \"dataset\": \"Starbucks\",\n" +" \"type\": \"add\",\n" +" \"body\": {\n" +" \"table\": \"Store\",\n" +" \"key\": \"118th & Frederick Douglas Blvd. - New York NY (W)\",\n" +" \"values\": {\n" +" \"location\": \"40.806176,-73.954109\"\n" +" }\n" +" }\n" +"}\n" +"{\n" +" \"dataset\": \"Starbucks\",\n" +" \"type\": \"add\",\n" +" \"body\": {\n" +" \"table\": \"Store\",\n" +" \"key\": \"42nd & Second - New York NY (W)\",\n" +" \"values\": {\n" +" \"location\": \"40.750069,-73.973393\"\n" +" }\n" +" }\n" +"}\n" +"{\n" +" \"dataset\": \"Starbucks\",\n" +" \"type\": \"add\",\n" +" \"body\": {\n" +" \"table\": \"Store\",\n" +" \"key\": \"Broadway @ 81st - New York NY (W)\",\n" +" \"values\": {\n" +" \"location\": \"40.784972,-73.978987\"\n" +" }\n" +" }\n" +"}\n" +"{\n" +" \"dataset\": \"Starbucks\",\n" +" \"type\": \"add\",\n" +" \"body\": {\n" +" \"table\": \"Store\",\n" +" \"key\": \"Fashion Inst of Technology - New York NY\",\n" +" \"values\": {\n" +" \"location\": \"40.746948,-73.994557\"\n" +" }\n" +" }\n" +"}\n" +"~~~" +msgstr "" + +msgid "Open another terminal and send the json to the Droonga engine." +msgstr "もう一つターミナルを開いて、jsonをDroonga engineに送信しましょう。" + +msgid "Send `stores.jsons` as follows:" +msgstr "以下のようにして`stores.json`を送信します:" + +msgid "" +"~~~\n" +"# droonga-request --tag starbucks stores.jsons\n" +"Elapsed time: 0.01101195\n" +"[\n" +" \"droonga.message\",\n" +" 1393562553,\n" +" {\n" +" \"inReplyTo\": \"1393562553.8918273\",\n" +" \"statusCode\": 200,\n" +" \"type\": \"add.result\",\n" +" \"body\": true\n" +" }\n" +"]\n" +"Elapsed time: 0.008872597\n" +"[\n" +" \"droonga.message\",\n" +" 1393562553,\n" +" {\n" +" \"inReplyTo\": \"1393562553.9034681\",\n" +" \"statusCode\": 200,\n" +" \"type\": \"add.result\",\n" +" \"body\": true\n" +" }\n" +"]\n" +"Elapsed time: 0.008392207\n" +"[\n" +" \"droonga.message\",\n" +" 1393562553,\n" +" {\n" +" \"inReplyTo\": \"1393562553.9126666\",\n" +" \"statusCode\": 200,\n" +" \"type\": \"add.result\",\n" +" \"body\": true\n" +" }\n" +"]\n" +"Elapsed time: 0.011983187\n" +"[\n" +" \"droonga.message\",\n" +" 1393562553,\n" +" {\n" +" \"inReplyTo\": \"1393562553.9212565\",\n" +" \"statusCode\": 200,\n" +" \"type\": \"add.result\",\n" +" \"body\": true\n" +" }\n" +"]\n" +"Elapsed time: 0.008101728\n" +"[\n" +" \"droonga.message\",\n" +" 1393562553,\n" +" {\n" +" \"inReplyTo\": \"1393562553.9338331\",\n" +" \"statusCode\": 200,\n" +" \"type\": \"add.result\",\n" +" \"body\": true\n" +" }\n" +"]\n" +"Elapsed time: 0.004175044\n" +"[\n" +" \"droonga.message\",\n" +" 1393562553,\n" +" {\n" +" \"inReplyTo\": \"1393562553.9421282\",\n" +" \"statusCode\": 200,\n" +" \"type\": \"add.result\",\n" +" \"body\": true\n" +" }\n" +"]\n" +"Elapsed time: 0.017018749\n" +"[\n" +" \"droonga.message\",\n" +" 1393562553,\n" +" {\n" +" \"inReplyTo\": \"1393562553.946642\",\n" +" \"statusCode\": 200,\n" +" \"type\": \"add.result\",\n" +" \"body\": true\n" +" }\n" +"]\n" +"Elapsed time: 0.007583209\n" +"[\n" +" \"droonga.message\",\n" +" 1393562553,\n" +" {\n" +" \"inReplyTo\": \"1393562553.9639654\",\n" +" \"statusCode\": 200,\n" +" \"type\": \"add.result\",\n" +" \"body\": true\n" +" }\n" +"]\n" +"Elapsed time: 0.00841723\n" +"[\n" +" \"droonga.message\",\n" +" 1393562553,\n" +" {\n" +" \"inReplyTo\": \"1393562553.9719582\",\n" +" \"statusCode\": 200,\n" +" \"type\": \"add.result\",\n" +" \"body\": true\n" +" }\n" +"]\n" +"Elapsed time: 0.009108127\n" +"[\n" +" \"droonga.message\",\n" +" 1393562553,\n" +" {\n" +" \"inReplyTo\": \"1393562553.9804838\",\n" +" \"statusCode\": 200,\n" +" \"type\": \"add.result\",\n" +" \"body\": true\n" +" }\n" +"]\n" +"Elapsed time: 0.005036642\n" +"[\n" +" \"droonga.message\",\n" +" 1393562553,\n" +" {\n" +" \"inReplyTo\": \"1393562553.989766\",\n" +" \"statusCode\": 200,\n" +" \"type\": \"add.result\",\n" +" \"body\": true\n" +" }\n" +"]\n" +"Elapsed time: 0.004036806\n" +"[\n" +" \"droonga.message\",\n" +" 1393562553,\n" +" {\n" +" \"inReplyTo\": \"1393562553.9952037\",\n" +" \"statusCode\": 200,\n" +" \"type\": \"add.result\",\n" +" \"body\": true\n" +" }\n" +"]\n" +"Elapsed time: 0.012368974\n" +"[\n" +" \"droonga.message\",\n" +" 1393562554,\n" +" {\n" +" \"inReplyTo\": \"1393562553.999501\",\n" +" \"statusCode\": 200,\n" +" \"type\": \"add.result\",\n" +" \"body\": true\n" +" }\n" +"]\n" +"Elapsed time: 0.004099008\n" +"[\n" +" \"droonga.message\",\n" +" 1393562554,\n" +" {\n" +" \"inReplyTo\": \"1393562554.0122097\",\n" +" \"statusCode\": 200,\n" +" \"type\": \"add.result\",\n" +" \"body\": true\n" +" }\n" +"]\n" +"Elapsed time: 0.027017019\n" +"[\n" +" \"droonga.message\",\n" +" 1393562554,\n" +" {\n" +" \"inReplyTo\": \"1393562554.016705\",\n" +" \"statusCode\": 200,\n" +" \"type\": \"add.result\",\n" +" \"body\": true\n" +" }\n" +"]\n" +"Elapsed time: 0.010383751\n" +"[\n" +" \"droonga.message\",\n" +" 1393562554,\n" +" {\n" +" \"inReplyTo\": \"1393562554.044215\",\n" +" \"statusCode\": 200,\n" +" \"type\": \"add.result\",\n" +" \"body\": true\n" +" }\n" +"]\n" +"Elapsed time: 0.004364288\n" +"[\n" +" \"droonga.message\",\n" +" 1393562554,\n" +" {\n" +" \"inReplyTo\": \"1393562554.0549927\",\n" +" \"statusCode\": 200,\n" +" \"type\": \"add.result\",\n" +" \"body\": true\n" +" }\n" +"]\n" +"Elapsed time: 0.003277611\n" +"[\n" +" \"droonga.message\",\n" +" 1393562554,\n" +" {\n" +" \"inReplyTo\": \"1393562554.0595262\",\n" +" \"statusCode\": 200,\n" +" \"type\": \"add.result\",\n" +" \"body\": true\n" +" }\n" +"]\n" +"Elapsed time: 0.007540272\n" +"[\n" +" \"droonga.message\",\n" +" 1393562554,\n" +" {\n" +" \"inReplyTo\": \"1393562554.063036\",\n" +" \"statusCode\": 200,\n" +" \"type\": \"add.result\",\n" +" \"body\": true\n" +" }\n" +"]\n" +"Elapsed time: 0.002973611\n" +"[\n" +" \"droonga.message\",\n" +" 1393562554,\n" +" {\n" +" \"inReplyTo\": \"1393562554.0707917\",\n" +" \"statusCode\": 200,\n" +" \"type\": \"add.result\",\n" +" \"body\": true\n" +" }\n" +"]\n" +"Elapsed time: 0.024142012\n" +"[\n" +" \"droonga.message\",\n" +" 1393562554,\n" +" {\n" +" \"inReplyTo\": \"1393562554.0739512\",\n" +" \"statusCode\": 200,\n" +" \"type\": \"add.result\",\n" +" \"body\": true\n" +" }\n" +"]\n" +"Elapsed time: 0.010329014\n" +"[\n" +" \"droonga.message\",\n" +" 1393562554,\n" +" {\n" +" \"inReplyTo\": \"1393562554.098288\",\n" +" \"statusCode\": 200,\n" +" \"type\": \"add.result\",\n" +" \"body\": true\n" +" }\n" +"]\n" +"Elapsed time: 0.004758853\n" +"[\n" +" \"droonga.message\",\n" +" 1393562554,\n" +" {\n" +" \"inReplyTo\": \"1393562554.1089437\",\n" +" \"statusCode\": 200,\n" +" \"type\": \"add.result\",\n" +" \"body\": true\n" +" }\n" +"]\n" +"Elapsed time: 0.007113416\n" +"[\n" +" \"droonga.message\",\n" +" 1393562554,\n" +" {\n" +" \"inReplyTo\": \"1393562554.113922\",\n" +" \"statusCode\": 200,\n" +" \"type\": \"add.result\",\n" +" \"body\": true\n" +" }\n" +"]\n" +"Elapsed time: 0.007472331\n" +"[\n" +" \"droonga.message\",\n" +" 1393562554,\n" +" {\n" +" \"inReplyTo\": \"1393562554.121428\",\n" +" \"statusCode\": 200,\n" +" \"type\": \"add.result\",\n" +" \"body\": true\n" +" }\n" +"]\n" +"Elapsed time: 0.011560447\n" +"[\n" +" \"droonga.message\",\n" +" 1393562554,\n" +" {\n" +" \"inReplyTo\": \"1393562554.1294332\",\n" +" \"statusCode\": 200,\n" +" \"type\": \"add.result\",\n" +" \"body\": true\n" +" }\n" +"]\n" +"Elapsed time: 0.006053761\n" +"[\n" +" \"droonga.message\",\n" +" 1393562554,\n" +" {\n" +" \"inReplyTo\": \"1393562554.1413999\",\n" +" \"statusCode\": 200,\n" +" \"type\": \"add.result\",\n" +" \"body\": true\n" +" }\n" +"]\n" +"Elapsed time: 0.013611626\n" +"[\n" +" \"droonga.message\",\n" +" 1393562554,\n" +" {\n" +" \"inReplyTo\": \"1393562554.1479707\",\n" +" \"statusCode\": 200,\n" +" \"type\": \"add.result\",\n" +" \"body\": true\n" +" }\n" +"]\n" +"Elapsed time: 0.007455591\n" +"[\n" +" \"droonga.message\",\n" +" 1393562554,\n" +" {\n" +" \"inReplyTo\": \"1393562554.1624238\",\n" +" \"statusCode\": 200,\n" +" \"type\": \"add.result\",\n" +" \"body\": true\n" +" }\n" +"]\n" +"Elapsed time: 0.005440424\n" +"[\n" +" \"droonga.message\",\n" +" 1393562554,\n" +" {\n" +" \"inReplyTo\": \"1393562554.1702914\",\n" +" \"statusCode\": 200,\n" +" \"type\": \"add.result\",\n" +" \"body\": true\n" +" }\n" +"]\n" +"Elapsed time: 0.005610303\n" +"[\n" +" \"droonga.message\",\n" +" 1393562554,\n" +" {\n" +" \"inReplyTo\": \"1393562554.1760805\",\n" +" \"statusCode\": 200,\n" +" \"type\": \"add.result\",\n" +" \"body\": true\n" +" }\n" +"]\n" +"Elapsed time: 0.025479938\n" +"[\n" +" \"droonga.message\",\n" +" 1393562554,\n" +" {\n" +" \"inReplyTo\": \"1393562554.1822054\",\n" +" \"statusCode\": 200,\n" +" \"type\": \"add.result\",\n" +" \"body\": true\n" +" }\n" +"]\n" +"Elapsed time: 0.007125251\n" +"[\n" +" \"droonga.message\",\n" +" 1393562554,\n" +" {\n" +" \"inReplyTo\": \"1393562554.2080746\",\n" +" \"statusCode\": 200,\n" +" \"type\": \"add.result\",\n" +" \"body\": true\n" +" }\n" +"]\n" +"Elapsed time: 0.009454133\n" +"[\n" +" \"droonga.message\",\n" +" 1393562554,\n" +" {\n" +" \"inReplyTo\": \"1393562554.2158518\",\n" +" \"statusCode\": 200,\n" +" \"type\": \"add.result\",\n" +" \"body\": true\n" +" }\n" +"]\n" +"Elapsed time: 0.003632905\n" +"[\n" +" \"droonga.message\",\n" +" 1393562554,\n" +" {\n" +" \"inReplyTo\": \"1393562554.2255347\",\n" +" \"statusCode\": 200,\n" +" \"type\": \"add.result\",\n" +" \"body\": true\n" +" }\n" +"]\n" +"Elapsed time: 0.003653783\n" +"[\n" +" \"droonga.message\",\n" +" 1393562554,\n" +" {\n" +" \"inReplyTo\": \"1393562554.2293708\",\n" +" \"statusCode\": 200,\n" +" \"type\": \"add.result\",\n" +" \"body\": true\n" +" }\n" +"]\n" +"Elapsed time: 0.003643588\n" +"[\n" +" \"droonga.message\",\n" +" 1393562554,\n" +" {\n" +" \"inReplyTo\": \"1393562554.2332237\",\n" +" \"statusCode\": 200,\n" +" \"type\": \"add.result\",\n" +" \"body\": true\n" +" }\n" +"]\n" +"Elapsed time: 0.003703875\n" +"[\n" +" \"droonga.message\",\n" +" 1393562554,\n" +" {\n" +" \"inReplyTo\": \"1393562554.237225\",\n" +" \"statusCode\": 200,\n" +" \"type\": \"add.result\",\n" +" \"body\": true\n" +" }\n" +"]\n" +"Elapsed time: 0.003402826\n" +"[\n" +" \"droonga.message\",\n" +" 1393562554,\n" +" {\n" +" \"inReplyTo\": \"1393562554.2411628\",\n" +" \"statusCode\": 200,\n" +" \"type\": \"add.result\",\n" +" \"body\": true\n" +" }\n" +"]\n" +"Elapsed time: 0.004817463\n" +"[\n" +" \"droonga.message\",\n" +" 1393562554,\n" +" {\n" +" \"inReplyTo\": \"1393562554.2447524\",\n" +" \"statusCode\": 200,\n" +" \"type\": \"add.result\",\n" +" \"body\": true\n" +" }\n" +"]\n" +"~~~" +msgstr "" + +msgid "Now a Droonga engine for searching Starbucks stores database is ready." +msgstr "Droonga engineを用いてスターバックスの店舗データベースを検索する準備ができました。" + +msgid "### Send request with droonga-request" +msgstr "### droonga-requestでリクエストを送る" + +msgid "Check if it is working. Create a query as a JSON file as follows." +msgstr "動作を確認してみましょう。クエリを以下のようなJSONファイルとして作成します。" + +msgid "search-all-stores.json:" +msgstr "" + +msgid "" +"~~~\n" +"{\n" +" \"dataset\": \"Starbucks\",\n" +" \"type\": \"search\",\n" +" \"body\": {\n" +" \"queries\": {\n" +" \"stores\": {\n" +" \"source\": \"Store\",\n" +" \"output\": {\n" +" \"elements\": [\n" +" \"startTime\",\n" +" \"elapsedTime\",\n" +" \"count\",\n" +" \"attributes\",\n" +" \"records\"\n" +" ],\n" +" \"attributes\": [\"_key\"],\n" +" \"limit\": -1\n" +" }\n" +" }\n" +" }\n" +" }\n" +"}\n" +"~~~" +msgstr "" + +msgid "Send the request to the Droonga Engine:" +msgstr "Droonga Engine にリクエストを送信します:" + +msgid "" +"~~~\n" +"# droonga-request search-all-stores.json\n" +"Elapsed time: 0.008286785\n" +"[\n" +" \"droonga.message\",\n" +" 1393562604,\n" +" {\n" +" \"inReplyTo\": \"1393562604.4970381\",\n" +" \"statusCode\": 200,\n" +" \"type\": \"search.result\",\n" +" \"body\": {\n" +" \"stores\": {\n" +" \"count\": 40,\n" +" \"records\": [\n" +" [\n" +" \"15th & Third - New York NY (W)\"\n" +" ],\n" +" [\n" +" \"41st and Broadway - New York NY (W)\"\n" +" ],\n" +" [\n" +" \"84th & Third Ave - New York NY (W)\"\n" +" ],\n" +" [\n" +" \"Macy's 35th Street Balcony - New York NY\"\n" +" ],\n" +" [\n" +" \"Second @ 81st - New York NY (W)\"\n" +" ],\n" +" [\n" +" \"52nd & Seventh - New York NY (W)\"\n" +" ],\n" +" [\n" +" \"1585 Broadway (47th) - New York NY (W)\"\n" +" ],\n" +" [\n" +" \"54th & Broadway - New York NY (W)\"\n" +" ],\n" +" [\n" +" \"60th & Broadway-II - New York NY (W)\"\n" +" ],\n" +" [\n" +" \"63rd & Broadway - New York NY (W)\"\n" +" ],\n" +" [\n" +" \"2 Columbus Ave. - New York NY (W)\"\n" +" ],\n" +" [\n" +" \"NY Plaza - New York NY (W)\"\n" +" ],\n" +" [\n" +" \"2138 Broadway - New York NY (W)\"\n" +" ],\n" +" [\n" +" \"Broadway @ 81st - New York NY (W)\"\n" +" ],\n" +" [\n" +" \"76th & Second - New York NY (W)\"\n" +" ],\n" +" [\n" +" \"2nd Ave. & 9th Street - New York NY\"\n" +" ],\n" +" [\n" +" \"150 E. 42nd Street - New York NY (W)\"\n" +" ],\n" +" [\n" +" \"Macy's 6th Floor - Herald Square - New York NY (W)\"\n" +" ],\n" +" [\n" +" \"Herald Square- Macy's - New York NY\"\n" +" ],\n" +" [\n" +" \"Macy's 5th Floor - Herald Square - New York NY (W)\"\n" +" ],\n" +" [\n" +" \"Marriott Marquis - Lobby - New York NY\"\n" +" ],\n" +" [\n" +" \"85th & First - New York NY (W)\"\n" +" ],\n" +" [\n" +" \"1656 Broadway - New York NY (W)\"\n" +" ],\n" +" [\n" +" \"Limited Brands-NYC - New York NY\"\n" +" ],\n" +" [\n" +" \"2 Broadway - New York NY (W)\"\n" +" ],\n" +" [\n" +" \"36th and Madison - New York NY (W)\"\n" +" ],\n" +" [\n" +" \"125th St. btwn Adam Clayton & FDB - New York NY\"\n" +" ],\n" +" [\n" +" \"118th & Frederick Douglas Blvd. - New York NY (W)\"\n" +" ],\n" +" [\n" +" \"Fashion Inst of Technology - New York NY\"\n" +" ],\n" +" [\n" +" \"1st Avenue & 75th St. - New York NY (W)\"\n" +" ],\n" +" [\n" +" \"West 43rd and Broadway - New York NY (W)\"\n" +" ],\n" +" [\n" +" \"80th & York - New York NY (W)\"\n" +" ],\n" +" [\n" +" \"Columbus @ 67th - New York NY (W)\"\n" +" ],\n" +" [\n" +" \"45th & Broadway - New York NY (W)\"\n" +" ],\n" +" [\n" +" \"92nd & 3rd - New York NY (W)\"\n" +" ],\n" +" [\n" +" \"165 Broadway - 1 Liberty - New York NY (W)\"\n" +" ],\n" +" [\n" +" \"19th & 8th - New York NY (W)\"\n" +" ],\n" +" [\n" +" \"195 Broadway - New York NY (W)\"\n" +" ],\n" +" [\n" +" \"70th & Broadway - New York NY (W)\"\n" +" ],\n" +" [\n" +" \"42nd & Second - New York NY (W)\"\n" +" ]\n" +" ]\n" +" }\n" +" }\n" +" }\n" +"]\n" +"~~~" +msgstr "" + +msgid "" +"Now the store names are retrieved. The engine looks working correctly.\n" +"Next, setup a protocol adapter for clients to accept search requests via HTTP." +msgstr "" +"店舗の名前が取得できました。エンジンは正しく動作しているようです。引き続き Protocol Adapter を構築して、検索リクエストをHTTPで受け付け" +"られるようにしましょう。" + +msgid "## Setup an HTTP Protocol Adapter" +msgstr "## HTTP Protocol Adapter を用意する" + +msgid "" +"Let's use the `droonga-http-server` as an HTTP protocol adapter. It is an npm " +"package for the Node.js." +msgstr "" +"HTTP Protocol Adapterとして`droonga-http-server`を使用します。`droonga-http-server`は、Nod" +"e.js のパッケージです。" + +msgid "### Install the droonga-http-server" +msgstr "### droonga-http-serverをインストールする" + +msgid " # npm install -g droonga-http-server" +msgstr "" + +msgid "Then, run it." +msgstr "次に、サーバを起動します。" + +msgid "" +" # droonga-http-server --port 3000 \\\n" +" --receive-host-name=192.168.0.10 \\\n" +" --droonga-engine-host-name=192.168.0.10 \\\n" +" --default-dataset=Starbucks \\\n" +" --daemon \\\n" +" --pid-file $PWD/droonga-http-server.pid" +msgstr "" + +msgid "### Search request via HTTP" +msgstr "### HTTPでの検索リクエスト" + +msgid "" +"We're all set. Let's send a search request to the protocol adapter via HTTP. A" +"t first, try to get all records of the `Stores` table by a request like follow" +"ing. (Note: The `attributes=_key` parameter means \"export the value of the col" +"umn `_key` to the search result\". If you don't set the parameter, each record " +"returned in the `records` will become just a blank array. You can specify mult" +"iple column names by the delimiter `,`. For example `attributes=_key,location`" +" will return both the primary key and the location for each record.)" +msgstr "" +"準備が整いました。 Protocol Adapter に向けて HTTP 経由でリクエストを発行し、データベースに問い合わせを行ってみましょう。まずは `S" +"hops` テーブルの中身を取得してみます。以下のようなリクエストを用います。(`attributes=_key` を指定しているのは「検索結果に `_ke" +"y` 値を含めて返してほしい」という意味です。これがないと、`records` に何も値がないレコードが返ってきてしまいます。`attributes` パラ" +"メータには `,` 区切りで複数の属性を指定することができます。`attributes=_key,location` と指定することで、緯度経度もレスポンス" +"として受け取ることができます)" + +msgid "" +" # curl \"http://192.168.0.10:3000/tables/Store?attributes=_key&limit=-1\"\n" +" {\n" +" \"stores\": {\n" +" \"count\": 40,\n" +" \"records\": [\n" +" [\n" +" \"15th & Third - New York NY (W)\"\n" +" ],\n" +" [\n" +" \"41st and Broadway - New York NY (W)\"\n" +" ],\n" +" [\n" +" \"84th & Third Ave - New York NY (W)\"\n" +" ],\n" +" [\n" +" \"Macy's 35th Street Balcony - New York NY\"\n" +" ],\n" +" [\n" +" \"Second @ 81st - New York NY (W)\"\n" +" ],\n" +" [\n" +" \"52nd & Seventh - New York NY (W)\"\n" +" ],\n" +" [\n" +" \"1585 Broadway (47th) - New York NY (W)\"\n" +" ],\n" +" [\n" +" \"54th & Broadway - New York NY (W)\"\n" +" ],\n" +" [\n" +" \"60th & Broadway-II - New York NY (W)\"\n" +" ],\n" +" [\n" +" \"63rd & Broadway - New York NY (W)\"\n" +" ],\n" +" [\n" +" \"2 Columbus Ave. - New York NY (W)\"\n" +" ],\n" +" [\n" +" \"NY Plaza - New York NY (W)\"\n" +" ],\n" +" [\n" +" \"2138 Broadway - New York NY (W)\"\n" +" ],\n" +" [\n" +" \"Broadway @ 81st - New York NY (W)\"\n" +" ],\n" +" [\n" +" \"76th & Second - New York NY (W)\"\n" +" ],\n" +" [\n" +" \"2nd Ave. & 9th Street - New York NY\"\n" +" ],\n" +" [\n" +" \"150 E. 42nd Street - New York NY (W)\"\n" +" ],\n" +" [\n" +" \"Macy's 6th Floor - Herald Square - New York NY (W)\"\n" +" ],\n" +" [\n" +" \"Herald Square- Macy's - New York NY\"\n" +" ],\n" +" [\n" +" \"Macy's 5th Floor - Herald Square - New York NY (W)\"\n" +" ],\n" +" [\n" +" \"Marriott Marquis - Lobby - New York NY\"\n" +" ],\n" +" [\n" +" \"85th & First - New York NY (W)\"\n" +" ],\n" +" [\n" +" \"1656 Broadway - New York NY (W)\"\n" +" ],\n" +" [\n" +" \"Limited Brands-NYC - New York NY\"\n" +" ],\n" +" [\n" +" \"2 Broadway - New York NY (W)\"\n" +" ],\n" +" [\n" +" \"36th and Madison - New York NY (W)\"\n" +" ],\n" +" [\n" +" \"125th St. btwn Adam Clayton & FDB - New York NY\"\n" +" ],\n" +" [\n" +" \"118th & Frederick Douglas Blvd. - New York NY (W)\"\n" +" ],\n" +" [\n" +" \"Fashion Inst of Technology - New York NY\"\n" +" ],\n" +" [\n" +" \"1st Avenue & 75th St. - New York NY (W)\"\n" +" ],\n" +" [\n" +" \"West 43rd and Broadway - New York NY (W)\"\n" +" ],\n" +" [\n" +" \"80th & York - New York NY (W)\"\n" +" ],\n" +" [\n" +" \"Columbus @ 67th - New York NY (W)\"\n" +" ],\n" +" [\n" +" \"45th & Broadway - New York NY (W)\"\n" +" ],\n" +" [\n" +" \"92nd & 3rd - New York NY (W)\"\n" +" ],\n" +" [\n" +" \"165 Broadway - 1 Liberty - New York NY (W)\"\n" +" ],\n" +" [\n" +" \"19th & 8th - New York NY (W)\"\n" +" ],\n" +" [\n" +" \"195 Broadway - New York NY (W)\"\n" +" ],\n" +" [\n" +" \"70th & Broadway - New York NY (W)\"\n" +" ],\n" +" [\n" +" \"42nd & Second - New York NY (W)\"\n" +" ]\n" +" ]\n" +" }\n" +" }" +msgstr "" + +msgid "" +"Because the `count` says `40`, you know there are all 40 records in the table." +" Search result records are returned as an array `records`." +msgstr "`count` の値からデータが全部で 36 件あることがわかります。`records` に配列として検索結果が入っています。" + +msgid "" +"Next step, let's try more meaningful query. To search stores which contain \"Co" +"lumbus\" in their name, give `Columbus` as the parameter `query`, and give `_ke" +"y` as the parameter `match_to` which means the column to be searched. Then:" +msgstr "" +"もう少し複雑なクエリを試してみましょう。例えば、店名に「Columbus」を含む店舗を検索します。`query` パラメータにクエリ `Columbus` " +"を、`match_to` パラメータに検索対象として `_key` を指定し、以下のようなリクエストを発行します。" + +msgid "" +" # curl \"http://192.168.0.10:3000/tables/Store?query=Columbus&match_to=_key" +"&attributes=_key&limit=-1\"\n" +" {\n" +" \"stores\": {\n" +" \"count\": 2,\n" +" \"records\": [\n" +" [\n" +" \"Columbus @ 67th - New York NY (W)\"\n" +" ],\n" +" [\n" +" \"2 Columbus Ave. - New York NY (W)\"\n" +" ]\n" +" ]\n" +" }\n" +" }" +msgstr "" + +msgid "As the result, two stores are found by the search condition." +msgstr "以上 2 件が検索結果として該当することがわかりました。" + +msgid "" +"For more details of the Droonga HTTP Server, see the [reference manual][http-s" +"erver]." +msgstr "Droonga HTTP Serverの詳細については[リファレンスマニュアル][http-server]を参照して下さい。" + +msgid "## Conclusion" +msgstr "## まとめ" + +msgid "" +"In this tutorial, you did setup both packages [droonga-engine][] and [droonga-" +"http-server][] which construct [Droonga][] service on a [Ubuntu Linux][Ubuntu]" +".\n" +"Moreover, you built a search system based on an HTTP protocol adapter with a D" +"roonga engine, and successfully searched." +msgstr "" +"[Ubuntu Linux][Ubuntu] 上に [Droonga][] を構成するパッケージである [droonga-engine][] と [droo" +"nga-http-server][] をセットアップしました。\n" +"これらのパッケージを利用することで、HTTP Protocol Adapter と Droonga Engine からなるシステムを構築し、実際に検索を行い" +"ました。" + +msgid "" +" [http-server]: ../../reference/http-server/\n" +" [Ubuntu]: http://www.ubuntu.com/\n" +" [Droonga]: https://droonga.org/\n" +" [droonga-engine]: https://github.com/droonga/droonga-engine\n" +" [droonga-http-server]: https://github.com/droonga/droonga-http-server\n" +" [Groonga]: http://groonga.org/\n" +" [Ruby]: http://www.ruby-lang.org/\n" +" [nvm]: https://github.com/creationix/nvm\n" +" [Socket.IO]: http://socket.io/\n" +" [Fluentd]: http://fluentd.org/\n" +" [Node.js]: http://nodejs.org/" +msgstr "" Added: _po/ja/tutorial/1.0.3/groonga/index.po (+551 -0) 100644 =================================================================== --- /dev/null +++ _po/ja/tutorial/1.0.3/groonga/index.po 2014-05-19 16:48:30 +0900 (59ca05d) @@ -0,0 +1,551 @@ +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"PO-Revision-Date: 2014-03-05 12:52+0900\n" +"Language: ja\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" + +msgid "" +"---\n" +"title: \"Droonga tutorial: How to migrate from Groonga?\"\n" +"layout: en\n" +"---" +msgstr "" +"---\n" +"title: \"Droongaチュートリアル: Groongaからの移行手順\"\n" +"layout: ja\n" +"---" + +msgid "" +"* TOC\n" +"{:toc}" +msgstr "" + +msgid "## The goal of this tutorial" +msgstr "## チュートリアルのゴール" + +msgid "" +"Learning steps to run a Droonga cluster by your hand, and use it as a [Groonga" +"][groonga] compatible server." +msgstr "Droongaクラスタを自分で構築して、[Groonga][groonga]互換のサーバとして利用できるようにするための手順を学ぶこと。" + +msgid "## Precondition" +msgstr "## 前提条件" + +msgid "" +"* You must have basic knowledge and experiences to set up and operate an [Ubun" +"tu][] Server.\n" +"* You must have basic knowledge and experiences to use the [Groonga][groonga] " +"via HTTP." +msgstr "" +"* [Ubuntu][]サーバのセットアップと操作について、基本的な知識と経験があること。\n" +"* [Groonga][groonga]のHTTP経由での利用について、基本的な知識と経験があること。" + +msgid "## What's Droonga?" +msgstr "## Droongaとは何か?" + +msgid "" +"It is a data processing engine based on a distributed architecture, named afte" +"r the terms \"distributed-Groonga\".\n" +"As its name suggests, it can work as a Groonga compatible server with some imp" +"rovements - replication and sharding." +msgstr "" +"Droongaは分散アーキテクチャに基づくデータ処理エンジンで、「distributed-Groonga」がその名の由来です。\n" +"名前が示す通り、Droongaはいくつかの点での改善(具体的には、レプリケーションとシャーディング)を含んだGroonga互換のサーバとして動作することがで" +"きます。" + +msgid "" +"In a certain sense, the Droonga is quite different from Groonga, about its arc" +"hitecture, design, API etc.\n" +"However, you don't have to understand the whole architecture of the Droonga, i" +"f you simply use it just as a Groonga compatible server." +msgstr "" +"アーキテクチャ、設計、APIなどの点で、DroongaはGroongaと大きく異なっています。\n" +"しかしながら、Droongaを単にGroonga互換のサーバとして使う限りにおいては、Droongaのアーキテクチャ全体を理解する必要はありません。" + +msgid "" +"For example, let's try to build a database system to find [Starbucks stores in" +" New York](http://geocommons.com/overlays/430038)." +msgstr "" +"例として、[ニューヨークにあるスターバックスの店舗](http://geocommons.com/overlays/430038)を検索できるデータベースシ" +"ステムを作成することにします。" + +msgid "## Set up a Droonga cluster" +msgstr "## Droongaクラスタをセットアップする" + +msgid "### Prepare an environment for experiments" +msgstr "### 実験用の環境を準備する" + +msgid "" +"Prepare a computer at first.\n" +"This tutorial describes steps to set up a Droonga cluster based on existing co" +"mputers.\n" +"Following instructions are basically written for a successfully prepared virtu" +"al machine of the `Ubuntu 13.10 x64` on the service [DigitalOcean](https://www" +".digitalocean.com/), with an available console." +msgstr "" +"まず最初にコンピュータを用意します。\n" +"このチュートリアルは、既存のコンピュータを使ってDroongaクラスタを構築する手順について解説しています。\n" +"以下の説明は基本的には、[DigitalOcean](https://www.digitalocean.com/)上のサーバで`Ubuntu 13.10 x" +"64`の仮想マシンが正しく準備されており、コンソールが利用できる状態になっている、という前提に基づいています。" + +msgid "" +"NOTE: Make sure to use instances with >= 2GB memory equipped, at least during " +"installation of required packages for Droonga.\n" +"Otherwise, you may experience a strange build error." +msgstr "" +"注意:Droongaの依存パッケージをインストールする前に、仮想マシンのインスタンスが少なくとも2GB以上のメモリを備えていることを確認して下さい。\n" +"メモリが足らないと、ビルド時におかしなエラーに遭遇することになります。" + +msgid "You need to prepare two or more computers for effective replication." +msgstr "また、有効なレプリケーションを実現するためには2台以上のコンピュータを用意する必要もあります。" + +msgid "### Steps to install Droonga components" +msgstr "### Droongaの構成コンポーネントをインストールする" + +msgid "" +"Groonga provides binary packages and you can install Groonga easily, for some " +"environments.\n" +"(See: [how to install Groonga](http://groonga.org/docs/install.html))" +msgstr "" +"Groongaはバイナリのパッケージを提供しているため、環境によっては簡単にインストールできます。\n" +"([Groongaのインストール手順](http://groonga.org/docs/install.html)を参照)" + +msgid "" +"However, currently there is no such an easy way to set up a database system ba" +"sed on Droonga.\n" +"We are planning to provide a better way (like a chef cookbook), but for now, y" +"ou have to set up it by your hand." +msgstr "" +"しかしながら、現在の所Droongaに基づくデータベースシステムをセットアップするための簡単な方法はありません。\n" +"将来的にはより良い方法(例えばChefのクックブックなど)を用意する計画がありますが、今のところは、セットアップは手動で行う必要があります。" + +msgid "" +"A database system based on the Droonga is called *Droonga cluster*.\n" +"A Droonga cluster is constructed from multiple computers, called *Droonga node" +"*.\n" +"So you have to set up multiple Droonga nodes for your Droonga cluster." +msgstr "" +"Droongaベースのデータベースシステムは、*Droongaクラスタ*と呼ばれます。\n" +"Droongaクラスタは、*Droongaノード*と呼ばれる複数のコンピュータによって構成されます。\n" +"よって、Droongaクラスタを構築するには複数のDroongaノードをセットアップする必要があります。" + +msgid "Assume that you have two computers: `192.168.0.10` and `192.168.0.11`." +msgstr "`192.168.0.10`と`192.168.0.11`の2つのコンピュータがあると仮定しましょう。" + +msgid " 1. Install required platform packages, *on each computer*." +msgstr " 1. *それぞれのコンピュータで*、プラットフォームごとに要求されるパッケージをインストールする。" + +msgid "" +" # apt-get update\n" +" # apt-get -y upgrade\n" +" # apt-get install -y ruby ruby-dev build-essential nodejs npm" +msgstr "" + +msgid "" +" 2. Install a gem package `droonga-engine`, *on each computer*.\n" +" It is the core component provides most features of Droonga system." +msgstr "" +" 2. *それぞれのコンピュータで*、Gemパッケージ `droonga-engine` をインストールする。\n" +" これはDroongaシステムの主要な機能を提供する、核となるコンポーネントです。" + +msgid " # gem install droonga-engine" +msgstr "" + +msgid "" +" 3. Install an npm package `droonga-http-server`, *on each computer*.\n" +" It is the frontend component required to translate HTTP requests to Droong" +"a's native one." +msgstr "" +" 3. *それぞれのコンピュータで*、npmパッケージ `droonga-http-server` をインストールする。\n" +" これはHTTPのリクエストをDroongaネイティブのリクエストに変換するために必要な、フロントエンドとなるコンポーネントです。" + +msgid " # npm install -g droonga-http-server" +msgstr "" + +msgid "" +" 4. Install [Serf][] command, *on each computer*.\n" +" It is required to do alive monitoring of nodes in the cluster." +msgstr "" +" 4. *それぞれのコンピュータで*、[Serf][]のコマンドをインストールします。\n" +" これはクラスタの各ノードの死活監視を行うために必要です。" + +msgid "" +" # wget https://dl.bintray.com/mitchellh/serf/0.5.0_linux_amd64.zip\n" +" # unzip 0.5.0_linux_amd64.zip\n" +" # sudo mv serf /usr/local/bin/" +msgstr "" + +msgid "" +" 5. Prepare a configuration directory for a Droonga node, *on each computer*.\n" +" All physical databases are placed under this directory." +msgstr "" +" 5. *それぞれのコンピュータで*、Droongaノードとしての情報を保存するための設定ディレクトリを用意する。\n" +" すべてのデータベースの実体は、このディレクトリ以下に保存されます。" + +msgid "" +" # mkdir ~/droonga\n" +" # cd ~/droonga" +msgstr "" + +msgid "" +" 6. Create a `catalog.json`, *on one of Droonga nodes*.\n" +" The file defines the structure of your Droonga cluster.\n" +" You'll specify the name of the dataset via the `--dataset` option and the " +"list of your Droonga node's IP addresses via the `--hosts` option, like:" +msgstr "" +" 6. *いずれか1つのDroongaノードで*、`catalog.json`を作成します。\n" +" このファイルはDroongaクラスタの構成を定義する物です。\n" +" データセット名を`--dataset`オプション、各DroongaノードのIPアドレスを`--hosts`オプションで、以下のように指定して下さい:" + +msgid "" +" # droonga-catalog-generate --dataset=Starbucks \\\n" +" --hosts=192.168.0.10,192.168.0.11 \\\n" +" --output=./catalog.json" +msgstr "" + +msgid "" +" If you have only one computer and trying to set up it just for testing, th" +"en you'll do:" +msgstr " コンピュータが1台だけの単なる検証用の構成をセットアップする場合は、以下のようにします:" + +msgid "" +" # droonga-catalog-generate --dataset=Starbucks \\\n" +" --hosts=127.0.0.1 \\\n" +" --output=./catalog.json" +msgstr "" + +msgid " 7. Share the generated `catalog.json` *to your all Droonga nodes*." +msgstr "7. *すべてのDroongaノードに*、先程作成した`catalog.json`を共有します。" + +msgid " # scp ~/droonga/catalog.json 192.168.0.11:~/droonga/" +msgstr "" + +msgid "" +" (Or, of course, you can generate same `catalog.json` on each computer, ins" +"tead of copying.)" +msgstr " (もしくは、できあがったファイルをコピーする代わりに、各コンピュータ上で同じ設定の`catalog.json`を作成しても結構です。)" + +msgid "" +"All Droonga nodes for your Droonga cluster are prepared by steps described abo" +"ve.\n" +"Let's continue to the next step." +msgstr "" +"上記の手順により、DroongaクラスタのためのすべてのDroongaノードの準備が完了しました。\n" +"次の段階に進みましょう。" + +msgid "## Use the Droonga cluster, via HTTP" +msgstr "## DroongaクラスタをHTTP経由で使用する" + +msgid "### Start and stop services on each Droonga node" +msgstr "### 各Droongaノードの上でのサービスの開始と停止" + +msgid "You can run Groonga as an HTTP server with the option `-d`, like:" +msgstr "GroongaをHTTPサーバとして使う場合は、以下のように `-d` オプションを指定するだけでサーバを起動できます:" + +msgid " # groonga -p 10041 -d --protocol http /tmp/databases/db" +msgstr "" + +msgid "" +"On the other hand, you have to run multiple servers for each Droonga node to u" +"se your Droonga cluster via HTTP." +msgstr "一方、DroongaクラスタをHTTP経由で使うためには、各Droongaノードにおいて複数のサービスを起動する必要があります。" + +msgid "To start them, run commands like following on each Droonga node:" +msgstr "サービスを起動するには、各Droongaノードで以下のようにコマンドを実行します:" + +msgid "" +" # cd ~/droonga\n" +" # host=192.168.0.10\n" +" # droonga-engine --host=$host \\\n" +" --daemon \\\n" +" --pid-file=$PWD/droonga-engine.pid\n" +" # droonga-http-server --port=10041 \\\n" +" --receive-host-name=$host \\\n" +" --droonga-engine-host-name=$host \\\n" +" --default-dataset=Starbucks \\\n" +" --daemon \\\n" +" --pid-file=$PWD/droonga-http-server.pid\n" +" # serf agent -node=\"${host}:10031\" -bind=$host \\\n" +" -event-handler=\"droonga-handle-serf-event --base-dir $PWD\" &" +msgstr "" + +msgid "" +"Note that you have to specify the host name of the Droonga node itself via som" +"e options.\n" +"It will be used to communicate with other Droonga nodes in the cluster.\n" +"So you have to specify different host name on another Droonga node, like:" +msgstr "" +"いくつかのオプションにおいて、そのDroongaノード自身のホスト名を指定する必要がある事に注意して下さい。\n" +"この情報は、クラスタ無いのたのDroongaノードとの通信のために使われます。\n" +"よって、別のDroongaノード上では以下のように別のホスト名を指定する事になります:" + +msgid "" +" # cd ~/droonga\n" +" # host=192.168.0.11\n" +" # droonga-engine --host=$host \\\n" +" ..." +msgstr "" + +msgid "" +"After that, run following command to start alive monitoring, on the node \"192." +"168.0.10\":" +msgstr "その後、死活監視のために、\"192.168.0.10\" のノードにおいて以下のコマンドを実行します:" + +msgid " # serf join 192.168.0.11" +msgstr "" + +msgid "" +"By the command two nodes construct a cluster and they monitor each other.\n" +"If one of nodes dies and there is any still alive node, survivor(s) will work " +"as the Droonga cluster.\n" +"Then you can recover the dead node and re-join it to the cluster secretly." +msgstr "" +"このコマンドにより、2つのノードはクラスタを形成し、互いの生死を監視するようになります。もしクラスタ内のどれか1つのノードが機能を停止し、他のノードがまだ機" +"能し続けていた場合には、残ったノードがDroongaクラスタとして動作し続けます。そのため、そのような事態が起こっても秘密裏に、機能停止したノードを復旧した" +"りクラスタに復帰させたりすることができます。" + +msgid "To stop services, run commands like following on each Droonga node:" +msgstr "サービスを停止するには、以下のコマンドを各Droongaノード上で実行します:" + +msgid "" +" # kill $(cat ~/droonga/droonga-engine.pid)\n" +" # kill $(cat ~/droonga/droonga-http-server.pid)\n" +" # serf leave" +msgstr "" + +msgid "### Create a table" +msgstr "" + +msgid "Now your Droonga cluster actually works as a Groonga's HTTP server." +msgstr "" + +msgid "" +"Requests are completely same to ones for a Groonga server.\n" +"To create a new table `Store`, you just have to send a GET request for the `ta" +"ble_create` command, like:" +msgstr "" + +msgid "" +" # endpoint=\"http://192.168.0.10:10041/d\"\n" +" # curl \"${endpoint}/table_create?name=Store&type=Hash&key_type=ShortText\"\n" +" [[0,1398662266.3853862,0.08530688285827637],true]" +msgstr "" + +msgid "" +"Note that you have to specify the host, one of Droonga nodes with active droon" +"ga-http-server, in your Droonga cluster.\n" +"In other words, you can use any favorite node in the cluster as an endpoint.\n" +"All requests will be distributed to suitable nodes in the cluster." +msgstr "" + +msgid "" +"OK, now the table has been created successfully.\n" +"Let's see it by the `table_list` command:" +msgstr "" + +msgid "" +" # curl \"${endpoint}/table_list\"\n" +" [[0,1398662423.509928,0.003869295120239258],[[[\"id\",\"UInt32\"],[\"name\",\"Sho" +"rtText\"],[\"path\",\"ShortText\"],[\"flags\",\"ShortText\"],[\"domain\",\"ShortText\"],[\"r" +"ange\",\"ShortText\"],[\"default_tokenizer\",\"ShortText\"],[\"normalizer\",\"ShortText\"" +"]],[256,\"Store\",\"/home/username/groonga/droonga-engine/000/db.0000100\",\"TABLE_" +"HASH_KEY|PERSISTENT\",\"ShortText\",null,null,null]]]" +msgstr "" + +msgid "Because it is a cluster, another endpoint returns same result." +msgstr "" + +msgid "" +" # curl \"http://192.168.0.11:10041/d/table_list\"\n" +" [[0,1398662423.509928,0.003869295120239258],[[[\"id\",\"UInt32\"],[\"name\",\"Sho" +"rtText\"],[\"path\",\"ShortText\"],[\"flags\",\"ShortText\"],[\"domain\",\"ShortText\"],[\"r" +"ange\",\"ShortText\"],[\"default_tokenizer\",\"ShortText\"],[\"normalizer\",\"ShortText\"" +"]],[256,\"Store\",\"/home/username/groonga/droonga-engine/000/db.0000100\",\"TABLE_" +"HASH_KEY|PERSISTENT\",\"ShortText\",null,null,null]]]" +msgstr "" + +msgid "### Create a column" +msgstr "" + +msgid "" +"Next, create a new column `location` to the `Store` table by the `column_creat" +"e` command, like:" +msgstr "" + +msgid "" +" # curl \"${endpoint}/column_create?table=Store&name=location&flags=COLUMN_S" +"CALAR&type=WGS84GeoPoint\"\n" +" [[0,1398664305.8856306,0.00026226043701171875],true]" +msgstr "" + +msgid "" +"Then verify that the column is correctly created, by the `column_list` command" +":" +msgstr "" + +msgid "" +" # curl \"${endpoint}/column_list?table=Store\"\n" +" [[0,1398664345.9680889,0.0011739730834960938],[[[\"id\",\"UInt32\"],[\"name\",\"S" +"hortText\"],[\"path\",\"ShortText\"],[\"type\",\"ShortText\"],[\"flags\",\"ShortText\"],[\"d" +"omain\",\"ShortText\"],[\"range\",\"ShortText\"],[\"source\",\"ShortText\"]],[257,\"locati" +"on\",\"/home/username/groonga/droonga-engine/000/db.0000101\",\"fix\",\"COLUMN_SCALA" +"R\",\"Store\",\"WGS84GeoPoint\",[]]]]" +msgstr "" + +msgid "### Create indexes" +msgstr "" + +msgid "Create indexes also." +msgstr "" + +msgid "" +" # curl \"${endpoint}/table_create?name=Location&type=PatriciaTrie&key_type=" +"WGS84GeoPoint\"\n" +" [[0,1398664401.4927232,0.12011909484863281],true]\n" +" # curl \"${endpoint}/column_create?table=Location&name=store&flags=COLUMN_I" +"NDEX&type=Store&source=location\"\n" +" [[0,1398664429.5348525,0.13435077667236328],true]\n" +" # curl \"${endpoint}/table_create?name=Term&type=PatriciaTrie&key_type=Shor" +"tText&default_tokenizer=TokenBigram&normalizer=NormalizerAuto\"\n" +" [[0,1398664454.446939,0.14734888076782227],true]\n" +" # curl \"${endpoint}/column_create?table=Term&name=store__key&flags=COLUMN_" +"INDEX|WITH_POSITION&type=Store&source=_key\"\n" +" [[0,1398664474.7112074,0.12619781494140625],true]" +msgstr "" + +msgid "### Load data to a table" +msgstr "" + +msgid "" +"Let's load data to the `Store` table.\n" +"First. prepare the data as a JSON file `stores.json`." +msgstr "" + +msgid "stores.json:" +msgstr "" + +msgid "" +"~~~\n" +"[\n" +"[\"_key\",\"location\"],\n" +"[\"1st Avenue & 75th St. - New York NY (W)\",\"40.770262,-73.954798\"],\n" +"[\"76th & Second - New York NY (W)\",\"40.771056,-73.956757\"],\n" +"[\"2nd Ave. & 9th Street - New York NY\",\"40.729445,-73.987471\"],\n" +"[\"15th & Third - New York NY (W)\",\"40.733946,-73.9867\"],\n" +"[\"41st and Broadway - New York NY (W)\",\"40.755111,-73.986225\"],\n" +"[\"84th & Third Ave - New York NY (W)\",\"40.777485,-73.954979\"],\n" +"[\"150 E. 42nd Street - New York NY (W)\",\"40.750784,-73.975582\"],\n" +"[\"West 43rd and Broadway - New York NY (W)\",\"40.756197,-73.985624\"],\n" +"[\"Macy's 35th Street Balcony - New York NY\",\"40.750703,-73.989787\"],\n" +"[\"Macy's 6th Floor - Herald Square - New York NY (W)\",\"40.750703,-73.989787\"]" +",\n" +"[\"Herald Square- Macy's - New York NY\",\"40.750703,-73.989787\"],\n" +"[\"Macy's 5th Floor - Herald Square - New York NY (W)\",\"40.750703,-73.989787\"]" +",\n" +"[\"80th & York - New York NY (W)\",\"40.772204,-73.949862\"],\n" +"[\"Columbus @ 67th - New York NY (W)\",\"40.774009,-73.981472\"],\n" +"[\"45th & Broadway - New York NY (W)\",\"40.75766,-73.985719\"],\n" +"[\"Marriott Marquis - Lobby - New York NY\",\"40.759123,-73.984927\"],\n" +"[\"Second @ 81st - New York NY (W)\",\"40.77466,-73.954447\"],\n" +"[\"52nd & Seventh - New York NY (W)\",\"40.761829,-73.981141\"],\n" +"[\"1585 Broadway (47th) - New York NY (W)\",\"40.759806,-73.985066\"],\n" +"[\"85th & First - New York NY (W)\",\"40.776101,-73.949971\"],\n" +"[\"92nd & 3rd - New York NY (W)\",\"40.782606,-73.951235\"],\n" +"[\"165 Broadway - 1 Liberty - New York NY (W)\",\"40.709727,-74.011395\"],\n" +"[\"1656 Broadway - New York NY (W)\",\"40.762434,-73.983364\"],\n" +"[\"54th & Broadway - New York NY (W)\",\"40.764275,-73.982361\"],\n" +"[\"Limited Brands-NYC - New York NY\",\"40.765219,-73.982025\"],\n" +"[\"19th & 8th - New York NY (W)\",\"40.743218,-74.000605\"],\n" +"[\"60th & Broadway-II - New York NY (W)\",\"40.769196,-73.982576\"],\n" +"[\"63rd & Broadway - New York NY (W)\",\"40.771376,-73.982709\"],\n" +"[\"195 Broadway - New York NY (W)\",\"40.710703,-74.009485\"],\n" +"[\"2 Broadway - New York NY (W)\",\"40.704538,-74.01324\"],\n" +"[\"2 Columbus Ave. - New York NY (W)\",\"40.769262,-73.984764\"],\n" +"[\"NY Plaza - New York NY (W)\",\"40.702802,-74.012784\"],\n" +"[\"36th and Madison - New York NY (W)\",\"40.748917,-73.982683\"],\n" +"[\"125th St. btwn Adam Clayton & FDB - New York NY\",\"40.808952,-73.948229\"],\n" +"[\"70th & Broadway - New York NY (W)\",\"40.777463,-73.982237\"],\n" +"[\"2138 Broadway - New York NY (W)\",\"40.781078,-73.981167\"],\n" +"[\"118th & Frederick Douglas Blvd. - New York NY (W)\",\"40.806176,-73.954109\"]," +"\n" +"[\"42nd & Second - New York NY (W)\",\"40.750069,-73.973393\"],\n" +"[\"Broadway @ 81st - New York NY (W)\",\"40.784972,-73.978987\"],\n" +"[\"Fashion Inst of Technology - New York NY\",\"40.746948,-73.994557\"]\n" +"]\n" +"~~~" +msgstr "" + +msgid "Then, send it as a POST request of the `load` command, like:" +msgstr "" + +msgid "" +" # curl --data \"@stores.json\" \"${endpoint}/load?table=Store\"\n" +" [[0,1398666180.023,0.069],[40]]" +msgstr "" + +msgid "Now all data in the JSON file are successfully loaded." +msgstr "" + +msgid "### Select data from a table" +msgstr "" + +msgid "OK, all data is now ready." +msgstr "" + +msgid "As the starter, let's select initial ten records with the `select` command:" +msgstr "" + +msgid "" +" # curl \"${endpoint}/select?table=Store&output_columns=_key&limit=10\"\n" +" [[0,1398666260.887927,0.000017404556274414062],[[[40],[[\"_key\",\"ShortText\"" +"]],[[\"1st Avenue & 75th St. - New York NY (W)\"],[\"2nd Ave. & 9th Street - New" +" York NY\"],[\"76th & Second - New York NY (W)\"],[\"15th & Third - New York NY " +"(W)\"],[\"41st and Broadway - New York NY (W)\"],[\"West 43rd and Broadway - New " +"York NY (W)\"],[\"84th & Third Ave - New York NY (W)\"],[\"150 E. 42nd Street - " +"New York NY (W)\"],[\"Macy's 35th Street Balcony - New York NY\"],[\"Herald Squar" +"e- Macy's - New York NY\"]]]]]" +msgstr "" + +msgid "Of course you can specify conditions via the `query` option:" +msgstr "" + +msgid "" +" # curl \"${endpoint}/select?table=Store&query=Columbus&match_columns=_key&o" +"utput_columns=_key&limit=10\"\n" +" [[0,1398670157.661574,0.0012705326080322266],[[[2],[[\"_key\",\"ShortText\"]]," +"[[\"Columbus @ 67th - New York NY (W)\"],[\"2 Columbus Ave. - New York NY (W)\"]" +"]]]]\n" +" # curl \"${endpoint}/select?table=Store&filter=_key@'Ave'&output_columns=_k" +"ey&limit=10\"\n" +" [[0,1398670586.193325,0.0003848075866699219],[[[3],[[\"_key\",\"ShortText\"]]," +"[[\"2nd Ave. & 9th Street - New York NY\"],[\"84th & Third Ave - New York NY (W)" +"\"],[\"2 Columbus Ave. - New York NY (W)\"]]]]]" +msgstr "" + +msgid "## Conclusion" +msgstr "## まとめ" + +msgid "" +"In this tutorial, you did set up a [Droonga][] cluster on [Ubuntu Linux][Ubunt" +"u] computers.\n" +"Moreover, you load data to it and select data from it successfully, as a [Groo" +"nga][] compatible server." +msgstr "" + +msgid "" +"Currently, Droonga supports only some limited features of Groonga compatible c" +"ommands.\n" +"See the [command reference][] for more details." +msgstr "" + +msgid "" +" [Ubuntu]: http://www.ubuntu.com/\n" +" [Droonga]: https://droonga.org/\n" +" [Groonga]: http://groonga.org/\n" +" [Serf]: http://www.serfdom.io/\n" +" [command reference]: ../../reference/commands/" +msgstr "" Added: _po/ja/tutorial/1.0.3/index.po (+38 -0) 100644 =================================================================== --- /dev/null +++ _po/ja/tutorial/1.0.3/index.po 2014-05-19 16:48:30 +0900 (90868d1) @@ -0,0 +1,38 @@ +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"PO-Revision-Date: 2014-03-05 12:52+0900\n" +"Language: ja\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" + +msgid "" +"---\n" +"title: Droonga tutorial\n" +"layout: en\n" +"---" +msgstr "" +"---\n" +"title: Droonga チュートリアル\n" +"layout: ja\n" +"---" + +msgid "## For Groonga users" +msgstr "## Groonga利用者向け" + +msgid " * [How to migrate from Groonga?](groonga/)" +msgstr " * [Groongaからの移行手順](groonga/)" + +msgid "## For application developers" +msgstr "## アプリケーション開発者向け" + +msgid " * [Basic usage tutorial](basic/)" +msgstr " * [基本的な使い方のチュートリアル](basic/)" + +msgid "## For plugin developers" +msgstr "## プラグイン開発者向け" + +msgid " * [Plugin development tutorial](plugin-development/)" +msgstr " * [プラグイン開発のチュートリアル](plugin-development/)" Added: _po/ja/tutorial/1.0.3/plugin-development/adapter/index.po (+1023 -0) 100644 =================================================================== --- /dev/null +++ _po/ja/tutorial/1.0.3/plugin-development/adapter/index.po 2014-05-19 16:48:30 +0900 (eb9c22c) @@ -0,0 +1,1023 @@ +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"PO-Revision-Date: 2014-03-05 12:52+0900\n" +"Language: ja\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" + +msgid "" +"---\n" +"title: \"Plugin: Adapt requests and responses, to add a new command based on ot" +"her existing commands\"\n" +"layout: en\n" +"---" +msgstr "" +"---\n" +"title: \"プラグイン: リクエストとレスポンスを加工し、既存のコマンドに基づいた新しいコマンドを作成する\"\n" +"layout: ja\n" +"---" + +msgid "" +"* TOC\n" +"{:toc}" +msgstr "" + +msgid "## The goal of this tutorial" +msgstr "## チュートリアルのゴール" + +msgid "Learning steps to develop a Droonga plugin by yourself." +msgstr "Droongaプラグインを自分で開発するための手順を身につけましょう。" + +msgid "" +"This page focuses on the \"adaption\" by Droonga plugins.\n" +"At the last, we create a new command `storeSearch` based on the existing `sear" +"ch` command, with a small practical plugin." +msgstr "" +"このページでは、Droongaプラグインによる「加工」(adaption)に焦点を当てます。\n" +"最後には、小さな練習用のプラグインを開発して、既存の`search`コマンドに基づく新しいコマンド`storeSearch`を開発することになります。" + +msgid "## Precondition" +msgstr "## 前提条件" + +msgid "* You must complete the [basic tutorial][]." +msgstr "* [基本的な使い方のチュートリアル][basic tutorial] を完了している必要があります。" + +msgid "## Adaption for incoming messages" +msgstr "## 入力メッセージの加工" + +msgid "" +"First, let's study basics with a simple logger plugin named `sample-logger` af" +"fects at the adaption phase." +msgstr "まず`sample-logger`という簡単なロガープラグインを使って、アダプション・フェーズに作用するプラグインを作りながら、基礎を学びましょう。" + +msgid "" +"We sometime need to modify incoming requests from outside to Droonga Engine.\n" +"We can use a plugin for this purpose.\n" +"Let's see how to create a plugin for the adaption phase, in this section." +msgstr "" +"外部のシステムからDroonga Engineにやってくるリクエストを加工する必要がある場合があります。このようなときに、プラグインを利用できます。このセク" +"ションでは、どのようにしてアダプション・フェーズのプラグインをつくるのかをみていきます。" + +msgid "### Directory Structure" +msgstr "### ディレクトリの構造" + +msgid "" +"Assume that we are going to add a new plugin to the system built in the [basic" +" tutorial][].\n" +"In that tutorial, Droonga engine was placed under `engine` directory." +msgstr "" +"[基本のチュートリアル][basic tutorial]で作成したシステムに対してプラグインを追加すると仮定します。\n" +"先のチュートリアルでは、Droongaエンジンは `engine` ディレクトリ内に置かれていました。" + +msgid "" +"Plugins need to be placed in an appropriate directory. Let's create the direct" +"ory:" +msgstr "プラグインは、適切な位置のディレクトリに置かれる必要があります。ディレクトリを作成しましょう:" + +msgid "" +"~~~\n" +"# cd engine\n" +"# mkdir -p lib/droonga/plugins\n" +"~~~" +msgstr "" + +msgid "After creating the directory, the directory structure should be like this:" +msgstr "ディレクトリを作成した後は、ディレクトリ構造は以下のようになります:" + +msgid "" +"~~~\n" +"engine\n" +"├── catalog.json\n" +"├── fluentd.conf\n" +"└── lib\n" +" └── droonga\n" +" └── plugins\n" +"~~~" +msgstr "" + +msgid "### Create a plugin" +msgstr "### プラグインの作成" + +msgid "" +"You must put codes for a plugin into a file which has the name *same to the pl" +"ugin itself*.\n" +"Because the plugin now you creating is `sample-logger`, put codes into a file " +"`sample-logger.rb` in the `droonga/plugins` directory." +msgstr "" +"プラグイン用のコードは、*プラグイン自身の名前と同じ名前*のファイルに書く必要があります。\n" +"これから作るプラグインの名前は`sample-logger`なので、コードは`droonga/plugins`ディレクトリ内の`sample-logger." +"rb`の中に書いていくことになります。" + +msgid "lib/droonga/plugins/sample-logger.rb:" +msgstr "" + +msgid "" +"~~~ruby\n" +"require \"droonga/plugin\"" +msgstr "" + +msgid "" +"module Droonga\n" +" module Plugins\n" +" module SampleLoggerPlugin\n" +" extend Plugin\n" +" register(\"sample-logger\")" +msgstr "" + +msgid "" +" class Adapter < Droonga::Adapter\n" +" # You'll put codes to modify messages here.\n" +" end\n" +" end\n" +" end\n" +"end\n" +"~~~" +msgstr "" +" class Adapter < Droonga::Adapter\n" +" # メッセージを加工するためのコードをここに書きます。\n" +" end\n" +" end\n" +" end\n" +"end\n" +"~~~" + +msgid "This plugin does nothing except registering itself to the Droonga Engine." +msgstr "このプラグインは、Droonga Engineに自分自身を登録する以外の事は何もしません。" + +msgid "" +" * The `sample-logger` is the name of the plugin itself. You'll use it in your" +" `catalog.json`, to activate the plugin.\n" +" * As the example above, you must define your plugin as a module.\n" +" * Behaviors at the adaption phase is defined a class called *adapter*.\n" +" An adapter class must be defined as a subclass of the `Droonga::Adapter`, u" +"nder the namespace of the plugin module." +msgstr "" +" * `sample-logger`は、このプラグイン自身の名前です。これは`catalog.json`の中で、プラグインを有効化するために使う事になります" +"。\n" +" * 上記の例のように、プラグインはモジュールとして定義する必要があります。\n" +" * アダプション・フェーズでの振る舞いは、*アダプター*と呼ばれるクラスとして定義します。\n" +" アダプタークラスは必ず、プラグインのモジュールの名前空間の配下で、`Droonga::Adapter`のサブクラスとして定義する必要があります。" + +msgid "### Activate the plugin with `catalog.json`" +msgstr "### `catalog.json`でプラグインを有効化する" + +msgid "" +"You need to update `catalog.json` to activate your plugin.\n" +"Insert the name of the plugin `\"sample-logger\"` to the `\"plugins\"` list under " +"the dataset, like:" +msgstr "" +"プラグインを有効化するには、`catalog.json`を更新する必要があります。\n" +"プラグインの名前`\"sample-logger\"`を、データセットの配下の`\"plugins\"`のリストに挿入します。例:" + +msgid "catalog.json:" +msgstr "" + +msgid "" +"~~~\n" +"(snip)\n" +" \"datasets\": {\n" +" \"Starbucks\": {\n" +" (snip)\n" +" \"plugins\": [\"sample-logger\", \"groonga\", \"crud\", \"search\"],\n" +"(snip)\n" +"~~~" +msgstr "" + +msgid "" +"Note: you must place `\"sample-logger\"` before `\"search\"`, because the `sample-" +"logger` plugin depends on the `search`. Droonga Engine applies plugins at the " +"adaption phase in the order defined in the `catalog.json`, so you must resolve" +" plugin dependencies by your hand (for now)." +msgstr "" +"注意:`\"sample-logger\"`は`\"search\"`よりも前に置く必要があります。これは、`sample-logger`プラグインが`search" +"`に依存しているからです。Droonga Engineはアダプション・フェーズにおいて、プラグインを`catalog.json`で定義された順に適用しますの" +"で、プラグイン同士の依存関係は(今のところは)自分で解決しなくてはなりません。" + +msgid "### Run and test" +msgstr "### 実行と動作を確認する" + +msgid "" +"Let's get Droonga started.\n" +"Note that you need to specify `./lib` directory in `RUBYLIB` environment varia" +"ble in order to make ruby possible to find your plugin." +msgstr "" +"Droongaを起動しましょう。\n" +"Rubyがあなたの書いたプラグインのコード群を見つけられるように、`RUBYLIB`環境変数に`./lib`を加えることに注意して下さい。" + +msgid "" +"~~~\n" +"# kill $(cat fluentd.pid)\n" +"# RUBYLIB=./lib fluentd --config fluentd.conf --log fluentd.log --daemon fluen" +"td.pid\n" +"~~~" +msgstr "" + +msgid "" +"Then, verify that the engine is correctly working.\n" +"First, create a request as a JSON." +msgstr "" +"そうしたら、Engineが正しく動作しているかを確かめます。\n" +"まず、以下のようなJSON形式のリクエストを作成します。" + +msgid "search-columbus.json:" +msgstr "" + +msgid "" +"~~~json\n" +"{\n" +" \"dataset\" : \"Starbucks\",\n" +" \"type\" : \"search\",\n" +" \"body\" : {\n" +" \"queries\" : {\n" +" \"stores\" : {\n" +" \"source\" : \"Store\",\n" +" \"condition\" : {\n" +" \"query\" : \"Columbus\",\n" +" \"matchTo\" : \"_key\"\n" +" },\n" +" \"output\" : {\n" +" \"elements\" : [\n" +" \"startTime\",\n" +" \"elapsedTime\",\n" +" \"count\",\n" +" \"attributes\",\n" +" \"records\"\n" +" ],\n" +" \"attributes\" : [\"_key\"],\n" +" \"limit\" : -1\n" +" }\n" +" }\n" +" }\n" +" }\n" +"}\n" +"~~~" +msgstr "" + +msgid "" +"This is corresponding to the example to search \"Columbus\" in the [basic tutori" +"al][].\n" +"Note that the request for the Protocol Adapter is encapsulated in `\"body\"` ele" +"ment." +msgstr "" +"これは[基本のチュートリアル](basic tutorial)において\"Columbus\"を検索する例に対応しています。\n" +"Protocol Adapterへのリクエストは`\"body\"`要素の中に置かれていることに注意して下さい。" + +msgid "Send the request to engine with `droonga-request`:" +msgstr "`droonga-request`コマンドを使ってリクエストをDroonga Engineに送信します:" + +msgid "" +"~~~\n" +"# droonga-request --tag starbucks search-columbus.json\n" +"Elapsed time: 0.021544\n" +"[\n" +" \"droonga.message\",\n" +" 1392617533,\n" +" {\n" +" \"inReplyTo\": \"1392617533.9644868\",\n" +" \"statusCode\": 200,\n" +" \"type\": \"search.result\",\n" +" \"body\": {\n" +" \"stores\": {\n" +" \"count\": 2,\n" +" \"records\": [\n" +" [\n" +" \"Columbus @ 67th - New York NY (W)\"\n" +" ],\n" +" [\n" +" \"2 Columbus Ave. - New York NY (W)\"\n" +" ]\n" +" ]\n" +" }\n" +" }\n" +" }\n" +"]\n" +"~~~" +msgstr "" + +msgid "This is the search result." +msgstr "これが検索結果です。" + +msgid "### Do something in the plugin: take logs" +msgstr "### プラグインを動作させる: ログをとる" + +msgid "" +"The plugin we have created do nothing so far. Let's get the plugin to do some " +"interesting." +msgstr "ここまでで作成したプラグインは、何もしない物でした。それでは、このプラグインを何か面白いことをする物にしましょう。" + +msgid "First of all, trap `search` request and log it. Update the plugin like below:" +msgstr "まず最初に、`search`のリクエストを捕まえてログ出力してみます。プラグインを以下のように更新して下さい:" + +msgid "" +"~~~ruby\n" +"(snip)\n" +" module SampleLoggerPlugin\n" +" extend Plugin\n" +" register(\"sample-logger\")" +msgstr "" + +msgid "" +" class Adapter < Droonga::Adapter\n" +" input_message.pattern = [\"type\", :equal, \"search\"]" +msgstr "" + +msgid "" +" def adapt_input(input_message)\n" +" logger.info(\"SampleLoggerPlugin::Adapter\", :message => input_message" +")\n" +" end\n" +" end\n" +" end\n" +"(snip)\n" +"~~~" +msgstr "" + +msgid "" +"The line beginning with `input_message.pattern` is a configuration.\n" +"This example defines a plugin for any incoming message with `\"type\":\"search\"`." +"\n" +"See the [reference manual's configuration section](../../../reference/plugin/a" +"dapter/#config)" +msgstr "" +"`input_message.pattern`で始まる行は、設定です。\n" +"この例では、プラグインを`\"type\":\"search\"`という情報を持つすべての入力メッセージに対して働くように定義しています。.\n" +"詳しくは[リファレンスマニュアルの設定のセクション](../../../reference/plugin/adapter/#config)を参照して下さい。" + +msgid "" +"The method `adapt_input` is called for every incoming message matching to the " +"pattern.\n" +"The argument `input_message` is a wrapped version of the incoming message." +msgstr "" +"`adapt_input`メソッドは、パターンに当てはまるすべての入力メッセージに対して毎回呼ばれます。\n" +"引数の`input_message`は、入力メッセージをラップした物です。" + +msgid "Restart fluentd:" +msgstr "fluentdを再起動します:" + +msgid "Send the request same as the previous section:" +msgstr "前のセクションと同じリクエストを送信します:" + +msgid "" +"~~~\n" +"# droonga-request --tag starbucks search-columbus.json\n" +"Elapsed time: 0.014714\n" +"[\n" +" \"droonga.message\",\n" +" 1392618037,\n" +" {\n" +" \"inReplyTo\": \"1392618037.935901\",\n" +" \"statusCode\": 200,\n" +" \"type\": \"search.result\",\n" +" \"body\": {\n" +" \"stores\": {\n" +" \"count\": 2,\n" +" \"records\": [\n" +" [\n" +" \"Columbus @ 67th - New York NY (W)\"\n" +" ],\n" +" [\n" +" \"2 Columbus Ave. - New York NY (W)\"\n" +" ]\n" +" ]\n" +" }\n" +" }\n" +" }\n" +"]\n" +"~~~" +msgstr "" + +msgid "You will see something like below fluentd's log in `fluentd.log`:" +msgstr "すると、fluentdのログファイルである`fluentd.log`に以下のようなログが出力される事を確認できるでしょう。" + +msgid "" +"~~~\n" +"2014-02-17 15:20:37 +0900 [info]: SampleLoggerPlugin::Adapter message=#<Droong" +"a::InputMessage:0x007f8ae3e1dd98 @raw_message={\"dataset\"=>\"Starbucks\", \"type\"=" +">\"search\", \"body\"=>{\"queries\"=>{\"stores\"=>{\"source\"=>\"Store\", \"condition\"=>{\"q" +"uery\"=>\"Columbus\", \"matchTo\"=>\"_key\"}, \"output\"=>{\"elements\"=>[\"startTime\", \"e" +"lapsedTime\", \"count\", \"attributes\", \"records\"], \"attributes\"=>[\"_key\"], \"limit" +"\"=>-1}}}}, \"replyTo\"=>{\"type\"=>\"search.result\", \"to\"=>\"127.0.0.1:64591/droonga" +"\"}, \"id\"=>\"1392618037.935901\", \"date\"=>\"2014-02-17 15:20:37 +0900\", \"appliedAd" +"apters\"=>[]}>\n" +"~~~" +msgstr "" + +msgid "" +"This shows the message is received by our `SampleLoggerPlugin::Adapter` and th" +"en passed to Droonga. Here we can modify the message before the actual data pr" +"ocessing." +msgstr "" +"このログは、メッセージが`SampleLoggerPlugin::Adapter`によって受信されて、Droongaに渡されたことを示しています。実際のデー" +"タ処理の前に、この時点でメッセージを加工することができます。" + +msgid "### Modify messages with the plugin" +msgstr "### プラグインでメッセージを加工する" + +msgid "" +"Suppose that we want to restrict the number of records returned in the respons" +"e, say `1`.\n" +"What we need to do is set `limit` to be `1` for every request.\n" +"Update plugin like below:" +msgstr "" +"レスポンスで返されるレコードの数を常に1つだけに制限したい場合、すべてのリクエストについて`limit`を`1`に指定する必要があります。プラグインを以下の" +"ように変更してみましょう:" + +msgid "" +"~~~ruby\n" +"(snip)\n" +" def adapt_input(input_message)\n" +" logger.info(\"SampleLoggerPlugin::Adapter\", :message => input_message" +")\n" +" input_message.body[\"queries\"][\"stores\"][\"output\"][\"limit\"] = 1\n" +" end\n" +"(snip)\n" +"~~~" +msgstr "" + +msgid "" +"Like above, you can modify the incoming message via methods of the argument `i" +"nput_message`.\n" +"See the [reference manual for the message class](../../../reference/plugin/ada" +"pter/#classes-Droonga-InputMessage)." +msgstr "" +"上の例のように、プラグインは`adapt_input`メソッドの引数として渡される`input_message`を通じて入力メッセージの内容を加工することが" +"できます。\n" +"詳細は[当該メッセージの実装であるクラスのリファレンスマニュアル](../../../reference/plugin/adapter/#classes-D" +"roonga-InputMessage)を参照して下さい。" + +msgid "" +"After restart, the response always includes only one record in `records` secti" +"on." +msgstr "再起動後、レスポンスは`records`の値としてレコードを常に(最大で)1つだけ含むようになります。" + +msgid "Send the request same as the previous:" +msgstr "先の場合と同じリクエストを投げてみましょう:" + +msgid "" +"~~~\n" +"# droonga-request --tag starbucks search-columbus.json\n" +"Elapsed time: 0.017343\n" +"[\n" +" \"droonga.message\",\n" +" 1392618279,\n" +" {\n" +" \"inReplyTo\": \"1392618279.0578449\",\n" +" \"statusCode\": 200,\n" +" \"type\": \"search.result\",\n" +" \"body\": {\n" +" \"stores\": {\n" +" \"count\": 2,\n" +" \"records\": [\n" +" [\n" +" \"Columbus @ 67th - New York NY (W)\"\n" +" ]\n" +" ]\n" +" }\n" +" }\n" +" }\n" +"]\n" +"~~~" +msgstr "" + +msgid "" +"Note that `count` is still `2` because `limit` does not affect to `count`. See" +" [search][] for details of the `search` command." +msgstr "" +"`count`が依然として`2`であることに注意して下さい。これは、`limit`が`count`には影響を与えないという`search`コマンド自体の仕様" +"によるものです。`search`コマンドの詳細については[`search`コマンドのリファレンスマニュアル][search]を参照して下さい。" + +msgid "" +"~~~\n" +"2014-02-17 15:24:39 +0900 [info]: SampleLoggerPlugin::Adapter message=#<Droong" +"a::InputMessage:0x007f956685c908 @raw_message={\"dataset\"=>\"Starbucks\", \"type\"=" +">\"search\", \"body\"=>{\"queries\"=>{\"stores\"=>{\"source\"=>\"Store\", \"condition\"=>{\"q" +"uery\"=>\"Columbus\", \"matchTo\"=>\"_key\"}, \"output\"=>{\"elements\"=>[\"startTime\", \"e" +"lapsedTime\", \"count\", \"attributes\", \"records\"], \"attributes\"=>[\"_key\"], \"limit" +"\"=>-1}}}}, \"replyTo\"=>{\"type\"=>\"search.result\", \"to\"=>\"127.0.0.1:64616/droonga" +"\"}, \"id\"=>\"1392618279.0578449\", \"date\"=>\"2014-02-17 15:24:39 +0900\", \"appliedA" +"dapters\"=>[]}>\n" +"~~~" +msgstr "" + +msgid "## Adaption for outgoing messages" +msgstr "## 出力メッセージの加工" + +msgid "" +"In case we need to modify outgoing messages from Droonga Engine, for example, " +"search results, then we can do it simply by another method.\n" +"In this section, we are going to define a method to adapt outgoing messages." +msgstr "" +"Droonga Engineからの出力メッセージ(例えば検索結果など)を加工したい場合は、別のメソッドを定義することでそれを実現できます。\n" +"このセクションでは、出力メッセージを加工するメソッドを定義してみましょう。" + +msgid "### Add a method to adapt outgoing messages" +msgstr "### 出力のメッセージを加工するメソッドを追加する" + +msgid "" +"Let's take logs of results of `search` command.\n" +"Define the `adapt_output` method to process outgoing messages.\n" +"Remove `adapt_input` at this moment for the simplicity." +msgstr "" +"`search`コマンドの結果のログを取ってみましょう。\n" +"出力メッセージを処理するために、`adapt_output`メソッドを定義します。\n" +"説明を簡単にするために、ここでは`adapt_input`メソッドの定義を一旦削除します。" + +msgid "" +" def adapt_output(output_message)\n" +" logger.info(\"SampleLoggerPlugin::Adapter\", :message => output_messag" +"e)\n" +" end\n" +" end\n" +" end\n" +"(snip)\n" +"~~~" +msgstr "" + +msgid "" +"The method `adapt_output` is called only for outgoing messages triggered by in" +"coming messages trapped by the plugin itself, even if there is only the matchi" +"ng pattern and the `adapt_input` method is not defined.\n" +"See the [reference manual for plugin developers](../../../reference/plugin/ada" +"pter/) for more details." +msgstr "" +"`adapt_output`メソッドは、そのプラグイン自身によって捕捉された入力メッセージに起因して送出された出力メッセージに対してのみ呼ばれます(マッチン" +"グパターンのみが指定されていて、`adapt_input`メソッドが定義されていない場合であっても)。\n" +"詳細は[プラグイン開発APIのリファレンスマニュアル](../../../reference/plugin/adapter/)を参照して下さい。" + +msgid "### Run" +msgstr "### 実行する" + +msgid "Let's restart fluentd:" +msgstr "fluentdを再起動しましょう:" + +msgid "" +"And send search request (Use the same JSON for request as in the previous sect" +"ion):" +msgstr "次に、検索リクエストを送ります(前のセクションと同じJSONをリクエストとして使います):" + +msgid "" +"~~~\n" +"# droonga-request --tag starbucks search-columbus.json\n" +"Elapsed time: 0.015491\n" +"[\n" +" \"droonga.message\",\n" +" 1392619269,\n" +" {\n" +" \"inReplyTo\": \"1392619269.184789\",\n" +" \"statusCode\": 200,\n" +" \"type\": \"search.result\",\n" +" \"body\": {\n" +" \"stores\": {\n" +" \"count\": 2,\n" +" \"records\": [\n" +" [\n" +" \"Columbus @ 67th - New York NY (W)\"\n" +" ],\n" +" [\n" +" \"2 Columbus Ave. - New York NY (W)\"\n" +" ]\n" +" ]\n" +" }\n" +" }\n" +" }\n" +"]\n" +"~~~" +msgstr "" + +msgid "The fluentd's log should be like as follows:" +msgstr "fluentdのログは以下のようになっているはずです:" + +msgid "" +"~~~\n" +"2014-02-17 15:41:09 +0900 [info]: SampleLoggerPlugin::Adapter message=#<Droong" +"a::OutputMessage:0x007fddcad4d5a0 @raw_message={\"dataset\"=>\"Starbucks\", \"type\"" +"=>\"dispatcher\", \"body\"=>{\"stores\"=>{\"count\"=>2, \"records\"=>[[\"Columbus @ 67th " +"- New York NY (W)\"], [\"2 Columbus Ave. - New York NY (W)\"]]}}, \"replyTo\"=>{\"" +"type\"=>\"search.result\", \"to\"=>\"127.0.0.1:64724/droonga\"}, \"id\"=>\"1392619269.18" +"4789\", \"date\"=>\"2014-02-17 15:41:09 +0900\", \"appliedAdapters\"=>[\"Droonga::Plug" +"ins::SampleLoggerPlugin::Adapter\", \"Droonga::Plugins::Error::Adapter\"]}>\n" +"~~~" +msgstr "" + +msgid "" +"This shows that the result of `search` is passed to the `adapt_output` method " +"(and logged), then outputted." +msgstr "ここには、`search`の結果が`adapt_output`メソッドに渡された事(そしてログ出力された事)が示されています。" + +msgid "### Modify results in the adaption phase" +msgstr "### 結果をアダプション・フェーズで加工する" + +msgid "" +"Let's modify the result.\n" +"For example, add `completedAt` attribute that shows the time completed the req" +"uest.\n" +"Update your plugin as follows:" +msgstr "" +"結果を加工してみましょう。\n" +"例えば、リクエストに対する処理が完了した時刻を示す`completedAt`というアトリビュートを加えるとします。\n" +"プラグインを以下のように更新して下さい:" + +msgid "" +"~~~ruby\n" +"(snip)\n" +" def adapt_output(output_message)\n" +" logger.info(\"SampleLoggerPlugin::Adapter\", :message => output_messag" +"e)\n" +" output_message.body[\"stores\"][\"completedAt\"] = Time.now\n" +" end\n" +"(snip)\n" +"~~~" +msgstr "" + +msgid "" +"Like above, you can modify the outgoing message via methods of the argument `o" +"utput_message`. \n" +"See the [reference manual for the message class](../../../reference/plugin/ada" +"pter/#classes-Droonga-OutputMessage)." +msgstr "" +"上の例のように、出力メッセージは`adapt_output`メソッドの引数として渡される`output_message`を通じて加工することができます。\n" +"詳細は[当該メッセージの実装のクラスのリファレンスマニュアル](../../../reference/plugin/adapter/#classes-Dro" +"onga-OutputMessage)を参照して下さい。" + +msgid "Send the same search request:" +msgstr "同じ検索リクエストを送ってみましょう:" + +msgid "" +"~~~\n" +"# droonga-request --tag starbucks search-columbus.json\n" +"Elapsed time: 0.013983\n" +"[\n" +" \"droonga.message\",\n" +" 1392619528,\n" +" {\n" +" \"inReplyTo\": \"1392619528.235121\",\n" +" \"statusCode\": 200,\n" +" \"type\": \"search.result\",\n" +" \"body\": {\n" +" \"stores\": {\n" +" \"count\": 2,\n" +" \"records\": [\n" +" [\n" +" \"Columbus @ 67th - New York NY (W)\"\n" +" ],\n" +" [\n" +" \"2 Columbus Ave. - New York NY (W)\"\n" +" ]\n" +" ],\n" +" \"completedAt\": \"2014-02-17T06:45:28.247669Z\"\n" +" }\n" +" }\n" +" }\n" +"]\n" +"~~~" +msgstr "" + +msgid "" +"Now you can see `completedAt` attribute containing the time completed the requ" +"est.\n" +"The results in `fluentd.log` will be like this:" +msgstr "" +"リクエストの処理が完了した時刻を含むアトリビュートである`completedAt`が追加された事を確認できました。\n" +"`fluentd.log`には以下のように出力されているはずです:" + +msgid "" +"~~~\n" +"2014-02-17 15:45:28 +0900 [info]: SampleLoggerPlugin::Adapter message=#<Droong" +"a::OutputMessage:0x007fd384f3ab60 @raw_message={\"dataset\"=>\"Starbucks\", \"type\"" +"=>\"dispatcher\", \"body\"=>{\"stores\"=>{\"count\"=>2, \"records\"=>[[\"Columbus @ 67th " +"- New York NY (W)\"], [\"2 Columbus Ave. - New York NY (W)\"]]}}, \"replyTo\"=>{\"" +"type\"=>\"search.result\", \"to\"=>\"127.0.0.1:64849/droonga\"}, \"id\"=>\"1392619528.23" +"5121\", \"date\"=>\"2014-02-17 15:45:28 +0900\", \"appliedAdapters\"=>[\"Droonga::Plug" +"ins::SampleLoggerPlugin::Adapter\", \"Droonga::Plugins::Error::Adapter\"]}>\n" +"~~~" +msgstr "" + +msgid "## Adaption for both incoming and outgoing messages" +msgstr "## 入出力メッセージの加工" + +msgid "" +"We have learned the basics of plugins for the adaption phase so far.\n" +"Let's try to build more practical plugin." +msgstr "" +"ここまでで、アダプション・フェーズで動作するプラグインの基本を学びました。\n" +"それでは、より実践的なプラグインを開発してみることにしましょう。" + +msgid "" +"You may feel the Droonga's `search` command is too flexible for your purpose.\n" +"Here, we're going to add our own `storeSearch` command to wrap the `search` co" +"mmand in order to provide an application-specific and simple interface, with a" +" new plugin named `store-search`." +msgstr "" +"Droongaの`search`コマンドを見た時、目的に対していささか柔軟すぎるという印象を持ったことと思います\n" +"そこで、ここではアプリケーション固有の単純なインターフェースを持つコマンドとして、`search`コマンドをラップする`storeSearch`というコマン" +"ドを、`store-search`というプラグインで追加していくことにします。" + +msgid "### Accepting of simple requests" +msgstr "### シンプルなリクエストを受け取る" + +msgid "" +"First, create the `store-search` plugin.\n" +"Remember, you must put codes into a file which has the name same to the plugin" +" now you are creating.\n" +"So, the file is `store-search.rb` in the `droonga/plugins` directory. Then def" +"ine your `StoreSearchPlugin` as follows:" +msgstr "" +"まず最初に、`store-search`プラグインを作ります。\n" +"思い出して下さい、プラグインを実装するコードは、これから作ろうとしているプラグインと同じ名前のファイルに書かなくてはなりませんでしたよね。\n" +"ですので、実装を書くファイルは`droonga/plugins`ディレクトリに置かれた`store-search.rb`となります。`StoreSearch" +"Plugin`を以下のように定義しましょう:" + +msgid "lib/droonga/plugins/store-search.rb:" +msgstr "" + +msgid "" +"module Droonga\n" +" module Plugins\n" +" module StoreSearchPlugin\n" +" extend Plugin\n" +" register(\"store-search\")" +msgstr "" + +msgid "" +" class Adapter < Droonga::Adapter\n" +" input_message.pattern = [\"type\", :equal, \"storeSearch\"]" +msgstr "" + +msgid "" +" def adapt_input(input_message)\n" +" logger.info(\"StoreSearchPlugin::Adapter\", :message => input_message)" +msgstr "" + +msgid "" +" query = input_message.body[\"query\"]\n" +" logger.info(\"storeSearch\", :query => query)" +msgstr "" + +msgid "" +" body = {\n" +" \"queries\" => {\n" +" \"stores\" => {\n" +" \"source\" => \"Store\",\n" +" \"condition\" => {\n" +" \"query\" => query,\n" +" \"matchTo\" => \"_key\",\n" +" },\n" +" \"output\" => {\n" +" \"elements\" => [\n" +" \"startTime\",\n" +" \"elapsedTime\",\n" +" \"count\",\n" +" \"attributes\",\n" +" \"records\",\n" +" ],\n" +" \"attributes\" => [\n" +" \"_key\",\n" +" ],\n" +" \"limit\" => -1,\n" +" }\n" +" }\n" +" }\n" +" }" +msgstr "" + +msgid "" +" input_message.type = \"search\"\n" +" input_message.body = body\n" +" end\n" +" end\n" +" end\n" +" end\n" +"end\n" +"~~~" +msgstr "" + +msgid "" +"Then update your `catalog.json` to activate the plugin.\n" +"Remove the `sample-logger` plugin previously created." +msgstr "" +"次に、プラグインを有効化するために`catalog.json`を更新します。\n" +"先程作成した`sample-logger`は削除しておきます。" + +msgid "" +"~~~\n" +"(snip)\n" +" \"datasets\": {\n" +" \"Starbucks\": {\n" +" (snip)\n" +" \"plugins\": [\"store-search\", \"groonga\", \"crud\", \"search\"],\n" +"(snip)\n" +"~~~" +msgstr "" + +msgid "" +"Remember, you must place your plugin `\"store-search\"` before the `\"search\"` be" +"cause yours depends on it." +msgstr "思い出して下さい、`\"store-search\"`は`\"search\"`に依存しているので、`\"search\"`よりも前に置く必要があります。" + +msgid "Now you can use this new command by the following request:" +msgstr "これで、以下のようなリクエストで新しいコマンドを使えるようになりました:" + +msgid "store-search-columbus.json:" +msgstr "" + +msgid "" +"~~~json\n" +"{\n" +" \"dataset\" : \"Starbucks\",\n" +" \"type\" : \"storeSearch\",\n" +" \"body\" : {\n" +" \"query\" : \"Columbus\"\n" +" }\n" +"}\n" +"~~~" +msgstr "" + +msgid "In order to issue this request, you need to run:" +msgstr "リクエストを発行するために、以下のようにコマンドを実行しましょう:" + +msgid "" +"~~~\n" +"# droonga-request --tag starbucks store-search-columbus.json\n" +"Elapsed time: 0.01494\n" +"[\n" +" \"droonga.message\",\n" +" 1392621168,\n" +" {\n" +" \"inReplyTo\": \"1392621168.0119512\",\n" +" \"statusCode\": 200,\n" +" \"type\": \"storeSearch.result\",\n" +" \"body\": {\n" +" \"stores\": {\n" +" \"count\": 2,\n" +" \"records\": [\n" +" [\n" +" \"Columbus @ 67th - New York NY (W)\"\n" +" ],\n" +" [\n" +" \"2 Columbus Ave. - New York NY (W)\"\n" +" ]\n" +" ]\n" +" }\n" +" }\n" +" }\n" +"]\n" +"~~~" +msgstr "" + +msgid "And you will see the result on fluentd's log in `fluentd.log`:" +msgstr "この時、`fluentd.log`には以下のようなログが出力されているはずです:" + +msgid "" +"~~~\n" +"2014-02-17 16:12:48 +0900 [info]: StoreSearchPlugin::Adapter message=#<Droonga" +"::InputMessage:0x007fe4791d3958 @raw_message={\"dataset\"=>\"Starbucks\", \"type\"=>" +"\"storeSearch\", \"body\"=>{\"query\"=>\"Columbus\"}, \"replyTo\"=>{\"type\"=>\"storeSearch" +".result\", \"to\"=>\"127.0.0.1:49934/droonga\"}, \"id\"=>\"1392621168.0119512\", \"date\"" +"=>\"2014-02-17 16:12:48 +0900\", \"appliedAdapters\"=>[]}>\n" +"2014-02-17 16:12:48 +0900 [info]: storeSearch query=\"Columbus\"\n" +"~~~" +msgstr "" + +msgid "Now we can perform store search with simple requests." +msgstr "以上の手順で、単純なリクエストによって店舗の検索を行えるようになりました。" + +msgid "" +"Note: look at the `\"type\"` of the response message. Now it became `\"storeSearc" +"h.result\"`, from `\"search.result\"`. Because it is triggered from the incoming " +"message with the type `\"storeSearch\"`, the outgoing message has the type `\"(in" +"coming command).result\"` automatically. In other words, you don't have to chan" +"ge the type of the outgoing messages, like `input_message.type = \"search\"` in " +"the method `adapt_input`." +msgstr "" +"注意:レスポンスのメッセージの`\"type\"`の値が`\"search.result\"`から`\"storeSearch.result\"`に変わっていることに注" +"目して下さい。これは、このレスポンスが、`type`が`\"storeSearch\"`であるリクエストに起因して発生した物であるために、Droonga Eng" +"ineによって自動的に`\"(入力メッセージのtype).result\"`という`type`が設定されたからです。言い換えると、出力メッセージの`type`は" +"、`adapt_input`での`input_message.type = \"search\"`のような方法でわざわざ自分で設定し直す必要はありません。" + +msgid "### Returning of simple responses" +msgstr "### シンプルなレスポンスを返す" + +msgid "" +"Second, let's return results in more simple way: just an array of the names of" +" stores." +msgstr "次に、結果をより単純な形で、単に店舗の名前の配列だけを返すだけという物にしてみましょう。" + +msgid "Define the `adapt_output` method as follows." +msgstr "`adapt_output`を以下のように定義して下さい。" + +msgid "" +"~~~ruby\n" +"(snip)\n" +" module StoreSearchPlugin\n" +" extend Plugin\n" +" register(\"store-search\")" +msgstr "" + +msgid "" +" class Adapter < Droonga::Adapter\n" +" (snip)" +msgstr "" + +msgid "" +" def adapt_output(output_message)\n" +" logger.info(\"StoreSearchPlugin::Adapter\", :message => output_message" +")" +msgstr "" + +msgid "" +" records = output_message.body[\"stores\"][\"records\"]\n" +" simplified_results = records.flatten" +msgstr "" + +msgid "" +" output_message.body = simplified_results\n" +" end\n" +" end\n" +" end\n" +"(snip)\n" +"~~~" +msgstr "" + +msgid "" +"The `adapt_output` method receives outgoing messages only corresponding to the" +" incoming messages trapped by the plugin." +msgstr "`adapt_output`メソッドは、そのプラグインによって捕捉された入力メッセージに対応する出力メッセージのみを受け取ります。" + +msgid "Send the request:" +msgstr "リクエストを送ってみましょう:" + +msgid "" +"~~~\n" +"# droonga-request --tag starbucks store-search-columbus.json\n" +"Elapsed time: 0.014859\n" +"[\n" +" \"droonga.message\",\n" +" 1392621288,\n" +" {\n" +" \"inReplyTo\": \"1392621288.158763\",\n" +" \"statusCode\": 200,\n" +" \"type\": \"storeSearch.result\",\n" +" \"body\": [\n" +" \"Columbus @ 67th - New York NY (W)\",\n" +" \"2 Columbus Ave. - New York NY (W)\"\n" +" ]\n" +" }\n" +"]\n" +"~~~" +msgstr "" + +msgid "The log in `fluentd.log` will be like this:" +msgstr "`fluentd.log`には以下のようなログが出力されているはずです:" + +msgid "" +"~~~\n" +"2014-02-17 16:14:48 +0900 [info]: StoreSearchPlugin::Adapter message=#<Droonga" +"::InputMessage:0x007ffb8ada9d68 @raw_message={\"dataset\"=>\"Starbucks\", \"type\"=>" +"\"storeSearch\", \"body\"=>{\"query\"=>\"Columbus\"}, \"replyTo\"=>{\"type\"=>\"storeSearch" +".result\", \"to\"=>\"127.0.0.1:49960/droonga\"}, \"id\"=>\"1392621288.158763\", \"date\"=" +">\"2014-02-17 16:14:48 +0900\", \"appliedAdapters\"=>[]}>\n" +"2014-02-17 16:14:48 +0900 [info]: storeSearch query=\"Columbus\"\n" +"2014-02-17 16:14:48 +0900 [info]: StoreSearchPlugin::Adapter message=#<Droonga" +"::OutputMessage:0x007ffb8ad78e48 @raw_message={\"dataset\"=>\"Starbucks\", \"type\"=" +">\"dispatcher\", \"body\"=>{\"stores\"=>{\"count\"=>2, \"records\"=>[[\"Columbus @ 67th -" +" New York NY (W)\"], [\"2 Columbus Ave. - New York NY (W)\"]]}}, \"replyTo\"=>{\"t" +"ype\"=>\"storeSearch.result\", \"to\"=>\"127.0.0.1:49960/droonga\"}, \"id\"=>\"139262128" +"8.158763\", \"date\"=>\"2014-02-17 16:14:48 +0900\", \"appliedAdapters\"=>[\"Droonga::" +"Plugins::StoreSearchPlugin::Adapter\", \"Droonga::Plugins::Error::Adapter\"], \"or" +"iginalTypes\"=>[\"storeSearch\"]}>\n" +"~~~" +msgstr "" + +msgid "Now you've got the simplified response." +msgstr "このように、単純化されたレスポンスを受け取ることができました。" + +msgid "" +"In the way just described, we can use adapter to implement the application spe" +"cific search logic." +msgstr "ここで解説したように、アダプターはアプリケーション固有の検索機能を実装するために利用できます。" + +msgid "## Conclusion" +msgstr "## まとめ" + +msgid "" +"We have learned how to add a new command based only on a custom adapter and an" +" existing command.\n" +"In the process, we also have learned how to receive and modify messages, both " +"of incoming and outgoing." +msgstr "" +"既存のコマンドと独自のアダプターのみを使って新しいコマンドを追加する方法について学びました。\n" +"その過程で、入力メッセージと出力メッセージの両方について、どのように受け取り加工するのかについても学びました。" + +msgid "" +"See also the [reference manual](../../../reference/plugin/adapter/) for more d" +"etails." +msgstr "詳細は[リファレンスマニュアル](../../../reference/plugin/adapter/)を参照して下さい。" + +msgid "" +" [basic tutorial]: ../../basic/\n" +" [overview]: ../../../overview/\n" +" [search]: ../../../reference/commands/select/" +msgstr "" Added: _po/ja/tutorial/1.0.3/plugin-development/handler/index.po (+718 -0) 100644 =================================================================== --- /dev/null +++ _po/ja/tutorial/1.0.3/plugin-development/handler/index.po 2014-05-19 16:48:30 +0900 (fb46492) @@ -0,0 +1,718 @@ +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"PO-Revision-Date: 2014-03-05 12:52+0900\n" +"Language: ja\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" + +msgid "" +"---\n" +"title: \"Plugin: Handle requests on all volumes, to add a new command working a" +"round the storage\"\n" +"layout: en\n" +"---" +msgstr "" +"---\n" +"title: \"プラグイン: 全てのパーティション上でリクエストを処理し、ストレージを操作する新たなコマンドを追加する\"\n" +"layout: ja\n" +"---" + +msgid "" +"* TOC\n" +"{:toc}" +msgstr "" + +msgid "## The goal of this tutorial" +msgstr "## チュートリアルのゴール" + +msgid "" +"This tutorial aims to help you to learn how to develop plugins which do someth" +"ing dispersively for/in each volume, around the handling phase.\n" +"In other words, this tutorial describes *how to add a new simple command to th" +"e Droonga Engine*." +msgstr "" + +msgid "## Precondition" +msgstr "## 前提条件" + +msgid "* You must complete the [tutorial for the adaption phase][adapter]." +msgstr "" + +msgid "## Handling of requests" +msgstr "" + +msgid "" +"When a request is transferred from the adaption phase, the Droonga Engine ente" +"rs into the *processing phase*." +msgstr "" + +msgid "" +"In the processing phase, the Droonga Engine processes the request step by step" +".\n" +"One *step* is constructed from some sub phases: *planning phase*, *distributio" +"n phase*, *handling phase*, and *collection phase*." +msgstr "" + +msgid "" +" * At the *planning phase*, the Droonga Engine generates multiple sub steps to" +" process the request.\n" +" In simple cases, you don't have to write codes for this phase, then there i" +"s just one sub step to handle the request.\n" +" * At the *distribution phase*, the Droonga Engine distributes task messages f" +"or the request, to multiple volumes.\n" +" (It is completely done by the Droonga Engine itself, so this phase is not p" +"luggable.)\n" +" * At the *handling phase*, *each single volume simply processes only one dist" +"ributed task message as its input, and returns a result.*\n" +" This is the time that actual storage accesses happen.\n" +" Actually, some commands (`search`, `add`, `create_table` and so on) access " +"to the storage at the time.\n" +" * At the *collection phase*, the Droonga Engine collects results from volumes" +" to one unified result.\n" +" There are some useful generic collectors, so you don't have to write codes " +"for this phase in most cases." +msgstr "" + +msgid "" +"After all steps are finished, the Droonga Engine transfers the result to the p" +"ost adaption phase." +msgstr "" + +msgid "" +"A class to define operations at the handling phase is called *handler*.\n" +"Put simply, adding of a new handler means adding a new command." +msgstr "" + +msgid "## Design a read-only command `countRecords`" +msgstr "" + +msgid "" +"Here, in this tutorial, we are going to add a new custom `countRecords` comman" +"d.\n" +"At first, let's design it." +msgstr "" + +msgid "" +"The command reports the number of records about a specified table, for each si" +"ngle volume.\n" +"So it will help you to know how records are distributed in the cluster.\n" +"Nothing is changed by the command, so it is a *read-only command*." +msgstr "" + +msgid "The request must have the name of one table, like:" +msgstr "" + +msgid "" +"~~~json\n" +"{\n" +" \"dataset\" : \"Starbucks\",\n" +" \"type\" : \"countRecords\",\n" +" \"body\" : {\n" +" \"table\": \"Store\"\n" +" }\n" +"}\n" +"~~~" +msgstr "" + +msgid "" +"Create a JSON file `count-records.json` with the content above.\n" +"We'll use it for testing." +msgstr "" + +msgid "" +"The response must have number of records in the table, for each single volume." +"\n" +"They can be appear in an array, like:" +msgstr "" + +msgid "" +"~~~json\n" +"{\n" +" \"inReplyTo\": \"(message id)\",\n" +" \"statusCode\": 200,\n" +" \"type\": \"countRecords.result\",\n" +" \"body\": [10, 10]\n" +"}\n" +"~~~" +msgstr "" + +msgid "" +"If there are 2 volumes and 20 records are stored evenly, the array will have t" +"wo elements like above.\n" +"It means that a volume has 10 records and another one also has 10 records." +msgstr "" + +msgid "" +"We're going to create a plugin to accept such requests and return such respons" +"es." +msgstr "" + +msgid "### Directory structure" +msgstr "" + +msgid "" +"The directory structure for plugins are in same rule as explained in the [tuto" +"rial for the adaption phase][adapter].\n" +"Now let's create the `count-records` plugin, as the file `count-records.rb`. T" +"he directory tree will be:" +msgstr "" + +msgid "" +"~~~\n" +"lib\n" +"└── droonga\n" +" └── plugins\n" +" └── count-records.rb\n" +"~~~" +msgstr "" + +msgid "Then, create a skeleton of a plugin as follows:" +msgstr "" + +msgid "lib/droonga/plugins/count-records.rb:" +msgstr "" + +msgid "" +"~~~ruby\n" +"require \"droonga/plugin\"" +msgstr "" + +msgid "" +"module Droonga\n" +" module Plugins\n" +" module CountRecordsPlugin\n" +" extend Plugin\n" +" register(\"count-records\")\n" +" end\n" +" end\n" +"end\n" +"~~~" +msgstr "" + +msgid "### Define a \"step\" for the command" +msgstr "" + +msgid "Define a \"step\" for the new `countRecords` command, in your plugin. Like:" +msgstr "" + +msgid "" +"module Droonga\n" +" module Plugins\n" +" module CountRecordsPlugin\n" +" extend Plugin\n" +" register(\"count-records\")" +msgstr "" + +msgid "" +" define_single_step do |step|\n" +" step.name = \"countRecords\"\n" +" end\n" +" end\n" +" end\n" +"end\n" +"~~~" +msgstr "" + +msgid "" +"The `step.name` equals to the name of the command itself.\n" +"Currently we just define the name of the command.\n" +"That's all." +msgstr "" + +msgid "### Define the handling logic" +msgstr "" + +msgid "" +"The command has no handler, so it does nothing yet.\n" +"Let's define the behavior." +msgstr "" + +msgid "" +" define_single_step do |step|\n" +" step.name = \"countRecords\"\n" +" step.handler = :Handler\n" +" end" +msgstr "" + +msgid "" +" class Handler < Droonga::Handler\n" +" def handle(message)\n" +" [0]\n" +" end\n" +" end\n" +" end\n" +" end\n" +"end\n" +"~~~" +msgstr "" + +msgid "The class `Handler` is a handler class for our new command." +msgstr "" + +msgid "" +" * It must inherit a builtin-class `Droonga::Handler`.\n" +" * It implements the logic to handle requests.\n" +" Its instance method `#handle` actually handles requests." +msgstr "" + +msgid "" +"Currently the handler does nothing and returns an result including an array of" +" a number.\n" +"The returned value is used to construct the response body." +msgstr "" + +msgid "" +"The handler is bound to the step with the configuration `step.handler`.\n" +"Because we define the class `Handler` after `define_single_step`, we specify t" +"he handler class with a symbol `:Handler`.\n" +"If you define the handler class before `define_single_step`, then you can writ" +"e as `step.handler = Handler` simply.\n" +"Moreover, a class path string like `\"OtherPlugin::Handler\"` is also available." +msgstr "" + +msgid "" +"Then, we also have to bind a collector to the step, with the configuration `st" +"ep.collector`." +msgstr "" + +msgid "" +"~~~ruby\n" +"# (snip)\n" +" define_single_step do |step|\n" +" step.name = \"countRecords\"\n" +" step.handler = :Handler\n" +" step.collector = Collectors::Sum\n" +" end\n" +"# (snip)\n" +"~~~" +msgstr "" + +msgid "" +"The `Collectors::Sum` is one of built-in collectors.\n" +"It merges results returned from handler instances for each volume to one resul" +"t." +msgstr "" + +msgid "### Activate the plugin with `catalog.json`" +msgstr "### `catalog.json`でプラグインを有効化する" + +msgid "" +"Update catalog.json to activate this plugin.\n" +"Add `\"count-records\"` to `\"plugins\"`." +msgstr "" + +msgid "" +"~~~\n" +"(snip)\n" +" \"datasets\": {\n" +" \"Starbucks\": {\n" +" (snip)\n" +" \"plugins\": [\"count-records\", \"groonga\", \"crud\", \"search\"],\n" +"(snip)\n" +"~~~" +msgstr "" + +msgid "### Run and test" +msgstr "### 実行と動作を確認する" + +msgid "" +"Let's get Droonga started.\n" +"Note that you need to specify ./lib directory in RUBYLIB environment variable " +"in order to make ruby possible to find your plugin." +msgstr "" + +msgid "" +" # kill $(cat fluentd.pid)\n" +" # RUBYLIB=./lib fluentd --config fluentd.conf --log fluentd.log --daemon f" +"luentd.pid" +msgstr "" + +msgid "" +"Then, send a request message for the `countRecords` command to the Droonga Eng" +"ine." +msgstr "" + +msgid "" +"~~~\n" +"# droonga-request --tag starbucks count-records.json\n" +"Elapsed time: 0.01494\n" +"[\n" +" \"droonga.message\",\n" +" 1392621168,\n" +" {\n" +" \"inReplyTo\": \"1392621168.0119512\",\n" +" \"statusCode\": 200,\n" +" \"type\": \"countRecords.result\",\n" +" \"body\": [\n" +" 0,\n" +" 0,\n" +" 0\n" +" ]\n" +" }\n" +"]\n" +"~~~" +msgstr "" + +msgid "" +"You'll get a response message like above.\n" +"Look at these points:" +msgstr "" + +msgid "" +" * The `type` of the response becomes `countRecords.result`.\n" +" It is automatically named by the Droonga Engine.\n" +" * The format of the `body` is same to the returned value of the handler's `ha" +"ndle` method." +msgstr "" + +msgid "There are three elements in the array. Why?" +msgstr "" + +msgid "" +" * Remember that the `Starbucks` dataset was configured with two replicas and " +"three sub volumes for each replica, in the `catalog.json` of [the basic tutori" +"al][basic].\n" +" * Because it is a read-only command, a request is delivered to only one repli" +"ca (and it is chosen at random).\n" +" Then only three single volumes receive the command, so only three results a" +"ppear, not six.\n" +" (TODO: I have to add a figure to indicate active nodes: [000, 001, 002, 010" +", 011, 012] => [000, 001, 002])\n" +" * The `Collectors::Sum` collects them.\n" +" Those three results are joined to just one array by the collector." +msgstr "" + +msgid "" +"As the result, just one array with three elements appears in the final respons" +"e." +msgstr "" + +msgid "### Read-only access to the storage" +msgstr "" + +msgid "" +"Now, each instance of the handler class always returns `0` as its result.\n" +"Let's implement codes to count up the number of records from the actual storag" +"e." +msgstr "" + +msgid "" +"~~~ruby\n" +"# (snip)\n" +" class Handler < Droonga::Handler\n" +" def handle(message)\n" +" request = message.request\n" +" table_name = request[\"table\"]\n" +" table = @context[table_name]\n" +" count = table.size\n" +" [count]\n" +" end\n" +" end\n" +"# (snip)\n" +"~~~" +msgstr "" + +msgid "" +"Look at the argument of the `handle` method.\n" +"It is different from the one an adapter receives.\n" +"A handler receives a message meaning a distributed task.\n" +"So you have to extract the request message from the distributed task by the co" +"de `request = message.request`." +msgstr "" + +msgid "" +"The instance variable `@context` is an instance of `Groonga::Context` for the " +"storage of the corresponding single volume.\n" +"See the [class reference of Rroonga][Groonga::Context].\n" +"You can use any feature of Rroonga via `@context`.\n" +"For now, we simply access to the table itself by its name and read the value o" +"f its `size` method - it returns the number of records." +msgstr "" + +msgid "" +"Then, test it.\n" +"Restart the Droonga Engine and send the request again." +msgstr "" + +msgid "" +"~~~\n" +"# kill $(cat fluentd.pid)\n" +"# RUBYLIB=./lib fluentd --config fluentd.conf --log fluentd.log --daemon fluen" +"td.pid\n" +"# droonga-request --tag starbucks count-records.json\n" +"Elapsed time: 0.01494\n" +"[\n" +" \"droonga.message\",\n" +" 1392621168,\n" +" {\n" +" \"inReplyTo\": \"1392621168.0119512\",\n" +" \"statusCode\": 200,\n" +" \"type\": \"countRecords.result\",\n" +" \"body\": [\n" +" 14,\n" +" 15,\n" +" 11\n" +" ]\n" +" }\n" +"]\n" +"~~~" +msgstr "" + +msgid "Because there are totally 40 records, they are stored evenly like above." +msgstr "" + +msgid "## Design a read-write command `deleteStores`" +msgstr "" + +msgid "Next, let's add another new custom command `deleteStores`." +msgstr "" + +msgid "" +"The command deletes records of the `Store` table, from the storage.\n" +"Because it modifies something in existing storage, it is a *read-write command" +"*." +msgstr "" + +msgid "The request must have the condition to select records to be deleted, like:" +msgstr "" + +msgid "" +"~~~json\n" +"{\n" +" \"dataset\" : \"Starbucks\",\n" +" \"type\" : \"deleteStores\",\n" +" \"body\" : {\n" +" \"keyword\": \"Broadway\"\n" +" }\n" +"}\n" +"~~~" +msgstr "" + +msgid "" +"Any record including the given keyword `\"Broadway\"` in its `\"key\"` is deleted " +"from the storage of all volumes." +msgstr "" + +msgid "" +"Create a JSON file `delete-stores-broadway.json` with the content above.\n" +"We'll use it for testing." +msgstr "" + +msgid "The response must have a boolean value to indicate \"success\" or \"fail\", like:" +msgstr "" + +msgid "" +"~~~json\n" +"{\n" +" \"inReplyTo\": \"(message id)\",\n" +" \"statusCode\": 200,\n" +" \"type\": \"deleteStores.result\",\n" +" \"body\": true\n" +"}\n" +"~~~" +msgstr "" + +msgid "" +"If the request is successfully processed, the `body` becomes `true`. Otherwise" +" `false`.\n" +"The `body` is just one boolean value, because we don't have to receive multipl" +"e results from volumes." +msgstr "" + +msgid "### Directory Structure" +msgstr "### ディレクトリの構造" + +msgid "" +"Now let's create the `delete-stores` plugin, as the file `delete-stores.rb`. T" +"he directory tree will be:" +msgstr "" + +msgid "" +"~~~\n" +"lib\n" +"└── droonga\n" +" └── plugins\n" +" └── delete-stores.rb\n" +"~~~" +msgstr "" + +msgid "lib/droonga/plugins/delete-stores.rb:" +msgstr "" + +msgid "" +"module Droonga\n" +" module Plugins\n" +" module DeleteStoresPlugin\n" +" extend Plugin\n" +" register(\"delete-stores\")\n" +" end\n" +" end\n" +"end\n" +"~~~" +msgstr "" + +msgid "Define a \"step\" for the new `deleteStores` command, in your plugin. Like:" +msgstr "" + +msgid "" +"module Droonga\n" +" module Plugins\n" +" module DeleteStoresPlugin\n" +" extend Plugin\n" +" register(\"delete-stores\")" +msgstr "" + +msgid "" +" define_single_step do |step|\n" +" step.name = \"deleteStores\"\n" +" step.write = true\n" +" end\n" +" end\n" +" end\n" +"end\n" +"~~~" +msgstr "" + +msgid "" +"Look at a new configuration `step.write`.\n" +"Because this command modifies the storage, we must indicate it clearly." +msgstr "" + +msgid "Let's define the handler." +msgstr "" + +msgid "" +" define_single_step do |step|\n" +" step.name = \"deleteStores\"\n" +" step.write = true\n" +" step.handler = :Handler\n" +" step.collector = Collectors::And\n" +" end" +msgstr "" + +msgid "" +" class Handler < Droonga::Handler\n" +" def handle(message)\n" +" request = message.request\n" +" keyword = request[\"keyword\"]\n" +" table = @context[\"Store\"]\n" +" table.delete do |record|\n" +" record.key =~ keyword\n" +" end\n" +" true\n" +" end\n" +" end\n" +" end\n" +" end\n" +"end\n" +"~~~" +msgstr "" + +msgid "" +"Remember, you have to extract the request message from the received task messa" +"ge." +msgstr "" + +msgid "" +"The handler finds and deletes existing records which have the given keyword in" +" its \"key\", by the [API of Rroonga][Groonga::Table_delete]." +msgstr "" + +msgid "" +"And, the `Collectors::And` is bound to the step by the configuration `step.col" +"lector`.\n" +"It is is also one of built-in collectors, and merges boolean values returned f" +"rom handler instances for each volume, to one boolean value." +msgstr "" + +msgid "" +"Update catalog.json to activate this plugin.\n" +"Add `\"delete-stores\"` to `\"plugins\"`." +msgstr "" + +msgid "" +"~~~\n" +"(snip)\n" +" \"datasets\": {\n" +" \"Starbucks\": {\n" +" (snip)\n" +" \"plugins\": [\"delete-stores\", \"count-records\", \"groonga\", \"crud\", \"se" +"arch\"],\n" +"(snip)\n" +"~~~" +msgstr "" + +msgid "Restart the Droonga Engine and send the request." +msgstr "" + +msgid "" +"~~~\n" +"# kill $(cat fluentd.pid)\n" +"# RUBYLIB=./lib fluentd --config fluentd.conf --log fluentd.log --daemon fluen" +"td.pid\n" +"# droonga-request --tag starbucks count-records.json\n" +"Elapsed time: 0.01494\n" +"[\n" +" \"droonga.message\",\n" +" 1392621168,\n" +" {\n" +" \"inReplyTo\": \"1392621168.0119512\",\n" +" \"statusCode\": 200,\n" +" \"type\": \"deleteStores.result\",\n" +" \"body\": true\n" +" }\n" +"]\n" +"~~~" +msgstr "" + +msgid "" +"Because results from volumes are unified to just one boolean value, the respon" +"se's `body` is a `true`.\n" +"As the verification, send the request of `countRecords` command." +msgstr "" + +msgid "" +"~~~\n" +"# droonga-request --tag starbucks count-records.json\n" +"Elapsed time: 0.01494\n" +"[\n" +" \"droonga.message\",\n" +" 1392621168,\n" +" {\n" +" \"inReplyTo\": \"1392621168.0119512\",\n" +" \"statusCode\": 200,\n" +" \"type\": \"countRecords.result\",\n" +" \"body\": [\n" +" 7,\n" +" 13,\n" +" 6\n" +" ]\n" +" }\n" +"]\n" +"~~~" +msgstr "" + +msgid "" +"Note, the number of records are smaller than the previous result.\n" +"This means that four or some records are deleted from each volume." +msgstr "" + +msgid "## Conclusion" +msgstr "## まとめ" + +msgid "" +"We have learned how to add a new simple command working around the data.\n" +"In the process, we also have learned how to create plugins working in the hand" +"ling phrase." +msgstr "" + +msgid "" +" [adapter]: ../adapter\n" +" [basic]: ../basic\n" +" [Groonga::Context]: http://ranguba.org/rroonga/en/Groonga/Context.html\n" +" [Groonga::Table_delete]: http://ranguba.org/rroonga/en/Groonga/Table.html#de" +"lete-instance_method" +msgstr "" Added: _po/ja/tutorial/1.0.3/plugin-development/index.po (+204 -0) 100644 =================================================================== --- /dev/null +++ _po/ja/tutorial/1.0.3/plugin-development/index.po 2014-05-19 16:48:30 +0900 (11dd96e) @@ -0,0 +1,204 @@ +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"PO-Revision-Date: 2014-03-05 12:52+0900\n" +"Language: ja\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" + +msgid "" +"---\n" +"title: Droonga plugin development tutorial\n" +"layout: en\n" +"---" +msgstr "" +"---\n" +"title: Droongaプラグイン開発チュートリアル\n" +"layout: ja\n" +"---" + +msgid "" +"* TOC\n" +"{:toc}" +msgstr "" + +msgid "## The goal of this tutorial" +msgstr "## チュートリアルのゴール" + +msgid "" +"Learning steps to develop a Droonga plugin by yourself.\n" +"You must complete the [basic tutorial][] before this." +msgstr "" +"Droongaプラグインの作り方を理解します。\n" +"[基本的な使い方のチュートリアル][basic tutorial]を完了している必要があります。" + +msgid "## What's \"plugin\"?" +msgstr "## プラグインとは" + +msgid "" +"Plugin is one of the most important concept of Droonga.\n" +"This makes Droonga flexible." +msgstr "" +"プラグインはDroongaの中でもっとも重要なコンセプトの一つです。\n" +"プラグインがDroongaを柔軟なものにしています。" + +msgid "" +"Generally, data processing tasks in the real world need custom treatments of t" +"he data, in various stages of the data stream.\n" +"This is not easy to be done in one-size-fits-all approach." +msgstr "多くの現実的なデータ処理タスクでは、問題に応じたデータの取り扱いが必要です。これを汎用の方法で解決するのは簡単ではありせん。" + +msgid "" +" * One may want to modify incoming requests to work well with other systems, o" +"ne may want to modify outgoing responses to help other systems understand the " +"result.\n" +" * One may want to do more complex data processing than that provided by Droon" +"ga as built-in, to have direct storage access for efficiency.\n" +" * One may need to control data distribution and collection logic of Droonga t" +"o profit from the distributed nature of Droonga." +msgstr "" +" * 外部のシステムと連携するために、入力のリクエスト形式を変更する必要があるかもしれません。外部のシステムが理解できるような形式で出力するために、出力を加" +"工する必要があるかもしれません。\n" +" * Droongaが標準で提供する機能よりもさらに複雑なデータ操作を、ストレージに直接アクセスしながら効率よく行う必要があるかもしれません。\n" +" * Droongaのデータ分散と回収ロジックをコントロールすることで、Droongaの分散性能を活かした高度なアプリケーションを構築する必要があるかもしれ" +"ません。" + +msgid "You can use plugins in those situations." +msgstr "このような場合にプラグインを利用することができます。" + +msgid "## Pluggable operations in Droonga Engine" +msgstr "## Droongaエンジンにおけるプラガブルな操作" + +msgid "" +"In Droonga Engine, there are 2 large pluggable phases and 3 sub phases for plu" +"gins.\n" +"In other words, from the point of view of plugins, each plugin can do from 1 t" +"o 4 operations.\n" +"See the [overview][] to grasp the big picture." +msgstr "" +"Droonga Engineにはプラガブルなフェーズが大きく分けて2つあり、そのうちの1つは3つのサブフェーズから構成されます。プラグインの観点からすると、" +"都合1つから4つの操作に処理を追加することができます。" + +msgid "" +"Adaption phase\n" +": At this phase, a plugin can modify incoming requests and outgoing responses." +msgstr "" +"アダプション・フェーズ\n" +": このフェーズでは、プラグインは入力のリクエストと出力のレスポンスを加工できます。" + +msgid "" +"Processing phase\n" +": At this phase, a plugin can process incoming requests on each volume, step b" +"y step." +msgstr "" +"プロセッシング・フェーズ\n" +": このフェーズでは、プラグインはそれぞれのボリューム上で入力のリクエストを逐次処理します。" + +msgid "The processing phase includes 3 sub pluggable phases:" +msgstr "プロセッシング・フェーズには3つのプラガブルなサブフェーズがあります:" + +msgid "" +"Handling phase\n" +": At this phase, a plugin can do low-level data handling, for example, databas" +"e operations and so on." +msgstr "" +"ハンドリング・フェーズ\n" +": このフェーズでは、プラグインは低レベルのデータ処理、たとえばデータベース操作などを行うことができます。" + +msgid "" +"Planning phase\n" +": At this phase, a plugin can split an incoming request to multiple steps." +msgstr "" +"プランニング・フェーズ\n" +": このフェーズでは、プラグインは入力のリクエストを複数のステップに分割できます。" + +msgid "" +"Collection phase\n" +": At this phase, a plugin can merge results from steps to a unified result." +msgstr "" +"コレクション・フェーズ\n" +": このフェーズでは、プラグインはステップから得られた結果をマージして一つの結果を生成できます。" + +msgid "" +"However, the point of view of these descriptions is based on the design of the" +" system itself, so you're maybe confused.\n" +"Then, let's shift our perspective on pluggable operations - what you want to d" +"o by a plugin." +msgstr "" +"上記の説明は、Droongaシステムの設計に基いているので、少々わかりづらいかもしれません。\n" +"ここでは、プラガブルな操作という観点から離れて、プラグインで何をしたいのかという観点から見てみましょう。" + +msgid "" +"Adding a new command based on another existing command.\n" +": For example, you possibly want to define a shorthand command wrapping the co" +"mplex `search` command.\n" +" *Adaption* of request and response messages makes it come true." +msgstr "" +"既に存在するコマンドを元にして新たなコマンドを作成する\n" +": たとえば、複雑な`search`コマンドをラップして、手軽に使えるコマンドを作りたいかもしれません。\n" +" リクエストとレスポンスに対する*アダプション*がそれを可能にします。" + +msgid "" +"Adding a new command working around the storage.\n" +": For example, you possibly want to modify data stored in the storage as you l" +"ike.\n" +" *Handling* of requests makes it come true." +msgstr "" +"新しいコマンドを追加してストレージを操作する\n" +": たとえば、ストレージに保存されているデータを自在に操作したいかもしれません。\n" +" リクエストに対する*ハンドリング*がそれを可能にします。" + +msgid "" +"Adding a new command for a complex task\n" +": For example, you possibly want to implement a powerful command like the buil" +"t-in `search` command.\n" +" *Planning and collection* of requests make it come true." +msgstr "" +"複雑なタスクを実現するコマンドを追加する\n" +": たとえば、標準の`search`コマンドのような強力なコマンドを実装したいかもしれません。リクエストに対する*プランニング*と*コレクション*がそれを可" +"能にします。" + +msgid "" +"In this tutorial, we focus on the adaption at first.\n" +"This is the most \"basic\" usecase of plugins, so it will help you to understand" +" the overview of Droonga plugin development.\n" +"Then, we focus on other cases in this order.\n" +"Following this tutorial, you will learn how to write plugins.\n" +"This will be the first step to create plugins fit with your own requirements." +msgstr "" +"このチュートリアルでは、最初に*アダプション*を扱います。\n" +"これはもっともプラグインの基本的なユースケースなので、Droongaにおけるプラグイン開発の基礎を理解する助けになるはずです。\n" +"その後、他のケースも上述の順で説明します。\n" +"このチュートリアルに従うと、プラグインの書き方を理解できるようになります。\n" +"自分独自の要求を満たすプラグインを作成するための第一歩となることでしょう。" + +msgid "## How to develop plugins?" +msgstr "## プラグインを開発するには" + +msgid "For more details, let's read these sub tutorials:" +msgstr "詳細は以下のサブチュートリアルを参照してください:" + +msgid "" +" 1. [Adapt requests and responses, to add a new command based on other existin" +"g commands][adapter].\n" +" 2. [Handle requests on all volumes, to add a new command working around the s" +"torage][handler].\n" +" 3. Handle requests only on a specific volume, to add a new command around the" +" storage more smartly. (under construction)\n" +" 4. Distribute requests and collect responses, to add a new complex command ba" +"sed on sub tasks. (under construction)" +msgstr "" +" 1. [リクエストとレスポンスを加工し、既存のコマンドに基づいた新たなコマンドを作成する][adapter]。\n" +" 2. [全てのボリューム上でリクエストを処理し、ストレージを操作する新たなコマンドを追加する][handler]。\n" +" 3. 特定のボリューム上だけでリクエストを処理し、より効率的にストレージを操作するコマンドを追加する (準備中)\n" +" 4. リクエストの分散とレスポンスの回収を行い、新たな複雑なコマンドを追加する (準備中)" + +msgid "" +" [basic tutorial]: ../basic/\n" +" [overview]: ../../overview/\n" +" [adapter]: ./adapter/\n" +" [handler]: ./handler/\n" +" [distribute-collect]: ./distribute-collect/" +msgstr "" Added: _po/ja/tutorial/1.0.3/watch.po (+281 -0) 100644 =================================================================== --- /dev/null +++ _po/ja/tutorial/1.0.3/watch.po 2014-05-19 16:48:30 +0900 (a8adf45) @@ -0,0 +1,281 @@ +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"PO-Revision-Date: 2014-03-05 12:52+0900\n" +"Language: ja\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" + +msgid "" +"---\n" +"title: Droonga tutorial\n" +"layout: en\n" +"---" +msgstr "" +"---\n" +"title: Droonga チュートリアル\n" +"layout: ja\n" +"---" + +msgid "" +"* TOC\n" +"{:toc}" +msgstr "" + +msgid "## Real-time search" +msgstr "" + +msgid "Droonga supports streaming-style real-time search." +msgstr "" + +msgid "### Update configurations of the Droonga engine" +msgstr "" + +msgid "Update your fluentd.conf and catalog.jsons, like:" +msgstr "" + +msgid "fluentd.conf:" +msgstr "" + +msgid "" +" <source>\n" +" type forward\n" +" port 24224\n" +" </source>\n" +" <match starbucks.message>\n" +" name localhost:24224/starbucks\n" +" type droonga\n" +" </match>\n" +" + <match droonga.message>\n" +" + name localhost:24224/droonga\n" +" + type droonga\n" +" + </match>\n" +" <match output.message>\n" +" type stdout\n" +" </match>" +msgstr "" + +msgid "catalog.json:" +msgstr "" + +msgid "" +" {\n" +" \"effective_date\": \"2013-09-01T00:00:00Z\",\n" +" \"zones\": [\n" +" + \"localhost:24224/droonga\",\n" +" \"localhost:24224/starbucks\"\n" +" ],\n" +" \"farms\": {\n" +" + \"localhost:24224/droonga\": {\n" +" + \"device\": \".\",\n" +" + \"capacity\": 10\n" +" + },\n" +" \"localhost:24224/starbucks\": {\n" +" \"device\": \".\",\n" +" \"capacity\": 10\n" +" }\n" +" },\n" +" \"datasets\": {\n" +" + \"Watch\": {\n" +" + \"workers\": 2,\n" +" + \"plugins\": [\"search\", \"groonga\", \"add\", \"watch\"],\n" +" + \"number_of_replicas\": 1,\n" +" + \"number_of_partitions\": 1,\n" +" + \"partition_key\": \"_key\",\n" +" + \"date_range\": \"infinity\",\n" +" + \"ring\": {\n" +" + \"localhost:23041\": {\n" +" + \"weight\": 50,\n" +" + \"partitions\": {\n" +" + \"2013-09-01\": [\n" +" + \"localhost:24224/droonga.watch\"\n" +" + ]\n" +" + }\n" +" + }\n" +" + }\n" +" + },\n" +" \"Starbucks\": {\n" +" \"workers\": 0,\n" +" \"plugins\": [\"search\", \"groonga\", \"add\"],\n" +" \"number_of_replicas\": 2,\n" +" \"number_of_partitions\": 2,\n" +" \"partition_key\": \"_key\",\n" +" \"date_range\": \"infinity\",\n" +" \"ring\": {\n" +" \"localhost:23041\": {\n" +" \"weight\": 50,\n" +" \"partitions\": {\n" +" \"2013-09-01\": [\n" +" \"localhost:24224/starbucks.000\",\n" +" \"localhost:24224/starbucks.001\"\n" +" ]\n" +" }\n" +" },\n" +" \"localhost:23042\": {\n" +" \"weight\": 50,\n" +" \"partitions\": {\n" +" \"2013-09-01\": [\n" +" \"localhost:24224/starbucks.002\",\n" +" \"localhost:24224/starbucks.003\"\n" +" ]\n" +" }\n" +" }\n" +" }\n" +" }\n" +" },\n" +" \"options\": {\n" +" \"plugins\": []\n" +" }\n" +" }" +msgstr "" + +msgid "### Add a streaming API to the protocol adapter" +msgstr "" + +msgid "Add a streaming API to the protocol adapter, like;" +msgstr "" + +msgid "application.js:" +msgstr "" + +msgid "" +" var express = require('express'),\n" +" droonga = require('express-droonga');" +msgstr "" + +msgid "" +" var application = express();\n" +" var server = require('http').createServer(application);\n" +" server.listen(3000); // the port to communicate with clients" +msgstr "" + +msgid "" +" //============== INSERTED ==============\n" +" var streaming = {\n" +" 'streaming': new droonga.command.HTTPStreaming({\n" +" dataset: 'Watch',\n" +" path: '/watch',\n" +" method: 'GET',\n" +" subscription: 'watch.subscribe',\n" +" unsubscription: 'watch.unsubscribe',\n" +" notification: 'watch.notification',\n" +" createSubscription: function(request) {\n" +" return {\n" +" condition: request.query.query\n" +" };\n" +" }\n" +" })\n" +" };\n" +" //============= /INSERTED ==============" +msgstr "" + +msgid "" +" application.droonga({\n" +" prefix: '/droonga',\n" +" tag: 'starbucks',\n" +" defaultDataset: 'Starbucks',\n" +" server: server, // this is required to initialize Socket.IO API!\n" +" plugins: [\n" +" droonga.API_REST,\n" +" droonga.API_SOCKET_IO,\n" +" droonga.API_GROONGA,\n" +" droonga.API_DROONGA\n" +" //============== INSERTED ==============\n" +" ,streaming\n" +" //============= /INSERTED ==============\n" +" ]\n" +" });" +msgstr "" + +msgid "" +" application.get('/', function(req, res) {\n" +" res.sendfile(__dirname + '/index.html');\n" +" });" +msgstr "" + +msgid "### Prepare feeds" +msgstr "" + +msgid "Prepare \"feed\"s like:" +msgstr "" + +msgid "feeds.jsons:" +msgstr "" + +msgid "" +" {\"id\":\"feed:0\",\"dataset\":\"Watch\",\"type\":\"watch.feed\",\"body\":{\"targets\":{\"k" +"ey\":\"old place 0\"}}}\n" +" {\"id\":\"feed:1\",\"dataset\":\"Watch\",\"type\":\"watch.feed\",\"body\":{\"targets\":{\"k" +"ey\":\"new place 0\"}}}\n" +" {\"id\":\"feed:2\",\"dataset\":\"Watch\",\"type\":\"watch.feed\",\"body\":{\"targets\":{\"k" +"ey\":\"old place 1\"}}}\n" +" {\"id\":\"feed:3\",\"dataset\":\"Watch\",\"type\":\"watch.feed\",\"body\":{\"targets\":{\"k" +"ey\":\"new place 1\"}}}\n" +" {\"id\":\"feed:4\",\"dataset\":\"Watch\",\"type\":\"watch.feed\",\"body\":{\"targets\":{\"k" +"ey\":\"old place 2\"}}}\n" +" {\"id\":\"feed:5\",\"dataset\":\"Watch\",\"type\":\"watch.feed\",\"body\":{\"targets\":{\"k" +"ey\":\"new place 2\"}}}" +msgstr "" + +msgid "### Try it!" +msgstr "" + +msgid "At first, restart servers in each console." +msgstr "" + +msgid "The engine:" +msgstr "" + +msgid " # fluentd --config fluentd.conf" +msgstr "" + +msgid "The protocol adapter:" +msgstr "" + +msgid " # nodejs application.js" +msgstr "" + +msgid "Next, connect to the streaming API via curl:" +msgstr "" + +msgid " # curl \"http://localhost:3000/droonga/watch?query=new\"" +msgstr "" + +msgid "Then the client starts to receive streamed results." +msgstr "" + +msgid "Next, open a new console and send \"feed\"s to the engine like:" +msgstr "" + +msgid " # fluent-cat droonga.message < feeds.jsons" +msgstr "" + +msgid "" +"Then the client receives three results \"new place 0\", \"new place 1\", and \"new " +"place 2\" like:" +msgstr "" + +msgid "" +" {\"targets\":{\"key\":\"new place 0\"}}\n" +" {\"targets\":{\"key\":\"new place 1\"}}\n" +" {\"targets\":{\"key\":\"new place 2\"}}" +msgstr "" + +msgid "" +"They are search results for the query \"new\", given as a query parameter of the" +" streaming API." +msgstr "" + +msgid "Results can be appear in different order, like:" +msgstr "" + +msgid "" +" {\"targets\":{\"key\":\"new place 1\"}}\n" +" {\"targets\":{\"key\":\"new place 0\"}}\n" +" {\"targets\":{\"key\":\"new place 2\"}}" +msgstr "" + +msgid "because \"feed\"s are processed in multiple workers asynchronously." +msgstr "" Added: ja/reference/1.0.3/catalog/index.md (+20 -0) 100644 =================================================================== --- /dev/null +++ ja/reference/1.0.3/catalog/index.md 2014-05-19 16:48:30 +0900 (ba4ade3) @@ -0,0 +1,20 @@ +--- +title: カタログ +layout: ja +--- + +{% comment %} +############################################## + THIS FILE IS AUTOMATICALLY GENERATED FROM + "_po/ja/reference/1.0.3/catalog/index.po" + DO NOT EDIT THIS FILE MANUALLY! +############################################## +{% endcomment %} + + +複数のリソースが集まり、Droongaネットワークを構成します。それらのリソースを **カタログ** に記述しなければいけません。ネットワーク上のすべてのノードは同じカタログを共有します。 + +カタログの指定はバージョン管理されています。利用可能なバージョンは以下のとおりです: + + * [version 2](version2/) + * [version 1](version1/): (It is deprecated since 1.0.0.) Added: ja/reference/1.0.3/catalog/version1/index.md (+303 -0) 100644 =================================================================== --- /dev/null +++ ja/reference/1.0.3/catalog/version1/index.md 2014-05-19 16:48:30 +0900 (fb16ae3) @@ -0,0 +1,303 @@ +--- +title: カタログ +layout: ja +--- + +{% comment %} +############################################## + THIS FILE IS AUTOMATICALLY GENERATED FROM + "_po/ja/reference/1.0.3/catalog/version1/index.po" + DO NOT EDIT THIS FILE MANUALLY! +############################################## +{% endcomment %} + + +複数のリソースが集まり、Droongaネットワークを構成します。それらのリソースを **カタログ** に記述しなければいけません。ネットワーク上のすべてのノードは同じカタログを共有します。 + +このドキュメントはカタログについて説明します。 + + * TOC +{:toc} + +## 管理方法 + +今のところ、カタログを書くことも書いたカタログをすべてのノードで共有することも手動で行う必要があります。 + +近い将来、カタログを生成するユーティリティープログラムを提供する予定です。さらにその後、Droongaネットワークは自動でカタログの管理やカタログの配布を行うようになる予定です。 + +## 用語集 + +このセクションではカタログに出てくる用語を説明します。 + +### カタログ + +カタログはネットワーク内のリソースを表現するデータの集まりです。 + +### ゾーン + +ゾーンはファームの集まりです。同じゾーン内のファームはお互いに近くに配置することが期待されています。例えば、同じホスト内、同じスイッチ内、同じネットワーク内といった具合です。 + +### ファーム + +ファームはDroongaエンジンのインスタンスです。Droongaエンジンは[Fluentd][]のプラグインfluent-plugin-droongaとして実装されています。 + +1つの `fluentd` プロセスは複数のDroongaエンジンを持てます。 `fluentd.conf` に `droonga` タイプの `match` エントリーを1つ以上追加すると、 `fluentd` プロセスは同じ数のDroongaエンジンのインスタンスを生成します。 + +ファームは複数のワーカーと1つのジョブキューを持ちます。ファームはリクエストをジョブキューに投入します。ワーカーはジョブキューからリクエストを取り出します。 + +### データセット + +データセットは論理テーブルの集まりです。論理テーブルは1つのデータセットに所属しなければいけません。 + +各データセットの名前は同じDroongaネットワーク内で重複してはいけません。 + +### 論理テーブル + +論理テーブルはパーティションされた1つ以上の物理テーブルで構成されます。論理テーブルは物理レコードを持ちません。物理テーブルから物理レコードを返します。 + +1つの論理テーブルを1つ以上の物理テーブルにどうやってパーティションするかをカスタマイズできます。例えば、パーティションキーやパーテション数をカスタマイズできます。 + +### 物理テーブル + +物理テーブルはGroongaデータベースのテーブルです。Groongaのテーブルに物理レコードを保存します。 + +### リング + +リングはパーティションセットの集まりです。データセットは必ず1つのリングを持ちます。データセットはリング上に論理テーブルを作ります。 + +Droongaエンジンは物理テーブル上にあるレコードを1つ以上のパーティションセットに複製します。 + +### パーティションセット + +パーティションセットはパーティションの集まりです。1つのパーティションセットは同じDroongaネットワーク内のすべての論理テーブルのすべてのレコードを保存します。言い換えると、データセットは1つのパーティションセットの中でパーティションされます。 + +1つのパーティションセットは他のパーティションセットの複製です。 + +将来、Droongaエンジンは1つ以上のパーティションセット内でのパーティションをサポートするかもしれません。古いデータと新しいデータで異なるパーティションサイズを使うことができるので便利でしょう。通常、古いデータは小さく、新しいデータは大きくなります。大きなデータに大きなパーティションサイズを使うのは妥当なことです。 + +### パーティション + +1つのパーティションは1つのGroongaデータベースに対応します。0個以上の物理テーブルを持ちます。 + +### プラグイン + +Droonga Engine can be extended by writing plugin scripts. +In most cases, a series of plugins work cooperatively to +achieve required behaviors. +So, plugins are organized by behaviors. +Each behavior can be attached to datasets and/or tables by +adding "plugins" section to the corresponding entry in the catalog. + +More than one plugin can be assigned in a "plugins" section as an array. +The order in the array controls the execution order of plugins +when adapting messages. +When adapting an incoming message, plugins are applied in forward order +whereas those are applied in reverse order when adapting an outgoing message. + +## 例 + +Consider the following case: + + * There are two farms. + * All farms (Droonga Engine instances) works on the same fluentd. + * Each farm has two partitions. + * There are two replicas. + * There are two partitions for each table. + +Catalog is written as a JSON file. Its file name is `catalog.json`. + +Here is a `catalog.json` for the above case: + +~~~json +{ + "version": 1, + "effective_date": "2013-06-05T00:05:51Z", + "zones": ["localhost:23003/farm0", "localhost:23003/farm1"], + "farms": { + "localhost:23003/farm0": { + "device": "disk0", + "capacity": 1024 + }, + "localhost:23003/farm1": { + "device": "disk1", + "capacity": 1024 + } + }, + "datasets": { + "Wiki": { + "workers": 4, + "plugins": ["groonga", "crud", "search"], + "number_of_replicas": 2, + "number_of_partitions": 2, + "partition_key": "_key", + "date_range": "infinity", + "ring": { + "localhost:23004": { + "weight": 10, + "partitions": { + "2013-07-24": [ + "localhost:23003/farm0.000", + "localhost:23003/farm1.000" + ] + } + }, + "localhost:23005": { + "weight": 10, + "partitions": { + "2013-07-24": [ + "localhost:23003/farm1.001", + "localhost:23003/farm0.001" + ] + } + } + } + } + } +} +~~~ + +## Parameters + +Here are descriptions about parameters in `catalog.json`. + +### `version` {#version} + +It is a format version of the catalog file. + +Droonga Engine will change `catalog.json` format in the +future. Droonga Engine can provide auto format update feature with the +information. + +The value must be `1`. + +This is a required parameter. + +Example: + +~~~json +{ + "version": 1 +} +~~~ + +### `effective_date` + +It is a date string representing the day the catalog becomes +effective. + +The date string format must be [W3C-DTF][]. + +This is a required parameter. + +Note: fluent-plugin-droonga 0.8.0 doesn't use this value yet. + +Example: + +~~~json +{ + "effective_date": "2013-11-29T11:29:29Z" +} +~~~ + +### `zones` + +`Zones` is an array to express proximities between farms. +Farms are grouped by a zone, and zones can be grouped by another zone recursively. +Zones make a single tree structure, expressed by nested arrays. +Farms in a same branch are regarded as relatively closer than other farms. + +e.g. + +When the value of `zones` is as follows, + +``` +[["A", ["B", "C"]], "D"] +``` + +it expresses the following tree. + + /\ + /\ D + A /\ + B C + +This tree means the farm "B" and "C" are closer than "A" or "D" to each other. +You should make elements in a `zones` close to each other, like in the +same host, in the same switch, in the same network. + +This is an optional parameter. + +Note: fluent-plugin-droonga 0.8.0 doesn't use this value yet. + +Example: + +~~~json +{ + "zones": [ + ["localhost:23003/farm0", + "localhost:23003/farm1"], + ["localhost:23004/farm0", + "localhost:23004/farm1"] + ] +} +~~~ + +*TODO: Discuss about the call of this parameter. This seems completely equals to the list of keys of `farms`.* + +### `farms` + +It is an array of Droonga Engine instances. + +*TODO: Improve me. For example, we have to describe relations of nested farms, ex. `children`.* + +**Farms** correspond with fluent-plugin-droonga instances. A fluentd process may have multiple **farms** if more than one **match** entry with type **droonga** appear in the "fluentd.conf". +Each **farm** has its own job queue. +Each **farm** can attach to a data partition which is a part of a **dataset**. + +This is a required parameter. + +Example: + +~~~json +{ + "farms": { + "localhost:23003/farm0": { + "device": "/disk0", + "capacity": 1024 + }, + "localhost:23003/farm1": { + "device": "/disk1", + "capacity": 1024 + } + } +} +~~~ + +### `datasets` + +A **dataset** is a set of **tables** which comprise a single logical **table** virtually. +Each **dataset** must have a unique name in the network. + +### `ring` + +`ring` is a series of partitions which comprise a dataset. `replica_count`, `number_of_partitons` and **time-slice** factors affect the number of partitions in a `ring`. + +### `workers` + +`workers` is an integer number which specifies the number of worker processes to deal with the dataset. +If `0` is specified, no worker is forked and all operations are done in the master process. + +### `number_of_partitions` + +`number_of_partition` is an integer number which represents the number of partitions divided by the hash function. The hash function which determines where each record resides the partition in a dataset is compatible with memcached. + +### `date_range` + +`date_range` determines when to split the dataset. If a string "infinity" is assigned, dataset is never split by time factor. + +### `number_of_replicas` + +`number_of_replicas` represents the number of replicas of dataset maintained in the network. + + [Fluentd]: http://fluentd.org/ + [W3C-DTF]: http://www.w3.org/TR/NOTE-datetime "Date and Time Formats" Added: ja/reference/1.0.3/catalog/version2/index.md (+856 -0) 100644 =================================================================== --- /dev/null +++ ja/reference/1.0.3/catalog/version2/index.md 2014-05-19 16:48:30 +0900 (f93e6c3) @@ -0,0 +1,856 @@ +--- +title: カタログ +layout: ja +--- + +{% comment %} +############################################## + THIS FILE IS AUTOMATICALLY GENERATED FROM + "_po/ja/reference/1.0.3/catalog/version2/index.po" + DO NOT EDIT THIS FILE MANUALLY! +############################################## +{% endcomment %} + + +* TOC +{:toc} + +## 概要 {#abstract} + +`Catalog`はDroongaクラスタの設定を管理するためのJSONデータです。Droongaクラスタは1つ以上の`datasets`からなり、`dataset`はその他の部分からなります。それらは全て`catalog`に記述し、クラスタ内の全てホストで共有しなければなりません。 + +## 使い方 {#usage} + +この [`version`](#paramter-version) の `catalog` は Droonga 1.0.0 以降で有効です。 + +## 書式 {#syntax} + + { + "version": <Version number>, + "effectiveDate": "<Effective date>", + "datasets": { + "<Name of the dataset 1>": { + "nWorkers": <Number of workers>, + "plugins": [ + "Name of the plugin 1", + ... + ], + "schema": { + "<Name of the table 1>": { + "type" : <"Array", "Hash", "PatriciaTrie" or "DoubleArrayTrie"> + "keyType" : "<Type of the primary key>", + "tokenizer" : "<Tokenizer>", + "normalizer" : "<Normalizer>", + "columns" : { + "<Name of the column 1>": { + "type" : <"Scalar", "Vector" or "Index">, + "valueType" : "<Type of the value>", + "vectorOptions": { + "weight" : <Weight>, + }, + "indexOptions" : { + "section" : <Section>, + "weight" : <Weight>, + "position" : <Position>, + "sources" : [ + "<Name of a column to be indexed>", + ... + ] + } + }, + "<Name of the column 2>": { ... }, + ... + } + }, + "<Name of the table 2>": { ... }, + ... + }, + "fact": "<Name of the fact table>", + "replicas": [ + { + "dimension": "<Name of the dimension column>", + "slicer": "<Name of the slicer function>", + "slices": [ + { + "label": "<Label of the slice>", + "volume": { + "address": "<Address string of the volume>" + } + }, + ... + } + }, + ... + ] + }, + "<Name of the dataset 2>": { ... }, + ... + } + } + +## 詳細 {#details} + +### Catalog 定義 {#catalog} + +値 +: 以下のキーと値のペアを持つオブジェクト。 + +#### パラメータ + +##### `version` {#parameter-version} + +概要 +: カタログファイルのバージョン番号。 + +値 +: `2`. (このページに記述されている仕様はこの値が`2`のときのみ有効です) + +既定値 +: なし。これは必須のパラメータです。 + +継承可能性 +: 不可。 + +##### `effectiveDate` {#parameter-effective_date} + +概要 +: このカタログが有効になる時刻。 + +値 +: [W3C-DTF](http://www.w3.org/TR/NOTE-datetime "Date and Time Formats") でフォーマットされたタイムゾーン付きの時刻。 + +既定値 +: なし。これは必須のパラメータです。 + +継承可能性 +: 不可。 + +##### `datasets` {#parameter-datasets} + +概要 +: データセットの定義。 + +: データセット名をキーとし、[`dataset` 定義](#dataset) を値とするオブジェクト。 + +既定値 +: なし。これは必須のパラメータです。 + +継承可能性 +: 不可。 + +##### `nWorkers` {#parameter-n_workers} + +概要 +: データベースインスタンス毎にspawnされるワーカの数。 + +値 +: 整数。 + +既定値 +: 0 (ワーカー無し。全ての処理がマスタープロセス内で行われます) + +継承可能性 +: 可。`dataset`と`volume`の定義でオーバライドできます。 + + +#### 例 + +A version 2 catalog effective after `2013-09-01T00:00:00Z`, with no datasets: + +~~~ +{ + "version": 2, + "effectiveDate": "2013-09-01T00:00:00Z", + "datasets": { + } +} +~~~ + +### Dataset 定義 {#dataset} + +値 +: 以下のキーと値のペアを持つオブジェクト。 + +#### パラメータ + +##### `plugins` {#parameter-plugins} + +概要 +: このデータセットにおいて有効にするプラグイン名文字列の配列。 + +値 +: 文字列の配列。 + +既定値 +: なし。これは必須のパラメータです。 + +継承可能性 +: 可。`dataset`と`volume`の定義でオーバライドできます。 + +##### `schema` {#parameter-schema} + +概要 +: テーブルとそのカラムの定義。 + +値 +: テーブル名をキーとし、[`table` 定義](#table)を値とするオブジェクト。 + +既定値 +: なし。これは必須のパラメータです。 + +継承可能性 +: 可。`dataset`と`volume`の定義でオーバライドできます。 + +##### `fact` {#parameter-fact} + +概要 +: fact テーブルの名前。`dataset`が複数の`slice`に格納される場合、[`schema`](#parameter-schema)パラメータで定義されたテーブルの中から、1つ[fact table](http://en.wikipedia.org/wiki/Fact_table)を選択する必要があります。 + +値 +: 文字列。 + +既定値 +: なし。 + +継承可能性 +: 可。`dataset`と`volume`の定義でオーバライドできます。 + +##### `replicas` {#parameter-replicas} + +概要 +: 互いに複製されるボリュームの集合。 + +値 +: [`volume` 定義](#volume)の配列。 + +既定値 +: なし。これは必須のパラメータです。 + +継承可能性 +: 不可。 + +#### 例 + +データベースインスタンスに1つにつき4ワーカーを持ち、プラグイン`groonga`、`crud`、`search`を使用するデータセット: + +~~~ +{ + "nWorkers": 4, + "plugins": ["groonga", "crud", "search"], + "schema": { + }, + "replicas": [ + ] +} +~~~ + +### Table 定義 {#table} + +値 +: 以下のキーと値のペアを持つオブジェクト。 + +#### パラメータ + +##### `type` {#parameter-table-type} + +概要 +: テーブルのキーを管理するためのデータ構造を指定する。 + +値 +: 以下のうちいずれかの値。 + +* `"Array"`: キーの無いテーブル +* `"Hash"`: ハッシュテーブル +* `"PatriciaTrie"`: パトリシアトライテーブル +* `"DoubleArrayTrie"`: ダブル配列トライテーブル + +既定値 +: `"Hash"` + +継承可能性 +: 不可。 + +##### `keyType` {#parameter-keyType} + +概要 +: テーブルにおけるキーのデータ型。`type`が`"Array"`の場合は指定してはいけません。 + +値 +: 以下のデータ型のうちのいずれか。 + +* `"Integer"` : 64bit 符号付き整数。 +* `"Float"` : 64bit 浮動小数点数。 +* `"Time"` : マイクロ秒精度の時刻。 +* `"ShortText"` : 4095バイトまでの文字列。 +* `"TokyoGeoPoint"` : 旧日本測地系による経緯度。 +* `"WGS84GeoPoint"` : [WGS84](http://en.wikipedia.org/wiki/World_Geodetic_System) による経緯度。 + +既定値 +: なし。キーを持つテーブルでは指定が必須です。 + +継承可能性 +: 不可。 + +##### `tokenizer` {#parameter-tokenizer} + +概要 +: 語彙表として使われるテーブルにおける、文字列型の値を分割するために使うトークナイザーの種類を指定します。`keyType`が`"ShortText"`である場合にのみ有効です。 + +値 +: 以下のトークナイザー名のうちのいずれか。 + +* `"TokenDelimit"` +* `"TokenUnigram"` +* `"TokenBigram"` +* `"TokenTrigram"` +* `"TokenBigramSplitSymbol"` +* `"TokenBigramSplitSymbolAlpha"` +* `"TokenBigramSplitSymbolAlphaDigit"` +* `"TokenBigramIgnoreBlank"` +* `"TokenBigramIgnoreBlankSplitSymbol"` +* `"TokenBigramIgnoreBlankSplitSymbolAlpha"` +* `"TokenBigramIgnoreBlankSplitSymbolAlphaDigit"` +* `"TokenDelimitNull"` + +既定値 +: なし。 + +継承可能性 +: 不可。 + +##### `normalizer` {#parameter-normalizer} + +概要 +: キーの値を正規化・制限するノーマライザーの種類を指定します。`keyType`が`"ShortText"`である場合にのみ有効です。 + +値 +: 以下のノーマライザー名のうちのいずれか。 + +* `"NormalizerAuto"` +* `"NormalizerNFKC51"` + +既定値 +: なし。 + +継承可能性 +: 不可。 + +##### `columns` {#parameter-columns} + +概要 +: テーブルのカラムの定義。 + +Value +: An object keyed by the name of the column with value the [`column` definition](#column). + +既定値 +: なし。 + +継承可能性 +: 不可。 + +#### 例 + +##### 例1: Hashテーブル + +`ShortText`型のキーを持つ`Hash`テーブルで、カラムは無いもの: + +~~~ +{ + "type": "Hash", + "keyType": "ShortText", + "columns": { + } +} +~~~ + +##### 例2: PatriciaTrieテーブル + +`TokenBigram`トークナイザと`NormalizerAuto`ノーマライザを利用する`PatriciaTrie`テーブル + +~~~ +{ + "type": "PatriciaTrie", + "keyType": "ShortText", + "tokenizer": "TokenBigram", + "normalizer": "NormalizerAuto", + "columns": { + } +} +~~~ + +### Column 定義 {#column} + +値 + +: An object with the following key/value pairs. + +#### パラメータ + +##### `type` {#parameter-column-type} + +Abstract +: Specifies the quantity of data stored as each column value. + +Value +: Any of the followings. + +* `"Scalar"`: A single value. +* `"Vector"`: A list of values. +* `"Index"` : A set of unique values with additional properties respectively. Properties can be specified in [`indexOptions`](#parameter-indexOptions). + +Default value +: `"Scalar"` + +継承可能性 +: 不可。 + +##### `valueType` {#parameter-valueType} + +Abstract +: Data type of the column value. + +Value +: Any of the following data types or the name of another table defined in the same dataset. When a table name is assigned, the column acts as a foreign key references the table. + +* `"Bool"` : `true` or `false`. +* `"Integer"` : 64bit signed integer. +* `"Float"` : 64bit floating-point number. +* `"Time"` : Time value with microseconds resolution. +* `"ShortText"` : Text value up to 4,095 bytes length. +* `"Text"` : Text value up to 2,147,483,647 bytes length. +* `"TokyoGeoPoint"` : Tokyo Datum based geometric point value. +* `"WGS84GeoPoint"` : [WGS84](http://en.wikipedia.org/wiki/World_Geodetic_System) based geometric point value. + +既定値 +: なし。これは必須のパラメータです。 + +継承可能性 +: 不可。 + +##### `vectorOptions` {#parameter-vectorOptions} + +概要 +: データベースインスタンスの場所を指定します。 + +Value +: An object which is a [`vectorOptions` definition](#vectorOptions) + +Default value +: `{}` (Void object). + +継承可能性 +: 不可。 + +##### `indexOptions` {#parameter-indexOptions} + +概要 +: データベースインスタンスの場所を指定します。 + +Value +: An object which is an [`indexOptions` definition](#indexOptions) + +Default value +: `{}` (Void object). + +継承可能性 +: 不可。 + +#### 例 + +##### 例1: スカラー型カラム + +`ShortText`を格納するスカラー型のカラム: + +~~~ +{ + "type": "Scalar", + "valueType": "ShortText" +} +~~~ + +##### 例1: スカラー型カラム + +A vector column to store `ShortText` values with weight: + +~~~ +{ + "type": "Scalar", + "valueType": "ShortText", + "vectorOptions": { + "weight": true + } +} +~~~ + +##### 例2: インデクスカラム + +`Store`テーブルの`address`カラムをインデクスするカラム: + +~~~ +{ + "type": "Index", + "valueType": "Store", + "indexOptions": { + "sources": [ + "address" + ] + } +} +~~~ + +### vectorOptions 定義 {#vectorOptions} + +値 +: 以下のキーと値のペアを持つオブジェクト。 + +#### パラメータ + +##### `weight` {#parameter-vectorOptions-weight} + +Abstract +: Specifies whether the vector column stores the weight data or not. Weight data is used for indicating the importance of the value. + +Value +: A boolean value (`true` or `false`). + +Default value +: `false`. + +継承可能性 +: 不可。 + +#### 例 + +Store the weight data. + +~~~ +{ + "weight": true +} +~~~ + +### indexOptions 定義 {#indexOptions} + +値 +: 以下のキーと値のペアを持つオブジェクト。 + +#### パラメータ + +##### `section` {#parameter-indexOptions-section} + +Abstract +: Specifies whether the index column stores the section data or not. Section data is typically used for distinguishing in which part of the sources the value appears. + +Value +: A boolean value (`true` or `false`). + +Default value +: `false`. + +継承可能性 +: 不可。 + +##### `weight` {#parameter-indexOptions-weight} + +Abstract +: Specifies whether the index column stores the weight data or not. Weight data is used for indicating the importance of the value in the sources. + +Value +: A boolean value (`true` or `false`). + +Default value +: `false`. + +継承可能性 +: 不可。 + +##### `position` {#parameter-indexOptions-position} + +Abstract +: Specifies whether the index column stores the position data or not. Position data is used for specifying the position where the value appears in the sources. It is indispensable for fast and accurate phrase-search. + +Value +: A boolean value (`true` or `false`). + +Default value +: `false`. + +継承可能性 +: 不可。 + +##### `sources` {#parameter-indexOptions-sources} + +Abstract +: Makes the column an inverted index of the referencing table's columns. + +Value +: An array of column names of the referencing table assigned as [`valueType`](#parameter-valueType). + +既定値 +: なし。 + +継承可能性 +: 不可。 + +#### 例 + +Store the section data, the weight data and the position data. +Index `name` and `address` on the referencing table. + +~~~ +{ + "section": true, + "weight": true, + "position": true + "sources": [ + "name", + "address" + ] +} +~~~ + +### Volume 定義 {#volume} + +概要 +: データセットを構成する単位。データセットは1つ、もしくは複数のボリュームからなります。ボリュームは単一のデータベースインスタンスか、`slices` の集合で構成されます。ボリュームが単一のデータベースインスタンスから構成される場合は、`address`パラメータを指定しなければなりません。このとき、それ以外のパラメータを指定してはいけません。そうでない場合は、`dimension`と`slicer`と`slices`が必須で、他は指定してはいけません。 + +値 +: 以下のキーと値のペアを持つオブジェクト。 + +#### パラメータ + +##### `address` {#parameter-address} + +概要 +: データベースインスタンスの場所を指定します。 + +値 +: 以下の書式の文字列。 + +"[database_type:]hostname[:port_number]/localpath/to/the/database" + +* database_type: 省略可能。既定値は"groonga"。 +* port_number: 省略可能。既定値は 10047。 + +既定値 +: なし。 + +継承可能性 +: 不可。 + +##### `dimension` {#parameter-dimension} + +概要 +: fact表の中でレコードをスライスする次元を指定します。fact表の'_key'または[`columns`](#parameter-columns)からスカラー型のカラムを選択します。[dimension](http://en.wikipedia.org/wiki/Dimension_%28data_warehouse%29)を参照してください。 + +値 +: 文字列。 + +既定値 +: `"_key"` + +継承可能性 +: 可。`dataset`と`volume`の定義でオーバライドできます。 + +##### `slicer` {#parameter-slicer} + +概要 +: dimensionカラムをsliceする関数。 + +値 +: スライサー関数の名前。 + +既定値 +: `"hash"` + +継承可能性 +: 可。`dataset`と`volume`の定義でオーバライドできます。 + +`slices`の集合からなるボリュームを定義するためには、レコードを複数のスライスに振り分けるための方法を決める必要があります。 + +`slice`で指定されたスライサー関数と、スライサー関数への入力として与えられる`dimension`で指定されたカラム(またはキー)によって、それが決まります。 + +スライサーは以下の3種類に分けられます: + +比率尺度 +: *比率尺度スライサー*は、個々のデータを指定された比率で、_keyのハッシュ値などに基づいて振り分けます。 + この種類のスライサー: + + * `hash` + +順序尺度 +: *順序尺度スライサー*は、個々のデータを順序のある値(時間、整数、`{High, Middle, Low}`など)に基づいて振り分けます。 + この種類のスライサー: + + * (未実装) + +名義尺度 +: *名義尺度スライサー*は、個々のデータをカテゴリを示す名義(国名、郵便番号、色など)で振り分けます。 + この種類のスライサー: + + * (未実装) + +##### `slices` {#parameter-slices} + +概要 +: データを格納するスライスの定義。 + +値 +: [`slice` 定義](#slice)の配列。 + +既定値 +: なし。 + +継承可能性 +: 不可。 + +#### 例 + +##### 例1: 単一のインスタンス + +"localhost:24224/volume.000"にあるボリューム: + +~~~ +{ + "address": "localhost:24224/volume.000" +} +~~~ + +##### Example 2: 複数のスライス + +3つのスライスから構成され、`_key`に対してratio-scaledなスライサー関数`hash`を適用してレコードを分散させるボリューム + +~~~ +{ + "dimension": "_key", + "slicer": "hash", + "slices": [ + { + "volume": { + "address": "localhost:24224/volume.000" + } + }, + { + "volume": { + "address": "localhost:24224/volume.001" + } + }, + { + "volume": { + "address": "localhost:24224/volume.002" + } + } + ] +~~~ + +### Slice 定義 {#slice} + +概要 +: スライスの定義。スライスされたデータの範囲と、それを保存するボリュームを指定する。 + +値 +: 以下のキーと値のペアを持つオブジェクト。 + +#### パラメータ + +##### `weight` {#parameter-slice-weight} + +概要 +: スライス内での割り当て量を指定します。`slicer`が atio-scaledの場合のみ有効。 + +値 +: 数値。 + +既定値 +: `1` + +継承可能性 +: 不可。 + +##### `label` {#parameter-label} + +概要 +: slicer が返す具体的な値。 slicerがnominal-scaledの場合のみ有効。 + +Value +: A value of the dimension column data type. When the value is not provided, this slice is regarded as *else*; matched only if all other labels are not matched. Therefore, only one slice without `label` is allowed in slices. + +既定値 +: なし。 + +継承可能性 +: 不可。 + +##### `boundary` {#parameter-boundary} + +概要 +: `slicer`の返す値と比較可能な具体的な値。`slicer`がordinal-scaledの場合のみ有効。 + +Value +: A value of the dimension column data type. When the value is not provided, this slice is regarded as *else*; this means the slice is open-ended. Therefore, only one slice without `boundary` is allowed in a slices. + +既定値 +: なし。 + +継承可能性 +: 不可。 + +##### `volume` {#parameter-volume} + +概要 +: スライスに対応するデータを格納するボリューム。 + +値 + +: [`volume` 定義](#volume)オブジェクト + +既定値 +: なし。 + +継承可能性 +: 不可。 + +#### 例 + +##### 例1: Ratio-scaled + +ratio-scaledなスライサーのためのスライス、重みは`1` + +~~~ +{ + "weight": 1, + "volume": { + } +} +~~~ + +##### 例2: Nominal-scaled + +nominal-scaledなスライサーのためのスライス、ラベルは `"1"` + +~~~ +{ + "label": "1", + "volume": { + } +} +~~~ + +##### 例3: Ordinal-scaled + +ordinal-scaledなスライサーに対するスライス、境界値は`100`: + +~~~ +{ + "boundary": 100, + "volume": { + } +} +~~~ + +## 実際の例 + +[基本的な使い方のチュートリアル][basic tutorial]に登場するカタログを参照してください。 + + [basic tutorial]: ../../../tutorial/basic Added: ja/reference/1.0.3/commands/add/index.md (+237 -0) 100644 =================================================================== --- /dev/null +++ ja/reference/1.0.3/commands/add/index.md 2014-05-19 16:48:30 +0900 (5d68a5e) @@ -0,0 +1,237 @@ +--- +title: add +layout: ja +--- + +{% comment %} +############################################## + THIS FILE IS AUTOMATICALLY GENERATED FROM + "_po/ja/reference/1.0.3/commands/add/index.po" + DO NOT EDIT THIS FILE MANUALLY! +############################################## +{% endcomment %} + + +* TOC +{:toc} + +## 概要 {#abstract} + +`add` は、テーブルにレコードを登録します。対象のテーブルが主キーを持っており、同じキーのレコードが既に存在している場合には、既存レコードのカラムの値を更新します。 + +形式 +: Request-Response型。コマンドに対しては必ず対応するレスポンスが返されます。 + +リクエストの `type` +: `add` + +リクエストの `body` +: パラメータのハッシュ。 + +レスポンスの `type` +: `add.result` + +## パラメータの構文 {#syntax} + +対象のテーブルが主キーを持つ場合: + + { + "table" : "<テーブル名>", + "key" : "<レコードの主キー>", + "values" : { + "<カラム1の名前>" : <値1>, + "<カラム2の名前>" : <値2>, + ... + } + } + +対象のテーブルが主キーを持たない場合: + + { + "table" : "<テーブル名>", + "values" : { + "<カラム1の名前>" : <値1>, + "<カラム2の名前>" : <値2>, + ... + } + } + +## 使い方 {#usage} + +本項の説明では以下のような2つのテーブルが存在している事を前提として、典型的な使い方を通じて `add` コマンドの使い方を説明します。 + +Personテーブル(主キー無し): + +|name|job (Jobテーブルを参照)| +|Alice Arnold|announcer| +|Alice Cooper|musician| + +Jobテーブル(主キー有り): + +|_key|label| +|announcer|announcer| +|musician|musician| + + +### 主キーを持たないテーブルにレコードを追加する {#adding-record-to-table-without-key} + +主キーを持たないテーブルにレコードを追加する場合は、 `key` を指定せずに `table` と `values` だけを指定します。 + + { + "type" : "add", + "body" : { + "table" : "Person", + "values" : { + "name" : "Bob Dylan", + "job" : "musician" + } + } + } + + => { + "type" : "add.result", + "body" : true + } + +`add` は再帰的に動作します。別のテーブルを参照しているカラムについて、参照先のテーブルに存在しない値を指定した場合、エラーにはならず、参照先のテーブルにも同時に新しいレコードが追加されます。例えば、以下は テーブルに存在しない主キー `doctor` を伴って Person テーブルにレコードを追加します。 + + { + "type" : "add", + "body" : { + "table" : "Person", + "values" : { + "name" : "Alice Miller", + "job" : "doctor" + } + } + } + + => { + "type" : "add.result", + "body" : true + } + +この時、Jobテーブルには主キーだけが指定された新しいレコードが自動的に追加されます。 + +|_key|label| +|announcer|announcer| +|musician|musician| +|doctor|(空文字)| + + +### 主キーを持つテーブルにレコードを追加する {#adding-record-to-table-with-key} + +主キーを持つテーブルにレコードを追加する場合は、 `table`、`key`、`values` のすべてを指定します。 + + { + "type" : "add", + "body" : { + "table" : "Job", + "key" : "writer", + "values" : { + "label" : "writer" + } + } + } + + => { + "type" : "add.result", + "body" : true + } + +### 既存レコードのカラムの値を更新する {#updating} + +主キーを持つテーブルに対する、既存レコードの主キーを伴う `add` コマンドは、既存レコードのカラムの値の更新操作と見なされます。 + + { + "type" : "add", + "body" : { + "table" : "Job", + "key" : "doctor", + "values" : { + "label" : "doctor" + } + } + } + + => { + "type" : "add.result", + "body" : true + } + + +主キーを持たないテーブルのレコードに対しては、値の更新操作はできません(常にレコードの追加と見なされます)。 + + +## パラメータの詳細 {#parameters} + +### `table` {#parameter-table} + +概要 +: レコードを登録するテーブルの名前を指定します。 + +値 +: テーブル名の文字列。 + +省略時の既定値 +: なし。このパラメータは必須です。 + +### `key` {#parameter-key} + +概要 +: レコードの主キーを指定します。 + +値 +: 主キーとなる文字列。 + +省略時の初期値 +: Nなし。対象のテーブルが主キーを持つ場合、このパラメータは必須です。主キーがない場合、このパラメータは無視されます。 + +既に同じ主キーを持つレコードが存在している場合は、レコードの各カラムの値を更新します。 + +対象のテーブルが主キーを持たない場合は、指定しても単に無視されます。 + +### `values` {#parameter-values} + +概要 +: レコードの各カラムの値を指定します。 + +値 +: カラム名をキー、カラムの値を値としたハッシュ。 + +省略時の初期値 +: `null` + +指定されなかったカラムの値は登録・更新されません。 + + +## レスポンス {#response} + +このコマンドは、レコードを正常に追加または更新できた場合、真偽値 `true` を`body` 、`200` を `statusCode` としたレスポンスを返します。以下はレスポンスの `body` の例です。 + + true + +## エラーの種類 {#errors} + +このコマンドは[一般的なエラー](/ja/reference/message/#error)に加えて、以下のエラーを場合に応じて返します。 + +### `MissingTableParameter` + +`table` パラメータの指定を忘れていることを示します。ステータスコードは `400` です。 + +### `MissingPrimaryKeyParameter` + +主キーが存在するテーブルに対して、`key` パラメータの指定を忘れていることを示します。ステータスコードは `400` です。 + +### `InvalidValue` + +カラムに設定しようとした値が不正である(例:位置情報型や整数型のカラムに通常の文字列を指定した、など)事を示します。ステータスコードは `400` です。 + +### `UnknownTable` + +指定されたデータセット内に、指定されたレコードが存在していない事を示します。ステータスコードは `404` です。 + +### `UnknownColumn` + +指定されたカラムがテーブルに存在しない未知のカラムである事を示します。ステータスコードは `400` です。 + Added: ja/reference/1.0.3/commands/column-create/index.md (+85 -0) 100644 =================================================================== --- /dev/null +++ ja/reference/1.0.3/commands/column-create/index.md 2014-05-19 16:48:30 +0900 (41aa5bf) @@ -0,0 +1,85 @@ +--- +title: column_create +layout: ja +--- + +{% comment %} +############################################## + THIS FILE IS AUTOMATICALLY GENERATED FROM + "_po/ja/reference/1.0.3/commands/column-create/index.po" + DO NOT EDIT THIS FILE MANUALLY! +############################################## +{% endcomment %} + + +* TOC +{:toc} + +## 概要 {#abstract} + +`column_create` は、指定したテーブルに新しいカラムを作成します。 + +このコマンドは[Groonga の `column_create` コマンド](http://groonga.org/ja/docs/reference/commands/column_create.html)と互換性があります。 + +形式 +: Request-Response型。コマンドに対しては必ず対応するレスポンスが返されます。 + +リクエストの `type` +: `column_create` + +リクエストの `body` +: パラメータのハッシュ。 + +レスポンスの `type` +: `column_create.result` + +## パラメータの構文 {#syntax} + + { + "table" : "<テーブル名>", + "name" : "<カラム名>", + "flags" : "<カラムの属性>", + "type" : "<値の型>", + "source" : "<インデックス対象のカラム名>" + } + +## パラメータの詳細 {#parameters} + +`table`, `name` 以外のパラメータはすべて省略可能です。 + +すべてのパラメータは[Groonga の `column_create` コマンドの引数](http://groonga.org/ja/docs/reference/commands/column_create.html#parameters)と共通です。詳細はGroongaのコマンドリファレンスを参照して下さい。 + +## レスポンス {#response} + +このコマンドは、レスポンスの `body` としてコマンドの実行結果に関する情報を格納した配列を返却します。 + + [ + [ + <Groongaのステータスコード>, + <開始時刻>, + <処理に要した時間> + ], + <カラムが作成されたかどうか> + ] + +このコマンドはレスポンスの `statusCode` として常に `200` を返します。これは、Groonga互換コマンドのエラー情報はGroongaのそれと同じ形で処理される必要があるためです。 + +レスポンスの `body` の詳細: + +ステータスコード +: コマンドが正常に受け付けられたかどうかを示す整数値です。以下のいずれかの値をとります。 + + * `0` (`Droonga::GroongaHandler::Status::SUCCESS`) : 正常に処理された。. + * `-22` (`Droonga::GroongaHandler::Status::INVALID_ARGUMENT`) : 引数が不正である。 + +開始時刻 +: 処理を開始した時刻を示す数値(UNIX秒)。 + +処理に要した時間 +: 処理を開始してから完了までの間にかかった時間を示す数値。 + +カラムが作成されたかどうか +: カラムが作成されたかどうかを示す真偽値です。以下のいずれかの値をとります。 + + * `true`:カラムを作成した。 + * `false`:カラムを作成しなかった。 Added: ja/reference/1.0.3/commands/index.md (+33 -0) 100644 =================================================================== --- /dev/null +++ ja/reference/1.0.3/commands/index.md 2014-05-19 16:48:30 +0900 (3aa1d31) @@ -0,0 +1,33 @@ +--- +title: コマンドリファレンス +layout: ja +--- + +{% comment %} +############################################## + THIS FILE IS AUTOMATICALLY GENERATED FROM + "_po/ja/reference/1.0.3/commands/index.po" + DO NOT EDIT THIS FILE MANUALLY! +############################################## +{% endcomment %} + + +以下のコマンドを利用できます。 + +## ビルトインのコマンド + + * [search](search/): データの検索 + * [add](add/): レコードの追加 + +## Groonga互換コマンド + + * [column_create](column-create/) + * [column_list](column-list/) + * [column_remove](column-remove/) + * [column_rename](column-rename/) + * [delete](delete/) + * [load](load/) + * [select](select/) + * [table_create](table-create/) + * [table_list](table-list/) + * [table_remove](table-remove/) Added: ja/reference/1.0.3/commands/search/index.md (+1307 -0) 100644 =================================================================== --- /dev/null +++ ja/reference/1.0.3/commands/search/index.md 2014-05-19 16:48:30 +0900 (418cdc5) @@ -0,0 +1,1307 @@ +--- +title: search +layout: ja +--- + +{% comment %} +############################################## + THIS FILE IS AUTOMATICALLY GENERATED FROM + "_po/ja/reference/1.0.3/commands/search/index.po" + DO NOT EDIT THIS FILE MANUALLY! +############################################## +{% endcomment %} + + +* TOC +{:toc} + +## 概要 {#abstract} + +`search` は、1つ以上のテーブルから指定された条件にマッチするレコードを検索し、見つかったレコードに関する情報を返却します。 + +これは、Droonga において検索機能を提供する最も低レベルのコマンドです。 +検索用のコマンドをプラグインとして実装する際は、内部的にこのコマンドを使用して検索を行うという用途が想定されます。 + +形式 +: Request-Response型。コマンドに対しては必ず対応するレスポンスが返されます。 + +リクエストの `type` +: `search` + +リクエストの `body` +: パラメータのハッシュ。 + +レスポンスの `type` +: `search.result` + +## パラメータの構文 {#syntax} + + { + "timeout" : <タイムアウトするまでの秒数>, + "queries" : { + "<クエリ1の名前>" : { + "source" : "<検索対象のテーブル名、または別の検索クエリの名前>", + "condition" : <検索条件>, + "sortBy" : <ソートの条件>, + "groupBy" : <集約の条件>, + "output" : <出力の指定> + }, + "<クエリ2の名前>" : { ... }, + ... + } + } + +## 使い方 {#usage} + +この項では、以下のテーブルが存在する状態を前提として、典型的な使い方を通じて `search` コマンドの使い方を説明します。 + +Personテーブル(主キーあり): + +|_key|name|age|sex|job|note| +|Alice Arnold|Alice Arnold|20|female|announcer|| +|Alice Cooper|Alice Cooper|30|male|musician|| +|Alice Miller|Alice Miller|25|female|doctor|| +|Bob Dole|Bob Dole|42|male|lawer|| +|Bob Cousy|Bob Cousy|38|male|basketball player|| +|Bob Wolcott|Bob Wolcott|36|male|baseball player|| +|Bob Evans|Bob Evans|31|male|driver|| +|Bob Ross|Bob Ross|54|male|painter|| +|Lewis Carroll|Lewis Carroll|66|male|writer|the author of Alice's Adventures in Wonderland| + +※`name`、`note` には `TokensBigram` を使用したインデックスが用意されていると仮定します。 + +### 基本的な使い方 {#usage-basic} + +最も単純な例として、Person テーブルのすべてのレコードを出力する例を示します。 + + { + "type" : "search", + "body" : { + "queries" : { + "people" : { + "source" : "Person", + "output" : { + "elements" : ["count", "records"], + "attributes" : ["_key", "name", "age", "sex", "job", "note"], + "limit" : -1 + } + } + } + } + } + + => { + "type" : "search.result", + "body" : { + "people" : { + "count" : 9, + "records" : [ + ["Alice Arnold", "Alice Arnold", 20, "female", "announcer", ""], + ["Alice Cooper", "Alice Cooper", 30, "male", "musician", ""], + ["Alice Miller", "Alice Miller", 25, "male", "doctor", ""], + ["Bob Dole", "Bob Dole", 42, "male", "lawer", ""], + ["Bob Cousy", "Bob Cousy", 38, "male", "basketball player", ""], + ["Bob Wolcott", "Bob Wolcott", 36, "male", "baseball player", ""], + ["Bob Evans", "Bob Evans", 31, "male", "driver", ""], + ["Bob Ross", "Bob Ross", 54, "male", "painter", ""], + ["Lewis Carroll", "Lewis Carroll", 66, "male", "writer", + "the author of Alice's Adventures in Wonderland"] + ] + } + } + } + +`people` は、この検索クエリおよびその処理結果に対して付けた一時的な名前です。 +`search` のレスポンスは、検索クエリに付けた名前を伴って返されます。 +よって、これは「この検索クエリの結果を `people` と呼ぶ」というような意味合いになります。 + +どうしてこのコマンドが全レコードのすべての情報を出力するのでしょうか? これは以下の理由に依ります。 + + * 検索条件を何も指定していないため。検索条件を指定しないとすべてのレコードがマッチします。 + * [`output`](#query-output) の `elements` パラメータに `records` (および `count`)が指定されているため。 `elements` は結果に出力する情報を制御します。マッチしたレコードの情報は `records` に、マッチしたレコードの総数は `count` に出力されます。 + * [`output`](#query-output) の `limit` パラメータに `-1` が指定されているため。 `limit` は出力するレコードの最大数の指定ですが、 `-1` を指定するとすべてのレコードが出力されます。 + * [`output`](#query-output) の `attributes` パラメータに Person テーブルのすべてのカラムの名前が列挙されているため。 `attributes` は個々のレコードに出力するカラムを制御します。 + + +#### 検索条件 {#usage-condition} + +検索条件は `condition` パラメータで指定します。指定方法は、大きく分けて「スクリプト構文形式」と「クエリー構文形式」の2通りがあります。詳細は [`condition` パラメータの仕様](#query-condition) を参照して下さい。 + +##### スクリプト構文形式の検索条件 {#usage-condition-script-syntax} + +スクリプト構文形式は、ECMAScriptの書式に似ています。「`name` に `Alice` を含み、且つ`age` が `25` 以上である」という検索条件は、スクリプト構文形式で以下のように表現できます。 + + { + "type" : "search", + "body" : { + "queries" : { + "people" : { + "source" : "Person", + "condition" : "name @ 'Alice' && age >= 25" + "output" : { + "elements" : ["count", "records"], + "attributes" : ["name", "age"], + "limit" : -1 + } + } + } + } + } + + => { + "type" : "search.result", + "body" : { + "people" : { + "count" : 2, + "records" : [ + ["Alice Arnold", 20], + ["Alice Cooper", 30], + ["Alice Miller", 25] + ] + } + } + } + +スクリプト構文の詳細な仕様は[Groonga のスクリプト構文のリファレンス](http://groonga.org/ja/docs/reference/grn_expr/script_syntax.html)を参照して下さい。 + +##### クエリー構文形式の検索条件 {#usage-condition-query-syntax} + +クエリー構文形式は、主にWebページなどに組み込む検索ボックス向けに用意されています。例えば「検索ボックスに入力された語句を `name` または `note` に含むレコードを検索する」という場面において、検索ボックスに入力された語句が `Alice` であった場合の検索条件は、クエリー構文形式で以下のように表現できます。 + + { + "type" : "search", + "body" : { + "queries" : { + "people" : { + "source" : "Person", + "condition" : { + "query" : "Alice", + "matchTo" : ["name", "note"] + }, + "output" : { + "elements" : ["count", "records"], + "attributes" : ["name", "note"], + "limit" : -1 + } + } + } + } + } + + => { + "type" : "search.result", + "body" : { + "people" : { + "count" : 4, + "records" : [ + ["Alice Arnold", ""], + ["Alice Cooper", ""], + ["Alice Miller", ""], + ["Lewis Carroll", + "the author of Alice's Adventures in Wonderland"] + ] + } + } + } + +クエリー構文の詳細な仕様は[Groonga のクエリー構文のリファレンス](http://groonga.org/ja/docs/reference/grn_expr/query_syntax.html)を参照して下さい。 + + +#### 検索結果のソート {#usage-sort} + +出力するレコードのソート条件は `sortBy` パラメータで指定します。以下は、結果を `age` カラムの値の昇順でソートする場合の例です。 + + { + "type" : "search", + "body" : { + "queries" : { + "people" : { + "source" : "Person", + "condition" : "name @ 'Alice'" + "sortBy" : ["age"], + "output" : { + "elements" : ["count", "records"], + "attributes" : ["name", "age"], + "limit" : -1 + } + } + } + } + } + + => { + "type" : "search.result", + "body" : { + "people" : { + "count" : 8, + "records" : [ + ["Alice Arnold", 20], + ["Alice Miller", 25], + ["Alice Cooper", 30] + ] + } + } + } + +ソートするカラム名の前に `-` を付けると、降順でのソートになります。以下は `age` の降順でソートする場合の例です。 + + { + "type" : "search", + "body" : { + "queries" : { + "people" : { + "source" : "Person", + "condition" : "name @ 'Alice'" + "sortBy" : ["-age"], + "output" : { + "elements" : ["count", "records"], + "attributes" : ["name", "age"], + "limit" : -1 + } + } + } + } + } + + => { + "type" : "search.result", + "body" : { + "people" : { + "count" : 8, + "records" : [ + ["Alice Cooper", 30], + ["Alice Miller", 25], + ["Alice Arnold", 20] + ] + } + } + } + +詳細は [`sortBy` パラメータの仕様](#query-sortBy) を参照して下さい。 + +#### 検索結果のページング {#usage-paging} + +[`output`](#query-output) パラメータの `offset` と `limit` を指定することで、出力されるレコードの範囲を指定できます。以下は、20件以上ある結果を先頭から順に10件ずつ取得する場合の例です。 + + { + "type" : "search", + "body" : { + "queries" : { + "people" : { + "source" : "Person", + "output" : { + "elements" : ["count", "records"], + "attributes" : ["name"], + "offset" : 0, + "limit" : 10 + } + } + } + } + } + + => 0件目から9件目までの10件が返される。 + + { + "type" : "search", + "body" : { + "queries" : { + "people" : { + "source" : "Person", + "output" : { + "elements" : ["count", "records"], + "attributes" : ["name"], + "offset" : 10, + "limit" : 10 + } + } + } + } + } + + => 10件目から19件目までの10件が返される。 + + { + "type" : "search", + "body" : { + "queries" : { + "people" : { + "source" : "Person", + "output" : { + "elements" : ["count", "records"], + "attributes" : ["name"], + "offset" : 20, + "limit" : 10 + } + } + } + } + } + + => 20件目から29件目までの10件が返される。 + +`limit` の指定 `-1` は、実際の運用では推奨されません。膨大な量のレコードがマッチした場合、出力のための処理にリソースを使いすぎてしまいますし、ネットワークの帯域も浪費してしまいます。コンピュータの性能にもよりますが、`limit` には `100` 程度までの値を上限として指定し、それ以上のレコードは適宜ページングで取得するようにして下さい。 + +詳細は [`output` パラメータの仕様](#query-output) を参照して下さい。 + +また、ページングは [`sortBy` パラメータの機能](#query-sortBy-hash)でも行う事ができ、一般的にはそちらの方が高速に動作します。 +よって、可能な限り `output` でのページングよりも `sortBy` でのページングの方を使う事が推奨されます。 + + +#### 出力形式 {#usage-format} + +ここまでの例では、レコードの一覧はすべて配列の配列として出力されていました。[`output`](#query-output) パラメータの `format` を指定すると、出力されるレコードの形式を変える事ができます。以下は、`format` に `complex` を指定した場合の例です。 + + { + "type" : "search", + "body" : { + "queries" : { + "people" : { + "source" : "Person", + "output" : { + "elements" : ["count", "records"], + "attributes" : ["_key", "name", "age", "sex", "job", "note"], + "limit" : 3, + "format" : "complex" + } + } + } + } + } + + => { + "type" : "search.result", + "body" : { + "people" : { + "count" : 9, + "records" : [ + { "_key" : "Alice Arnold", + "name" : "Alice Arnold", + "age" : 20, + "sex" : "female", + "job" : "announcer", + "note" : "" }, + { "_key" : "Alice Cooper", + "name" : "Alice Cooper", + "age" : 30, + "sex" : "male", + "job" : "musician", + "note" : "" }, + { "_key" : "Alice Miller", + "name" : "Alice Miller", + "age" : 25, + "sex" : "female", + "job" : "doctor", + "note" : "" } + ] + } + } + } + +`format` に `complex` を指定した場合、レコードの一覧はこの例のようにカラム名をキーとしたハッシュの配列として出力されます。 +`format` に `simple` を指定した場合、または `format` の指定を省略した場合、レコードの一覧は配列の配列として出力されます。 + +詳細は [`output` パラメータの仕様](#query-output) および [レスポンスの仕様](#response) を参照して下さい。 + + +### 高度な使い方 {#usage-advanced} + +#### 検索結果の集約 {#usage-group} + +[`groupBy`](#query-groupBy) パラメータを指定することで、レコードを指定カラムの値で集約した結果を取得することができます。以下は、テーブルの内容を `sex` カラムの値で集約した結果と、集約前のレコードがそれぞれ何件あったかを取得する例です。 + + { + "type" : "search", + "body" : { + "queries" : { + "sexuality" : { + "source" : "Person", + "groupBy" : "sex", + "output" : { + "elements" : ["count", "records"], + "attributes" : ["_key", "_nsubrecs"], + "limit" : -1 + } + } + } + } + } + + => { + "type" : "search.result", + "body" : { + "sexuality" : { + "count" : 2, + "records" : + ["female", 2], + ["male", 7] + ] + } + } + } + +上記の結果は、 `sex` の値が `female` であるレコードが2件、`male` であるレコードが7件存在していて、`sex` の値の種類としては2通りが登録されている事を示しています。 + +また、集約前のレコードを代表値として取得する事もできます。以下は、`sex` カラムの値で集約した結果と、それぞれの集約前のレコードを2件ずつ取得する例です。 + + { + "type" : "search", + "body" : { + "queries" : { + "sexuality" : { + "source" : "Person", + "groupBy" : { + "keys" : "sex", + "maxNSubRecords" : 2 + }, + "output" : { + "elements" : ["count", "records"], + "attributes" : [ + "_key", + "_nsubrecs", + { "label" : "subrecords", + "source" : "_subrecs", + "attributes" : ["name"] } + ], + "limit" : -1 + } + } + } + } + } + + => { + "type" : "search.result", + "body" : { + "sexuality" : { + "count" : 2, + "records" : + ["female", 2, [["Alice Arnold"], ["Alice Miller"]]], + ["male", 7, [["Alice Cooper"], ["Bob Dole"]]] + ] + } + } + } + + +詳細は [`groupBy` パラメータの仕様](#query-groupBy) を参照して下さい。 + + +#### 複数の検索クエリの列挙 {#usage-multiple-queries} + +`search` は、一度に複数の検索クエリを受け付ける事ができます。以下は、`age` が `25` 以下のレコードと `age` が `40` 以上のレコードを同時に検索する例です。 + + { + "type" : "search", + "body" : { + "queries" : { + "junior" : { + "source" : "Person", + "condition" : "age <= 25", + "output" : { + "elements" : ["count", "records"], + "attributes" : ["name", "age"], + "limit" : -1 + } + }, + "senior" : { + "source" : "Person", + "condition" : "age >= 40", + "output" : { + "elements" : ["count", "records"], + "attributes" : ["name", "age"], + "limit" : -1 + } + } + } + } + } + + => { + "type" : "search.result", + "body" : { + "junior" : { + "count" : 2, + "records" : [ + ["Alice Arnold", 20], + ["Alice Miller", 25] + ] + }, + "senior" : { + "count" : 3, + "records" : [ + ["Bob Dole", 42], + ["Bob Ross", 54], + ["Lewis Carroll", 66] + ] + } + } + } + +レスポンスに含まれる検索結果は、各クエリに付けた一時的な名前で識別することになります。 + +#### 検索のチェーン {#usage-chain} + +検索クエリを列挙する際は、`source` パラメータの値として実在するテーブルの名前だけでなく、別の検索クエリに付けた一時的な名前を指定する事ができます。これにより、1つの検索クエリでは表現できない複雑な検索を行う事ができます。 + +以下は、Personテーブルについて `name` カラムが `Alice` を含んでいるレコードを検索た結果と、それをさらに `sex` カラムの値で集約した結果を同時に取得する例です。 + + { + "type" : "search", + "body" : { + "queries" : { + "people" : { + "source" : "Person", + "condition" : "name @ 'Alice'" + "output" : { + "elements" : ["count", "records"], + "attributes" : ["name", "age"], + "limit" : -1 + } + }, + "sexuality" : { + "source" : "people", + "groupBy" : "sex", + "output" : { + "elements" : ["count", "records"], + "attributes" : ["_key", "_nsubrecs"], + "limit" : -1 + } + } + } + } + } + + => { + "type" : "search.result", + "body" : { + "people" : { + "count" : 8, + "records" : [ + ["Alice Cooper", 30], + ["Alice Miller", 25], + ["Alice Arnold", 20] + ] + }, + "sexuality" : { + "count" : 2, + "records" : + ["female", 2], + ["male", 1] + ] + } + } + } + +個々の検索クエリの結果は出力しない(中間テーブルとしてのみ使う)事もできます。 +以下は、Personテーブルについて `job` カラムの値で集約した結果をまず求め、そこからさらに `player` という語句を含んでいる項目に絞り込む例です。 +(※この場合の2つ目の検索ではインデックスが使用されないため、検索処理が遅くなる可能性があります。) + + { + "type" : "search", + "body" : { + "queries" : { + "allJob" : { + "source" : "Person", + "groupBy" : "job" + }, + "playerJob" : { + "source" : "allJob", + "condition" : "_key @ `player`", + "output" : { + "elements" : ["count", "records"], + "attributes" : ["_key", "_nsubrecs"], + "limit" : -1 + } + } + } + } + } + + => { + "type" : "search.result", + "body" : { + "playerJob" : { + "count" : 2, + "records" : [ + ["basketball player", 1], + ["baseball player", 1] + ] + } + } + } + + +## パラメータの詳細 {#parameters} + +### 全体のパラメータ {#container-parameters} + +#### `timeout` {#parameter-timeout} + +※註:このパラメータはバージョン {{ site.droonga_version }} では未実装です。指定しても機能しません。 + +概要 +: 検索処理がタイムアウトするまでの時間を指定します。 + +値 +: タイムアウトするまでの時間の数値(単位:ミリ秒)。 + +省略時の初期値 +: 10000(10秒) + +指定した時間以内に Droonga Engine が検索の処理を完了できなかった場合、Droonga はその時点で検索処理を打ち切り、エラーを返却します。 +クライアントは、この時間を過ぎた後は検索処理に関するリソースを解放して問題ありません。 + +#### `queries` {#parameter-queries} + +概要 +: 検索クエリとして、検索の条件と出力の形式を指定します。 + +値 +: 個々の検索クエリの名前をキー、[個々の検索クエリ](#query-parameters)の内容を値としたハッシュ。 + +省略時の既定値 +: なし。このパラメータは必須です。 + +`search` は、複数の検索クエリを一度に受け取る事ができます。 + +バージョン {{ site.droonga_version }} ではすべての検索クエリの結果を一度にレスポンスとして返却する動作のみ対応していますが、将来的には、それぞれの検索クエリの結果を分割して受け取る(結果が出た物からバラバラに受け取る)動作にも対応する予定です。 + +### 個々の検索クエリのパラメータ {#query-parameters} + +#### `source` {#query-source} + +概要 +: 検索対象とするデータソースを指定します。 + +値 +: テーブル名の文字列、または結果を参照する別の検索クエリの名前の文字列。 + +省略時の既定値 +: なし。このパラメータは必須です。 + +別の検索クエリの処理結果をデータソースとして指定する事により、ファセット検索などを行う事ができます。 + +なお、その場合の各検索クエリの実行順(依存関係)は Droonga が自動的に解決します。 +依存関係の順番通りに各検索クエリを並べて記述する必要はありません。 + +#### `condition` {#query-condition} + +概要 +: 検索の条件を指定します。 + +値 +: 以下のパターンのいずれかをとります。 + + 1. [スクリプト構文](http://groonga.org/ja/docs/reference/grn_expr/script_syntax.html)形式の文字列。 + 2. [スクリプト構文](http://groonga.org/ja/docs/reference/grn_expr/script_syntax.html)形式の文字列を含むハッシュ。 + 3. [クエリー構文](http://groonga.org/ja/docs/reference/grn_expr/query_syntax.html)形式の文字列を含むハッシュ。 + 4. 1〜3および演算子の文字列の配列。 + +省略時の既定値 +: なし。 + +検索条件を指定しなかった場合、データソースに含まれるすべてのレコードが検索結果として取り出され、その後の処理に使われます。 + +##### スクリプト構文形式の文字列による検索条件 {#query-condition-script-syntax-string} + +以下のような形式の文字列で検索条件を指定します。 + + "name == 'Alice' && age >= 20" + +上記の例は「 `name` カラムの値が `"Alice"` と等しく、且つ `age` カラムの値が20以上である」という意味になります。 + +詳細は[Groonga のスクリプト構文のリファレンス](http://groonga.org/ja/docs/reference/grn_expr/script_syntax.html)を参照して下さい。 + +##### スクリプト構文形式の文字列を含むハッシュによる検索条件 {#query-condition-script-syntax-hash} + +[スクリプト構文形式の文字列による検索条件](#query-condition-script-syntax-string)をベースとした、以下のような形式のハッシュで検索条件を指定します。 + + { + "script" : "name == 'Alice' && age >= 20", + "allowUpdate" : true + } + +(詳細未稿:仕様が未確定、動作が不明、未実装のため) + +##### クエリー構文形式の文字列を含むハッシュ {#query-condition-query-syntax-hash} + +以下のような形式のハッシュで検索条件を指定します。 + + { + "query" : "Alice", + "matchTo" : ["name * 2", "job * 1"], + "defaultOperator" : "&&", + "allowPragma" : true, + "allowColumn" : true, + "matchEscalationThreshold" : 10 + } + +`query` +: クエリを文字列で指定します。 + 詳細は[Groonga のクエリー構文の仕様](http://groonga.org/ja/docs/reference/grn_expr/query_syntax.html)を参照して下さい。 + このパラメータは省略できません。 + + +: 検索対象のカラムを、カラム名の文字列またはその配列で指定します。 + カラム名の後に `name * 2` のような指定を加える事で、重み付けができます。 + このパラメータは省略可能で、省略時の初期値は `"_key"` です。 + +`defaultOperator`: `query` に複数のクエリが列挙されている場合の既定の論理演算の条件を指定します。 + 以下のいずれかの文字列を指定します。 + + * `"&&"` : AND条件と見なす。 + * `"||"` : OR条件と見なす。 + * `"-"` : [論理否定](http://groonga.org/ja/docs/reference/grn_expr/query_syntax.html#logical-not)条件と見なす。 + + このパラメータは省略可能で、省略時の初期値は `"&&"` です。 + +`allowPragma` +: `query` の先頭において、`*E-1` のようなプラグマの指定を許容するかどうかを真偽値で指定します。 + このパラメータは省略可能で、省略時の初期値は `true` (プラグマの指定を許容する)です。 + +`allowColumn` +: `query` において、カラム名を指定した `name:Alice` のような書き方を許容するかどうかを真偽値で指定します。 + このパラメータは省略可能で、省略時の初期値は `true` (カラム名の指定を許容する)です。 + +`matchEscalationThreshold` +: 検索方法をエスカレーションするかどうかを決定するための閾値を指定します。 + インデックスを用いた全文検索のヒット件数がこの閾値以下であった場合は、非分かち書き検索、部分一致検索へエスカレーションします。 + 詳細は [Groonga の検索の仕様の説明](http://groonga.org/ja/docs/spec/search.html)を参照して下さい。 + このパラメータは省略可能で、省略時の初期値は `0` です。 + + +##### 配列による検索条件 {#query-condition-array} + +以下のような形式の配列で検索条件を指定します。 + + [ + "&&", + <検索条件1>, + <検索条件2>, + ... + ] + +配列の最初の要素は、論理演算子を以下のいずれかの文字列で指定します。 + + * `"&&"` : AND条件と見なす。 + * `"||"` : OR条件と見なす。 + * `"-"` : [論理否定](http://groonga.org/ja/docs/reference/grn_expr/query_syntax.html#logical-not)条件と見なす。 + +配列の2番目以降の要素で示された検索条件について、1番目の要素で指定した論理演算子による論理演算を行います。 +例えば以下は、スクリプト構文形式の文字列による検索条件2つによるAND条件であると見なされ、「 `name` カラムの値が `"Alice"` と等しく、且つ `age` カラムの値が20以上である」という意味になります。 + + ["&&", "name == 'Alice'", "age >= 20"] + +配列を入れ子にする事により、より複雑な検索条件を指定する事もできます。 +例えば以下は、「 `name` カラムの値が `"Alice"` と等しく、且つ `age` カラムの値が20以上であるが、 `job` カラムの値が `"engineer"` ではない」という意味になります。 + + [ + "-", + ["&&", "name == 'Alice'", "age >= 20"], + "job == 'engineer'" + ] + +#### `sortBy` {#query-sortBy} + +概要 +: ソートの条件および取り出すレコードの範囲を指定します。 + +値 +: 以下のパターンのいずれかをとります。 + + 1. カラム名の文字列の配列。 + 2. ソート条件と取り出すレコードの範囲を指定するハッシュ。 + +省略時の既定値 +: なし。 + +ソート条件が指定されなかった場合、すべての検索結果がそのままの並び順でソート結果として取り出され、その後の処理に使われます。 + +##### 基本的なソート条件の指定 {#query-sortBy-array} + +ソート条件はカラム名の文字列の配列として指定します。 + +Droongaはまず最初に指定したカラムの値でレコードをソートし、カラムの値が同じレコードが複数あった場合は2番目に指定したカラムの値でさらにソートする、という形で、すべての指定カラムの値に基づいてソートを行います。 + +ソート対象のカラムを1つだけ指定する場合であっても、必ず配列として指定する必要があります。 + +ソート順序は指定したカラムの値での昇順となります。カラム名の前に `-` を加えると降順となります。 + +例えば以下は、「 `name` の値で昇順にソートし、同じ値のレコードはさらに `age` の値で降順にソートする」という意味になります。 + + ["name", "-age"] + +##### ソート結果から取り出すレコードの範囲の指定 {#query-sortBy-hash} + +ソートの指定において、以下の形式でソート結果から取り出すレコードの範囲を指定する事ができます。 + + { + "keys" : [<ソート対象のカラム>], + "offset" : <ページングの起点>, + "limit" : <取り出すレコード数> + } + +`keys` +: ソート条件を[基本的なソート条件の指定](#query-sortBy-array)の形式で指定します。 + このパラメータは省略できません。 + +`offset` +: 取り出すレコードのページングの起点を示す `0` または正の整数。 + + このパラメータは省略可能で、省略時の既定値は `0` です。 + +`limit` +: 取り出すレコード数を示す `-1` 、 `0` 、または正の整数。 + `-1`を指定すると、すべてのレコードを取り出します。 + + このパラメータは省略可能で、省略時の既定値は `-1` です。 + +例えば以下は、ソート結果の10番目から19番目までの10件のレコードを取り出すという意味になります。 + + { + "keys" : ["name", "-age"], + "offset" : 10, + "limit" : 10 + } + +これらの指定を行った場合、取り出されたレコードのみがその後の処理の対象となります。 +そのため、 `output` における `offset` および `limit` の指定よりも高速に動作します。 + + +#### `groupBy` {#query-groupBy} + +概要 +: 処理対象のレコード群を集約する条件を指定します。 + +値 +: 以下のパターンのいずれかをとります。 + + 1. 基本的な集約条件(カラム名または式)の文字列。 + 2. 複雑な集約条件を指定するハッシュ。 + +省略時の既定値 +: なし。 + +集約条件を指定した場合、指定に基づいてレコードを集約した結果がレコードとして取り出され、その後の処理に使われます。 + +##### 基本的な集約条件の指定 {#query-groupBy-string} + +基本的な集約条件では、処理対象のレコード群が持つカラムの名前を文字列として指定します。 + +Droongaはそのカラムの値が同じであるレコードを集約し、カラムの値をキーとした新しいレコード群を結果として出力します。 +集約結果のレコードは以下のカラムを持ちます。 + +`_key` +: 集約前のレコード群における、集約対象のカラムの値です。 + +`_nsubrecs` +: 集約前のレコード群における、集約対象のカラムの値が一致するレコードの総数を示す数値です。 + +例えば以下は、`job` カラムの値でレコードを集約し、`job` カラムの値としてどれだけの種類が存在しているのか、および、各 `job` の値を持つレコードが何件存在しているのかを集約結果として取り出すという意味になります。 + + "job" + +##### 複雑な集約条件の指定 {#query-groupBy-hash} + +集約の指定において、集約結果の一部として出力する集約前のレコードの数を、以下の形式で指定する事ができます。 + + { + "key" : "<基本的な集約条件>", + "maxNSubRecords" : <集約結果の一部として出力する集約前のレコードの数> + } + +`key` +: [基本的な集約条件の指定](#query-groupBy-string)の形式による、集約条件を指定する文字列。 + このパラメータは省略できません。 + +`maxNSubRecords` +: 集約結果の一部として出力する集約前のレコードの最大数を示す `0` または正の整数。 + `-1` は指定できません。 + + このパラメータは省略可能で、省略時の既定値は `0` です。 + +例えば以下は、`job` カラムの値でレコードを集約した結果について、各 `job` カラムの値を含んでいるレコードを代表として1件ずつ取り出すという意味になります。 + + { + "key" : "job", + "maxNSubRecords" : 1 + } + +集約結果のレコードは、[基本的な集約条件の指定](#query-groupBy-string)の集約結果のレコード群が持つすべてのカラムに加えて、以下のカラムを持ちます。 + +`_subrecs` +: 集約前のレコード群における、集約対象のカラムの値が一致するレコードの配列。 + +※バージョン {{ site.droonga_version }} では、データセットが複数のボリュームに別れている場合、集約前のレコードの代表が `maxNSubRecords` で指定した数よりも多く返される場合があります。これは既知の問題で、将来のバージョンで修正される予定です。 + + +#### `output` {#query-output} + +概要 +: 処理結果の出力形式を指定します。 + +値 +: 出力形式を指定するハッシュ。 + +省略時の既定値 +: なし。 + +指定を省略した場合、その検索クエリの検索結果はレスポンスには出力されません。 +集約操作などのために必要な中間テーブルにあたる検索結果を求めるだけの検索クエリにおいては、 `output` を省略して処理時間や転送するデータ量を減らすことができます。 + +出力形式は、以下の形式のハッシュで指定します。 + + { + "elements" : [<出力する情報の名前の配列>], + "format" : "<検索結果のレコードの出力スタイル>", + "offset" : <ページングの起点>, + "limit" : <出力するレコード数>, + "attributes" : <レコードのカラムの出力指定の配列> + } + +`elements` +: その検索クエリの結果として[レスポンス](#response)に出力する情報を、プロパティ名の文字列の配列で指定します。 + 以下の項目を指定できます。項目は1つだけ指定する場合であっても必ず配列で指定します。 + + * `"startTime"` ※バージョン {{ site.droonga_version }} では未実装です。指定しても機能しません。 + * `"elapsedTime"` ※バージョン {{ site.droonga_version }} では未実装です。指定しても機能しません。 + * `"count"` + * `"attributes"` + * `"records"` + + このパラメータは省略可能で、省略時の初期値はありません(結果を何も出力しません)。 + +`format` +: 検索結果のレコードの出力スタイルを指定します。 + 以下のいずれかの値(文字列)を取ります。 + + * `"simple"` : 個々のレコードを配列として出力します。 + * `"complex"` : 個々のレコードをハッシュとして出力します。 + + このパラメータは省略可能で、省略時の初期値は `"simple"` です。 + +`offset` +: 出力するレコードのページングの起点を示す `0` または正の整数。 + + このパラメータは省略可能で、省略時の既定値は `0` です。 + +`limit` +: 出力するレコード数を示す `-1` 、 `0` 、または正の整数。 + `-1`を指定すると、すべてのレコードを出力します。 + + このパラメータは省略可能で、省略時の既定値は `0` です。 + +`attributes` +: レコードのカラムの値について、出力形式を配列で指定します。 + 個々のカラムの値の出力形式は以下のいずれかで指定します。 + + 1. カラムの定義の配列。 + 2. カラムの定義を値としたハッシュ + + 各カラムは以下の形式のいずれかで指定します。 + + * カラム名の文字列。例は以下の通りです。 + * `"name"` : `name` カラムの値をそのまま `name` カラムとして出力します。 + * `"age"` : `age` カラムの値をそのまま `age` カラムとして出力します。 + * 詳細な出力形式指定のハッシュ。例は以下の通りです。 + * 以下の例は、 `name` カラムの値を `realName` カラムとして出力します。 + + { "label" : "realName", "source" : "name" } + + * 以下の例は、 `name` カラムの値について、全文検索にヒットした位置を強調したHTMLコード片の文字列を `html` カラムとして出力します。 + + { "label" : "html", "source": "snippet_html(name)" } + + * 以下の例は、`country` カラムについて、すべてのレコードの当該カラムの値が文字列 `"Japan"` であるものとして出力します。 + (存在しないカラムを実際に作成する前にクライアント側の挙動を確認したい場合などに、この機能が利用できます。) + + { "label" : "country", "source" : "'Japan'" } + + * 以下の例は、集約前の元のレコードの総数を、集約後のレコードの `"itemsCount"` カラムの値として出力します。 + + { "label" : "itemsCount", "source" : "_nsubrecs", } + + * 以下の例は、集約前の元のレコードの配列を、集約後のレコードの `"items"` カラムの値として出力します。 + `"attributes"` は、この項の説明と同じ形式で指定します。 + + { "label" : "items", "source" : "_subrecs", + "attributes": ["name", "price"] } + + カラムの定義の配列には、上記の形式で示されたカラムの定義を0個以上含めることができます。例: + + [ + "name", + "age", + { "label" : "realName", "source" : "name" } + ] + + カラムの定義を値としたハッシュでは、カラムの出力名をキー、上記の形式で示されたカラムの定義を値として、カラムの定義を0個以上含めることができます。例: + + { + "name" : "name", + "age" : "age", + "realName" : { "source" : "name" }, + "country" : { "source" : "'Japan'" } + } + + このパラメータは省略可能で、省略時の既定値はありません。カラムの指定がない場合、カラムの値は一切出力されません。 + + +## レスポンス {#response} + +このコマンドは、検索結果を`body` 、ステータスコード `200` を `statusCode` の値としたレスポンスを返します。 + +検索結果のハッシュは、個々の検索クエリの名前をキー、対応する[個々の検索クエリ](#query-parameters)の処理結果を値とした、以下のような形式を取ります。 + + { + "<クエリ1の名前>" : { + "startTime" : "<検索を開始した時刻>", + "elapsedTime" : <検索にかかった時間(単位:ミリ秒)), + "count" : <指定された検索条件に該当するレコードの総数>, + "attributes" : <出力されたレコードのカラムの情報の配列またはハッシュ>, + "records" : [<出力されたレコードの配列>] + }, + "<クエリ2の名前>" : { ... }, + ... + } + +検索クエリの処理結果のハッシュは以下の項目を持つことができ、[検索クエリの `output`](#query-output) の `elements` で明示的に指定された項目のみが出力されます。 + +### `startTime` {#response-query-startTime} + +検索を開始した時刻(ローカル時刻)の文字列です。 + +形式は、[W3C-DTF](http://www.w3.org/TR/NOTE-datetime "Date and Time Formats")のタイムゾーンを含む形式となります。 +例えば以下の要領です。 + + 2013-11-29T08:15:30+09:00 + +### `elapsedTime` {#response-query-elapsedTime} + +検索にかかった時間の数値(単位:ミリ秒)です。 + +### `count` {#response-query-count} + +検索条件に該当するレコードの総数の数値です。 +この値は、検索クエリの [`sortBy`](#query-sortBy) や [`output`](#query-output) における `offset` および `limit` の指定の影響を受けません。 + +### `attributes` および `records` {#response-query-attributes-and-records} + + * `attributes` は出力されたレコードのカラムの情報を示す配列またはハッシュです。 + * `records` は出力されたレコードの配列です。 + +`attributes` および `records` の出力形式は[検索クエリの `output`](#query-output) の `format` の指定に従って以下の2通りに別れます。 + +#### 単純な形式のレスポンス {#response-query-simple-attributes-and-records} + +`format` が `"simple"` の場合、個々の検索クエリの結果は以下の形を取ります。 + + { + "startTime" : "<検索を開始した時刻>", + "elapsedTime" : <検索にかかった時間), + "count" : <検索結果のレコードの総数>, + "attributes" : [ + { "name" : "<カラム1の名前>", + "type" : "<カラム1の型>", + "vector" : <カラム1がベクターカラムかどうか> }, + { "name" : "<カラム2の名前>", + "type" : "<カラム2の型>", + "vector" : <カラム2がベクターカラムかどうか> }, + { "name" : "<カラム3(サブレコードが存在する場合)の名前>" + "attributes" : [ + { "name" : "<カラム3-1のカラムの名前>", + "type" : "<カラム3-1のカラムの型>", + "vector" : <カラム3-1がベクターカラムかどうか> }, + { "name" : "<カラム3-2のカラムの名前>", + "type" : "<カラム3-2のカラムの型>", + "vector" : <カラム3-2がベクターカラムかどうか> }, + ], + ... + }, + ... + ], + "records" : [ + [<レコード1のカラム1の値>, + <レコード1のカラム2の値>, + [ + [<レコード1のサブレコード1のカラム3-1の値>, + <レコード1のサブレコード1のカラム3-2の値>, + ...], + [<レコード1のサブレコード2のカラム3-1の値>, + <レコード1のサブレコード2のカラム3-2の値>, + ...], + ...], + ...], + [<レコード2のカラム1の値>, + <レコード2のカラム2の値>, + [ + [<レコード2のサブレコード1のカラム3-1の値>, + <レコード2のサブレコード1のカラム3-2の値>, + ...], + [<レコード2のサブレコード2のカラム3-1の値>, + <レコード2のサブレコード2のカラム3-2の値>, + ...], + ...], + ...], + ... + ] + } + +これは、受け取ったデータの扱いやすさよりも、データの転送量を小さく抑える事を優先する出力形式です。 +大量のレコードを検索結果として受け取る場合や、多量のアクセスが想定される場合などに適しています。 + +##### `attributes` {#response-query-simple-attributes} + +出力されたレコードのカラムについての情報の配列で、[検索クエリの `output`](#query-output) における `attributes` で指定された順番で個々のカラムの情報を含みます。 + +個々のカラムの情報はハッシュの形をとり、その形式はレコードの値に応じて以下の3種類で与えられます。ハッシュのキーと値は以下のとおりです。 + +###### 通常のカラム + +`name` +: カラムの出力名の文字列です。[検索クエリの `output`](#query-output) における `attributes` の指定内容に基づきます。 + +`type` +: カラムの値の型を示す文字列です。 + 値は[Groonga のプリミティブなデータ型](http://groonga.org/ja/docs/reference/types.html)の名前か、もしくはテーブル名です。 + +`vector` +: カラムが[ベクター型](http://groonga.org/ja/docs/tutorial/data.html#vector-types)かどうかを示す真偽値です。 + 以下のいずれかの値をとります。 + + * `true` : カラムはベクター型である。 + * `false` : カラムはベクター型ではない(スカラー型である)。 + +###### サブレコードに対応するカラム + +`name` +: カラムの出力名の文字列です。[検索クエリの `output`](#query-output) における `attributes` の指定内容に基づきます。 + +サブレコードのカラム情報を含む配列です。この形式は主レコードの `attributes` と同様です。つまり `attribuets` は再帰的な構造になっています。 + +###### 式 + +`name` +: カラムの出力名の文字列です。[検索クエリの `output`](#query-output) における `attributes` の指定内容に基づきます。 + +##### `records` {#response-query-simple-records} + +出力されたレコードの配列です。 + +個々のレコードは配列の形をとり、[検索クエリの `output`](#query-output) における `attributes` で指定された各カラムの値を同じ順番で含みます。 + +[日時型](http://groonga.org/ja/docs/tutorial/data.html#date-and-time-type)のカラムの値は、[W3C-DTF](http://www.w3.org/TR/NOTE-datetime "Date and Time Formats")のタイムゾーンを含む形式の文字列として出力されます。 + +#### 複雑な形式のレスポンス {#response-query-complex-attributes-and-records} + +`format` が `"complex"` の場合、個々の検索クエリの結果は以下の形を取ります。 + + { + "startTime" : "<検索を開始した時刻>", + "elapsedTime" : <検索にかかった時間), + "count" : <検索結果のレコードの総数>, + "attributes" : { + "<カラム1の名前>" : { "type" : "<カラム1の型>", + "vector" : <カラム1がベクターカラムかどうか> }, + "<カラム2の名前>" : { "type" : "<カラム2の型>", + "vector" : <カラム2がベクターカラムかどうか> }, + "<カラム3(サブレコードが存在する場合)の名前>" : { + "attributes" : { + "<カラム3-1の名前>" : { "type" : "<カラム3-1の型>", + "vector" : <カラム3-1がベクターカラムかどうか> }, + "<カラム3-2の名前>" : { "type" : "<カラム3-2の型>", + "vector" : <カラム3-2がベクターカラムかどうか> }, + ... + } + }, + ... + ], + "records" : [ + { "<カラム1の名前>" : <レコード1のカラム1の値>, + "<カラム2の名前>" : <レコード1のカラム2の値>, + "<カラム3の名前(サブレコードが存在する場合)>" : [ + { "<カラム3-1の名前>" : <レコード1のサブレコード1のカラム3-1の値>, + "<カラム3-2の名前>" : <レコード1のサブレコード1のカラム3-2の値>, + ... }, + { "<カラム3-1の名前>" : <レコード1のサブレコード2のカラム3-1の値>, + "<カラム3-2の名前>" : <レコード1のサブレコード2のカラム3-2の値>, + ... }, + ... + ], + ... }, + { "<カラム1の名前>" : <レコード2のカラム1の値>, + "<カラム2の名前>" : <レコード2のカラム2の値>, + "<カラム3の名前(サブレコードが存在する場合)>" : [ + { "<カラム3-1の名前>" : <レコード2のサブレコード1のカラム3-1の値>, + "<カラム3-2の名前>" : <レコード2のサブレコード1のカラム3-2の値>, + ... }, + { "<カラム3-1の名前>" : <レコード2のサブレコード2のカラム3-1の値>, + "<カラム3-2の名前>" : <レコード2のサブレコード2のカラム3-2の値>, + ... }, + ... + ], + ... }, + ... + ] + } + +これは、データの転送量を小さく抑える事よりも、受け取ったデータの扱いやすさを優先する出力形式です。 +検索結果の件数が小さい事があらかじめ分かっている場合や、管理機能などのそれほど多量のアクセスが見込まれない場合などに適しています。 + +##### `attributes` {#response-query-complex-attributes} + +出力されたレコードのカラムについての情報を含むハッシュで、[検索クエリの `output`](#query-output) における `attributes` で指定された出力カラム名がキー、カラムの情報が値となります。 + +個々のカラムの情報はハッシュの形をとり、その形式はレコードの値に応じて以下の3種類で与えられます。ハッシュのキーと値は以下のとおりです。 + +###### 通常のカラム + +`type` +: カラムの値の型を示す文字列です。 + 値は[Groonga のプリミティブなデータ型](http://groonga.org/ja/docs/reference/types.html)の名前か、もしくはテーブル名です。 + +`vector` +: カラムが[ベクター型](http://groonga.org/ja/docs/tutorial/data.html#vector-types)かどうかを示す真偽値です。 + 以下のいずれかの値をとります。 + + * `true` : カラムはベクター型である。 + * `false` : カラムはベクター型ではない(スカラー型である)。 + +###### サブレコードに対応するカラム + +サブレコードのカラム情報を含む配列です。この形式は主レコードの `attributes` と同様です。つまり `attribuets` は再帰的な構造になっています。 + +###### 式 + +キーはありません。空のハッシュ `{}` です。 + +##### `records` {#response-query-complex-records} + + +出力されたレコードの配列です。 + +個々のレコードは、[検索クエリの `output`](#query-output) における `attributes` で指定された出力カラム名をキー、カラムの値を値としたハッシュとなります。 + +[日時型](http://groonga.org/ja/docs/tutorial/data.html#date-and-time-type)のカラムの値は、[W3C-DTF](http://www.w3.org/TR/NOTE-datetime "Date and Time Formats")のタイムゾーンを含む形式の文字列として出力されます。 + + +## エラーの種類 {#errors} + +このコマンドは[一般的なエラー](/ja/reference/message/#error)に加えて、以下のエラーを場合に応じて返します。 + +### `MissingSourceParameter` + +`source` の指定がないクエリがあることを示します。ステータスコードは `400` です。 + +### `UnknownSource` + +`source` の値として、他のクエリの名前ではない、実際には存在しないテーブルの名前が指定されていることを示します。ステータスコードは `404` です。 + +### `CyclicSource` + +`source` の循環参照があることを示します。ステータスコードは `400` です。 + +### `SearchTimeout` + +`timeout` で指定された時間内に検索処理が完了しなかったことを示します。ステータスコードは `500` です。 Added: ja/reference/1.0.3/commands/select/index.md (+91 -0) 100644 =================================================================== --- /dev/null +++ ja/reference/1.0.3/commands/select/index.md 2014-05-19 16:48:30 +0900 (2736bd3) @@ -0,0 +1,91 @@ +--- +title: select +layout: ja +--- + +{% comment %} +############################################## + THIS FILE IS AUTOMATICALLY GENERATED FROM + "_po/ja/reference/1.0.3/commands/select/index.po" + DO NOT EDIT THIS FILE MANUALLY! +############################################## +{% endcomment %} + + +* TOC +{:toc} + +## 概要 {#abstract} + +`select` は、テーブルから指定された条件にマッチするレコードを検索し、見つかったレコードを返却します。 + +このコマンドは[Groonga の `select` コマンド](http://groonga.org/ja/docs/reference/commands/select.html)と互換性があります。 + +形式 +: Request-Response型。コマンドに対しては必ず対応するレスポンスが返されます。 + +リクエストの `type` +: `select` + +リクエストの `body` +: パラメータのハッシュ。 + +レスポンスの `type` +: `select.result` + +## パラメータの構文 {#syntax} + + { + "table" : "<テーブル名>", + "match_columns" : "<検索対象のカラム名のリストを'||'区切りで指定>", + "query" : "<単純な検索条件>", + "filter" : "<複雑な検索条件>", + "scorer" : "<見つかったすべてのレコードに適用する式>", + "sortby" : "<ソートキーにするカラム名のリストをカンマ(',')区切りで指定>", + "output_columns" : "<L返却するカラム名のリストをカンマ(',')区切りで指定>", + "offset" : <ページングの起点>, + "limit" : <返却するレコード数>, + "drilldown" : "<ドリルダウンするカラム名>", + "drilldown_sortby" : "ドリルダウン結果のソートキーにするカラム名のリストをカンマ(',')区切りで指定>", + "drilldown_output_columns" : + "ドリルダウン結果として返却するカラム名のリストをカンマ(',')区切りで指定>", + "drilldown_offset" : <ドリルダウン結果のページングの起点>, + "drilldown_limit" : <返却するドリルダウン結果のレコード数>, + "cache" : "<クエリキャッシュの指定>", + "match_escalation_threshold": + <検索方法をエスカレーションする閾値>, + "query_flags" : "<queryパラメーターのカスタマイズ用フラグ>", + "query_expander" : "<クエリー展開用の引数>" + } + +## パラメータの詳細 {#parameters} + +`table` 以外のパラメータはすべて省略可能です。 + +また、バージョン {{ site.droonga_version }} の時点では以下のパラメータのみが動作します。 +これら以外のパラメータは未実装のため無視されます。 + + * `table` + * `match_columns` + * `query` + * `filter` + * `output_columns` + * `offset` + * `limit` + * `drilldown` + * `drilldown_output_columns` + * `drilldown_sortby` + * `drilldown_offset` + * `drilldown_limit` + +すべてのパラメータの意味は[Groonga の `select` コマンドの引数](http://groonga.org/ja/docs/reference/commands/select.html#parameters)と共通です。詳細はGroongaのコマンドリファレンスを参照して下さい。 + + + +## レスポンス {#response} + +このコマンドは、レスポンスの `body` として検索結果の配列を返却します。 + +検索結果の配列の構造は[Groonga の `select` コマンドの返り値](http://groonga.org/ja/docs/reference/commands/select.html#id6)と共通です。詳細はGroongaのコマンドリファレンスを参照して下さい。 + +このコマンドはレスポンスの `statusCode` として常に `200` を返します。これは、Groonga互換コマンドのエラー情報はGroongaのそれと同じ形で処理される必要があるためです。 Added: ja/reference/1.0.3/commands/table-create/index.md (+86 -0) 100644 =================================================================== --- /dev/null +++ ja/reference/1.0.3/commands/table-create/index.md 2014-05-19 16:48:30 +0900 (ec002ee) @@ -0,0 +1,86 @@ +--- +title: table_create +layout: ja +--- + +{% comment %} +############################################## + THIS FILE IS AUTOMATICALLY GENERATED FROM + "_po/ja/reference/1.0.3/commands/table-create/index.po" + DO NOT EDIT THIS FILE MANUALLY! +############################################## +{% endcomment %} + + +* TOC +{:toc} + +## 概要 {#abstract} + +`table_create` は、新しいテーブルを作成します。 + +このコマンドは[Groonga の `table_create` コマンド](http://groonga.org/ja/docs/reference/commands/table_create.html)と互換性があります。 + +形式 +: Request-Response型。コマンドに対しては必ず対応するレスポンスが返されます。 + +リクエストの `type` +: `table_create` + +リクエストの `body` +: パラメータのハッシュ。 + +レスポンスの `type` +: `table_create.result` + +## パラメータの構文 {#syntax} + + { + "name" : "<テーブル名>", + "flags" : "<テーブルの属性>", + "key_type" : "<主キーの型>", + "value_type" : "<値の型>", + "default_tokenizer" : "<既定のトークナイザー>", + "normalizer" : "<ノーマライザー>" + } + +## パラメータの詳細 {#parameters} + +`name` 以外のパラメータはすべて省略可能です。 + +すべてのパラメータは[Groonga の `table_create` コマンドの引数](http://groonga.org/ja/docs/reference/commands/table_create.html#parameters)と共通です。詳細はGroongaのコマンドリファレンスを参照して下さい。 + +## レスポンス {#response} + +このコマンドは、レスポンスの `body` としてコマンドの実行結果に関する情報を格納した配列を返却します。 + + [ + [ + <Groongaのステータスコード>, + <開始時刻>, + <処理に要した時間> + ], + <テーブルが作成されたかどうか> + ] + +このコマンドはレスポンスの `statusCode` として常に `200` を返します。これは、Groonga互換コマンドのエラー情報はGroongaのそれと同じ形で処理される必要があるためです。 + +レスポンスの `body` の詳細: + +ステータスコード +: コマンドが正常に受け付けられたかどうかを示す整数値です。以下のいずれかの値をとります。 + + * `0` (`Droonga::GroongaHandler::Status::SUCCESS`) : 正常に処理された。. + * `-22` (`Droonga::GroongaHandler::Status::INVALID_ARGUMENT`) : 引数が不正である。 + +開始時刻 +: 処理を開始した時刻を示す数値(UNIX秒)。 + +処理に要した時間 +: 処理を開始してから完了までの間にかかった時間を示す数値。 + +テーブルが作成されたかどうか +: テーブルが作成されたかどうかを示す真偽値です。以下のいずれかの値をとります。 + + * `true`:テーブルを作成した。 + * `false`:テーブルを作成しなかった。 Added: ja/reference/1.0.3/commands/table-remove/index.md (+81 -0) 100644 =================================================================== --- /dev/null +++ ja/reference/1.0.3/commands/table-remove/index.md 2014-05-19 16:48:30 +0900 (82678d5) @@ -0,0 +1,81 @@ +--- +title: table_remove +layout: en +--- + +{% comment %} +############################################## + THIS FILE IS AUTOMATICALLY GENERATED FROM + "_po/ja/reference/1.0.3/commands/table-remove/index.po" + DO NOT EDIT THIS FILE MANUALLY! +############################################## +{% endcomment %} + + +* TOC +{:toc} + +## 概要 {#abstract} + +`table_remove` は、既存のテーブルを1つ削除します。 + +このコマンドは[Groonga の `table_remove` コマンド](http://groonga.org/ja/docs/reference/commands/table_remove.html)と互換性があります。 + +形式 +: Request-Response型。コマンドに対しては必ず対応するレスポンスが返されます。 + +リクエストの `type` +: `table_remove` + +リクエストの `body` +: パラメータのハッシュ。 + +レスポンスの `type` +: `table_remove.result` + +## パラメータの構文 {#syntax} + + { + "name" : "<テーブル名>" + } + +## パラメータの詳細 {#parameters} + +唯一のパラメータとなる `name` は省略不可能です。 + +すべてのパラメータは[Groonga の `table_remove` コマンドの引数](http://groonga.org/ja/docs/reference/commands/table_remove.html#parameters)と共通です。詳細はGroongaのコマンドリファレンスを参照して下さい。 + +## レスポンス {#response} + +このコマンドは、レスポンスの `body` としてコマンドの実行結果に関する情報を格納した配列を返却します。 + + [ + [ + <Groongaのステータスコード>, + <開始時刻>, + <処理に要した時間> + ], + <テーブルが削除されたかどうか> + ] + +このコマンドはレスポンスの `statusCode` として常に `200` を返します。これは、Groonga互換コマンドのエラー情報はGroongaのそれと同じ形で処理される必要があるためです。 + +レスポンスの `body` の詳細: + +ステータスコード +: コマンドが正常に受け付けられたかどうかを示す整数値です。以下のいずれかの値をとります。 + + * `0` (`Droonga::GroongaHandler::Status::SUCCESS`) : 正常に処理された。. + * `-22` (`Droonga::GroongaHandler::Status::INVALID_ARGUMENT`) : 引数が不正である。 + +開始時刻 +: 処理を開始した時刻を示す数値(UNIX秒)。 + +処理に要した時間 +: 処理を開始してから完了までの間にかかった時間を示す数値。 + +テーブルが削除されたかどうか +: テーブルが削除されたかどうかを示す真偽値です。以下のいずれかの値をとります。 + + * `true`:テーブルを削除した。 + * `false`:テーブルを削除しなかった。 Added: ja/reference/1.0.3/http-server/index.md (+164 -0) 100644 =================================================================== --- /dev/null +++ ja/reference/1.0.3/http-server/index.md 2014-05-19 16:48:30 +0900 (f363ade) @@ -0,0 +1,164 @@ +--- +title: HTTPサーバ +layout: ja +--- + +{% comment %} +############################################## + THIS FILE IS AUTOMATICALLY GENERATED FROM + "_po/ja/reference/1.0.3/http-server/index.po" + DO NOT EDIT THIS FILE MANUALLY! +############################################## +{% endcomment %} + + +* TOC +{:toc} + +## 概要 {#abstract} + +[Droonga HTTP Server][droonga-http-server]は、Droonga Engine用のHTTP Protocol Adapterです。 + +Droonga Engineはfluentdプロトコルにのみ対応しているため、Droonga Engineとの通信には`fluent-cat`などを使う必要があります。 +このアプリケーションは、Droonga EngineとHTTP経由で通信するための機能を提供します。 + +## インストール {#install} + +Droonga HTTP Serverは、[Node.js][] 用の[droonga-http-server npmモジュール][droonga-http-server npm module]として提供されています。 +以下のように、`npm`コマンドでインストールすることができます: + + # npm install -g droonga-http-server + +## 使い方 {#usage} + +### コマンドラインオプション {#usage-command} + +Droonga HTTP Serverは、HTTPサーバを起動するための`droonga-http-server`コマンドを含んでいます。 +以下のようにコマンドラインオプションを指定して起動できます: + + # droonga-http-server --port 3003 + +指定可能なオプションと既定値は以下の通りです: + +`--port <13000>` +: HTTPリクエストを受け付けるポート番号。 + +`--receive-host-name <127.0.0.1>` +: HTTPサーバが動作するコンピュータ自身のホスト名(またはIPアドレス)。 + Droonga EngineからProtocol Adapterへレスポンスのメッセージを送出する際の宛先に使われます。 + +`--droonga-engine-host-name <127.0.0.1>` +: Droonga Engineが動作するコンピュータのホスト名(またはIPアドレス)。 + +`--droonga-engine-port <24224>` +: Droonga Engineがメッセージを受け付けるポートの番号。 + +`--default-dataset <Droonga>` +: 既定のデータセット名。 + 組み込みのHTTP APIから発行されるリクエストに使われます。 + +`--tag <droonga>` +: Droonga Engineに送るfluentdメッセージに使われます。 + +`--enable-logging` +: このオプションを指定した場合、ログが標準出力に出力されるようになります。 + +`--cache-size <100>` +: LRUレスポンスキャッシュの最大サイズ。 + Droonga HTTP ServerはすべてのGETリクエストについて、レスポンスをここで指定した件数までメモリ上にキャッシュします。 + +コマンドラインオプションには、組み合わせるDroonga Engineに合わせた値を適切に指定する必要があります。例えば、HTTPサーバが192.168.10.90のコンピュータ上で動作し、Droonga Engineが192.168.10.100のコンピュータ上で以下の設定を伴って動作する時: + +fluentd.conf: + + <source> + type forward + port 24324 + </source> + <match books.message> + name localhost:24224/books + type droonga + </match> + <match output.message> + type stdout + </match> + +catalog.json: + + { + "version": 2, + "effectiveDate": "2013-09-01T00:00:00Z", + "datasets": { + "Books": { + ... + } + } + } + +この時、192.168.10.90のコンピュータ上でHTTPサーバを起動する際のコマンドラインオプションは以下のようになります: + + # droonga-http-server --receive-host-name 192.168.10.90 \ + --droonga-engine-host-name 192.168.10.100 \ + --droonga-engine-port 24324 \ + --default-dataset Books \ + --tag books + +[基本のチュートリアル][basic tutorial]も併せて参照して下さい。 + +## 組み込みのAPI {#usage-api} + +Droonga HTTP Serverは以下のAPIを含んでいます: + +### REST API {#usage-rest} + +#### `GET /tables/<テーブル名>` {#usage-rest-get-tables-table} + +単純な[検索リクエスト](../commands/search/)を発行します。 +リクエストの[`source`](../commands/search/#query-source)は、パス中で指定されたテーブル名となります。 +指定できるクエリパラメータは以下の通りです: + +`attributes` +: [`output.attributes`](../commands/search/#query-output)に対応。 + 値はカンマ区切りのリストです。例:`attributes=_key,name,age`. + +`query` +: [`condition.*.query`](../commands/search/#query-condition-query-syntax-hash)に対応。 + 値はクエリ文字列です。 + +`match_to` +: [`condition.*.matchTo`](../commands/search/#query-condition-query-syntax-hash)に対応。 + 値はカンマ区切りのリストです。例:`match_to=_key,name`. + +`match_escalation_threshold` +: [`condition.*.matchEscalationThreshold`](../commands/search/#query-condition-query-syntax-hash)に対応。 + 値は整数です。 + +`script` +: [`condition`](../commands/search/#query-condition-query-syntax-hash)におけるスクリプト形式の指定に対応。もし`query`と両方同時に指定した場合には、両者の`and`条件と見なされます。 + +`adjusters` +: `adjusters`に対応します。 + +`sort_by` +: [`sortBy`](../commands/search/#query-sortBy)に対応します。 + 値はカラム名の文字列です。 + +`limit` +: [`output.limit`](../commands/search/#query-output)に対応。 + 値は整数です。 + +`offset` +: [`output.offset`](../commands/search/#query-output)に対応。 + 値は整数です。 + +### Groonga HTTPサーバ互換API {#usage-groonga} + +#### `GET /d/<コマンド名>` {#usage-groonga-d} + +(未稿) + + + [basic tutorial]: ../../tutorial/basic/ + [droonga-http-server]: https://github.com/droonga/droonga-http-server + [droonga-http-server npm module]: https://npmjs.org/package/droonga-http-server + [Node.js]: http://nodejs.org/ Added: ja/reference/1.0.3/index.md (+28 -0) 100644 =================================================================== --- /dev/null +++ ja/reference/1.0.3/index.md 2014-05-19 16:48:30 +0900 (16b0cb9) @@ -0,0 +1,28 @@ +--- +title: リファレンスマニュアル +layout: ja +--- + +{% comment %} +############################################## + THIS FILE IS AUTOMATICALLY GENERATED FROM + "_po/ja/reference/1.0.3/index.po" + DO NOT EDIT THIS FILE MANUALLY! +############################################## +{% endcomment %} + + +[カタログの仕様](catalog/) +: Droonga Engineの振る舞いを定義する`catalog.json`の詳細。 + +[メッセージの形式](message/) +: Droonga Engine内を流れるメッセージの形式の詳細。 + +[コマンドリファレンス](commands/) +: Droonga Engineで利用可能な組み込みのコマンドの詳細。 + +[HTTPサーバ](http-server/) +: [droonga-http-server](https://github.com/droonga/droonga-http-server)の使用方法。 + +[プラグイン開発](plugin/) +: Droonga Engine用の独自のプラグインを開発するための公開APIの詳細。 Added: ja/reference/1.0.3/message/index.md (+215 -0) 100644 =================================================================== --- /dev/null +++ ja/reference/1.0.3/message/index.md 2014-05-19 16:48:30 +0900 (fda1c9d) @@ -0,0 +1,215 @@ +--- +title: メッセージ形式 +layout: ja +--- + +{% comment %} +############################################## + THIS FILE IS AUTOMATICALLY GENERATED FROM + "_po/ja/reference/1.0.3/message/index.po" + DO NOT EDIT THIS FILE MANUALLY! +############################################## +{% endcomment %} + + +* TOC +{:toc} + + +## リクエスト {#request} + +リクエストのメッセージの基本的な形式は以下の通りです。 + + { + "id" : "<メッセージの識別子>", + "type" : "<メッセージの種類>", + "replyTo" : "<レスポンスの受信者へのパス>", + "dataset" : "<対象データセット名>", + "body" : <メッセージ本文> + } + +### `id` {#request-id} + +概要 +: そのメッセージの一意な識別子。 + +値 +: 識別子となる文字列。一意でさえあれば、どんな形式のどんな文字列でも指定できます。値は対応するレスポンスの['inReplyTo`](#response-inReplyTo)に使われます。 + +省略時の既定値 +: なし。この情報は省略できません。 + +### `type` {#request-type} + +概要 +: そのメッセージの種類。 + +値 +: [コマンド](/ja/reference/commands/)の名前の文字列 + +省略時の既定値 +: なし。この情報は省略できません。 + +### `replyTo` {#request-replyTo} + +概要 +: レスポンスの受信者へのパス。 + +値 +: `<ホスト>:<ポート番号>/<タグ名>` で示されたパス文字列。例:`localhost:24224/output`. + +省略時の既定値 +: なし。この情報は省略可能で、省略した場合はレスポンスのメッセージは単に捨てられます。 + +### `dataset` {#request-dataset} + +概要 +: 対象となるデータセット。 + +値 +: データセット名の文字列。 + +省略時の既定値 +: なし。この情報は省略できません。 + +### `body` {#request-body} + +概要 +: メッセージの本文。 + +値 +: オブジェクト、文字列、数値、真偽値、または `null`。 + +省略時の既定値 +: なし。この情報は省略可能です。 + +## レスポンス {#response} + +レスポンスのメッセージの基本的な形式は以下の通りです。 + + { + "type" : "<メッセージの種類>", + "inReplyTo" : "<対応するリクエストメッセージの識別子>", + "statusCode" : <ステータスコード>, + "body" : <メッセージの本文>, + "errors" : <ノードから返されたエラー> + } + +### `type` {#response-type} + +概要 +: そのメッセージの種類。 + +値 +: メッセージの種類を示す文字列。多くの場合は、元のリクエストメッセージの `type` の値に `.result` という接尾辞を伴った文字列です。 + +### `inReplyTo` {#response-inReplyTo} + +概要 +: 対応するリクエストメッセージの識別子。 + +値 +: 対応するリクエストメッセージの識別子の文字列 related request message. + +### `statusCode` {#response-statusCode} + +概要 +: そのメッセージの種類。 + +値 +: ステータスコードを示す整数。 + +レスポンスのステータスコードはHTTPのステータスコードに似ています。 + +`200` およびその他の `2xx` のステータス +: コマンドが正常に処理されたことを示します。 + +### `body` {#response-body} + +概要 +: そのリクエストメッセージの処理結果の情報。 + +値 +: オブジェクト、文字列、数値、真偽値、または `null`。 + +### `errors` {#response-errors} + +概要 +: 各ノードから返されたすべてのエラー。 + +値 +: オブジェクト。 + +この情報は、コマンドが複数のボリュームに分散して処理された時にのみ現れます。それ以外の場合、レスポンスメッセージは `errors` フィールドを含みません。詳細は[エラーレスポンスの説明](#error)を参照して下さい。 + +## エラーレスポンス {#error} + +コマンドの中にはエラーを返す物があります。 + +エラーレスポンスは通常のレスポンスと同じ `type` を伴って返されますが、通常のレスポンスとは異なる `statusCode` と `body` を持ちます。大まかなエラーの種類は `statusCode` で示され、詳細な情報は `body` の内容として返されます。 + +コマンドが複数のボリュームに分散して処理されて、各ボリュームがエラーを返した場合、レスポンスメッセージは `errors` フィールドを持ちます。各ボリュームから返されたエラーは以下のように保持されます: + + { + "type" : "add.result", + "inReplyTo" : "...", + "statusCode" : 400, + "body" : { + "name": "UnknownTable", + "message": ... + }, + "errors" : { + "/path/to/the/node1" : { + "statusCode" : 400, + "body" : { + "name": "UnknownTable", + "message": ... + } + }, + "/path/to/the/node2" : { + "statusCode" : 400, + "body" : { + "name": "UnknownTable", + "message": ... + } + } + } + } + +このような場合、すべてのエラーの中で代表的な1つがメッセージの `body` に出力されます。 + + +### エラーレスポンスのステータスコード {#error-status} + +エラーレスポンスのステータスコードはHTTPのステータスコードに似ています。 + +`400` およびその他の `4xx` のステータス +: リクエストのメッセージが原因でのエラーであることを示します。 + +`500` およびその他の `5xx` のステータス +: Droonga Engine内部のエラーであることを示します。 + +### エラーレスポンスの `body` {#error-body} + +エラーレスポンスの `body` の基本的な形式は以下の通りです。 + + { + "name" : "<エラーの種類>", + "message" : "<人間が読みやすい形式で示されたエラーの詳細>", + "detail" : <任意の形式の、追加のエラー情報> + } + +追加の情報がない場合、 `detail` は出力されないことがあります。 + +#### エラーの種類 {#error-type} + +すべてのコマンドに共通するエラーとして、以下の物があります。 + +`MissingDatasetParameter` +: `dataset` の指定がないことを示します。ステータスコードは `400` です。 + +`UnknownDataset` +: 指定されたデータセットが存在しないことを示します。ステータスコードは `404` です。 + +`UnknownType` +: `type` に指定されたコマンドを処理するハンドラが存在しない、未知のコマンドであることを示します。ステータスコードは `400` です。 Added: ja/reference/1.0.3/plugin/adapter/index.md (+317 -0) 100644 =================================================================== --- /dev/null +++ ja/reference/1.0.3/plugin/adapter/index.md 2014-05-19 16:48:30 +0900 (cfe1314) @@ -0,0 +1,317 @@ +--- +title: アダプション・フェーズでのプラグインAPI +layout: ja +--- + +{% comment %} +############################################## + THIS FILE IS AUTOMATICALLY GENERATED FROM + "_po/ja/reference/1.0.3/plugin/adapter/index.po" + DO NOT EDIT THIS FILE MANUALLY! +############################################## +{% endcomment %} + + +* TOC +{:toc} + + +## 概要 {#abstract} + +各々のDroonga Engineプラグインは、それ自身のための*アダプター*を持つことができます。アダプション・フェーズでは、アダプターは入力メッセージ(Protocol AdapterからDroonga Engineへ送られてきたリクエストに相当)と出力メッセージ(Droonga EngineからProtocol Adapterへ送られるレスポンスに相当)の両方について変更を加えることができます。 + + +### アダプターの定義の仕方 {#howto-define} + +例えば、「foo」という名前のプラグインにアダプターを定義する場合は以下のようにします: + +~~~ruby +require "droonga/plugin" + +module Droonga::Plugins::FooPlugin + extend Plugin + register("foo") + + class Adapter < Droonga::Adapter + # このアダプターを設定するための操作 + XXXXXX = XXXXXX + + def adapt_input(input_message) + # 入力メッセージを変更するための操作 + input_message.XXXXXX = XXXXXX + end + + def adapt_output(output_message) + # 出力メッセージを変更するための操作 + output_message.XXXXXX = XXXXXX + end + end +end +~~~ + +アダプターを定義するための手順は以下の通りです: + + 1. プラグイン用のモジュール(例:`Droonga::Plugins::FooPlugin`)を定義し、プラグインとして登録する。(必須) + 2. [`Droonga::Adapter`](#classes-Droonga-Adapter)を継承したアダプタークラス(例:`Droonga::Plugins::FooPlugin::Adapter`)を定義する。(必須) + 3. [アダプターを適用する条件を設定する](#howto-configure)。(必須) + 4. 入力メッセージに対する変更操作を[`#adapt_input`](#classes-Droonga-Adapter-adapt_input)として定義する。(任意) + 5. 出力メッセージに対する変更操作を[`#adapt_output`](#classes-Droonga-Adapter-adapt_output)として定義する。(任意) + +[プラグイン開発のチュートリアル](../../../tutorial/plugin-development/adapter/)も参照して下さい。 + + +### アダプターはどのように操作するか {#how-works} + +アダプターは以下のように動作します: + + 1. Droonga Engineが起動する。 + * アダプタークラス(例:`Droonga::Plugins::FooPlugin::Adapter`)の唯一のインスタンスが作られ、登録される。 + * 入力のマッチングパターンおよび出力のマッチングパターンが登録される。 + * Droonga Engineが起動し、入力メッセージを待ち受ける。 + 2. 入力メッセージがProtocol AdapterからDroonga Engineへ送られてくる。 + この時点で(入力メッセージ用の)アダプション・フェーズが開始される。 + * そのメッセージが[入力のマッチングパターン](#config)にマッチするアダプターについて、アダプターの[`#adapt_input`](#classes-Droonga-Adapter-adapt_input)が呼ばれる。 + * このメソッドは、[入力メッセージ自身が持つメソッド](#classes-Droonga-InputMessage)を通じて入力メッセージを変更することができる。 + 3. すべてのアダプターが適用された時点で、入力メッセージ用のアダプション・フェーズが終了し、メッセージが次のプランニング・フェーズに送られる。 + 4. 出力メッセージが前のコレクション・フェーズから送られてくる。 + この時点で(出力メッセージ用の)アダプション・フェーズが開始される。 + * そのメッセージ外貨の両方の条件を満たす場合に、アダプターの[`#adapt_output`](#classes-Droonga-Adapter-adapt_output)が呼ばれる: + - そのメッセージが、そのアダプター自身によって処理された入力メッセージに起因した物である。 + - そのメッセージが、アダプターの[出力のマッチングパターン](#config)にマッチする。 + * このメソッドは、[出力メッセージ自身が持つメソッド](#classes-Droonga-OutputMessage)を通じて出力メッセージを変更することができる。 + 5. すべてのアダプターが適用された時点で、出力メッセージ用のアダプション・フェーズが終了し、メッセージがProtocol Adapterに送られる。 + +上記の通り、Droonga Engineは各プラグインのアダプタークラスについて、インスタンスを全体で1つだけ生成します。 +対になった入力メッセージと出力メッセージのための状態を示す情報をアダプター自身のインスタンス変数として保持してはいけません。 +代わりに、状態を示す情報を入力メッセージのbodyの一部として埋め込み、対応する出力メッセージのbodyから取り出すようにして下さい。 + +アダプター内で発生したすべてのエラーは、Droonga Engine自身によって処理されます。[エラー処理][error handling]も併せて参照して下さい。 + + +## 設定 {#config} + +`input_message.pattern` ([マッチングパターン][matching pattern], 省略可能, 初期値=`nil`) +: 入力メッセージに対する[マッチングパターン][matching pattern]。 + パターンが指定されていない(もしくは`nil`が指定された)場合は、すべてのメッセージがマッチします。 + +`output_message.pattern` ([マッチングパターン][matching pattern], 省略可能, 初期値=`nil`) +: 出力メッセージに対する[マッチングパターン][matching pattern]。 + パターンが指定されていない(もしくは`nil`が指定された)場合は、すべてのメッセージがマッチします。 + +## クラスとメソッド {#classes} + +### `Droonga::Adapter` {#classes-Droonga-Adapter} + +これはすべてのアダプターに共通の基底クラスです。独自プラグインのアダプタークラスは、このクラスを継承する必要があります。 + +#### `#adapt_input(input_message)` {#classes-Droonga-Adapter-adapt_input} + +このメソッドは、[`Droonga::InputMessage`](#classes-Droonga-InputMessage)でラップされた入力メッセージを受け取ります。 +入力メッセージは、メソッドを通じて内容を変更することができます。 + +この基底クラスにおいて、このメソッドは何もしない単なるプレースホルダとして定義されています。 +入力メッセージを変更するには、以下のようにメソッドを再定義して下さい: + +~~~ruby +module Droonga::Plugins::QueryFixer + class Adapter < Droonga::Adapter + def adapt_input(input_message) + input_message.body["query"] = "fixed query" + end + end +end +~~~ + +#### `#adapt_output(output_message)` {#classes-Droonga-Adapter-adapt_output} + +このメソッドは、[`Droonga::OutputMessage`](#classes-Droonga-OutputMessage)でラップされた出力メッセージを受け取ります。 +出力メッセージは、メソッドを通じて内容を変更することができます。 + +この基底クラスにおいて、このメソッドは何もしない単なるプレースホルダとして定義されています。 +出力メッセージを変更するには、以下のようにメソッドを再定義して下さい: + +~~~ruby +module Droonga::Plugins::ErrorConcealer + class Adapter < Droonga::Adapter + def adapt_output(output_message) + output_message.status_code = Droonga::StatusCode::OK + end + end +end +~~~ + +### `Droonga::InputMessage` {#classes-Droonga-InputMessage} + +#### `#type`, `#type=(type)` {#classes-Droonga-InputMessage-type} + +入力メッセージの`"type"`の値を返します。 + +以下のように、新しい文字列値を代入することで値を変更できます: + +~~~ruby +module Droonga::Plugins::MySearch + class Adapter < Droonga::Adapter + input_message.pattern = ["type", :equal, "my-search"] + + def adapt_input(input_message) + p input_message.type + # => "my-search" + # このメッセージは「my-search」というメッセージタイプに + # 対応したプラグインによって処理される。 + + input_message.type = "search" + + p input_message.type + # => "search" + # メッセージタイプが変更された。 + # このメッセージはsearchプラグインによって、 + # 通常の検索リクエストとして処理される。 + end + end +end +~~~ + +#### `#body`, `#body=(body)` {#classes-Droonga-InputMessage-body} + +入力メッセージの`"body"`の値を返します。 + +以下のように、新しい値を代入したり部分的に値を代入したりすることで、値を変更することができます: + +~~~ruby +module Droonga::Plugins::MinimumLimit + class Adapter < Droonga::Adapter + input_message.pattern = ["type", :equal, "search"] + + MAXIMUM_LIMIT = 10 + + def adapt_input(input_message) + input_message.body["queries"].each do |name, query| + query["output"] ||= {} + query["output"]["limit"] ||= MAXIMUM_LIMIT + query["output"]["limit"] = [query["output"]["limit"], MAXIMUM_LIMIT].min + end + # この時点で、すべての検索クエリが"output.limit=10"の指定を持っている。 + end + end +end +~~~ + +別の例: + +~~~ruby +module Droonga::Plugins::MySearch + class Adapter < Droonga::Adapter + input_message.pattern = ["type", :equal, "my-search"] + + def adapt_input(input_message) + # 独自形式のメッセージからクエリ文字列を取り出す。 + query_string = input_message["body"]["query"] + + # "search"型の内部的な検索リクエストを組み立てる。 + input_message.type = "search" + input_message.body = { + "queries" => { + "source" => "Store", + "condition" => { + "query" => query_string, + "matchTo" => ["name"], + }, + "output" => { + "elements" => ["records"], + "limit" => 10, + }, + }, + } + # この時点で、"type"と"body"は両方とも完全に置き換えられている。 + end + end +end +~~~ + +### `Droonga::OutputMessage` {#classes-Droonga-OutputMessage} + +#### `#status_code`, `#status_code=(status_code)` {#classes-Droonga-OutputMessage-status_code} + +出力メッセージの`"statusCode"`の値を返します。 + +以下のように、新しいステータスコードを代入することで値を変更できます: + +~~~ruby +module Droonga::Plugins::ErrorConcealer + class Adapter < Droonga::Adapter + input_message.pattern = ["type", :equal, "search"] + + def adapt_output(output_message) + unless output_message.status_code == StatusCode::InternalServerError + output_message.status_code = Droonga::StatusCode::OK + output_message.body = {} + output_message.errors = nil + # この時点で、内部的なサーバーエラーはすべて無視されるため + # クライアントは通常のレスポンスを受け取る事になる。 + end + end + end +end +~~~ + +#### `#errors`, `#errors=(errors)` {#classes-Droonga-OutputMessage-errors} + +出力メッセージの`"errors"`の値を返します。 + +以下のように、新しいエラー情報を代入したり値を部分的に書き換えたりする事ができます: + +~~~ruby +module Droonga::Plugins::ErrorExporter + class Adapter < Droonga::Adapter + input_message.pattern = ["type", :equal, "search"] + + def adapt_output(output_message) + output_message.errors.delete(secret_database) + # 秘密のデータベースからのエラー情報を削除する。 + + output_message.body["errors"] = { + "records" => output_message.errors.collect do |database, error| + { + "database" => database, + "error" => error + } + end, + } + # エラー情報を、"error"という名前の擬似的な検索結果に変換する。 + end + end +end +~~~ + +#### `#body`, `#body=(body)` {#classes-Droonga-OutputMessage-body} + +出力メッセージの`"body"`の値を返します。 + +以下のように、新しい値を代入したり部分的に値を代入したりすることで、値を変更することができます: + +~~~ruby +module Droonga::Plugins::SponsoredSearch + class Adapter < Droonga::Adapter + input_message.pattern = ["type", :equal, "search"] + + def adapt_output(output_message) + output_message.body.each do |name, result| + next unless result["records"] + result["records"].unshift(sponsored_entry) + end + # これにより、すべての検索結果が広告エントリを含むようになる。 + end + + def sponsored_entry + { + "title"=> "SALE!", + "url"=> "http://..." + } + end + end +end +~~~ + + + [matching pattern]: ../matching-pattern/ + [error handling]: ../error/ Added: ja/reference/1.0.3/plugin/collector/index.md (+58 -0) 100644 =================================================================== --- /dev/null +++ ja/reference/1.0.3/plugin/collector/index.md 2014-05-19 16:48:30 +0900 (67d6145) @@ -0,0 +1,58 @@ +--- +title: コレクター +layout: ja +--- + +{% comment %} +############################################## + THIS FILE IS AUTOMATICALLY GENERATED FROM + "_po/ja/reference/1.0.3/plugin/collector/index.po" + DO NOT EDIT THIS FILE MANUALLY! +############################################## +{% endcomment %} + + +* TOC +{:toc} + + +## 概要 {#abstract} + +コレクターは、2つの入力値を1つの値に結合します。 +Droonga Engineは3つ以上の値に対しても、指定されたコレクターを繰り返し適用することによって、それらを1つの値にします。 + +## 組み込みのコレクタークラス {#builtin-collectors} + +組み込みのプラグインによって使われている、定義済みのコレクタークラスがいくつかあります。 +これらは当然ですが、自作プラグインからも利用することができます。 + +### `Droonga::Collectors::And` + +`and` 論理演算子によって2つの値を比較した結果を返します。 +両方の値が論理的に真である場合、どちらかの値が返されます(どちらが返されるかは不定です)。 + +`null` (`nil`) および `false` は論理的に偽として扱われ、それ以外の場合はすべて真として扱われます。 + +### `Droonga::Collectors::Or` + +`or` 論理演算子によって2つの値を比較した結果を返します。 +片方の値だけが論理的に真である場合、その値が返り値となります。 +そうでなく2つの値が論理的に等しい場合は、どちらかの値が返されます(どちらが返されるかは不定です)。 + +`null` (`nil`) および `false` は論理的に偽として扱われ、それ以外の場合はすべて真として扱われます。 + +### `Droonga::Collectors::Sum` + +2つの値のまとめた結果を返します。 + +このコレクターは若干複雑な動作をします。 + + * 片方の値が `null` (`nil`) である場合、もう片方の値を返します。 + * 両方の値がハッシュである場合、ハッシュの結合結果を値として返します。 + * 結果のハッシュは、2つのハッシュが持つキーのすべてを持ちます。 + 両方のハッシュでキーが重複した場合、重複したキーの値はどちらかのハッシュの値となります。 + * 重複するキーの値についてどちらのハッシュの値が使われるかは不定です。 + * それ以外の場合は、 `a + b` の結果を値として返します。 + * 両方ともの値が配列または文字列であった場合、それらを連結した結果を値として返します。 + どちらの値が左辺になるかは不定です。 + Added: ja/reference/1.0.3/plugin/error/index.md (+70 -0) 100644 =================================================================== --- /dev/null +++ ja/reference/1.0.3/plugin/error/index.md 2014-05-19 16:48:30 +0900 (4000553) @@ -0,0 +1,70 @@ +--- +title: プラグインでのエラーの扱い +layout: ja +--- + +{% comment %} +############################################## + THIS FILE IS AUTOMATICALLY GENERATED FROM + "_po/ja/reference/1.0.3/plugin/error/index.po" + DO NOT EDIT THIS FILE MANUALLY! +############################################## +{% endcomment %} + + +* TOC +{:toc} + + +## 概要 {#abstract} + +プラグイン内部で発生した例外のうち、そのプラグイン自身によって補足されなかった物は、すべて、入力メッセージに対する[エラーレスポンス][error response]として返されます。この時のエラーレスポンスのステータスコードは`500`(Internal Errorを意味する)です。 + +整形されたエラー情報を返したい場合は、低レベルのエラーを捕捉した上で、`Droonga::ErrorMessage::BadRequest`または`Droonga::ErrorMessage::InternalServerError`を継承したカスタムエラークラスでラップして再度`raise`して下さい。 +(ちなみに、これらの基底クラスはプラグインの名前空間に初期状態で`include`されているため、エラークラスの定義時には単に`class CustomError < BadRequest`などと書くだけで参照できます。) + + +## 組み込みのエラークラス {#builtin-errors} + +組み込みのプラグインやDroonga Engine自身によってあらかじめ定義されているエラークラスとしては、以下の物があります。 + +### `Droonga::ErrorMessage::NotFound` + +データセットまたは指定された情報ソースの中に、探している情報が見つからなかったことを示す。例: + + # 第2引数はエラーの詳細な情報。(省略可能) + raise Droonga::NotFound.new("#{name} is not found!", :elapsed_time => elapsed_time) + +### `Droonga::ErrorMessage::BadRequest` + +文法エラーやバリデーションエラーなど、入力メッセージ自体にエラーが含まれていたことを示す。例: + + # 第2引数はエラーの詳細な情報。(省略可能) + raise Droonga::NotFound.new("Syntax error in #{query}!", :detail => detail) + +### `Droonga::ErrorMessage::InternalServerError` + +タイムアウト、ファイル入出力のエラーなど、その他の未知のエラーであることを示す。例: + + # 第2引数はエラーの詳細な情報。(省略可能) + raise Droonga::MessageProcessingError.new("busy!", :elapsed_time => elapsed_time) + + +## 組み込みのステータスコード {#builtin-status-codes} + +エラーのステータスコードとしては、以下のステータスコードか、もしくは[慣習に従ったステータスコード](../../message/#error-status)を使用します。 + +`Droonga::StatusCode::OK` +: `200`と等価。 + +`Droonga::StatusCode::NOT_FOUND` +: `404`と等価。 + +`Droonga::StatusCode::BAD_REQUEST` +: `400`と等価。 + +`Droonga::StatusCode::INTERNAL_ERROR` +: `500`と等価。 + + + [error response]: ../../message/#error Added: ja/reference/1.0.3/plugin/handler/index.md (+230 -0) 100644 =================================================================== --- /dev/null +++ ja/reference/1.0.3/plugin/handler/index.md 2014-05-19 16:48:30 +0900 (240b895) @@ -0,0 +1,230 @@ +--- +title: ハンドリング・フェーズでのプラグインAPI +layout: ja +--- + +{% comment %} +############################################## + THIS FILE IS AUTOMATICALLY GENERATED FROM + "_po/ja/reference/1.0.3/plugin/handler/index.po" + DO NOT EDIT THIS FILE MANUALLY! +############################################## +{% endcomment %} + + +* TOC +{:toc} + + +## 概要 {#abstract} + +各々のDroonga Engineプラグインは、それ自身のための*ハンドラー*を持つことができます。ハンドリング・フェーズでは、ハンドラーはリクエストを処理して結果を返すことができます。 + + +### ハンドラーの定義の仕方 {#howto-define} + +例えば、「foo」という名前のプラグインにハンドラーを定義する場合は以下のようにします: + +~~~ruby +require "droonga/plugin" + +module Droonga::Plugins::FooPlugin + extend Plugin + register("foo") + + define_single_step do |step| + step.name = "foo" + step.handler = :Handler + step.collector = Collectors::And + end + + class Handler < Droonga::Handler + def handle(message) + # リクエストを処理するための操作 + end + end +end +~~~ + +ハンドラーを定義するための手順は以下の通りです: + + 1. プラグイン用のモジュール(例:`Droonga::Plugins::FooPlugin`)を定義し、プラグインとして登録する。(必須) + 2. [`Droonga::SingleStepDefinition`](#class-Droonga-SingleStepDefinition)を使い、実装しようとしているハンドラーに対応する「single step」を定義する。(必須) + 3. [`Droonga::Handler`](#classes-Droonga-Handler)を継承したハンドラークラス(例:`Droonga::Plugins::FooPlugin::Handler`)を定義する。(必須) + 4. リクエストを処理する操作を[`#handle`](#classes-Droonga-Handler-handle)として定義する。(任意) + + +[プラグイン開発チュートリアル](../../../tutorial/plugin-development/handler/)も併せて参照して下さい。 + + +### ハンドラーはどのように操作するか {#how-works} + +ハンドラーは以下のように動作します: + + 1. Droonga Engineが起動する。 + * stepとハンドラークラスが登録される。 + * Droonga Engineが起動し、入力メッセージを待ち受ける。 + 2. アダプション・フェーズからメッセージが転送されてくる。 + この時点でプロセッシング・フェーズが開始される。 + * Droonga Engineが、メッセージタイプからstepの定義を見つける。 + * Droonga Engineが、登録済みの定義に従ってsingle stepを作成する。 + * single stepが、登録済みのハンドラークラスのインスタンスを作成する。 + この時点でハンドリング・フェーズが開始される。 + * ハンドラーの[`#handle`](#classes-Droonga-Handler-handle)メソッドが、リクエストの情報を含むタスクメッセージを伴って呼ばれる。 + * このメソッドにより、入力メッセージを任意に処理することができる。 + * このメソッドは、処理結果の出力を戻り値として返す。 + * ハンドラーの処理が完了した時点で、そのタスクメッセージ(およびリクエスト)のハンドリング・フェーズが終了する。 + * メッセージタイプからstepが見つからなかった場合は、何も処理されない。 + * すべてのstepが処理を終えた時点で、そのリクエストに対するプロセッシング・フェーズが終了する。 + +上記の通り、Droonga Engineは各リクエストに対してその都度ハンドラークラスのインスタンスを生成します。 + +ハンドラー内で発生したすべてのエラーは、Droonga Engine自身によって処理されます。[エラー処理][error handling]も併せて参照して下さい。 + + +## 設定 {#config} + +`action.synchronous` (真偽値, 省略可能, 初期値=`false`) +: リクエストを同期的に処理する必要があるかどうかを示す。 + 例えば、テーブル内に新しいカラムを追加するリクエストは、テーブルが存在しない場合には必ず、テーブル作成用のリクエストの後で処理する必要がある。このような場合のハンドラーは、 `action.synchronous = true` の指定を伴うことになる。 + + +## クラスとメソッド {#classes} + +### `Droonga::SingleStepDefinition` {#classes-Droonga-SingleStepDefinition} + +このクラスは、ハンドラーに対応するstepの詳細を記述する機能を提供します。 + +#### `#name`, `#name=(name)` {#classes-Droonga-SingleStepDefinition-name} + +step自身の名前を記述します。値は文字列です。 + +Droonga Engineは、メッセージの`type`に一致する`name`を持つstepが存在する場合に、入力メッセージをコマンドのリクエストとして扱います。 +言い換えると、このメソッドはstepに対応するコマンドの名前を定義します。 + + +#### `#handler`, `#handler=(handler)` {#classes-Droonga-SingleStepDefinition-handler} + +特定のハンドラークラスをstepに紐付けます。 +ハンドラークラスは以下のいずれかの方法で指定します: + + * `Handler` や `Droonga::Plugins::FooPlugin::Handler` のような、ハンドラークラス自体への参照。 + 当然ながら、参照先のクラスはその時点で定義済みでなければなりません。 + * `:Handler`のような、その名前空間で定義されているハンドラークラスのクラス名のシンボル。 + この記法は、stepを先に記述して後からハンドラークラスを定義する場合に有用です。 + * `"Droonga::Plugins::FooPlugin::Handler"` のような、ハンドラークラスのクラスパス文字列。 + この記法もまた、stepの後でハンドラークラスを定義する場合に有用です。 + +ハンドラークラスをシンボルまたは文字列で指定した場合、参照先のクラスは、Droonga Engineが実際にそのstepを処理する時点までの間に定義しておく必要があります。 +Droonga Engineがハンドラークラスの実体を見つけられなかった場合、またはハンドラークラスが未指定の場合には、Droonga Engineはそのリクエストに対して何も処理を行いません。 + +#### `#collector`, `#collector=(collector)` {#classes-Droonga-SingleStepDefinition-collector} + +特定のコレクタークラスをstepに紐付けます。 +コレクタークラスは以下のいずれかの方法で指定します: + + * `Collectors::Something` や `Droonga::Plugins::FooPlugin::MyCollector` のような、コレクタークラス自体への参照。 + 当然ながら、参照先のクラスはその時点で定義済みでなければなりません。 + * `:MyCollector`のような、その名前空間で定義されているコレクタークラスのクラス名のシンボル。 + この記法は、stepを先に記述して後からコレクタークラスを定義する場合に有用です。 + * `"Droonga::Plugins::FooPlugin::MyCollector"` のような、コレクタークラスのクラスパス文字列。 + この記法もまた、stepの後でコレクタークラスを定義する場合に有用です。 + +コレクタークラスをシンボルまたは文字列で指定した場合、参照先のクラスは、Droonga Engineが実際にそのstepの結果を集約する時点までの間に定義しておく必要があります。 +Droonga Engineがコレクタークラスの実体を見つけられなかった場合、またはコレクタークラスが未指定の場合には、Droonga Engineは処理結果を集約せず、複数のメッセージとして返します。 + +[コレクターの説明][collector]も併せて参照して下さい。 + +#### `#write`, `#write=(write)` {#classes-Droonga-SingleStepDefinition-write} + +stepがストレージ内の情報を変更し得るかどうかを記述します。 +リクエストがストレージ内のデータを変更することを意図する物である場合、そのリクエストはすべてのreplicaで処理される必要があります。 +それ以外の場合、Droonga Engineは結果をキャッシュしたり、CPUやメモリの使用量を削減するなどして、処理を最適化することができます。 + +取り得る値: + + * `true`: そのstepではストレージの内容が変更される可能性がある事を示す。 + * `false`: そのstepではストレージの内容が変更される可能性はない事を示す。(初期値)" + +#### `#inputs`, `#inputs=(inputs)` {#classes-Droonga-SingleStepDefinition-inputs} + +(未稿) + +#### `#output`, `#output=(output)` {#classes-Droonga-SingleStepDefinition-output} + +(未稿) + +### `Droonga::Handler` {#classes-Droonga-Handler} + +これはすべてのハンドラーに共通の基底クラスです。独自プラグインのハンドラークラスは、このクラスを継承する必要があります。 + +#### `#handle(message)` {#classes-Droonga-Handler-handle} + +このメソッドは、[`Droonga::HandlerMessage`](#classes-Droonga-HandlerMessage)でラップされたタスクメッセージを受け取ります。 +プラグインは、このタスクメッセージのメソッドからリクエストの情報を読み取る事ができます。 + +この基底クラスにおいて、このメソッドは何もしない単なるプレースホルダとして定義されています。 +メッセージを処理するには、以下のようにメソッドを再定義して下さい: + +~~~ruby +module Droonga::Plugins::MySearch + class Handler < Droonga::Handler + def handle(message) + search_query = message.request["body"]["query"] + ... + { ... } # the result + end + end +end +~~~ + +Droonga Engineは、このメソッドの戻り値を処理の結果として扱います。 +結果の値は、レスポンスのbodyの組み立てに使われ、Protocol Adapterに送られます。 + + +### `Droonga::HandlerMessage` {#classes-Droonga-HandlerMessage} + +このクラスはタスクメッセージに対するラッパーとして働きます。 + +Droonga Engineは送られてきたリクエストのメッセージを解析し、そのリクエストを処理するための複数のタスクメッセージを作成します。 +1つのタスクメッセージは、リクエストの実体、step、後続するタスクの一覧などの情報を持ちます。 + +#### `#request` {#classes-Droonga-HandlerMessage-request} + +このメソッドはリクエストメッセージを返します。例: + +~~~ruby +module Droonga::Plugins::MySearch + class Handler < Droonga::Handler + def handle(message) + request = message.request + search_query = request["body"]["query"] + ... + end + end +end +~~~ + +#### `@context` {#classes-Droonga-HandlerMessage-context} + +対応するボリュームのストレージを示す、`Groonga::Context`のインスタンスへの参照。 +[Rroongaのクラスリファレンス][Groonga::Context]も併せて参照して下さい + +`@context`を経由して、Rroongaのすべての機能を利用できます。 +例えば、以下は指定されたテーブルのすべてのレコードの数を返す例です: + +~~~ruby +module Droonga::Plugins::CountRecords + class Handler < Droonga::Handler + def handle(message) + request = message.request + table_name = request["body"]["table"] + count = @context[table_name].size + end + end +end +~~~ + + [error handling]: ../error/ + [collector]: ../collector/ + [Groonga::Context]: http://ranguba.org/rroonga/en/Groonga/Context.html Added: ja/reference/1.0.3/plugin/index.md (+21 -0) 100644 =================================================================== --- /dev/null +++ ja/reference/1.0.3/plugin/index.md 2014-05-19 16:48:30 +0900 (ab39f6b) @@ -0,0 +1,21 @@ +--- +title: プラグイン開発 +layout: ja +--- + +{% comment %} +############################################## + THIS FILE IS AUTOMATICALLY GENERATED FROM + "_po/ja/reference/1.0.3/plugin/index.po" + DO NOT EDIT THIS FILE MANUALLY! +############################################## +{% endcomment %} + + +Droonga Engineはプラグインに対して、処理の各段階ごとに異なるAPIセットを提供します。[プラグイン開発のチュートリアル](../../tutorial/plugin-development/)も参照してください。 + + * [アダプション・フェーズでのAPI](adapter/) + * [ハンドリング・フェーズでのAPI](handler/) + * [メッセージのためのマッチングパターン](matching-pattern/) + * [コレクター](collector/) + * [エラー処理](error/) Added: ja/reference/1.0.3/plugin/matching-pattern/index.md (+242 -0) 100644 =================================================================== --- /dev/null +++ ja/reference/1.0.3/plugin/matching-pattern/index.md 2014-05-19 16:48:30 +0900 (fc8ec94) @@ -0,0 +1,242 @@ +--- +title: メッセージのマッチングパターン +layout: ja +--- + +{% comment %} +############################################## + THIS FILE IS AUTOMATICALLY GENERATED FROM + "_po/ja/reference/1.0.3/plugin/matching-pattern/index.po" + DO NOT EDIT THIS FILE MANUALLY! +############################################## +{% endcomment %} + + +* TOC +{:toc} + + +## 概要 {#abstract} + +Droonga Engineはメッセージのパターンを指定するための小規模な言語を実装しています。これを*マッチングパターン*と呼びます。 +マッチングパターンは、プラグインなどの様々な場所で処理対象のメッセージを指定するために使われます。 + + +## 例 {#examples} + +### 単純なマッチング + + pattern = ["type", :equal, "search"] + +これは以下のようなメッセージにマッチします: + + { + "type": "search", + ... + } + +### 深い位置にある対象へのマッチング + + pattern = ["body.success", :equal, true] + +これは以下のようなメッセージにマッチします: + + { + "type": "add.result", + "body": { + "success": true + } + } + +以下にはマッチしません: + + { + "type": "add.result", + "body": { + "success": false + } + } + +### パターン自体のネスト + + pattern = [ + ["type", :equal, "table_create"], + :or, + ["body.success", :equal, true] + ] + +これは以下の両方にマッチします: + + { + "type": "table_create", + ... + } + +および: + + { + "type": "column_create", + ... + "body": { + "success": true + } + } + + +## 書式 {#syntax} + +マッチングパターンには「基本パターン」と「ネストしたパターン」の2種類があります。 + +### 基本パターン {#syntax-basic} + +#### 構造 {#syntax-basic-structure} + +基本パターンは以下のように、2つ以上の要素を含む配列として表現されます: + + ["type", :equal, "search"] + + * 最初の要素は *ターゲットパス* です。これは、[メッセージ][message]の中でチェックされる情報の位置を示します。 + * 2番目の要素は *演算子* です。これは、ターゲットパスで示された情報をどのようにチェックするかを示します。 + * 3番目の要素は *演算子のための引数* です。これは、プリミティブ値(文字列、数値、または真偽値)、もしくはそれらの値の配列です。ただし、いくつかの演算子は引数を取りません。 + +#### ターゲットパス {#syntax-basic-target-path} + +ターゲットパスは以下の文字列のような形で示します: + + "body.success" + +Droonga Engineのマッチング機構は、これをドットで区切られた *パスコンポーネント* のリストとして解釈します。 +1つのパスコンポーネントはメッセージ中の同名のプロパティを表します。 +よって、上記の例は以下の位置を示します: + + { + "body": { + "success": <target> + } + } + + + + +#### 利用可能な演算子 {#syntax-basic-operators} + +演算子はシンボルとして指定します。 + +`:equal` +: ターゲットの値が与えられた値と等しい場合に `true` を返します。それ以外の場合は `false` を返します。 + 例えば、 + + ["type", :equal, "search"] + + 上記のパターンは以下のようなメッセージにマッチします: + + { + "type": "search", + ... + } + +`:in` +: ターゲットの値が与えられた配列の中に含まれている場合に `true` を返します。それ以外の場合は `false` を返します。 + 例えば、 + + ["type", :in, ["search", "select"]] + + 上記のパターンは以下のようなメッセージにマッチします: + + { + "type": "select", + ... + } + + 以下にはマッチしません: + + { + "type": "find", + ... + } + +`:include` +: ターゲットの値の配列の中に指定された値が含まれている場合に `true` を返します。それ以外の場合は `false` を返します。 + 言い換えると、これは `:in` 演算子の反対の働きをします。 + 例えば、 + + ["body.tags", :include, "News"] + + 上記のパターンは以下のようなメッセージにマッチします: + + { + "type": "my.notification", + "body": { + "tags": ["News", "Groonga", "Droonga", "Fluentd"] + } + } + +`:exist` +: ターゲットに指定された情報が存在する場合は `true` を返します。それ以外の場合は `false` を返します。 + 例えば、 + + ["body.comments", :exist, "News"] + + 上記のパターンは以下のようなメッセージにマッチします: + + { + "type": "my.notification", + "body": { + "title": "Hello!", + "comments": [] + } + } + + 以下にはマッチしません: + + { + "type": "my.notification", + "body": { + "title": "Hello!" + } + } + +`:start_with` +: ターゲットの文字列が指定された文字列で始まる場合に `true` を返します。それ以外の場合は `false` を返します。 + 例えば、 + + ["body.path", :start_with, "/archive/"] + + 上記のパターンは以下のようなメッセージにマッチします: + + { + "type": "my.notification", + "body": { + "path": "/archive/2014/02/28.html" + } + } + + +### ネストしたパターン {#syntax-nested} + +#### 構造 {#syntax-nested-structure} + +ネストしたパターンは、以下のような3つの要素を持つ配列として表現されます: + + [ + ["type", :equal, "table_create"], + :or, + ["type", :equal, "column_create"] + ] + + * 最初の要素と最後の要素は基本パターンまたはネストしたパターンです。(言い換えると、ネストしたパターンは再帰的に書くことができます。) + * 2番目の要素は *論理演算子* です。 + +#### 利用可能な演算子 {#syntax-nested-operators} + +`:and` +: 与えられた両方のパターンが `true` を返す場合に、`true` を返します。それ以外の場合は `false` を返します。 + +`:or` +: 与えられたパターン(1番目または3番目の要素)のいずれかまたは両方が `true` を返す場合に `true` を返します。それ以外の場合は `false` を返します。 + + + + + [message]:../../message/ + Added: ja/tutorial/1.0.3/basic/index.md (+1508 -0) 100644 =================================================================== --- /dev/null +++ ja/tutorial/1.0.3/basic/index.md 2014-05-19 16:48:30 +0900 (171e62a) @@ -0,0 +1,1508 @@ +--- +title: "Droonga チュートリアル: 基本的な使い方" +layout: ja +--- + +{% comment %} +############################################## + THIS FILE IS AUTOMATICALLY GENERATED FROM + "_po/ja/tutorial/1.0.3/basic/index.po" + DO NOT EDIT THIS FILE MANUALLY! +############################################## +{% endcomment %} + + +* TOC +{:toc} + +## チュートリアルのゴール + +Droonga を使った検索システムを自分で構築できるようになる。 + +## 前提条件 + +* [Ubuntu][] Server を自分でセットアップしたり、基本的な操作ができること +* [Ruby][] と [Node.js][] の基本的な知識があること + +## 概要 + +### 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 に渡され、最終的にユーザに返ります。 + +例として、[ニューヨークにあるスターバックスの店舗](http://geocommons.com/overlays/430038)を検索できるデータベースシステムを作成することにします。 + + +## 実験用のマシンを用意する + +まずコンピュータを調達しましょう。このチュートリアルでは、既存のコンピュータにDroongaによる検索システムを構築する手順を解説します。 +以降の説明は基本的に、[DigitalOcean](https://www.digitalocean.com/)で `Ubuntu 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 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": { + "Starbucks": { + "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`を以下のように定義しています: + + * 最上位には1つのボリュームがあり、このボリュームには「レプリカ」と名付けられた2つのサブボリュームが含まれる。 + * 1段階下がった次のレベルには、1つのレプリカ・ボリュームごとに「スライス」と名付けられた3つのサブボリュームが含まれる。 + これらはDroongaのデータセットの最小の構成要素である。 + +これらの6つの、`"address"`の情報を持つ最小単位のボリュームは、内部的に*シングル・ボリューム*と呼ばれます。 +`"address"`の情報は、対応する物理的なストレージであるGroongaのデータベースの位置を示していて、それらのデータベースは`droonga-engine`によって自動的に作成されます。 + +`catalog.json` の詳細については [catalog.json](/ja/reference/catalog) を参照してください。 + +### droonga-engine を起動する + +以下のようにして droonga-engine を起動します。 + + # droonga-engine --host 192.168.0.10 --log-file=$PWD/droonga-engine.log --daemon --pid-file $PWD/droonga-engine.pid + +### droonga-engine を終了する + +最初にdroonga-engineを終了する方法を知っておきましょう。 + +droonga-engineにSIGTERMを送ります。 + + # kill $(cat droonga-engine.pid) + +これがdroonga-engineを終了する方法です。 + +再度droonga-engineを起動します。 + + # droonga-engine --host 192.168.0.10 --log-file=$PWD/droonga-engine.log --daemon --pid-file $PWD/droonga-engine.pid + +### データベースを作成する + +Dronga Engine が起動したので、データを投入しましょう。 +店舗のデータ `stores.jsons` を用意します。 + +stores.jsons: + +~~~ +{ + "dataset": "Starbucks", + "type": "add", + "body": { + "table": "Store", + "key": "1st Avenue & 75th St. - New York NY (W)", + "values": { + "location": "40.770262,-73.954798" + } + } +} +{ + "dataset": "Starbucks", + "type": "add", + "body": { + "table": "Store", + "key": "76th & Second - New York NY (W)", + "values": { + "location": "40.771056,-73.956757" + } + } +} +{ + "dataset": "Starbucks", + "type": "add", + "body": { + "table": "Store", + "key": "2nd Ave. & 9th Street - New York NY", + "values": { + "location": "40.729445,-73.987471" + } + } +} +{ + "dataset": "Starbucks", + "type": "add", + "body": { + "table": "Store", + "key": "15th & Third - New York NY (W)", + "values": { + "location": "40.733946,-73.9867" + } + } +} +{ + "dataset": "Starbucks", + "type": "add", + "body": { + "table": "Store", + "key": "41st and Broadway - New York NY (W)", + "values": { + "location": "40.755111,-73.986225" + } + } +} +{ + "dataset": "Starbucks", + "type": "add", + "body": { + "table": "Store", + "key": "84th & Third Ave - New York NY (W)", + "values": { + "location": "40.777485,-73.954979" + } + } +} +{ + "dataset": "Starbucks", + "type": "add", + "body": { + "table": "Store", + "key": "150 E. 42nd Street - New York NY (W)", + "values": { + "location": "40.750784,-73.975582" + } + } +} +{ + "dataset": "Starbucks", + "type": "add", + "body": { + "table": "Store", + "key": "West 43rd and Broadway - New York NY (W)", + "values": { + "location": "40.756197,-73.985624" + } + } +} +{ + "dataset": "Starbucks", + "type": "add", + "body": { + "table": "Store", + "key": "Macy's 35th Street Balcony - New York NY", + "values": { + "location": "40.750703,-73.989787" + } + } +} +{ + "dataset": "Starbucks", + "type": "add", + "body": { + "table": "Store", + "key": "Macy's 6th Floor - Herald Square - New York NY (W)", + "values": { + "location": "40.750703,-73.989787" + } + } +} +{ + "dataset": "Starbucks", + "type": "add", + "body": { + "table": "Store", + "key": "Herald Square- Macy's - New York NY", + "values": { + "location": "40.750703,-73.989787" + } + } +} +{ + "dataset": "Starbucks", + "type": "add", + "body": { + "table": "Store", + "key": "Macy's 5th Floor - Herald Square - New York NY (W)", + "values": { + "location": "40.750703,-73.989787" + } + } +} +{ + "dataset": "Starbucks", + "type": "add", + "body": { + "table": "Store", + "key": "80th & York - New York NY (W)", + "values": { + "location": "40.772204,-73.949862" + } + } +} +{ + "dataset": "Starbucks", + "type": "add", + "body": { + "table": "Store", + "key": "Columbus @ 67th - New York NY (W)", + "values": { + "location": "40.774009,-73.981472" + } + } +} +{ + "dataset": "Starbucks", + "type": "add", + "body": { + "table": "Store", + "key": "45th & Broadway - New York NY (W)", + "values": { + "location": "40.75766,-73.985719" + } + } +} +{ + "dataset": "Starbucks", + "type": "add", + "body": { + "table": "Store", + "key": "Marriott Marquis - Lobby - New York NY", + "values": { + "location": "40.759123,-73.984927" + } + } +} +{ + "dataset": "Starbucks", + "type": "add", + "body": { + "table": "Store", + "key": "Second @ 81st - New York NY (W)", + "values": { + "location": "40.77466,-73.954447" + } + } +} +{ + "dataset": "Starbucks", + "type": "add", + "body": { + "table": "Store", + "key": "52nd & Seventh - New York NY (W)", + "values": { + "location": "40.761829,-73.981141" + } + } +} +{ + "dataset": "Starbucks", + "type": "add", + "body": { + "table": "Store", + "key": "1585 Broadway (47th) - New York NY (W)", + "values": { + "location": "40.759806,-73.985066" + } + } +} +{ + "dataset": "Starbucks", + "type": "add", + "body": { + "table": "Store", + "key": "85th & First - New York NY (W)", + "values": { + "location": "40.776101,-73.949971" + } + } +} +{ + "dataset": "Starbucks", + "type": "add", + "body": { + "table": "Store", + "key": "92nd & 3rd - New York NY (W)", + "values": { + "location": "40.782606,-73.951235" + } + } +} +{ + "dataset": "Starbucks", + "type": "add", + "body": { + "table": "Store", + "key": "165 Broadway - 1 Liberty - New York NY (W)", + "values": { + "location": "40.709727,-74.011395" + } + } +} +{ + "dataset": "Starbucks", + "type": "add", + "body": { + "table": "Store", + "key": "1656 Broadway - New York NY (W)", + "values": { + "location": "40.762434,-73.983364" + } + } +} +{ + "dataset": "Starbucks", + "type": "add", + "body": { + "table": "Store", + "key": "54th & Broadway - New York NY (W)", + "values": { + "location": "40.764275,-73.982361" + } + } +} +{ + "dataset": "Starbucks", + "type": "add", + "body": { + "table": "Store", + "key": "Limited Brands-NYC - New York NY", + "values": { + "location": "40.765219,-73.982025" + } + } +} +{ + "dataset": "Starbucks", + "type": "add", + "body": { + "table": "Store", + "key": "19th & 8th - New York NY (W)", + "values": { + "location": "40.743218,-74.000605" + } + } +} +{ + "dataset": "Starbucks", + "type": "add", + "body": { + "table": "Store", + "key": "60th & Broadway-II - New York NY (W)", + "values": { + "location": "40.769196,-73.982576" + } + } +} +{ + "dataset": "Starbucks", + "type": "add", + "body": { + "table": "Store", + "key": "63rd & Broadway - New York NY (W)", + "values": { + "location": "40.771376,-73.982709" + } + } +} +{ + "dataset": "Starbucks", + "type": "add", + "body": { + "table": "Store", + "key": "195 Broadway - New York NY (W)", + "values": { + "location": "40.710703,-74.009485" + } + } +} +{ + "dataset": "Starbucks", + "type": "add", + "body": { + "table": "Store", + "key": "2 Broadway - New York NY (W)", + "values": { + "location": "40.704538,-74.01324" + } + } +} +{ + "dataset": "Starbucks", + "type": "add", + "body": { + "table": "Store", + "key": "2 Columbus Ave. - New York NY (W)", + "values": { + "location": "40.769262,-73.984764" + } + } +} +{ + "dataset": "Starbucks", + "type": "add", + "body": { + "table": "Store", + "key": "NY Plaza - New York NY (W)", + "values": { + "location": "40.702802,-74.012784" + } + } +} +{ + "dataset": "Starbucks", + "type": "add", + "body": { + "table": "Store", + "key": "36th and Madison - New York NY (W)", + "values": { + "location": "40.748917,-73.982683" + } + } +} +{ + "dataset": "Starbucks", + "type": "add", + "body": { + "table": "Store", + "key": "125th St. btwn Adam Clayton & FDB - New York NY", + "values": { + "location": "40.808952,-73.948229" + } + } +} +{ + "dataset": "Starbucks", + "type": "add", + "body": { + "table": "Store", + "key": "70th & Broadway - New York NY (W)", + "values": { + "location": "40.777463,-73.982237" + } + } +} +{ + "dataset": "Starbucks", + "type": "add", + "body": { + "table": "Store", + "key": "2138 Broadway - New York NY (W)", + "values": { + "location": "40.781078,-73.981167" + } + } +} +{ + "dataset": "Starbucks", + "type": "add", + "body": { + "table": "Store", + "key": "118th & Frederick Douglas Blvd. - New York NY (W)", + "values": { + "location": "40.806176,-73.954109" + } + } +} +{ + "dataset": "Starbucks", + "type": "add", + "body": { + "table": "Store", + "key": "42nd & Second - New York NY (W)", + "values": { + "location": "40.750069,-73.973393" + } + } +} +{ + "dataset": "Starbucks", + "type": "add", + "body": { + "table": "Store", + "key": "Broadway @ 81st - New York NY (W)", + "values": { + "location": "40.784972,-73.978987" + } + } +} +{ + "dataset": "Starbucks", + "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 --tag starbucks 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": "Starbucks", + "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 + +次に、サーバを起動します。 + + # droonga-http-server --port 3000 \ + --receive-host-name=192.168.0.10 \ + --droonga-engine-host-name=192.168.0.10 \ + --default-dataset=Starbucks \ + --daemon \ + --pid-file $PWD/droonga-http-server.pid + + +### HTTPでの検索リクエスト + +準備が整いました。 Protocol Adapter に向けて HTTP 経由でリクエストを発行し、データベースに問い合わせを行ってみましょう。まずは `Shops` テーブルの中身を取得してみます。以下のようなリクエストを用います。(`attributes=_key` を指定しているのは「検索結果に `_key` 値を含めて返してほしい」という意味です。これがないと、`records` に何も値がないレコードが返ってきてしまいます。`attributes` パラメータには `,` 区切りで複数の属性を指定することができます。`attributes=_key,location` と指定することで、緯度経度もレスポンスとして受け取ることができます) + + # curl "http://192.168.0.10:3000/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:3000/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の詳細については[リファレンスマニュアル][http-server]を参照して下さい。 + + +## まとめ + +[Ubuntu Linux][Ubuntu] 上に [Droonga][] を構成するパッケージである [droonga-engine][] と [droonga-http-server][] をセットアップしました。 +これらのパッケージを利用することで、HTTP Protocol Adapter と Droonga Engine からなるシステムを構築し、実際に検索を行いました。 + + + [http-server]: ../../reference/http-server/ + [Ubuntu]: http://www.ubuntu.com/ + [Droonga]: https://droonga.org/ + [droonga-engine]: https://github.com/droonga/droonga-engine + [droonga-http-server]: https://github.com/droonga/droonga-http-server + [Groonga]: http://groonga.org/ + [Ruby]: http://www.ruby-lang.org/ + [nvm]: https://github.com/creationix/nvm + [Socket.IO]: http://socket.io/ + [Fluentd]: http://fluentd.org/ + [Node.js]: http://nodejs.org/ Added: ja/tutorial/1.0.3/groonga/index.md (+304 -0) 100644 =================================================================== --- /dev/null +++ ja/tutorial/1.0.3/groonga/index.md 2014-05-19 16:48:30 +0900 (fcc29c3) @@ -0,0 +1,304 @@ +--- +title: "Droongaチュートリアル: Groongaからの移行手順" +layout: ja +--- + +{% comment %} +############################################## + THIS FILE IS AUTOMATICALLY GENERATED FROM + "_po/ja/tutorial/1.0.3/groonga/index.po" + DO NOT EDIT THIS FILE MANUALLY! +############################################## +{% endcomment %} + + +* TOC +{:toc} + +## チュートリアルのゴール + +Droongaクラスタを自分で構築して、[Groonga][groonga]互換のサーバとして利用できるようにするための手順を学ぶこと。 + +## 前提条件 + +* [Ubuntu][]サーバのセットアップと操作について、基本的な知識と経験があること。 +* [Groonga][groonga]のHTTP経由での利用について、基本的な知識と経験があること。 + +## Droongaとは何か? + +Droongaは分散アーキテクチャに基づくデータ処理エンジンで、「distributed-Groonga」がその名の由来です。 +名前が示す通り、Droongaはいくつかの点での改善(具体的には、レプリケーションとシャーディング)を含んだGroonga互換のサーバとして動作することができます。 + +アーキテクチャ、設計、APIなどの点で、DroongaはGroongaと大きく異なっています。 +しかしながら、Droongaを単にGroonga互換のサーバとして使う限りにおいては、Droongaのアーキテクチャ全体を理解する必要はありません。 + +例として、[ニューヨークにあるスターバックスの店舗](http://geocommons.com/overlays/430038)を検索できるデータベースシステムを作成することにします。 + +## Droongaクラスタをセットアップする + +### 実験用の環境を準備する + +まず最初にコンピュータを用意します。 +このチュートリアルは、既存のコンピュータを使ってDroongaクラスタを構築する手順について解説しています。 +以下の説明は基本的には、[DigitalOcean](https://www.digitalocean.com/)上のサーバで`Ubuntu 13.10 x64`の仮想マシンが正しく準備されており、コンソールが利用できる状態になっている、という前提に基づいています。 + +注意:Droongaの依存パッケージをインストールする前に、仮想マシンのインスタンスが少なくとも2GB以上のメモリを備えていることを確認して下さい。 +メモリが足らないと、ビルド時におかしなエラーに遭遇することになります。 + +また、有効なレプリケーションを実現するためには2台以上のコンピュータを用意する必要もあります。 + +### Droongaの構成コンポーネントをインストールする + +Groongaはバイナリのパッケージを提供しているため、環境によっては簡単にインストールできます。 +([Groongaのインストール手順](http://groonga.org/docs/install.html)を参照) + +しかしながら、現在の所Droongaに基づくデータベースシステムをセットアップするための簡単な方法はありません。 +将来的にはより良い方法(例えばChefのクックブックなど)を用意する計画がありますが、今のところは、セットアップは手動で行う必要があります。 + +Droongaベースのデータベースシステムは、*Droongaクラスタ*と呼ばれます。 +Droongaクラスタは、*Droongaノード*と呼ばれる複数のコンピュータによって構成されます。 +よって、Droongaクラスタを構築するには複数のDroongaノードをセットアップする必要があります。 + +`192.168.0.10`と`192.168.0.11`の2つのコンピュータがあると仮定しましょう。 + + 1. *それぞれのコンピュータで*、プラットフォームごとに要求されるパッケージをインストールする。 + + # apt-get update + # apt-get -y upgrade + # apt-get install -y ruby ruby-dev build-essential nodejs npm + + 2. *それぞれのコンピュータで*、Gemパッケージ `droonga-engine` をインストールする。 + これはDroongaシステムの主要な機能を提供する、核となるコンポーネントです。 + + # gem install droonga-engine + + 3. *それぞれのコンピュータで*、npmパッケージ `droonga-http-server` をインストールする。 + これはHTTPのリクエストをDroongaネイティブのリクエストに変換するために必要な、フロントエンドとなるコンポーネントです。 + + # npm install -g droonga-http-server + + 4. *それぞれのコンピュータで*、[Serf][]のコマンドをインストールします。 + これはクラスタの各ノードの死活監視を行うために必要です。 + + # wget https://dl.bintray.com/mitchellh/serf/0.5.0_linux_amd64.zip + # unzip 0.5.0_linux_amd64.zip + # sudo mv serf /usr/local/bin/ + + 5. *それぞれのコンピュータで*、Droongaノードとしての情報を保存するための設定ディレクトリを用意する。 + すべてのデータベースの実体は、このディレクトリ以下に保存されます。 + + # mkdir ~/droonga + # cd ~/droonga + + 6. *いずれか1つのDroongaノードで*、`catalog.json`を作成します。 + このファイルはDroongaクラスタの構成を定義する物です。 + データセット名を`--dataset`オプション、各DroongaノードのIPアドレスを`--hosts`オプションで、以下のように指定して下さい: + + # droonga-catalog-generate --dataset=Starbucks \ + --hosts=192.168.0.10,192.168.0.11 \ + --output=./catalog.json + + コンピュータが1台だけの単なる検証用の構成をセットアップする場合は、以下のようにします: + + # droonga-catalog-generate --dataset=Starbucks \ + --hosts=127.0.0.1 \ + --output=./catalog.json + +7. *すべてのDroongaノードに*、先程作成した`catalog.json`を共有します。 + + # scp ~/droonga/catalog.json 192.168.0.11:~/droonga/ + + (もしくは、できあがったファイルをコピーする代わりに、各コンピュータ上で同じ設定の`catalog.json`を作成しても結構です。) + +上記の手順により、DroongaクラスタのためのすべてのDroongaノードの準備が完了しました。 +次の段階に進みましょう。 + +## DroongaクラスタをHTTP経由で使用する + +### 各Droongaノードの上でのサービスの開始と停止 + +GroongaをHTTPサーバとして使う場合は、以下のように `-d` オプションを指定するだけでサーバを起動できます: + + # groonga -p 10041 -d --protocol http /tmp/databases/db + +一方、DroongaクラスタをHTTP経由で使うためには、各Droongaノードにおいて複数のサービスを起動する必要があります。 + +サービスを起動するには、各Droongaノードで以下のようにコマンドを実行します: + + # cd ~/droonga + # host=192.168.0.10 + # droonga-engine --host=$host \ + --daemon \ + --pid-file=$PWD/droonga-engine.pid + # droonga-http-server --port=10041 \ + --receive-host-name=$host \ + --droonga-engine-host-name=$host \ + --default-dataset=Starbucks \ + --daemon \ + --pid-file=$PWD/droonga-http-server.pid + # serf agent -node="${host}:10031" -bind=$host \ + -event-handler="droonga-handle-serf-event --base-dir $PWD" & + +いくつかのオプションにおいて、そのDroongaノード自身のホスト名を指定する必要がある事に注意して下さい。 +この情報は、クラスタ無いのたのDroongaノードとの通信のために使われます。 +よって、別のDroongaノード上では以下のように別のホスト名を指定する事になります: + + # cd ~/droonga + # host=192.168.0.11 + # droonga-engine --host=$host \ + ... + +その後、死活監視のために、"192.168.0.10" のノードにおいて以下のコマンドを実行します: + + # serf join 192.168.0.11 + +このコマンドにより、2つのノードはクラスタを形成し、互いの生死を監視するようになります。もしクラスタ内のどれか1つのノードが機能を停止し、他のノードがまだ機能し続けていた場合には、残ったノードがDroongaクラスタとして動作し続けます。そのため、そのような事態が起こっても秘密裏に、機能停止したノードを復旧したりクラスタに復帰させたりすることができます。 + +サービスを停止するには、以下のコマンドを各Droongaノード上で実行します: + + # kill $(cat ~/droonga/droonga-engine.pid) + # kill $(cat ~/droonga/droonga-http-server.pid) + # serf leave + +### Create a table + +Now your Droonga cluster actually works as a Groonga's HTTP server. + +Requests are completely same to ones for a Groonga server. +To create a new table `Store`, you just have to send a GET request for the `table_create` command, like: + + # endpoint="http://192.168.0.10:10041/d" + # curl "${endpoint}/table_create?name=Store&type=Hash&key_type=ShortText" + [[0,1398662266.3853862,0.08530688285827637],true] + +Note that you have to specify the host, one of Droonga nodes with active droonga-http-server, in your Droonga cluster. +In other words, you can use any favorite node in the cluster as an endpoint. +All requests will be distributed to suitable nodes in the cluster. + +OK, now the table has been created successfully. +Let's see it by the `table_list` command: + + # curl "${endpoint}/table_list" + [[0,1398662423.509928,0.003869295120239258],[[["id","UInt32"],["name","ShortText"],["path","ShortText"],["flags","ShortText"],["domain","ShortText"],["range","ShortText"],["default_tokenizer","ShortText"],["normalizer","ShortText"]],[256,"Store","/home/username/groonga/droonga-engine/000/db.0000100","TABLE_HASH_KEY|PERSISTENT","ShortText",null,null,null]]] + +Because it is a cluster, another endpoint returns same result. + + # curl "http://192.168.0.11:10041/d/table_list" + [[0,1398662423.509928,0.003869295120239258],[[["id","UInt32"],["name","ShortText"],["path","ShortText"],["flags","ShortText"],["domain","ShortText"],["range","ShortText"],["default_tokenizer","ShortText"],["normalizer","ShortText"]],[256,"Store","/home/username/groonga/droonga-engine/000/db.0000100","TABLE_HASH_KEY|PERSISTENT","ShortText",null,null,null]]] + +### Create a column + +Next, create a new column `location` to the `Store` table by the `column_create` command, like: + + # curl "${endpoint}/column_create?table=Store&name=location&flags=COLUMN_SCALAR&type=WGS84GeoPoint" + [[0,1398664305.8856306,0.00026226043701171875],true] + +Then verify that the column is correctly created, by the `column_list` command: + + # curl "${endpoint}/column_list?table=Store" + [[0,1398664345.9680889,0.0011739730834960938],[[["id","UInt32"],["name","ShortText"],["path","ShortText"],["type","ShortText"],["flags","ShortText"],["domain","ShortText"],["range","ShortText"],["source","ShortText"]],[257,"location","/home/username/groonga/droonga-engine/000/db.0000101","fix","COLUMN_SCALAR","Store","WGS84GeoPoint",[]]]] + +### Create indexes + +Create indexes also. + + # curl "${endpoint}/table_create?name=Location&type=PatriciaTrie&key_type=WGS84GeoPoint" + [[0,1398664401.4927232,0.12011909484863281],true] + # curl "${endpoint}/column_create?table=Location&name=store&flags=COLUMN_INDEX&type=Store&source=location" + [[0,1398664429.5348525,0.13435077667236328],true] + # curl "${endpoint}/table_create?name=Term&type=PatriciaTrie&key_type=ShortText&default_tokenizer=TokenBigram&normalizer=NormalizerAuto" + [[0,1398664454.446939,0.14734888076782227],true] + # curl "${endpoint}/column_create?table=Term&name=store__key&flags=COLUMN_INDEX|WITH_POSITION&type=Store&source=_key" + [[0,1398664474.7112074,0.12619781494140625],true] + + +### Load data to a table + +Let's load data to the `Store` table. +First. prepare the data as a JSON file `stores.json`. + +stores.json: + +~~~ +[ +["_key","location"], +["1st Avenue & 75th St. - New York NY (W)","40.770262,-73.954798"], +["76th & Second - New York NY (W)","40.771056,-73.956757"], +["2nd Ave. & 9th Street - New York NY","40.729445,-73.987471"], +["15th & Third - New York NY (W)","40.733946,-73.9867"], +["41st and Broadway - New York NY (W)","40.755111,-73.986225"], +["84th & Third Ave - New York NY (W)","40.777485,-73.954979"], +["150 E. 42nd Street - New York NY (W)","40.750784,-73.975582"], +["West 43rd and Broadway - New York NY (W)","40.756197,-73.985624"], +["Macy's 35th Street Balcony - New York NY","40.750703,-73.989787"], +["Macy's 6th Floor - Herald Square - New York NY (W)","40.750703,-73.989787"], +["Herald Square- Macy's - New York NY","40.750703,-73.989787"], +["Macy's 5th Floor - Herald Square - New York NY (W)","40.750703,-73.989787"], +["80th & York - New York NY (W)","40.772204,-73.949862"], +["Columbus @ 67th - New York NY (W)","40.774009,-73.981472"], +["45th & Broadway - New York NY (W)","40.75766,-73.985719"], +["Marriott Marquis - Lobby - New York NY","40.759123,-73.984927"], +["Second @ 81st - New York NY (W)","40.77466,-73.954447"], +["52nd & Seventh - New York NY (W)","40.761829,-73.981141"], +["1585 Broadway (47th) - New York NY (W)","40.759806,-73.985066"], +["85th & First - New York NY (W)","40.776101,-73.949971"], +["92nd & 3rd - New York NY (W)","40.782606,-73.951235"], +["165 Broadway - 1 Liberty - New York NY (W)","40.709727,-74.011395"], +["1656 Broadway - New York NY (W)","40.762434,-73.983364"], +["54th & Broadway - New York NY (W)","40.764275,-73.982361"], +["Limited Brands-NYC - New York NY","40.765219,-73.982025"], +["19th & 8th - New York NY (W)","40.743218,-74.000605"], +["60th & Broadway-II - New York NY (W)","40.769196,-73.982576"], +["63rd & Broadway - New York NY (W)","40.771376,-73.982709"], +["195 Broadway - New York NY (W)","40.710703,-74.009485"], +["2 Broadway - New York NY (W)","40.704538,-74.01324"], +["2 Columbus Ave. - New York NY (W)","40.769262,-73.984764"], +["NY Plaza - New York NY (W)","40.702802,-74.012784"], +["36th and Madison - New York NY (W)","40.748917,-73.982683"], +["125th St. btwn Adam Clayton & FDB - New York NY","40.808952,-73.948229"], +["70th & Broadway - New York NY (W)","40.777463,-73.982237"], +["2138 Broadway - New York NY (W)","40.781078,-73.981167"], +["118th & Frederick Douglas Blvd. - New York NY (W)","40.806176,-73.954109"], +["42nd & Second - New York NY (W)","40.750069,-73.973393"], +["Broadway @ 81st - New York NY (W)","40.784972,-73.978987"], +["Fashion Inst of Technology - New York NY","40.746948,-73.994557"] +] +~~~ + +Then, send it as a POST request of the `load` command, like: + + # curl --data "@stores.json" "${endpoint}/load?table=Store" + [[0,1398666180.023,0.069],[40]] + +Now all data in the JSON file are successfully loaded. + +### Select data from a table + +OK, all data is now ready. + +As the starter, let's select initial ten records with the `select` command: + + # curl "${endpoint}/select?table=Store&output_columns=_key&limit=10" + [[0,1398666260.887927,0.000017404556274414062],[[[40],[["_key","ShortText"]],[["1st Avenue & 75th St. - New York NY (W)"],["2nd Ave. & 9th Street - New York NY"],["76th & Second - New York NY (W)"],["15th & Third - New York NY (W)"],["41st and Broadway - New York NY (W)"],["West 43rd and Broadway - New York NY (W)"],["84th & Third Ave - New York NY (W)"],["150 E. 42nd Street - New York NY (W)"],["Macy's 35th Street Balcony - New York NY"],["Herald Square- Macy's - New York NY"]]]]] + +Of course you can specify conditions via the `query` option: + + # curl "${endpoint}/select?table=Store&query=Columbus&match_columns=_key&output_columns=_key&limit=10" + [[0,1398670157.661574,0.0012705326080322266],[[[2],[["_key","ShortText"]],[["Columbus @ 67th - New York NY (W)"],["2 Columbus Ave. - New York NY (W)"]]]]] + # curl "${endpoint}/select?table=Store&filter=_key@'Ave'&output_columns=_key&limit=10" + [[0,1398670586.193325,0.0003848075866699219],[[[3],[["_key","ShortText"]],[["2nd Ave. & 9th Street - New York NY"],["84th & Third Ave - New York NY (W)"],["2 Columbus Ave. - New York NY (W)"]]]]] + + +## まとめ + +In this tutorial, you did set up a [Droonga][] cluster on [Ubuntu Linux][Ubuntu] computers. +Moreover, you load data to it and select data from it successfully, as a [Groonga][] compatible server. + +Currently, Droonga supports only some limited features of Groonga compatible commands. +See the [command reference][] for more details. + + [Ubuntu]: http://www.ubuntu.com/ + [Droonga]: https://droonga.org/ + [Groonga]: http://groonga.org/ + [Serf]: http://www.serfdom.io/ + [command reference]: ../../reference/commands/ Added: ja/tutorial/1.0.3/index.md (+27 -0) 100644 =================================================================== --- /dev/null +++ ja/tutorial/1.0.3/index.md 2014-05-19 16:48:30 +0900 (4da3dd4) @@ -0,0 +1,27 @@ +--- +title: Droonga チュートリアル +layout: ja +--- + +{% comment %} +############################################## + THIS FILE IS AUTOMATICALLY GENERATED FROM + "_po/ja/tutorial/1.0.3/index.po" + DO NOT EDIT THIS FILE MANUALLY! +############################################## +{% endcomment %} + + +## Groonga利用者向け + + * [Groongaからの移行手順](groonga/) + +## アプリケーション開発者向け + + * [基本的な使い方のチュートリアル](basic/) + +## プラグイン開発者向け + + * [プラグイン開発のチュートリアル](plugin-development/) + + Added: ja/tutorial/1.0.3/plugin-development/adapter/index.md (+699 -0) 100644 =================================================================== --- /dev/null +++ ja/tutorial/1.0.3/plugin-development/adapter/index.md 2014-05-19 16:48:30 +0900 (3a57278) @@ -0,0 +1,699 @@ +--- +title: "プラグイン: リクエストとレスポンスを加工し、既存のコマンドに基づいた新しいコマンドを作成する" +layout: ja +--- + +{% comment %} +############################################## + THIS FILE IS AUTOMATICALLY GENERATED FROM + "_po/ja/tutorial/1.0.3/plugin-development/adapter/index.po" + DO NOT EDIT THIS FILE MANUALLY! +############################################## +{% endcomment %} + + +* TOC +{:toc} + +## チュートリアルのゴール + +Droongaプラグインを自分で開発するための手順を身につけましょう。 + +このページでは、Droongaプラグインによる「加工」(adaption)に焦点を当てます。 +最後には、小さな練習用のプラグインを開発して、既存の`search`コマンドに基づく新しいコマンド`storeSearch`を開発することになります。 + +## 前提条件 + +* [基本的な使い方のチュートリアル][basic tutorial] を完了している必要があります。 + + +## 入力メッセージの加工 + +まず`sample-logger`という簡単なロガープラグインを使って、アダプション・フェーズに作用するプラグインを作りながら、基礎を学びましょう。 + +外部のシステムからDroonga Engineにやってくるリクエストを加工する必要がある場合があります。このようなときに、プラグインを利用できます。このセクションでは、どのようにしてアダプション・フェーズのプラグインをつくるのかをみていきます。 + +### ディレクトリの構造 + +[基本のチュートリアル][basic tutorial]で作成したシステムに対してプラグインを追加すると仮定します。 +先のチュートリアルでは、Droongaエンジンは `engine` ディレクトリ内に置かれていました。 + +プラグインは、適切な位置のディレクトリに置かれる必要があります。ディレクトリを作成しましょう: + +~~~ +# cd engine +# mkdir -p lib/droonga/plugins +~~~ + +ディレクトリを作成した後は、ディレクトリ構造は以下のようになります: + +~~~ +engine +├── catalog.json +├── fluentd.conf +└── lib + └── droonga + └── plugins +~~~ + + +### プラグインの作成 + +プラグイン用のコードは、*プラグイン自身の名前と同じ名前*のファイルに書く必要があります。 +これから作るプラグインの名前は`sample-logger`なので、コードは`droonga/plugins`ディレクトリ内の`sample-logger.rb`の中に書いていくことになります。 + +lib/droonga/plugins/sample-logger.rb: + +~~~ruby +require "droonga/plugin" + +module Droonga + module Plugins + module SampleLoggerPlugin + extend Plugin + register("sample-logger") + + class Adapter < Droonga::Adapter + # メッセージを加工するためのコードをここに書きます。 + end + end + end +end +~~~ + +このプラグインは、Droonga Engineに自分自身を登録する以外の事は何もしません。 + + * `sample-logger`は、このプラグイン自身の名前です。これは`catalog.json`の中で、プラグインを有効化するために使う事になります。 + * 上記の例のように、プラグインはモジュールとして定義する必要があります。 + * アダプション・フェーズでの振る舞いは、*アダプター*と呼ばれるクラスとして定義します。 + アダプタークラスは必ず、プラグインのモジュールの名前空間の配下で、`Droonga::Adapter`のサブクラスとして定義する必要があります。 + + +### `catalog.json`でプラグインを有効化する + +プラグインを有効化するには、`catalog.json`を更新する必要があります。 +プラグインの名前`"sample-logger"`を、データセットの配下の`"plugins"`のリストに挿入します。例: + +catalog.json: + +~~~ +(snip) + "datasets": { + "Starbucks": { + (snip) + "plugins": ["sample-logger", "groonga", "crud", "search"], +(snip) +~~~ + +注意:`"sample-logger"`は`"search"`よりも前に置く必要があります。これは、`sample-logger`プラグインが`search`に依存しているからです。Droonga Engineはアダプション・フェーズにおいて、プラグインを`catalog.json`で定義された順に適用しますので、プラグイン同士の依存関係は(今のところは)自分で解決しなくてはなりません。 + +### 実行と動作を確認する + +Droongaを起動しましょう。 +Rubyがあなたの書いたプラグインのコード群を見つけられるように、`RUBYLIB`環境変数に`./lib`を加えることに注意して下さい。 + +~~~ +# kill $(cat fluentd.pid) +# RUBYLIB=./lib fluentd --config fluentd.conf --log fluentd.log --daemon fluentd.pid +~~~ + +そうしたら、Engineが正しく動作しているかを確かめます。 +まず、以下のようなJSON形式のリクエストを作成します。 + +search-columbus.json: + +~~~json +{ + "dataset" : "Starbucks", + "type" : "search", + "body" : { + "queries" : { + "stores" : { + "source" : "Store", + "condition" : { + "query" : "Columbus", + "matchTo" : "_key" + }, + "output" : { + "elements" : [ + "startTime", + "elapsedTime", + "count", + "attributes", + "records" + ], + "attributes" : ["_key"], + "limit" : -1 + } + } + } + } +} +~~~ + +これは[基本のチュートリアル](basic tutorial)において"Columbus"を検索する例に対応しています。 +Protocol Adapterへのリクエストは`"body"`要素の中に置かれていることに注意して下さい。 + +`droonga-request`コマンドを使ってリクエストをDroonga Engineに送信します: + +~~~ +# droonga-request --tag starbucks search-columbus.json +Elapsed time: 0.021544 +[ + "droonga.message", + 1392617533, + { + "inReplyTo": "1392617533.9644868", + "statusCode": 200, + "type": "search.result", + "body": { + "stores": { + "count": 2, + "records": [ + [ + "Columbus @ 67th - New York NY (W)" + ], + [ + "2 Columbus Ave. - New York NY (W)" + ] + ] + } + } + } +] +~~~ + +これが検索結果です。 + + +### プラグインを動作させる: ログをとる + +ここまでで作成したプラグインは、何もしない物でした。それでは、このプラグインを何か面白いことをする物にしましょう。 + +まず最初に、`search`のリクエストを捕まえてログ出力してみます。プラグインを以下のように更新して下さい: + +lib/droonga/plugins/sample-logger.rb: + +~~~ruby +(snip) + module SampleLoggerPlugin + extend Plugin + register("sample-logger") + + class Adapter < Droonga::Adapter + input_message.pattern = ["type", :equal, "search"] + + def adapt_input(input_message) + logger.info("SampleLoggerPlugin::Adapter", :message => input_message) + end + end + end +(snip) +~~~ + +`input_message.pattern`で始まる行は、設定です。 +この例では、プラグインを`"type":"search"`という情報を持つすべての入力メッセージに対して働くように定義しています。. +詳しくは[リファレンスマニュアルの設定のセクション](../../../reference/plugin/adapter/#config)を参照して下さい。 + +`adapt_input`メソッドは、パターンに当てはまるすべての入力メッセージに対して毎回呼ばれます。 +引数の`input_message`は、入力メッセージをラップした物です。 + +fluentdを再起動します: + +~~~ +# kill $(cat fluentd.pid) +# RUBYLIB=./lib fluentd --config fluentd.conf --log fluentd.log --daemon fluentd.pid +~~~ + +前のセクションと同じリクエストを送信します: + +~~~ +# droonga-request --tag starbucks search-columbus.json +Elapsed time: 0.014714 +[ + "droonga.message", + 1392618037, + { + "inReplyTo": "1392618037.935901", + "statusCode": 200, + "type": "search.result", + "body": { + "stores": { + "count": 2, + "records": [ + [ + "Columbus @ 67th - New York NY (W)" + ], + [ + "2 Columbus Ave. - New York NY (W)" + ] + ] + } + } + } +] +~~~ + +すると、fluentdのログファイルである`fluentd.log`に以下のようなログが出力される事を確認できるでしょう。 + +~~~ +2014-02-17 15:20:37 +0900 [info]: SampleLoggerPlugin::Adapter message=#<Droonga::InputMessage:0x007f8ae3e1dd98 @raw_message={"dataset"=>"Starbucks", "type"=>"search", "body"=>{"queries"=>{"stores"=>{"source"=>"Store", "condition"=>{"query"=>"Columbus", "matchTo"=>"_key"}, "output"=>{"elements"=>["startTime", "elapsedTime", "count", "attributes", "records"], "attributes"=>["_key"], "limit"=>-1}}}}, "replyTo"=>{"type"=>"search.result", "to"=>"127.0.0.1:64591/droonga"}, "id"=>"1392618037.935901", "date"=>"2014-02-17 15:20:37 +0900", "appliedAdapters"=>[]}> +~~~ + +このログは、メッセージが`SampleLoggerPlugin::Adapter`によって受信されて、Droongaに渡されたことを示しています。実際のデータ処理の前に、この時点でメッセージを加工することができます。 + +### プラグインでメッセージを加工する + +レスポンスで返されるレコードの数を常に1つだけに制限したい場合、すべてのリクエストについて`limit`を`1`に指定する必要があります。プラグインを以下のように変更してみましょう: + +lib/droonga/plugins/sample-logger.rb: + +~~~ruby +(snip) + def adapt_input(input_message) + logger.info("SampleLoggerPlugin::Adapter", :message => input_message) + input_message.body["queries"]["stores"]["output"]["limit"] = 1 + end +(snip) +~~~ + +上の例のように、プラグインは`adapt_input`メソッドの引数として渡される`input_message`を通じて入力メッセージの内容を加工することができます。 +詳細は[当該メッセージの実装であるクラスのリファレンスマニュアル](../../../reference/plugin/adapter/#classes-Droonga-InputMessage)を参照して下さい。 + +fluentdを再起動します: + +~~~ +# kill $(cat fluentd.pid) +# RUBYLIB=./lib fluentd --config fluentd.conf --log fluentd.log --daemon fluentd.pid +~~~ + +再起動後、レスポンスは`records`の値としてレコードを常に(最大で)1つだけ含むようになります。 + +先の場合と同じリクエストを投げてみましょう: + +~~~ +# droonga-request --tag starbucks search-columbus.json +Elapsed time: 0.017343 +[ + "droonga.message", + 1392618279, + { + "inReplyTo": "1392618279.0578449", + "statusCode": 200, + "type": "search.result", + "body": { + "stores": { + "count": 2, + "records": [ + [ + "Columbus @ 67th - New York NY (W)" + ] + ] + } + } + } +] +~~~ + +`count`が依然として`2`であることに注意して下さい。これは、`limit`が`count`には影響を与えないという`search`コマンド自体の仕様によるものです。`search`コマンドの詳細については[`search`コマンドのリファレンスマニュアル][search]を参照して下さい。 + +すると、fluentdのログファイルである`fluentd.log`に以下のようなログが出力される事を確認できるでしょう。 + +~~~ +2014-02-17 15:24:39 +0900 [info]: SampleLoggerPlugin::Adapter message=#<Droonga::InputMessage:0x007f956685c908 @raw_message={"dataset"=>"Starbucks", "type"=>"search", "body"=>{"queries"=>{"stores"=>{"source"=>"Store", "condition"=>{"query"=>"Columbus", "matchTo"=>"_key"}, "output"=>{"elements"=>["startTime", "elapsedTime", "count", "attributes", "records"], "attributes"=>["_key"], "limit"=>-1}}}}, "replyTo"=>{"type"=>"search.result", "to"=>"127.0.0.1:64616/droonga"}, "id"=>"1392618279.0578449", "date"=>"2014-02-17 15:24:39 +0900", "appliedAdapters"=>[]}> +~~~ + + +## 出力メッセージの加工 + +Droonga Engineからの出力メッセージ(例えば検索結果など)を加工したい場合は、別のメソッドを定義することでそれを実現できます。 +このセクションでは、出力メッセージを加工するメソッドを定義してみましょう。 + + +### 出力のメッセージを加工するメソッドを追加する + +`search`コマンドの結果のログを取ってみましょう。 +出力メッセージを処理するために、`adapt_output`メソッドを定義します。 +説明を簡単にするために、ここでは`adapt_input`メソッドの定義を一旦削除します。 + +lib/droonga/plugins/sample-logger.rb: + +~~~ruby +(snip) + module SampleLoggerPlugin + extend Plugin + register("sample-logger") + + class Adapter < Droonga::Adapter + input_message.pattern = ["type", :equal, "search"] + + def adapt_output(output_message) + logger.info("SampleLoggerPlugin::Adapter", :message => output_message) + end + end + end +(snip) +~~~ + +`adapt_output`メソッドは、そのプラグイン自身によって捕捉された入力メッセージに起因して送出された出力メッセージに対してのみ呼ばれます(マッチングパターンのみが指定されていて、`adapt_input`メソッドが定義されていない場合であっても)。 +詳細は[プラグイン開発APIのリファレンスマニュアル](../../../reference/plugin/adapter/)を参照して下さい。 + +### 実行する + +fluentdを再起動しましょう: + +~~~ +# kill $(cat fluentd.pid) +# RUBYLIB=./lib fluentd --config fluentd.conf --log fluentd.log --daemon fluentd.pid +~~~ + +次に、検索リクエストを送ります(前のセクションと同じJSONをリクエストとして使います): + +~~~ +# droonga-request --tag starbucks search-columbus.json +Elapsed time: 0.015491 +[ + "droonga.message", + 1392619269, + { + "inReplyTo": "1392619269.184789", + "statusCode": 200, + "type": "search.result", + "body": { + "stores": { + "count": 2, + "records": [ + [ + "Columbus @ 67th - New York NY (W)" + ], + [ + "2 Columbus Ave. - New York NY (W)" + ] + ] + } + } + } +] +~~~ + +fluentdのログは以下のようになっているはずです: + +~~~ +2014-02-17 15:41:09 +0900 [info]: SampleLoggerPlugin::Adapter message=#<Droonga::OutputMessage:0x007fddcad4d5a0 @raw_message={"dataset"=>"Starbucks", "type"=>"dispatcher", "body"=>{"stores"=>{"count"=>2, "records"=>[["Columbus @ 67th - New York NY (W)"], ["2 Columbus Ave. - New York NY (W)"]]}}, "replyTo"=>{"type"=>"search.result", "to"=>"127.0.0.1:64724/droonga"}, "id"=>"1392619269.184789", "date"=>"2014-02-17 15:41:09 +0900", "appliedAdapters"=>["Droonga::Plugins::SampleLoggerPlugin::Adapter", "Droonga::Plugins::Error::Adapter"]}> +~~~ + +ここには、`search`の結果が`adapt_output`メソッドに渡された事(そしてログ出力された事)が示されています。 + + +### 結果をアダプション・フェーズで加工する + +結果を加工してみましょう。 +例えば、リクエストに対する処理が完了した時刻を示す`completedAt`というアトリビュートを加えるとします。 +プラグインを以下のように更新して下さい: + +lib/droonga/plugins/sample-logger.rb: + +~~~ruby +(snip) + def adapt_output(output_message) + logger.info("SampleLoggerPlugin::Adapter", :message => output_message) + output_message.body["stores"]["completedAt"] = Time.now + end +(snip) +~~~ + +上の例のように、出力メッセージは`adapt_output`メソッドの引数として渡される`output_message`を通じて加工することができます。 +詳細は[当該メッセージの実装のクラスのリファレンスマニュアル](../../../reference/plugin/adapter/#classes-Droonga-OutputMessage)を参照して下さい。 + +fluentdを再起動します: + +~~~ +# kill $(cat fluentd.pid) +# RUBYLIB=./lib fluentd --config fluentd.conf --log fluentd.log --daemon fluentd.pid +~~~ + +同じ検索リクエストを送ってみましょう: + +~~~ +# droonga-request --tag starbucks search-columbus.json +Elapsed time: 0.013983 +[ + "droonga.message", + 1392619528, + { + "inReplyTo": "1392619528.235121", + "statusCode": 200, + "type": "search.result", + "body": { + "stores": { + "count": 2, + "records": [ + [ + "Columbus @ 67th - New York NY (W)" + ], + [ + "2 Columbus Ave. - New York NY (W)" + ] + ], + "completedAt": "2014-02-17T06:45:28.247669Z" + } + } + } +] +~~~ + +リクエストの処理が完了した時刻を含むアトリビュートである`completedAt`が追加された事を確認できました。 +`fluentd.log`には以下のように出力されているはずです: + +~~~ +2014-02-17 15:45:28 +0900 [info]: SampleLoggerPlugin::Adapter message=#<Droonga::OutputMessage:0x007fd384f3ab60 @raw_message={"dataset"=>"Starbucks", "type"=>"dispatcher", "body"=>{"stores"=>{"count"=>2, "records"=>[["Columbus @ 67th - New York NY (W)"], ["2 Columbus Ave. - New York NY (W)"]]}}, "replyTo"=>{"type"=>"search.result", "to"=>"127.0.0.1:64849/droonga"}, "id"=>"1392619528.235121", "date"=>"2014-02-17 15:45:28 +0900", "appliedAdapters"=>["Droonga::Plugins::SampleLoggerPlugin::Adapter", "Droonga::Plugins::Error::Adapter"]}> +~~~ + + +## 入出力メッセージの加工 + +ここまでで、アダプション・フェーズで動作するプラグインの基本を学びました。 +それでは、より実践的なプラグインを開発してみることにしましょう。 + +Droongaの`search`コマンドを見た時、目的に対していささか柔軟すぎるという印象を持ったことと思います +そこで、ここではアプリケーション固有の単純なインターフェースを持つコマンドとして、`search`コマンドをラップする`storeSearch`というコマンドを、`store-search`というプラグインで追加していくことにします。 + +### シンプルなリクエストを受け取る + +まず最初に、`store-search`プラグインを作ります。 +思い出して下さい、プラグインを実装するコードは、これから作ろうとしているプラグインと同じ名前のファイルに書かなくてはなりませんでしたよね。 +ですので、実装を書くファイルは`droonga/plugins`ディレクトリに置かれた`store-search.rb`となります。`StoreSearchPlugin`を以下のように定義しましょう: + +lib/droonga/plugins/store-search.rb: + +~~~ruby +require "droonga/plugin" + +module Droonga + module Plugins + module StoreSearchPlugin + extend Plugin + register("store-search") + + class Adapter < Droonga::Adapter + input_message.pattern = ["type", :equal, "storeSearch"] + + def adapt_input(input_message) + logger.info("StoreSearchPlugin::Adapter", :message => input_message) + + query = input_message.body["query"] + logger.info("storeSearch", :query => query) + + body = { + "queries" => { + "stores" => { + "source" => "Store", + "condition" => { + "query" => query, + "matchTo" => "_key", + }, + "output" => { + "elements" => [ + "startTime", + "elapsedTime", + "count", + "attributes", + "records", + ], + "attributes" => [ + "_key", + ], + "limit" => -1, + } + } + } + } + + input_message.type = "search" + input_message.body = body + end + end + end + end +end +~~~ + +次に、プラグインを有効化するために`catalog.json`を更新します。 +先程作成した`sample-logger`は削除しておきます。 + +catalog.json: + +~~~ +(snip) + "datasets": { + "Starbucks": { + (snip) + "plugins": ["store-search", "groonga", "crud", "search"], +(snip) +~~~ + +思い出して下さい、`"store-search"`は`"search"`に依存しているので、`"search"`よりも前に置く必要があります。 + +fluentdを再起動します: + +~~~ +# kill $(cat fluentd.pid) +# RUBYLIB=./lib fluentd --config fluentd.conf --log fluentd.log --daemon fluentd.pid +~~~ + +これで、以下のようなリクエストで新しいコマンドを使えるようになりました: + +store-search-columbus.json: + +~~~json +{ + "dataset" : "Starbucks", + "type" : "storeSearch", + "body" : { + "query" : "Columbus" + } +} +~~~ + +リクエストを発行するために、以下のようにコマンドを実行しましょう: + +~~~ +# droonga-request --tag starbucks store-search-columbus.json +Elapsed time: 0.01494 +[ + "droonga.message", + 1392621168, + { + "inReplyTo": "1392621168.0119512", + "statusCode": 200, + "type": "storeSearch.result", + "body": { + "stores": { + "count": 2, + "records": [ + [ + "Columbus @ 67th - New York NY (W)" + ], + [ + "2 Columbus Ave. - New York NY (W)" + ] + ] + } + } + } +] +~~~ + +この時、`fluentd.log`には以下のようなログが出力されているはずです: + +~~~ +2014-02-17 16:12:48 +0900 [info]: StoreSearchPlugin::Adapter message=#<Droonga::InputMessage:0x007fe4791d3958 @raw_message={"dataset"=>"Starbucks", "type"=>"storeSearch", "body"=>{"query"=>"Columbus"}, "replyTo"=>{"type"=>"storeSearch.result", "to"=>"127.0.0.1:49934/droonga"}, "id"=>"1392621168.0119512", "date"=>"2014-02-17 16:12:48 +0900", "appliedAdapters"=>[]}> +2014-02-17 16:12:48 +0900 [info]: storeSearch query="Columbus" +~~~ + +以上の手順で、単純なリクエストによって店舗の検索を行えるようになりました。 + +注意:レスポンスのメッセージの`"type"`の値が`"search.result"`から`"storeSearch.result"`に変わっていることに注目して下さい。これは、このレスポンスが、`type`が`"storeSearch"`であるリクエストに起因して発生した物であるために、Droonga Engineによって自動的に`"(入力メッセージのtype).result"`という`type`が設定されたからです。言い換えると、出力メッセージの`type`は、`adapt_input`での`input_message.type = "search"`のような方法でわざわざ自分で設定し直す必要はありません。 + +### シンプルなレスポンスを返す + +次に、結果をより単純な形で、単に店舗の名前の配列だけを返すだけという物にしてみましょう。 + +`adapt_output`を以下のように定義して下さい。 + +lib/droonga/plugins/store-search.rb: + +~~~ruby +(snip) + module StoreSearchPlugin + extend Plugin + register("store-search") + + class Adapter < Droonga::Adapter + (snip) + + def adapt_output(output_message) + logger.info("StoreSearchPlugin::Adapter", :message => output_message) + + records = output_message.body["stores"]["records"] + simplified_results = records.flatten + + output_message.body = simplified_results + end + end + end +(snip) +~~~ + +`adapt_output`メソッドは、そのプラグインによって捕捉された入力メッセージに対応する出力メッセージのみを受け取ります。 + +fluentdを再起動します: + +~~~ +# kill $(cat fluentd.pid) +# RUBYLIB=./lib fluentd --config fluentd.conf --log fluentd.log --daemon fluentd.pid +~~~ + +リクエストを送ってみましょう: + +~~~ +# droonga-request --tag starbucks store-search-columbus.json +Elapsed time: 0.014859 +[ + "droonga.message", + 1392621288, + { + "inReplyTo": "1392621288.158763", + "statusCode": 200, + "type": "storeSearch.result", + "body": [ + "Columbus @ 67th - New York NY (W)", + "2 Columbus Ave. - New York NY (W)" + ] + } +] +~~~ + +`fluentd.log`には以下のようなログが出力されているはずです: + +~~~ +2014-02-17 16:14:48 +0900 [info]: StoreSearchPlugin::Adapter message=#<Droonga::InputMessage:0x007ffb8ada9d68 @raw_message={"dataset"=>"Starbucks", "type"=>"storeSearch", "body"=>{"query"=>"Columbus"}, "replyTo"=>{"type"=>"storeSearch.result", "to"=>"127.0.0.1:49960/droonga"}, "id"=>"1392621288.158763", "date"=>"2014-02-17 16:14:48 +0900", "appliedAdapters"=>[]}> +2014-02-17 16:14:48 +0900 [info]: storeSearch query="Columbus" +2014-02-17 16:14:48 +0900 [info]: StoreSearchPlugin::Adapter message=#<Droonga::OutputMessage:0x007ffb8ad78e48 @raw_message={"dataset"=>"Starbucks", "type"=>"dispatcher", "body"=>{"stores"=>{"count"=>2, "records"=>[["Columbus @ 67th - New York NY (W)"], ["2 Columbus Ave. - New York NY (W)"]]}}, "replyTo"=>{"type"=>"storeSearch.result", "to"=>"127.0.0.1:49960/droonga"}, "id"=>"1392621288.158763", "date"=>"2014-02-17 16:14:48 +0900", "appliedAdapters"=>["Droonga::Plugins::StoreSearchPlugin::Adapter", "Droonga::Plugins::Error::Adapter"], "originalTypes"=>["storeSearch"]}> +~~~ + +このように、単純化されたレスポンスを受け取ることができました。 + +ここで解説したように、アダプターはアプリケーション固有の検索機能を実装するために利用できます。 + +## まとめ + +既存のコマンドと独自のアダプターのみを使って新しいコマンドを追加する方法について学びました。 +その過程で、入力メッセージと出力メッセージの両方について、どのように受け取り加工するのかについても学びました。 + +詳細は[リファレンスマニュアル](../../../reference/plugin/adapter/)を参照して下さい。 + + + [basic tutorial]: ../../basic/ + [overview]: ../../../overview/ + [search]: ../../../reference/commands/select/ Added: ja/tutorial/1.0.3/plugin-development/handler/index.md (+542 -0) 100644 =================================================================== --- /dev/null +++ ja/tutorial/1.0.3/plugin-development/handler/index.md 2014-05-19 16:48:30 +0900 (48210c3) @@ -0,0 +1,542 @@ +--- +title: "プラグイン: 全てのパーティション上でリクエストを処理し、ストレージを操作する新たなコマンドを追加する" +layout: ja +--- + +{% comment %} +############################################## + THIS FILE IS AUTOMATICALLY GENERATED FROM + "_po/ja/tutorial/1.0.3/plugin-development/handler/index.po" + DO NOT EDIT THIS FILE MANUALLY! +############################################## +{% endcomment %} + + +* TOC +{:toc} + +## チュートリアルのゴール + +This tutorial aims to help you to learn how to develop plugins which do something dispersively for/in each volume, around the handling phase. +In other words, this tutorial describes *how to add a new simple command to the Droonga Engine*. + +## 前提条件 + +* You must complete the [tutorial for the adaption phase][adapter]. + +## Handling of requests + +When a request is transferred from the adaption phase, the Droonga Engine enters into the *processing phase*. + +In the processing phase, the Droonga Engine processes the request step by step. +One *step* is constructed from some sub phases: *planning phase*, *distribution phase*, *handling phase*, and *collection phase*. + + * At the *planning phase*, the Droonga Engine generates multiple sub steps to process the request. + In simple cases, you don't have to write codes for this phase, then there is just one sub step to handle the request. + * At the *distribution phase*, the Droonga Engine distributes task messages for the request, to multiple volumes. + (It is completely done by the Droonga Engine itself, so this phase is not pluggable.) + * At the *handling phase*, *each single volume simply processes only one distributed task message as its input, and returns a result.* + This is the time that actual storage accesses happen. + Actually, some commands (`search`, `add`, `create_table` and so on) access to the storage at the time. + * At the *collection phase*, the Droonga Engine collects results from volumes to one unified result. + There are some useful generic collectors, so you don't have to write codes for this phase in most cases. + +After all steps are finished, the Droonga Engine transfers the result to the post adaption phase. + +A class to define operations at the handling phase is called *handler*. +Put simply, adding of a new handler means adding a new command. + + + + + + +## Design a read-only command `countRecords` + +Here, in this tutorial, we are going to add a new custom `countRecords` command. +At first, let's design it. + +The command reports the number of records about a specified table, for each single volume. +So it will help you to know how records are distributed in the cluster. +Nothing is changed by the command, so it is a *read-only command*. + +The request must have the name of one table, like: + +~~~json +{ + "dataset" : "Starbucks", + "type" : "countRecords", + "body" : { + "table": "Store" + } +} +~~~ + +Create a JSON file `count-records.json` with the content above. +We'll use it for testing. + +The response must have number of records in the table, for each single volume. +They can be appear in an array, like: + +~~~json +{ + "inReplyTo": "(message id)", + "statusCode": 200, + "type": "countRecords.result", + "body": [10, 10] +} +~~~ + +If there are 2 volumes and 20 records are stored evenly, the array will have two elements like above. +It means that a volume has 10 records and another one also has 10 records. + +We're going to create a plugin to accept such requests and return such responses. + + +### Directory structure + +The directory structure for plugins are in same rule as explained in the [tutorial for the adaption phase][adapter]. +Now let's create the `count-records` plugin, as the file `count-records.rb`. The directory tree will be: + +~~~ +lib +└── droonga + └── plugins + └── count-records.rb +~~~ + +Then, create a skeleton of a plugin as follows: + +lib/droonga/plugins/count-records.rb: + +~~~ruby +require "droonga/plugin" + +module Droonga + module Plugins + module CountRecordsPlugin + extend Plugin + register("count-records") + end + end +end +~~~ + +### Define a "step" for the command + +Define a "step" for the new `countRecords` command, in your plugin. Like: + +lib/droonga/plugins/count-records.rb: + +~~~ruby +require "droonga/plugin" + +module Droonga + module Plugins + module CountRecordsPlugin + extend Plugin + register("count-records") + + define_single_step do |step| + step.name = "countRecords" + end + end + end +end +~~~ + +The `step.name` equals to the name of the command itself. +Currently we just define the name of the command. +That's all. + +### Define the handling logic + +The command has no handler, so it does nothing yet. +Let's define the behavior. + +lib/droonga/plugins/count-records.rb: + +~~~ruby +require "droonga/plugin" + +module Droonga + module Plugins + module CountRecordsPlugin + extend Plugin + register("count-records") + + define_single_step do |step| + step.name = "countRecords" + step.handler = :Handler + end + + class Handler < Droonga::Handler + def handle(message) + [0] + end + end + end + end +end +~~~ + +The class `Handler` is a handler class for our new command. + + * It must inherit a builtin-class `Droonga::Handler`. + * It implements the logic to handle requests. + Its instance method `#handle` actually handles requests. + +Currently the handler does nothing and returns an result including an array of a number. +The returned value is used to construct the response body. + +The handler is bound to the step with the configuration `step.handler`. +Because we define the class `Handler` after `define_single_step`, we specify the handler class with a symbol `:Handler`. +If you define the handler class before `define_single_step`, then you can write as `step.handler = Handler` simply. +Moreover, a class path string like `"OtherPlugin::Handler"` is also available. + +Then, we also have to bind a collector to the step, with the configuration `step.collector`. + +lib/droonga/plugins/count-records.rb: + +~~~ruby +# (snip) + define_single_step do |step| + step.name = "countRecords" + step.handler = :Handler + step.collector = Collectors::Sum + end +# (snip) +~~~ + +The `Collectors::Sum` is one of built-in collectors. +It merges results returned from handler instances for each volume to one result. + + +### `catalog.json`でプラグインを有効化する + +Update catalog.json to activate this plugin. +Add `"count-records"` to `"plugins"`. + +~~~ +(snip) + "datasets": { + "Starbucks": { + (snip) + "plugins": ["count-records", "groonga", "crud", "search"], +(snip) +~~~ + +### 実行と動作を確認する + +Let's get Droonga started. +Note that you need to specify ./lib directory in RUBYLIB environment variable in order to make ruby possible to find your plugin. + + # kill $(cat fluentd.pid) + # RUBYLIB=./lib fluentd --config fluentd.conf --log fluentd.log --daemon fluentd.pid + +Then, send a request message for the `countRecords` command to the Droonga Engine. + +~~~ +# droonga-request --tag starbucks count-records.json +Elapsed time: 0.01494 +[ + "droonga.message", + 1392621168, + { + "inReplyTo": "1392621168.0119512", + "statusCode": 200, + "type": "countRecords.result", + "body": [ + 0, + 0, + 0 + ] + } +] +~~~ + +You'll get a response message like above. +Look at these points: + + * The `type` of the response becomes `countRecords.result`. + It is automatically named by the Droonga Engine. + * The format of the `body` is same to the returned value of the handler's `handle` method. + +There are three elements in the array. Why? + + * Remember that the `Starbucks` dataset was configured with two replicas and three sub volumes for each replica, in the `catalog.json` of [the basic tutorial][basic]. + * Because it is a read-only command, a request is delivered to only one replica (and it is chosen at random). + Then only three single volumes receive the command, so only three results appear, not six. + (TODO: I have to add a figure to indicate active nodes: [000, 001, 002, 010, 011, 012] => [000, 001, 002]) + * The `Collectors::Sum` collects them. + Those three results are joined to just one array by the collector. + +As the result, just one array with three elements appears in the final response. + +### Read-only access to the storage + +Now, each instance of the handler class always returns `0` as its result. +Let's implement codes to count up the number of records from the actual storage. + +lib/droonga/plugins/count-records.rb: + +~~~ruby +# (snip) + class Handler < Droonga::Handler + def handle(message) + request = message.request + table_name = request["table"] + table = @context[table_name] + count = table.size + [count] + end + end +# (snip) +~~~ + +Look at the argument of the `handle` method. +It is different from the one an adapter receives. +A handler receives a message meaning a distributed task. +So you have to extract the request message from the distributed task by the code `request = message.request`. + +The instance variable `@context` is an instance of `Groonga::Context` for the storage of the corresponding single volume. +See the [class reference of Rroonga][Groonga::Context]. +You can use any feature of Rroonga via `@context`. +For now, we simply access to the table itself by its name and read the value of its `size` method - it returns the number of records. + +Then, test it. +Restart the Droonga Engine and send the request again. + +~~~ +# kill $(cat fluentd.pid) +# RUBYLIB=./lib fluentd --config fluentd.conf --log fluentd.log --daemon fluentd.pid +# droonga-request --tag starbucks count-records.json +Elapsed time: 0.01494 +[ + "droonga.message", + 1392621168, + { + "inReplyTo": "1392621168.0119512", + "statusCode": 200, + "type": "countRecords.result", + "body": [ + 14, + 15, + 11 + ] + } +] +~~~ + +Because there are totally 40 records, they are stored evenly like above. + +## Design a read-write command `deleteStores` + +Next, let's add another new custom command `deleteStores`. + +The command deletes records of the `Store` table, from the storage. +Because it modifies something in existing storage, it is a *read-write command*. + +The request must have the condition to select records to be deleted, like: + +~~~json +{ + "dataset" : "Starbucks", + "type" : "deleteStores", + "body" : { + "keyword": "Broadway" + } +} +~~~ + +Any record including the given keyword `"Broadway"` in its `"key"` is deleted from the storage of all volumes. + +Create a JSON file `delete-stores-broadway.json` with the content above. +We'll use it for testing. + +The response must have a boolean value to indicate "success" or "fail", like: + +~~~json +{ + "inReplyTo": "(message id)", + "statusCode": 200, + "type": "deleteStores.result", + "body": true +} +~~~ + +If the request is successfully processed, the `body` becomes `true`. Otherwise `false`. +The `body` is just one boolean value, because we don't have to receive multiple results from volumes. + + +### ディレクトリの構造 + +Now let's create the `delete-stores` plugin, as the file `delete-stores.rb`. The directory tree will be: + +~~~ +lib +└── droonga + └── plugins + └── delete-stores.rb +~~~ + +Then, create a skeleton of a plugin as follows: + +lib/droonga/plugins/delete-stores.rb: + +~~~ruby +require "droonga/plugin" + +module Droonga + module Plugins + module DeleteStoresPlugin + extend Plugin + register("delete-stores") + end + end +end +~~~ + + +### Define a "step" for the command + +Define a "step" for the new `deleteStores` command, in your plugin. Like: + +lib/droonga/plugins/delete-stores.rb: + +~~~ruby +require "droonga/plugin" + +module Droonga + module Plugins + module DeleteStoresPlugin + extend Plugin + register("delete-stores") + + define_single_step do |step| + step.name = "deleteStores" + step.write = true + end + end + end +end +~~~ + +Look at a new configuration `step.write`. +Because this command modifies the storage, we must indicate it clearly. + +### Define the handling logic + +Let's define the handler. + +lib/droonga/plugins/delete-stores.rb: + +~~~ruby +require "droonga/plugin" + +module Droonga + module Plugins + module DeleteStoresPlugin + extend Plugin + register("delete-stores") + + define_single_step do |step| + step.name = "deleteStores" + step.write = true + step.handler = :Handler + step.collector = Collectors::And + end + + class Handler < Droonga::Handler + def handle(message) + request = message.request + keyword = request["keyword"] + table = @context["Store"] + table.delete do |record| + record.key =~ keyword + end + true + end + end + end + end +end +~~~ + +Remember, you have to extract the request message from the received task message. + +The handler finds and deletes existing records which have the given keyword in its "key", by the [API of Rroonga][Groonga::Table_delete]. + +And, the `Collectors::And` is bound to the step by the configuration `step.collector`. +It is is also one of built-in collectors, and merges boolean values returned from handler instances for each volume, to one boolean value. + +### `catalog.json`でプラグインを有効化する + +Update catalog.json to activate this plugin. +Add `"delete-stores"` to `"plugins"`. + +~~~ +(snip) + "datasets": { + "Starbucks": { + (snip) + "plugins": ["delete-stores", "count-records", "groonga", "crud", "search"], +(snip) +~~~ + +### 実行と動作を確認する + +Restart the Droonga Engine and send the request. + +~~~ +# kill $(cat fluentd.pid) +# RUBYLIB=./lib fluentd --config fluentd.conf --log fluentd.log --daemon fluentd.pid +# droonga-request --tag starbucks count-records.json +Elapsed time: 0.01494 +[ + "droonga.message", + 1392621168, + { + "inReplyTo": "1392621168.0119512", + "statusCode": 200, + "type": "deleteStores.result", + "body": true + } +] +~~~ + +Because results from volumes are unified to just one boolean value, the response's `body` is a `true`. +As the verification, send the request of `countRecords` command. + +~~~ +# droonga-request --tag starbucks count-records.json +Elapsed time: 0.01494 +[ + "droonga.message", + 1392621168, + { + "inReplyTo": "1392621168.0119512", + "statusCode": 200, + "type": "countRecords.result", + "body": [ + 7, + 13, + 6 + ] + } +] +~~~ + +Note, the number of records are smaller than the previous result. +This means that four or some records are deleted from each volume. + +## まとめ + +We have learned how to add a new simple command working around the data. +In the process, we also have learned how to create plugins working in the handling phrase. + + + [adapter]: ../adapter + [basic]: ../basic + [Groonga::Context]: http://ranguba.org/rroonga/en/Groonga/Context.html + [Groonga::Table_delete]: http://ranguba.org/rroonga/en/Groonga/Table.html#delete-instance_method Added: ja/tutorial/1.0.3/plugin-development/index.md (+92 -0) 100644 =================================================================== --- /dev/null +++ ja/tutorial/1.0.3/plugin-development/index.md 2014-05-19 16:48:30 +0900 (4383a04) @@ -0,0 +1,92 @@ +--- +title: Droongaプラグイン開発チュートリアル +layout: ja +--- + +{% comment %} +############################################## + THIS FILE IS AUTOMATICALLY GENERATED FROM + "_po/ja/tutorial/1.0.3/plugin-development/index.po" + DO NOT EDIT THIS FILE MANUALLY! +############################################## +{% endcomment %} + + +* TOC +{:toc} + +## チュートリアルのゴール + +Droongaプラグインの作り方を理解します。 +[基本的な使い方のチュートリアル][basic tutorial]を完了している必要があります。 + + +## プラグインとは + +プラグインはDroongaの中でもっとも重要なコンセプトの一つです。 +プラグインがDroongaを柔軟なものにしています。 + +多くの現実的なデータ処理タスクでは、問題に応じたデータの取り扱いが必要です。これを汎用の方法で解決するのは簡単ではありせん。 + + * 外部のシステムと連携するために、入力のリクエスト形式を変更する必要があるかもしれません。外部のシステムが理解できるような形式で出力するために、出力を加工する必要があるかもしれません。 + * Droongaが標準で提供する機能よりもさらに複雑なデータ操作を、ストレージに直接アクセスしながら効率よく行う必要があるかもしれません。 + * Droongaのデータ分散と回収ロジックをコントロールすることで、Droongaの分散性能を活かした高度なアプリケーションを構築する必要があるかもしれません。 + +このような場合にプラグインを利用することができます。 + +## Droongaエンジンにおけるプラガブルな操作 + +Droonga Engineにはプラガブルなフェーズが大きく分けて2つあり、そのうちの1つは3つのサブフェーズから構成されます。プラグインの観点からすると、都合1つから4つの操作に処理を追加することができます。 + +アダプション・フェーズ +: このフェーズでは、プラグインは入力のリクエストと出力のレスポンスを加工できます。 + +プロセッシング・フェーズ +: このフェーズでは、プラグインはそれぞれのボリューム上で入力のリクエストを逐次処理します。 + +プロセッシング・フェーズには3つのプラガブルなサブフェーズがあります: + +ハンドリング・フェーズ +: このフェーズでは、プラグインは低レベルのデータ処理、たとえばデータベース操作などを行うことができます。 + +プランニング・フェーズ +: このフェーズでは、プラグインは入力のリクエストを複数のステップに分割できます。 + +コレクション・フェーズ +: このフェーズでは、プラグインはステップから得られた結果をマージして一つの結果を生成できます。 + +上記の説明は、Droongaシステムの設計に基いているので、少々わかりづらいかもしれません。 +ここでは、プラガブルな操作という観点から離れて、プラグインで何をしたいのかという観点から見てみましょう。 + +既に存在するコマンドを元にして新たなコマンドを作成する +: たとえば、複雑な`search`コマンドをラップして、手軽に使えるコマンドを作りたいかもしれません。 + リクエストとレスポンスに対する*アダプション*がそれを可能にします。 + +新しいコマンドを追加してストレージを操作する +: たとえば、ストレージに保存されているデータを自在に操作したいかもしれません。 + リクエストに対する*ハンドリング*がそれを可能にします。 + +複雑なタスクを実現するコマンドを追加する +: たとえば、標準の`search`コマンドのような強力なコマンドを実装したいかもしれません。リクエストに対する*プランニング*と*コレクション*がそれを可能にします。 + +このチュートリアルでは、最初に*アダプション*を扱います。 +これはもっともプラグインの基本的なユースケースなので、Droongaにおけるプラグイン開発の基礎を理解する助けになるはずです。 +その後、他のケースも上述の順で説明します。 +このチュートリアルに従うと、プラグインの書き方を理解できるようになります。 +自分独自の要求を満たすプラグインを作成するための第一歩となることでしょう。 + +## プラグインを開発するには + +詳細は以下のサブチュートリアルを参照してください: + + 1. [リクエストとレスポンスを加工し、既存のコマンドに基づいた新たなコマンドを作成する][adapter]。 + 2. [全てのボリューム上でリクエストを処理し、ストレージを操作する新たなコマンドを追加する][handler]。 + 3. 特定のボリューム上だけでリクエストを処理し、より効率的にストレージを操作するコマンドを追加する (準備中) + 4. リクエストの分散とレスポンスの回収を行い、新たな複雑なコマンドを追加する (準備中) + + + [basic tutorial]: ../basic/ + [overview]: ../../overview/ + [adapter]: ./adapter/ + [handler]: ./handler/ + [distribute-collect]: ./distribute-collect/ Added: ja/tutorial/1.0.3/watch.md (+217 -0) 100644 =================================================================== --- /dev/null +++ ja/tutorial/1.0.3/watch.md 2014-05-19 16:48:30 +0900 (587333f) @@ -0,0 +1,217 @@ +--- +title: Droonga チュートリアル +layout: ja +--- + +{% comment %} +############################################## + THIS FILE IS AUTOMATICALLY GENERATED FROM + "_po/ja/tutorial/1.0.3/watch.po" + DO NOT EDIT THIS FILE MANUALLY! +############################################## +{% endcomment %} + + +* TOC +{:toc} + +## Real-time search + +Droonga supports streaming-style real-time search. + +### Update configurations of the Droonga engine + +Update your fluentd.conf and catalog.jsons, like: + +fluentd.conf: + + <source> + type forward + port 24224 + </source> + <match starbucks.message> + name localhost:24224/starbucks + type droonga + </match> + + <match droonga.message> + + name localhost:24224/droonga + + type droonga + + </match> + <match output.message> + type stdout + </match> + +catalog.json: + + { + "effective_date": "2013-09-01T00:00:00Z", + "zones": [ + + "localhost:24224/droonga", + "localhost:24224/starbucks" + ], + "farms": { + + "localhost:24224/droonga": { + + "device": ".", + + "capacity": 10 + + }, + "localhost:24224/starbucks": { + "device": ".", + "capacity": 10 + } + }, + "datasets": { + + "Watch": { + + "workers": 2, + + "plugins": ["search", "groonga", "add", "watch"], + + "number_of_replicas": 1, + + "number_of_partitions": 1, + + "partition_key": "_key", + + "date_range": "infinity", + + "ring": { + + "localhost:23041": { + + "weight": 50, + + "partitions": { + + "2013-09-01": [ + + "localhost:24224/droonga.watch" + + ] + + } + + } + + } + + }, + "Starbucks": { + "workers": 0, + "plugins": ["search", "groonga", "add"], + "number_of_replicas": 2, + "number_of_partitions": 2, + "partition_key": "_key", + "date_range": "infinity", + "ring": { + "localhost:23041": { + "weight": 50, + "partitions": { + "2013-09-01": [ + "localhost:24224/starbucks.000", + "localhost:24224/starbucks.001" + ] + } + }, + "localhost:23042": { + "weight": 50, + "partitions": { + "2013-09-01": [ + "localhost:24224/starbucks.002", + "localhost:24224/starbucks.003" + ] + } + } + } + } + }, + "options": { + "plugins": [] + } + } + +### Add a streaming API to the protocol adapter + + +Add a streaming API to the protocol adapter, like; + +application.js: + + var express = require('express'), + droonga = require('express-droonga'); + + var application = express(); + var server = require('http').createServer(application); + server.listen(3000); // the port to communicate with clients + + //============== INSERTED ============== + var streaming = { + 'streaming': new droonga.command.HTTPStreaming({ + dataset: 'Watch', + path: '/watch', + method: 'GET', + subscription: 'watch.subscribe', + unsubscription: 'watch.unsubscribe', + notification: 'watch.notification', + createSubscription: function(request) { + return { + condition: request.query.query + }; + } + }) + }; + //============= /INSERTED ============== + + application.droonga({ + prefix: '/droonga', + tag: 'starbucks', + defaultDataset: 'Starbucks', + server: server, // this is required to initialize Socket.IO API! + plugins: [ + droonga.API_REST, + droonga.API_SOCKET_IO, + droonga.API_GROONGA, + droonga.API_DROONGA + //============== INSERTED ============== + ,streaming + //============= /INSERTED ============== + ] + }); + + application.get('/', function(req, res) { + res.sendfile(__dirname + '/index.html'); + }); + +### Prepare feeds + +Prepare "feed"s like: + +feeds.jsons: + + {"id":"feed:0","dataset":"Watch","type":"watch.feed","body":{"targets":{"key":"old place 0"}}} + {"id":"feed:1","dataset":"Watch","type":"watch.feed","body":{"targets":{"key":"new place 0"}}} + {"id":"feed:2","dataset":"Watch","type":"watch.feed","body":{"targets":{"key":"old place 1"}}} + {"id":"feed:3","dataset":"Watch","type":"watch.feed","body":{"targets":{"key":"new place 1"}}} + {"id":"feed:4","dataset":"Watch","type":"watch.feed","body":{"targets":{"key":"old place 2"}}} + {"id":"feed:5","dataset":"Watch","type":"watch.feed","body":{"targets":{"key":"new place 2"}}} + +### Try it! + +At first, restart servers in each console. + +The engine: + + # fluentd --config fluentd.conf + +The protocol adapter: + + # nodejs application.js + +Next, connect to the streaming API via curl: + + # curl "http://localhost:3000/droonga/watch?query=new" + +Then the client starts to receive streamed results. + +Next, open a new console and send "feed"s to the engine like: + + # fluent-cat droonga.message < feeds.jsons + +Then the client receives three results "new place 0", "new place 1", and "new place 2" like: + + {"targets":{"key":"new place 0"}} + {"targets":{"key":"new place 1"}} + {"targets":{"key":"new place 2"}} + +They are search results for the query "new", given as a query parameter of the streaming API. + +Results can be appear in different order, like: + + {"targets":{"key":"new place 1"}} + {"targets":{"key":"new place 0"}} + {"targets":{"key":"new place 2"}} + +because "feed"s are processed in multiple workers asynchronously. + Added: reference/1.0.3/catalog/index.md (+13 -0) 100644 =================================================================== --- /dev/null +++ reference/1.0.3/catalog/index.md 2014-05-19 16:48:30 +0900 (1f11907) @@ -0,0 +1,13 @@ +--- +title: Catalog +layout: en +--- + +A Droonga network consists of several resources. You need to describe +them in **catalog**. All the nodes in the network shares the same +catalog. + +Catalog specification is versioned. Here are available versions: + + * [version 2](version2/) + * [version 1](version1/): (It is deprecated since 1.0.0.) Added: reference/1.0.3/catalog/version1/index.md (+320 -0) 100644 =================================================================== --- /dev/null +++ reference/1.0.3/catalog/version1/index.md 2014-05-19 16:48:30 +0900 (f2af226) @@ -0,0 +1,320 @@ +--- +title: Catalog +layout: en +--- + +A Droonga network consists of several resources. You need to describe +them in **catalog**. All the nodes in the network shares the same +catalog. + +This documentation describes about catalog. + + * TOC +{:toc} + +## How to manage + +So far, you need to write catalog and share it to all the nodes +manually. + +Some utility programs will generate catalog in near feature. +Furthermore Droonga network will maintain and share catalog +automatically. + +## Glossary + +This section describes terms in catalog. + +### Catalog + +Catalog is a series of data which represents the resources in the +network. + +### Zone + +Zone is a set of farms. Farms in a zone are expected to close to each +other, like in the same host, in the same switch, in the same network. + +### Farm + +A farm is a Droonga Engine instance. Droonga Engine is implemented as +a [Fluentd][] plugin, fluent-plugin-droonga. + +A `fluentd` process can have multiple Droonga Engines. If you add one +or more `match` entries with type `droonga` into `fluentd.conf`, a +`fluentd` process instantiates one or more Droonga Engines. + +A farm has its own workers and a job queue. A farm push request to its +job queue and workers pull a request from the job queue. + +### Dataset + +Dataset is a set of logical tables. A logical table must belong to +only one dataset. + +Each dataset must have an unique name in the same Droonga network. + +### Logical table + +Logical table consists of one or more partitioned physical tables. +Logical table doesn't have physical records. It returns physical +records from physical tables. + +You can custom how to partition a logical table into one or more +physical tables. For example, you can custom partition key, the +number of partitions and so on. + +### Physical table + +Physical table is a table in Groonga database. It stores physical +records to the table. + +### Ring + +Ring is a series of partition sets. Dataset must have one +ring. Dataset creates logical tables on the ring. + +Droonga Engine replicates each record in a logical table into one or +more partition sets. + +### Partition set + +Partition set is a set of partitions. A partition set stores all +records in all logical tables in the same Droonga network. In other +words, dataset is partitioned in a partition set. + +A partition set is a replication of other partition set. + +Droonga Engine may support partitioning in one or more partition +sets in the future. It will be useful to use different partition +size for old data and new data. Normally, old data are smaller and +new data are bigger. It is reasonable that you use larger partition +size for bigger data. + +### Partition + +Partition is a Groonga database. It has zero or more physical +tables. + +### Plugin + +Droonga Engine can be extended by writing plugin scripts. +In most cases, a series of plugins work cooperatively to +achieve required behaviors. +So, plugins are organized by behaviors. +Each behavior can be attached to datasets and/or tables by +adding "plugins" section to the corresponding entry in the catalog. + +More than one plugin can be assigned in a "plugins" section as an array. +The order in the array controls the execution order of plugins +when adapting messages. +When adapting an incoming message, plugins are applied in forward order +whereas those are applied in reverse order when adapting an outgoing message. + +## Example + +Consider the following case: + + * There are two farms. + * All farms (Droonga Engine instances) works on the same fluentd. + * Each farm has two partitions. + * There are two replicas. + * There are two partitions for each table. + +Catalog is written as a JSON file. Its file name is `catalog.json`. + +Here is a `catalog.json` for the above case: + +~~~json +{ + "version": 1, + "effective_date": "2013-06-05T00:05:51Z", + "zones": ["localhost:23003/farm0", "localhost:23003/farm1"], + "farms": { + "localhost:23003/farm0": { + "device": "disk0", + "capacity": 1024 + }, + "localhost:23003/farm1": { + "device": "disk1", + "capacity": 1024 + } + }, + "datasets": { + "Wiki": { + "workers": 4, + "plugins": ["groonga", "crud", "search"], + "number_of_replicas": 2, + "number_of_partitions": 2, + "partition_key": "_key", + "date_range": "infinity", + "ring": { + "localhost:23004": { + "weight": 10, + "partitions": { + "2013-07-24": [ + "localhost:23003/farm0.000", + "localhost:23003/farm1.000" + ] + } + }, + "localhost:23005": { + "weight": 10, + "partitions": { + "2013-07-24": [ + "localhost:23003/farm1.001", + "localhost:23003/farm0.001" + ] + } + } + } + } + } +} +~~~ + +## Parameters + +Here are descriptions about parameters in `catalog.json`. + +### `version` {#version} + +It is a format version of the catalog file. + +Droonga Engine will change `catalog.json` format in the +future. Droonga Engine can provide auto format update feature with the +information. + +The value must be `1`. + +This is a required parameter. + +Example: + +~~~json +{ + "version": 1 +} +~~~ + +### `effective_date` + +It is a date string representing the day the catalog becomes +effective. + +The date string format must be [W3C-DTF][]. + +This is a required parameter. + +Note: fluent-plugin-droonga 0.8.0 doesn't use this value yet. + +Example: + +~~~json +{ + "effective_date": "2013-11-29T11:29:29Z" +} +~~~ + +### `zones` + +`Zones` is an array to express proximities between farms. +Farms are grouped by a zone, and zones can be grouped by another zone recursively. +Zones make a single tree structure, expressed by nested arrays. +Farms in a same branch are regarded as relatively closer than other farms. + +e.g. + +When the value of `zones` is as follows, + +``` +[["A", ["B", "C"]], "D"] +``` + +it expresses the following tree. + + /\ + /\ D + A /\ + B C + +This tree means the farm "B" and "C" are closer than "A" or "D" to each other. +You should make elements in a `zones` close to each other, like in the +same host, in the same switch, in the same network. + +This is an optional parameter. + +Note: fluent-plugin-droonga 0.8.0 doesn't use this value yet. + +Example: + +~~~json +{ + "zones": [ + ["localhost:23003/farm0", + "localhost:23003/farm1"], + ["localhost:23004/farm0", + "localhost:23004/farm1"] + ] +} +~~~ + +*TODO: Discuss about the call of this parameter. This seems completely equals to the list of keys of `farms`.* + +### `farms` + +It is an array of Droonga Engine instances. + +*TODO: Improve me. For example, we have to describe relations of nested farms, ex. `children`.* + +**Farms** correspond with fluent-plugin-droonga instances. A fluentd process may have multiple **farms** if more than one **match** entry with type **droonga** appear in the "fluentd.conf". +Each **farm** has its own job queue. +Each **farm** can attach to a data partition which is a part of a **dataset**. + +This is a required parameter. + +Example: + +~~~json +{ + "farms": { + "localhost:23003/farm0": { + "device": "/disk0", + "capacity": 1024 + }, + "localhost:23003/farm1": { + "device": "/disk1", + "capacity": 1024 + } + } +} +~~~ + +### `datasets` + +A **dataset** is a set of **tables** which comprise a single logical **table** virtually. +Each **dataset** must have a unique name in the network. + +### `ring` + +`ring` is a series of partitions which comprise a dataset. `replica_count`, `number_of_partitons` and **time-slice** factors affect the number of partitions in a `ring`. + +### `workers` + +`workers` is an integer number which specifies the number of worker processes to deal with the dataset. +If `0` is specified, no worker is forked and all operations are done in the master process. + +### `number_of_partitions` + +`number_of_partition` is an integer number which represents the number of partitions divided by the hash function. The hash function which determines where each record resides the partition in a dataset is compatible with memcached. + +### `date_range` + +`date_range` determines when to split the dataset. If a string "infinity" is assigned, dataset is never split by time factor. + +### `number_of_replicas` + +`number_of_replicas` represents the number of replicas of dataset maintained in the network. + + [Fluentd]: http://fluentd.org/ + [W3C-DTF]: http://www.w3.org/TR/NOTE-datetime "Date and Time Formats" Added: reference/1.0.3/catalog/version2/index.md (+858 -0) 100644 =================================================================== --- /dev/null +++ reference/1.0.3/catalog/version2/index.md 2014-05-19 16:48:30 +0900 (6ea8075) @@ -0,0 +1,858 @@ +--- +title: Catalog +layout: en +--- + +* TOC +{:toc} + +## Abstract {#abstract} + +`Catalog` is a JSON data to manage the configuration of a Droonga cluster. +A Droonga cluster consists of one or more `datasets`, and a `dataset` consists of other portions. They all must be explicitly described in a `catalog` and be shared with all the hosts in the cluster. + +## Usage {#usage} + +This [`version`](#parameter-version) of `catalog` will be available from Droonga 1.0.0. + +## Syntax {#syntax} + + { + "version": <Version number>, + "effectiveDate": "<Effective date>", + "datasets": { + "<Name of the dataset 1>": { + "nWorkers": <Number of workers>, + "plugins": [ + "Name of the plugin 1", + ... + ], + "schema": { + "<Name of the table 1>": { + "type" : <"Array", "Hash", "PatriciaTrie" or "DoubleArrayTrie"> + "keyType" : "<Type of the primary key>", + "tokenizer" : "<Tokenizer>", + "normalizer" : "<Normalizer>", + "columns" : { + "<Name of the column 1>": { + "type" : <"Scalar", "Vector" or "Index">, + "valueType" : "<Type of the value>", + "vectorOptions": { + "weight" : <Weight>, + }, + "indexOptions" : { + "section" : <Section>, + "weight" : <Weight>, + "position" : <Position>, + "sources" : [ + "<Name of a column to be indexed>", + ... + ] + } + }, + "<Name of the column 2>": { ... }, + ... + } + }, + "<Name of the table 2>": { ... }, + ... + }, + "fact": "<Name of the fact table>", + "replicas": [ + { + "dimension": "<Name of the dimension column>", + "slicer": "<Name of the slicer function>", + "slices": [ + { + "label": "<Label of the slice>", + "volume": { + "address": "<Address string of the volume>" + } + }, + ... + } + }, + ... + ] + }, + "<Name of the dataset 2>": { ... }, + ... + } + } + +## Details {#details} + +### Catalog definition {#catalog} + +Value +: An object with the following key/value pairs. + +#### Parameters + +##### `version` {#parameter-version} + +Abstract +: Version number of the catalog file. + +Value +: `2`. (Specification written in this page is valid only when this value is `2`) + +Default value +: None. This is a required parameter. + +Inheritable +: False. + +##### `effectiveDate` {#parameter-effective_date} + +Abstract +: The time when this catalog becomes effective. + +Value +: A local time string formatted in the [W3C-DTF](http://www.w3.org/TR/NOTE-datetime "Date and Time Formats"), with the time zone. + +Default value +: None. This is a required parameter. + +Inheritable +: False. + +##### `datasets` {#parameter-datasets} + +Abstract +: Definition of datasets. + +Value +: An object keyed by the name of the dataset with value the [`dataset` definition](#dataset). + +Default value +: None. This is a required parameter. + +Inheritable +: False. + +##### `nWorkers` {#parameter-n_workers} + +Abstract +: The number of worker processes spawned for each database instance. + +Value +: An integer value. + +Default value +: 0 (No worker. All operations are done in the master process) + +Inheritable +: True. Overridable in `dataset` and `volume` definition. + + +#### Example + +A version 2 catalog effective after `2013-09-01T00:00:00Z`, with no datasets: + +~~~ +{ + "version": 2, + "effectiveDate": "2013-09-01T00:00:00Z", + "datasets": { + } +} +~~~ + +### Dataset definition {#dataset} + +Value +: An object with the following key/value pairs. + +#### Parameters + +##### `plugins` {#parameter-plugins} + +Abstract +: Name strings of the plugins enabled for the dataset. + +Value +: An array of strings. + +Default value +: None. This is a required parameter. + +Inheritable +: True. Overridable in `dataset` and `volume` definition. + +##### `schema` {#parameter-schema} + +Abstract +: Definition of tables and their columns. + +Value +: An object keyed by the name of the table with value the [`table` definition](#table). + +Default value +: None. This is a required parameter. + +Inheritable +: True. Overridable in `dataset` and `volume` definition. + +##### `fact` {#parameter-fact} + +Abstract +: The name of the fact table. When a `dataset` is stored as more than one `slice`, one [fact table](http://en.wikipedia.org/wiki/Fact_table) must be selected from tables defined in [`schema`](#parameter-schema) parameter. + +Value +: A string. + +Default value +: None. + +Inheritable +: True. Overridable in `dataset` and `volume` definition. + +##### `replicas` {#parameter-replicas} + +Abstract +: A collection of volumes which are the copies of each other. + +Value +: An array of [`volume` definitions](#volume). + +Default value +: None. This is a required parameter. + +Inheritable +: False. + +#### Example + +A dataset with 4 workers per a database instance, with plugins `groonga`, `crud` and `search`: + +~~~ +{ + "nWorkers": 4, + "plugins": ["groonga", "crud", "search"], + "schema": { + }, + "replicas": [ + ] +} +~~~ + +### Table definition {#table} + +Value +: An object with the following key/value pairs. + +#### Parameters + +##### `type` {#parameter-table-type} + +Abstract +: Specifies which data structure is used for managing keys of the table. + +Value +: Any of the following values. + +* `"Array"`: for tables which have no keys. +* `"Hash"`: for hash tables. +* `"PatriciaTrie"`: for patricia trie tables. +* `"DoubleArrayTrie"`: for double array trie tables. + +Default value +: `"Hash"` + +Inheritable +: False. + +##### `keyType` {#parameter-keyType} + +Abstract +: Data type of the key of the table. Mustn't be assigned when the `type` is `"Array"`. + +Value +: Any of the following data types. + +* `"Integer"` : 64bit signed integer. +* `"Float"` : 64bit floating-point number. +* `"Time"` : Time value with microseconds resolution. +* `"ShortText"` : Text value up to 4095 bytes length. +* `"TokyoGeoPoint"` : Tokyo Datum based geometric point value. +* `"WGS84GeoPoint"` : [WGS84](http://en.wikipedia.org/wiki/World_Geodetic_System) based geometric point value. + +Default value +: None. Mandatory for tables with keys. + +Inheritable +: False. + +##### `tokenizer` {#parameter-tokenizer} + +Abstract +: Specifies the type of tokenizer used for splitting each text value, when the table is used as a lexicon. Only available when the `keyType` is `"ShortText"`. + +Value +: Any of the following tokenizer names. + +* `"TokenDelimit"` +* `"TokenUnigram"` +* `"TokenBigram"` +* `"TokenTrigram"` +* `"TokenBigramSplitSymbol"` +* `"TokenBigramSplitSymbolAlpha"` +* `"TokenBigramSplitSymbolAlphaDigit"` +* `"TokenBigramIgnoreBlank"` +* `"TokenBigramIgnoreBlankSplitSymbol"` +* `"TokenBigramIgnoreBlankSplitSymbolAlpha"` +* `"TokenBigramIgnoreBlankSplitSymbolAlphaDigit"` +* `"TokenDelimitNull"` + +Default value +: None. + +Inheritable +: False. + +##### `normalizer` {#parameter-normalizer} + +Abstract +: Specifies the type of normalizer which normalizes and restricts the key values. Only available when the `keyType` is `"ShortText"`. + +Value +: Any of the following normalizer names. + +* `"NormalizerAuto"` +* `"NormalizerNFKC51"` + +Default value +: None. + +Inheritable +: False. + +##### `columns` {#parameter-columns} + +Abstract +: Column definition for the table. + +Value +: An object keyed by the name of the column with value the [`column` definition](#column). + +Default value +: None. + +Inheritable +: False. + +#### Examples + +##### Example 1: Hash table + +A `Hash` table whose key is `ShortText` type, with no columns: + +~~~ +{ + "type": "Hash", + "keyType": "ShortText", + "columns": { + } +} +~~~ + +##### Example 2: PatriciaTrie table + +A `PatriciaTrie` table with `TokenBigram` tokenizer and `NormalizerAuto` normalizer, with no columns: + +~~~ +{ + "type": "PatriciaTrie", + "keyType": "ShortText", + "tokenizer": "TokenBigram", + "normalizer": "NormalizerAuto", + "columns": { + } +} +~~~ + +### Column definition {#column} + +Value + +: An object with the following key/value pairs. + +#### Parameters + +##### `type` {#parameter-column-type} + +Abstract +: Specifies the quantity of data stored as each column value. + +Value +: Any of the followings. + +* `"Scalar"`: A single value. +* `"Vector"`: A list of values. +* `"Index"` : A set of unique values with additional properties respectively. Properties can be specified in [`indexOptions`](#parameter-indexOptions). + +Default value +: `"Scalar"` + +Inheritable +: False. + +##### `valueType` {#parameter-valueType} + +Abstract +: Data type of the column value. + +Value +: Any of the following data types or the name of another table defined in the same dataset. When a table name is assigned, the column acts as a foreign key references the table. + +* `"Bool"` : `true` or `false`. +* `"Integer"` : 64bit signed integer. +* `"Float"` : 64bit floating-point number. +* `"Time"` : Time value with microseconds resolution. +* `"ShortText"` : Text value up to 4,095 bytes length. +* `"Text"` : Text value up to 2,147,483,647 bytes length. +* `"TokyoGeoPoint"` : Tokyo Datum based geometric point value. +* `"WGS84GeoPoint"` : [WGS84](http://en.wikipedia.org/wiki/World_Geodetic_System) based geometric point value. + +Default value +: None. This is a required parameter. + +Inheritable +: False. + +##### `vectorOptions` {#parameter-vectorOptions} + +Abstract +: Specifies the optional properties of a "Vector" column. + +Value +: An object which is a [`vectorOptions` definition](#vectorOptions) + +Default value +: `{}` (Void object). + +Inheritable +: False. + +##### `indexOptions` {#parameter-indexOptions} + +Abstract +: Specifies the optional properties of an "Index" column. + +Value +: An object which is an [`indexOptions` definition](#indexOptions) + +Default value +: `{}` (Void object). + +Inheritable +: False. + +#### Examples + +##### Example 1: Scalar column + +A scaler column to store `ShortText` values: + +~~~ +{ + "type": "Scalar", + "valueType": "ShortText" +} +~~~ + +##### Example 2: Vector column + +A vector column to store `ShortText` values with weight: + +~~~ +{ + "type": "Scalar", + "valueType": "ShortText", + "vectorOptions": { + "weight": true + } +} +~~~ + +##### Example 3: Index column + +A column to index `address` column on `Store` table: + +~~~ +{ + "type": "Index", + "valueType": "Store", + "indexOptions": { + "sources": [ + "address" + ] + } +} +~~~ + +### vectorOptions definition {#vectorOptions} + +Value +: An object with the following key/value pairs. + +#### Parameters + +##### `weight` {#parameter-vectorOptions-weight} + +Abstract +: Specifies whether the vector column stores the weight data or not. Weight data is used for indicating the importance of the value. + +Value +: A boolean value (`true` or `false`). + +Default value +: `false`. + +Inheritable +: False. + +#### Example + +Store the weight data. + +~~~ +{ + "weight": true +} +~~~ + +### indexOptions definition {#indexOptions} + +Value +: An object with the following key/value pairs. + +#### Parameters + +##### `section` {#parameter-indexOptions-section} + +Abstract +: Specifies whether the index column stores the section data or not. Section data is typically used for distinguishing in which part of the sources the value appears. + +Value +: A boolean value (`true` or `false`). + +Default value +: `false`. + +Inheritable +: False. + +##### `weight` {#parameter-indexOptions-weight} + +Abstract +: Specifies whether the index column stores the weight data or not. Weight data is used for indicating the importance of the value in the sources. + +Value +: A boolean value (`true` or `false`). + +Default value +: `false`. + +Inheritable +: False. + +##### `position` {#parameter-indexOptions-position} + +Abstract +: Specifies whether the index column stores the position data or not. Position data is used for specifying the position where the value appears in the sources. It is indispensable for fast and accurate phrase-search. + +Value +: A boolean value (`true` or `false`). + +Default value +: `false`. + +Inheritable +: False. + +##### `sources` {#parameter-indexOptions-sources} + +Abstract +: Makes the column an inverted index of the referencing table's columns. + +Value +: An array of column names of the referencing table assigned as [`valueType`](#parameter-valueType). + +Default value +: None. + +Inheritable +: False. + +#### Example + +Store the section data, the weight data and the position data. +Index `name` and `address` on the referencing table. + +~~~ +{ + "section": true, + "weight": true, + "position": true + "sources": [ + "name", + "address" + ] +} +~~~ + +### Volume definition {#volume} + +Abstract +: A unit to compose a dataset. A dataset consists of one or more volumes. A volume consists of either a single instance of database or a collection of `slices`. When a volume consists of a single database instance, `address` parameter must be assigned and the other parameters must not be assigned. Otherwise, `dimension`, `slicer` and `slices` are required, and vice versa. + +Value +: An object with the following key/value pairs. + +#### Parameters + +##### `address` {#parameter-address} + +Abstract +: Specifies the location of the database instance. + +Value +: A string in the following format. + +"[database_type:]hostname[:port_number]/localpath/to/the/database" + +* database_type: Optional. Default value is "groonga". +* port_number: Optional. Default value is 10047. + +Default value +: None. + +Inheritable +: False. + +##### `dimension` {#parameter-dimension} + +Abstract +: Specifies the dimension to slice the records in the fact table. Either '_key" or a scalar type column can be selected from [`columns`](#parameter-columns) parameter of the fact table. See [dimension](http://en.wikipedia.org/wiki/Dimension_%28data_warehouse%29). + +Value +: A string. + +Default value +: `"_key"` + +Inheritable +: True. Overridable in `dataset` and `volume` definition. + +##### `slicer` {#parameter-slicer} + +Abstract +: Function to slice the value of dimension column. + +Value +: Name of slicer function. + +Default value +: `"hash"` + +Inheritable +: True. Overridable in `dataset` and `volume` definition. + +In order to define a volume which consists of a collection of `slices`, +the way how slice records into slices must be decided. + +The slicer function that specified as `slicer` and +the column (or key) specified as `dimension`, +which is input for the slicer function, defines that. + +Slicers are categorized into three types. Here are three types of slicers: + +Ratio-scaled +: *Ratio-scaled slicers* slice datapoints in the specified ratio, + e.g. hash function of _key. + Slicers of this type are: + + * `hash` + +Ordinal-scaled +: *Ordinal-scaled slicers* slice datapoints with ordinal values; + the values have some ranking, e.g. time, integer, + element of `{High, Middle, Low}`. + Slicers of this type are: + + * (not implemented yet) + +Nominal-scaled +: *Nominal-scaled slicers* slice datapoints with nominal values; + the values denotes categories,which have no order, + e.g. country, zip code, color. + Slicers of this type are: + + * (not implemented yet) + +##### `slices` {#parameter-slices} + +Abstract +: Definition of slices which store the contents of the data. + +Value +: An array of [`slice` definitions](#slice). + +Default value +: None. + +Inheritable +: False. + +#### Examples + +##### Example 1: Single instance + +A volume at "localhost:24224/volume.000": + +~~~ +{ + "address": "localhost:24224/volume.000" +} +~~~ + +##### Example 2: Slices + +A volume that consists of three slices, records are to be distributed according to `hash`, +which is ratio-scaled slicer function, of `_key`. + +~~~ +{ + "dimension": "_key", + "slicer": "hash", + "slices": [ + { + "volume": { + "address": "localhost:24224/volume.000" + } + }, + { + "volume": { + "address": "localhost:24224/volume.001" + } + }, + { + "volume": { + "address": "localhost:24224/volume.002" + } + } + ] +~~~ + +### Slice definition {#slice} + +Abstract +: Definition of each slice. Specifies the range of sliced data and the volume to store the data. + +Value +: An object with the following key/value pairs. + +#### Parameters + +##### `weight` {#parameter-slice-weight} + +Abstract +: Specifies the share in the slices. Only available when the `slicer` is ratio-scaled. + +Value +: A numeric value. + +Default value +: `1`. + +Inheritable +: False. + +##### `label` {#parameter-label} + +Abstract +: Specifies the concrete value that slicer may return. Only available when the slicer is nominal-scaled. + +Value +: A value of the dimension column data type. When the value is not provided, this slice is regarded as *else*; matched only if all other labels are not matched. Therefore, only one slice without `label` is allowed in slices. + +Default value +: None. + +Inheritable +: False. + +##### `boundary` {#parameter-boundary} + +Abstract +: Specifies the concrete value that can compare with `slicer`'s return value. Only available when the `slicer` is ordinal-scaled. + +Value +: A value of the dimension column data type. When the value is not provided, this slice is regarded as *else*; this means the slice is open-ended. Therefore, only one slice without `boundary` is allowed in a slices. + +Default value +: None. + +Inheritable +: False. + +##### `volume` {#parameter-volume} + +Abstract +: A volume to store the data which corresponds to the slice. + +Value + +: An object which is a [`volume` definition](#volume) + +Default value +: None. + +Inheritable +: False. + +#### Examples + +##### Example 1: Ratio-scaled + +Slice for a ratio-scaled slicer, with the weight `1`: + +~~~ +{ + "weight": 1, + "volume": { + } +} +~~~ + +##### Example 2: Nominal-scaled + +Slice for a nominal-scaled slicer, with the label `"1"`: + +~~~ +{ + "label": "1", + "volume": { + } +} +~~~ + +##### Example 3: Ordinal-scaled + +Slice for a ordinal-scaled slicer, with the boundary `100`: + +~~~ +{ + "boundary": 100, + "volume": { + } +} +~~~ + +## Realworld example + +See the catalog of [basic tutorial]. + + [basic tutorial]: ../../../tutorial/basic Added: reference/1.0.3/commands/add/index.md (+228 -0) 100644 =================================================================== --- /dev/null +++ reference/1.0.3/commands/add/index.md 2014-05-19 16:48:30 +0900 (92b32a1) @@ -0,0 +1,228 @@ +--- +title: add +layout: en +--- + +* TOC +{:toc} + +## Abstract {#abstract} + +The `add` command adds a new record to the specified table. Column values of the existing record are updated by given values, if the table has a primary key and there is existing record with the specified key. + +Style +: Request-Response. One response message is always returned per one request. + +`type` of the request +: `add` + +`body` of the request +: A hash of parameters. + +`type` of the response +: `add.result` + +## Parameter syntax {#syntax} + +If the table has a primary key column: + + { + "table" : "<Name of the table>", + "key" : "<The primary key of the record>", + "values" : { + "<Name of the column 1>" : <value 1>, + "<Name of the column 2>" : <value 2>, + ... + } + } + +If the table has no primary key column: + + { + "table" : "<Name of the table>", + "values" : { + "<Name of the column 1>" : <value 1>, + "<Name of the column 2>" : <value 2>, + ... + } + } + +## Usage {#usage} + +This section describes how to use the `add` command, via a typical usage with following two tables: + +Person table (without primary key): + +|name|job (referring the Job table)| +|Alice Arnold|announcer| +|Alice Cooper|musician| + +Job table (with primary key) + +|_key|label| +|announcer|announcer| +|musician|musician| + + +### Adding a new record to a table without primary key {#adding-record-to-table-without-key} + +Specify only `table` and `values`, without `key`, if the table has no primary key. + + { + "type" : "add", + "body" : { + "table" : "Person", + "values" : { + "name" : "Bob Dylan", + "job" : "musician" + } + } + } + + => { + "type" : "add.result", + "body" : true + } + +The `add` command works recursively. If there is no existing record with the key in the referred table, then it is also automatically added silently so you'll see no error response. For example this will add a new Person record with a new Job record named `doctor`. + + { + "type" : "add", + "body" : { + "table" : "Person", + "values" : { + "name" : "Alice Miller", + "job" : "doctor" + } + } + } + + => { + "type" : "add.result", + "body" : true + } + +By the command above, a new record will be automatically added to the Job table like; + +|_key|label| +|announcer|announcer| +|musician|musician| +|doctor|(blank)| + + +### Adding a new record to a table with primary key {#adding-record-to-table-with-key} + +Specify all parameters `table`, `values` and `key`, if the table has a primary key column. + + { + "type" : "add", + "body" : { + "table" : "Job", + "key" : "writer", + "values" : { + "label" : "writer" + } + } + } + + => { + "type" : "add.result", + "body" : true + } + +### Updating column values of an existing record {#updating} + +This command works as "updating" operation, if the table has a primary key column and there is an existing record for the specified key. + + { + "type" : "add", + "body" : { + "table" : "Job", + "key" : "doctor", + "values" : { + "label" : "doctor" + } + } + } + + => { + "type" : "add.result", + "body" : true + } + + +You cannot update column values of existing records, if the table has no primary key column. Then this command will always work as "adding" operation for the table. + + +## Parameter details {#parameters} + +### `table` {#parameter-table} + +Abstract +: The name of a table which a record is going to be added to. + +Value +: A name string of an existing table. + +Default value +: Nothing. This is a required parameter. + +### `key` {#parameter-key} + +Abstract +: The primary key for the record going to be added. + +Value +: A primary key string. + +Default value +: Nothing. This is required if the table has a primary key column. Otherwise, this is ignored. + +Existing column values will be updated, if there is an existing record for the key. + +This parameter will be ignored if the table has no primary key column. + +### `values` {#parameter-values} + +Abstract +: New values for columns of the record. + +Value +: A hash. Keys of the hash are column names, values of the hash are new values for each column. + +Default value +: `null` + +Value of unspecified columns will not be changed. + + +## Responses {#response} + +This returns a boolean value `true` like following as the response's `body`, with `200` as its `statusCode`, if a record is successfully added or updated. + + true + +## Error types {#errors} + +This command reports errors not only [general errors](/reference/message/#error) but also followings. + +### `MissingTableParameter` + +Means you've forgotten to specify the `table` parameter. The status code is `400`. + +### `MissingPrimaryKeyParameter` + +Means you've forgotten to specify the `key` parameter, for a table with the primary key column. The status code is `400`. + +### `InvalidValue` + +Means you've specified an invalid value for a column. For example, a string for a geolocation column, a string for an integer column, etc. The status code is `400`. + +### `UnknownTable` + +Means you've specified a table which is not existing in the specified dataset. The status code is `404`. + +### `UnknownColumn` + +Means you've specified any column which is not existing in the specified table. The status code is `404`. + Added: reference/1.0.3/commands/column-create/index.md (+76 -0) 100644 =================================================================== --- /dev/null +++ reference/1.0.3/commands/column-create/index.md 2014-05-19 16:48:30 +0900 (471424c) @@ -0,0 +1,76 @@ +--- +title: column_create +layout: en +--- + +* TOC +{:toc} + +## Abstract {#abstract} + +The `column_create` command creates a new column into the specified table. + +This is compatible to [the `column_create` command of the Groonga](http://groonga.org/docs/reference/commands/column_create.html). + +Style +: Request-Response. One response message is always returned per one request. + +`type` of the request +: `column_create` + +`body` of the request +: A hash of parameters. + +`type` of the response +: `column_create.result` + +## Parameter syntax {#syntax} + + { + "table" : "<Name of the table>", + "name" : "<Name of the column>", + "flags" : "<Flags for the column>", + "type" : "<Type of the value>", + "source" : "<Name of a column to be indexed>" + } + +## Parameter details {#parameters} + +All parameters except `table` and `name` are optional. + +They are compatible to [the parameters of the `column_create` command of the Groonga](http://groonga.org/docs/reference/commands/column_create.html#parameters). See the linked document for more details. + +## Responses {#response} + +This returns an array meaning the result of the operation, as the `body`. + + [ + [ + <Groonga's status code>, + <Start time>, + <Elapsed time> + ], + <Column is successfully created or not> + ] + +This command always returns a response with `200` as its `statusCode`, because this is a Groonga compatible command and errors of this command must be handled in the way same to Groonga's one. + +Response body's details: + +Status code +: An integer meaning the operation's result. Possible values are: + + * `0` (`Droonga::GroongaHandler::Status::SUCCESS`) : Successfully processed. + * `-22` (`Droonga::GroongaHandler::Status::INVALID_ARGUMENT`) : There is any invalid argument. + +Start time +: An UNIX time which the operation was started on. + +Elapsed time +: A decimal of seconds meaning the elapsed time for the operation. + +Column is successfully created or not +: A boolean value meaning the column was successfully created or not. Possible values are: + + * `true`:The column was successfully created. + * `false`:The column was not created. Added: reference/1.0.3/commands/index.md (+24 -0) 100644 =================================================================== --- /dev/null +++ reference/1.0.3/commands/index.md 2014-05-19 16:48:30 +0900 (3b8d792) @@ -0,0 +1,24 @@ +--- +title: Commands +layout: en +--- + +Here are available commands + +## Built-in commands + + * [search](search/): Searches data + * [add](add/): Adds a record + +## Groonga compatible commands + + * [column_create](column-create/) + * [column_list](column-list/) + * [column_remove](column-remove/) + * [column_rename](column-rename/) + * [delete](delete/) + * [load](load/) + * [select](select/) + * [table_create](table-create/) + * [table_list](table-list/) + * [table_remove](table-remove/) Added: reference/1.0.3/commands/search/index.md (+1290 -0) 100644 =================================================================== --- /dev/null +++ reference/1.0.3/commands/search/index.md 2014-05-19 16:48:30 +0900 (cf2ad54) @@ -0,0 +1,1290 @@ +--- +title: search +layout: en +--- + +* TOC +{:toc} + +## Abstract {#abstract} + +The `search` command finds records from the specified table based on given conditions, and returns found records and/or related information. + +This is designed as the most basic (low layer) command on Droonga, to search information from a database. When you want to add a new plugin including "search" feature, you should develop it as just a wrapper of this command, instead of developing something based on more low level technologies. + +Style +: Request-Response. One response message is always returned per one request. + +`type` of the request +: `search` + +`body` of the request +: A hash of parameters. + +`type` of the response +: `search.result` + +## Parameter syntax {#syntax} + + { + "timeout" : <Seconds to be timed out>, + "queries" : { + "<Name of the query 1>" : { + "source" : "<Name of a table or another query>", + "condition" : <Search conditions>, + "sortBy" : <Sort conditions>, + "groupBy" : <Group conditions>, + "output" : <Output conditions> + }, + "<Name of the query 2>" : { ... }, + ... + } + } + +## Usage {#usage} + +This section describes how to use this command, via a typical usage with following table: + +Person table (with primary key): + +|_key|name|age|sex|job|note| +|Alice Arnold|Alice Arnold|20|female|announcer|| +|Alice Cooper|Alice Cooper|30|male|musician|| +|Alice Miller|Alice Miller|25|female|doctor|| +|Bob Dole|Bob Dole|42|male|lawer|| +|Bob Cousy|Bob Cousy|38|male|basketball player|| +|Bob Wolcott|Bob Wolcott|36|male|baseball player|| +|Bob Evans|Bob Evans|31|male|driver|| +|Bob Ross|Bob Ross|54|male|painter|| +|Lewis Carroll|Lewis Carroll|66|male|writer|the author of Alice's Adventures in Wonderland| + +Note: `name` and `note` are indexed with `TokensBigram`. + +### Basic usage {#usage-basic} + +This is a simple example to output all records of the Person table: + + { + "type" : "search", + "body" : { + "queries" : { + "people" : { + "source" : "Person", + "output" : { + "elements" : ["count", "records"], + "attributes" : ["_key", "name", "age", "sex", "job", "note"], + "limit" : -1 + } + } + } + } + } + + => { + "type" : "search.result", + "body" : { + "people" : { + "count" : 9, + "records" : [ + ["Alice Arnold", "Alice Arnold", 20, "female", "announcer", ""], + ["Alice Cooper", "Alice Cooper", 30, "male", "musician", ""], + ["Alice Miller", "Alice Miller", 25, "male", "doctor", ""], + ["Bob Dole", "Bob Dole", 42, "male", "lawer", ""], + ["Bob Cousy", "Bob Cousy", 38, "male", "basketball player", ""], + ["Bob Wolcott", "Bob Wolcott", 36, "male", "baseball player", ""], + ["Bob Evans", "Bob Evans", 31, "male", "driver", ""], + ["Bob Ross", "Bob Ross", 54, "male", "painter", ""], + ["Lewis Carroll", "Lewis Carroll", 66, "male", "writer", + "the author of Alice's Adventures in Wonderland"] + ] + } + } + } + +The name `people` is a temporary name for the search query and its result. +A response of a `search` command will be returned as a hash, and the keys are same to keys of the given `queries`. +So, this means: "name the search result of the query as `people`". + +Why the command above returns all informations of the table? Because: + + * There is no search condition. This command matches all records in the specified table, if no condition is specified. + * [`output`](#query-output)'s `elements` contains `records` (and `count`) column(s). The parameter `elements` controls the returned information. Matched records are returned as `records`, the total number of matched records are returned as `count`. + * [`output`](#query-output)'s `limit` is `-1`. The parameter `limit` controls the number of returned records, and `-1` means "return all records". + * [`output`](#query-output)'s `attributes` contains all columns of the Person table. The parameter `attributes` controls which columns' value are returned. + + +#### Search conditions {#usage-condition} + +Search conditions are specified via the `condition` parameter. There are two styles of search conditions: "script syntax" and "query syntax". See [`condition` parameter](#query-condition) for more details. + +##### Search conditions in Script syntax {#usage-condition-script-syntax} + +Search conditions in script syntax are similar to ECMAScript. For example, following query means "find records that `name` contains `Alice` and `age` is larger than or equal to `25`": + + { + "type" : "search", + "body" : { + "queries" : { + "people" : { + "source" : "Person", + "condition" : "name @ 'Alice' && age >= 25" + "output" : { + "elements" : ["count", "records"], + "attributes" : ["name", "age"], + "limit" : -1 + } + } + } + } + } + + => { + "type" : "search.result", + "body" : { + "people" : { + "count" : 2, + "records" : [ + ["Alice Arnold", 20], + ["Alice Cooper", 30], + ["Alice Miller", 25] + ] + } + } + } + +[Script syntax is compatible to Groonga's one](http://groonga.org/docs/reference/grn_expr/script_syntax.html). See the linked document for more details. + +##### Search conditions in Query syntax {#usage-condition-query-syntax} + +The query syntax is mainly designed for search boxes in webpages. For example, following query means "find records that `name` or `note` contain the given word, and the word is `Alice`": + + { + "type" : "search", + "body" : { + "queries" : { + "people" : { + "source" : "Person", + "condition" : { + "query" : "Alice", + "matchTo" : ["name", "note"] + }, + "output" : { + "elements" : ["count", "records"], + "attributes" : ["name", "note"], + "limit" : -1 + } + } + } + } + } + + => { + "type" : "search.result", + "body" : { + "people" : { + "count" : 4, + "records" : [ + ["Alice Arnold", ""], + ["Alice Cooper", ""], + ["Alice Miller", ""], + ["Lewis Carroll", + "the author of Alice's Adventures in Wonderland"] + ] + } + } + } + +[Query syntax is compatible to Groonga's one](http://groonga.org/docs/reference/grn_expr/query_syntax.html). See the linked document for more details. + + +#### Sorting of search results {#usage-sort} + +Returned records can be sorted by conditions specified as the `sortBy` parameter. For example, following query means "sort results by their `age`, in ascending order": + + { + "type" : "search", + "body" : { + "queries" : { + "people" : { + "source" : "Person", + "condition" : "name @ 'Alice'" + "sortBy" : ["age"], + "output" : { + "elements" : ["count", "records"], + "attributes" : ["name", "age"], + "limit" : -1 + } + } + } + } + } + + => { + "type" : "search.result", + "body" : { + "people" : { + "count" : 8, + "records" : [ + ["Alice Arnold", 20], + ["Alice Miller", 25], + ["Alice Cooper", 30] + ] + } + } + } + +If you add `-` before name of columns, then search results are returned in descending order. For example: + + { + "type" : "search", + "body" : { + "queries" : { + "people" : { + "source" : "Person", + "condition" : "name @ 'Alice'" + "sortBy" : ["-age"], + "output" : { + "elements" : ["count", "records"], + "attributes" : ["name", "age"], + "limit" : -1 + } + } + } + } + } + + => { + "type" : "search.result", + "body" : { + "people" : { + "count" : 8, + "records" : [ + ["Alice Cooper", 30], + ["Alice Miller", 25], + ["Alice Arnold", 20] + ] + } + } + } + +See [`sortBy` parameter](#query-sortBy) for more details. + +#### Paging of search results {#usage-paging} + +Search results can be retuned partially via `offset` and `limit` under the [`output`](#query-output) parameter. For example, following queries will return 20 or more search results by 10's. + + { + "type" : "search", + "body" : { + "queries" : { + "people" : { + "source" : "Person", + "output" : { + "elements" : ["count", "records"], + "attributes" : ["name"], + "offset" : 0, + "limit" : 10 + } + } + } + } + } + + => returns 10 results from the 1st to the 10th. + + { + "type" : "search", + "body" : { + "queries" : { + "people" : { + "source" : "Person", + "output" : { + "elements" : ["count", "records"], + "attributes" : ["name"], + "offset" : 10, + "limit" : 10 + } + } + } + } + } + + => returns 10 results from the 11th to the 20th. + + { + "type" : "search", + "body" : { + "queries" : { + "people" : { + "source" : "Person", + "output" : { + "elements" : ["count", "records"], + "attributes" : ["name"], + "offset" : 20, + "limit" : 10 + } + } + } + } + } + + => returns 10 results from the 21st to the 30th. + +The value `-1` is not recommended for the `limit` parameter, in regular use. It will return too much results and increase traffic loads. Instead `100` or less value is recommended for the `limit` parameter. Then you should do paging by the `offset` parameter. + +See [`output` parameter](#query-output) for more details. + +Moreover, you can do paging via [the `sortBy` parameter](#query-sortBy-hash) and it will work faster than the paging by the `output` parameter. You should do paging via the `sortBy` parameter instead of `output` as much as possible. + + +#### Output format {#usage-format} + +Search result records in examples above are shown as arrays of arrays, but they can be returned as arrays of hashes by the [`output`](#query-output)'s `format` parameter. If you specify `complex` for the `format`, then results are returned like: + + { + "type" : "search", + "body" : { + "queries" : { + "people" : { + "source" : "Person", + "output" : { + "elements" : ["count", "records"], + "attributes" : ["_key", "name", "age", "sex", "job", "note"], + "limit" : 3, + "format" : "complex" + } + } + } + } + } + + => { + "type" : "search.result", + "body" : { + "people" : { + "count" : 9, + "records" : [ + { "_key" : "Alice Arnold", + "name" : "Alice Arnold", + "age" : 20, + "sex" : "female", + "job" : "announcer", + "note" : "" }, + { "_key" : "Alice Cooper", + "name" : "Alice Cooper", + "age" : 30, + "sex" : "male", + "job" : "musician", + "note" : "" }, + { "_key" : "Alice Miller", + "name" : "Alice Miller", + "age" : 25, + "sex" : "female", + "job" : "doctor", + "note" : "" } + ] + } + } + } + +Search result records will be returned as an array of hashes, when you specify `complex` as the value of the `format` parameter. +Otherwise - `simple` or nothing is specified -, records are returned as an array of arrays. + +See [`output` parameters](#query-output) and [responses](#response) for more details. + + +### Advanced usage {#usage-advanced} + +#### Grouping {#usage-group} + +You can group search results by a column, via the [`groupBy`](#query-groupBy) parameters. For example, following query returns a result grouped by the `sex` column, with the count of original search results: + + { + "type" : "search", + "body" : { + "queries" : { + "sexuality" : { + "source" : "Person", + "groupBy" : "sex", + "output" : { + "elements" : ["count", "records"], + "attributes" : ["_key", "_nsubrecs"], + "limit" : -1 + } + } + } + } + } + + => { + "type" : "search.result", + "body" : { + "sexuality" : { + "count" : 2, + "records" : + ["female", 2], + ["male", 7] + ] + } + } + } + +The result means: "There are two `female` records and seven `male` records, moreover there are two types for the column `sex`. + +You can also extract the ungrouped record by the `maxNSubRecords` parameter and the `_subrecs` virtual column. For example, following query returns the result grouped by `sex` and extract two ungrouped records: + + { + "type" : "search", + "body" : { + "queries" : { + "sexuality" : { + "source" : "Person", + "groupBy" : { + "keys" : "sex", + "maxNSubRecords" : 2 + }, + "output" : { + "elements" : ["count", "records"], + "attributes" : [ + "_key", + "_nsubrecs", + { "label" : "subrecords", + "source" : "_subrecs", + "attributes" : ["name"] } + ], + "limit" : -1 + } + } + } + } + } + + => { + "type" : "search.result", + "body" : { + "sexuality" : { + "count" : 2, + "records" : + ["female", 2, [["Alice Arnold"], ["Alice Miller"]]], + ["male", 7, [["Alice Cooper"], ["Bob Dole"]]] + ] + } + } + } + + +See [`groupBy` parameters](#query-groupBy) for more details. + + +#### Multiple search queries in one request {#usage-multiple-queries} + +Multiple queries can be appear in one `search` command. For example, following query searches people younger than 25 or older than 40: + + { + "type" : "search", + "body" : { + "queries" : { + "junior" : { + "source" : "Person", + "condition" : "age <= 25", + "output" : { + "elements" : ["count", "records"], + "attributes" : ["name", "age"], + "limit" : -1 + } + }, + "senior" : { + "source" : "Person", + "condition" : "age >= 40", + "output" : { + "elements" : ["count", "records"], + "attributes" : ["name", "age"], + "limit" : -1 + } + } + } + } + } + + => { + "type" : "search.result", + "body" : { + "junior" : { + "count" : 2, + "records" : [ + ["Alice Arnold", 20], + ["Alice Miller", 25] + ] + }, + "senior" : { + "count" : 3, + "records" : [ + ["Bob Dole", 42], + ["Bob Ross", 54], + ["Lewis Carroll", 66] + ] + } + } + } + +Each search result can be identified by the temporary name given for each query. + +#### Chained search queries {#usage-chain} + +You can specify not only an existing table, but search result of another query also, as the value of the "source" parameter. Chained search queries can do flexible search in just one request. + +For example, the following query returns two results: records that their `name` contains `Alice`, and results grouped by their `sex` column: + + { + "type" : "search", + "body" : { + "queries" : { + "people" : { + "source" : "Person", + "condition" : "name @ 'Alice'" + "output" : { + "elements" : ["count", "records"], + "attributes" : ["name", "age"], + "limit" : -1 + } + }, + "sexuality" : { + "source" : "people", + "groupBy" : "sex", + "output" : { + "elements" : ["count", "records"], + "attributes" : ["_key", "_nsubrecs"], + "limit" : -1 + } + } + } + } + } + + => { + "type" : "search.result", + "body" : { + "people" : { + "count" : 8, + "records" : [ + ["Alice Cooper", 30], + ["Alice Miller", 25], + ["Alice Arnold", 20] + ] + }, + "sexuality" : { + "count" : 2, + "records" : + ["female", 2], + ["male", 1] + ] + } + } + } + +You can use search queries just internally, without output. For example, the following query does: 1) group records of the Person table by their `job` column, and 2) extract grouped results which have the text `player` in their `job`. (*Note: The second query will be done without indexes, so it can be slow.) + + { + "type" : "search", + "body" : { + "queries" : { + "allJob" : { + "source" : "Person", + "groupBy" : "job" + }, + "playerJob" : { + "source" : "allJob", + "condition" : "_key @ `player`", + "output" : { + "elements" : ["count", "records"], + "attributes" : ["_key", "_nsubrecs"], + "limit" : -1 + } + } + } + } + } + + => { + "type" : "search.result", + "body" : { + "playerJob" : { + "count" : 2, + "records" : [ + ["basketball player", 1], + ["baseball player", 1] + ] + } + } + } + + +## Parameter details {#parameters} + +### Container parameters {#container-parameters} + +#### `timeout` {#parameter-timeout} + +*Note: This parameter is not implemented yet on the version {{ site.droonga_version }}. + +Abstract +: Threshold to time out for the request. + +Value +: An integer in milliseconds. + +Default value +: `10000` (10 seconds) + +Droonga Engine will return an error response instead of a search result, if the search operation take too much time, longer than the given `timeout`. +Clients may free resources for the search operation after the timeout. + +#### `queries` {#parameter-queries} + +Abstract +: Search queries. + +Value +: A hash. Keys of the hash are query names, values of the hash are [queries (hashes of query parameters)](#query-parameters). + +Default value +: Nothing. This is a required parameter. + +You can put multiple search queries in a `search` request. + +On the {{ site.droonga_version }}, all search results for a request are returned in one time. In the future, as an optional behaviour, each result can be returned as separated messages progressively. + +### Parameters of each query {#query-parameters} + +#### `source` {#query-source} + +Abstract +: A source of a search operation. + +Value +: A name string of an existing table, or a name of another query. + +Default value +: Nothing. This is a required parameter. + +You can do a facet search, specifying a name of another search query as its source. + +The order of operations is automatically resolved by Droonga itself. +You don't have to write queries in the order they should be operated in. + +#### `condition` {#query-condition} + +Abstract +: Conditions to search records from the given source. + +Value +: Possible patterns: + + 1. A [script syntax](http://groonga.org/docs/reference/grn_expr/script_syntax.html) string. + 2. A hash including [script syntax](http://groonga.org/docs/reference/grn_expr/script_syntax.html) string. + 3. A hash including [query syntax](http://groonga.org/docs/reference/grn_expr/query_syntax.html) string. + 4. An array of conditions from 1 to 3 and an operator. + +Default value +: Nothing. + +If no condition is given, then all records in the source will appear as the search result, for following operations and the output. + +##### Search condition in a Script syntax string {#query-condition-script-syntax-string} + +This is a sample condition in the script syntax: + + "name == 'Alice' && age >= 20" + +It means "the value of the `name` column equals to `"Alice"`, and the value of the `age` column is `20` or more". + +See [the reference document of the script syntax on Groonga](http://groonga.org/docs/reference/grn_expr/script_syntax.html) for more details. + +##### Search condition in a hash based on the Script syntax {#query-condition-script-syntax-hash} + +In this pattern, you'll specify a search condition as a hash based on a +[script syntax string](#query-condition-script-syntax-string), like: + + { + "script" : "name == 'Alice' && age >= 20", + "allowUpdate" : true + } + +(*Note: under construction because the specification of the `allowUpdate` parameter is not defined yet.) + +##### Search condition in a hash based on the Query syntax {#query-condition-query-syntax-hash} + +In this pattern, you'll specify a search condition as a hash like: + + { + "query" : "Alice", + "matchTo" : ["name * 2", "job * 1"], + "defaultOperator" : "&&", + "allowPragma" : true, + "allowColumn" : true, + "matchEscalationThreshold" : 10 + } + +`query` +: A string to specify the main search query. In most cases, a text posted via a search box in a webpage will be given. + See [the document of the query syntax in Groonga](http://groonga.org/docs/reference/grn_expr/query_syntax.html) for more details. + This parameter is always required. + +`matchTo` +: An array of strings, meaning the list of column names to be searched by default. If you specify no column name in the `query`, it will work as a search query for columns specified by this parameter. + You can apply weighting for each column, like `name * 2`. + This parameter is optional. + +`defaultOperator` +: A string to specify the default logical operator for multiple queries listed in the `query`. Possible values: + + * `"&&"` : means "AND" condition. + * `"||"` : means "OR" condition. + * `"-"` : means ["NOT" condition](http://groonga.org/docs/reference/grn_expr/query_syntax.html#logical-not). + + This parameter is optional, the default value is `"&&"`. + +`allowPragma` +: A boolean value to allow (`true`) or disallow (`false`) to use "pragma" like `*E-1`, on the head of the `query`. + This parameter is optional, the default value is `true`. + +`allowColumn` +: A boolean value to allow (`true`) or disallow (`false`) to specify column name for each query in the `query`, like `name:Alice`. + This parameter is optional, the default value is `true`. + +`matchEscalationThreshold` +: An integer to specify the threshold to escalate search methods. + When the number of search results by indexes is smaller than this value, then Droonga does the search based on partial matching, etc. + See also [the specification of the search behavior of Groonga](http://groonga.org/docs/spec/search.html) for more details. + This parameter is optional, the default value is `0`. + + +##### Complex search condition as an array {#query-condition-array} + +In this pattern, you'll specify a search condition as an array like: + + [ + "&&", + <search condition 1>, + <search condition 2>, + ... + ] + +The fist element of the array is an operator string. Possible values: + + * `"&&"` : means "AND" condition. + * `"||"` : means "OR" condition. + * `"-"` : means ["NOT" condition](http://groonga.org/docs/reference/grn_expr/query_syntax.html#logical-not). + +Rest elements are logically operated based on the operator. +For example this is an "AND" operated condition based on two conditions, means "the value of the `name` equals to `"Alice"`, and, the value of the `age` is `20` or more": + + ["&&", "name == 'Alice'", "age >= 20"] + +Nested array means more complex conditions. For example, this means "`name` equals to `"Alice"` and `age` is `20` or more, but `job` does not equal to `"engineer"`": + + [ + "-", + ["&&", "name == 'Alice'", "age >= 20"], + "job == 'engineer'" + ] + +#### `sortBy` {#query-sortBy} + +Abstract +: Conditions for sorting and paging. + +Value +: Possible patterns: + + 1. An array of column name strings. + 2. A hash including an array of sort column name strings and paging conditions. + +Default value +: Nothing. + +If sort conditions are not specified, then all results will appear as-is, for following operations and the output. + +##### Basic sort condition {#query-sortBy-array} + +Sort condition is given as an array of column name strings. + +At first Droonga tries to sort records by the value of the first given sort column. After that, if there are multiple records which have same value for the column, then Droonga tries to sort them by the secondary given sort column. These processes are repeated for all given sort columns. + +You must specify sort columns as an array, even if there is only one column. + +Records are sorted by the value of the column value, in an ascending order. Results can be sorted in descending order if sort column name has a prefix `-`. + +For example, this condition means "sort records by the `name` at first in an ascending order, and sort them by their `age~ column in the descending order": + + ["name", "-age"] + +##### Paging of sorted results {#query-sortBy-hash} + +Paging conditions can be specified as a part of a sort condition hash, like: + + { + "keys" : [<Sort columns>], + "offset" : <Offset of paging>, + "limit" : <Number of results to be extracted> + } + +`keys` +: Sort conditions same to [the basic sort condition](#query-sortBy-array). + This parameter is always required. + +`offset` +: An integer meaning the offset to the paging of sorted results. Possible values are `0` or larger integers. + + This parameter is optional and the default value is `0`. + +`limit` +: An integer meaning the number of sorted results to be extracted. Possible values are `-1`, `0`, or larger integers. The value `-1` means "return all results". + + This parameter is optional and the default value is `-1`. + +For example, this condition extracts 10 sorted results from 11th to 20th: + + { + "keys" : ["name", "-age"], + "offset" : 10, + "limit" : 10 + } + +In most cases, paging by a sort condition is faster than paging by `output`'s `limit` and `output`, because this operation reduces the number of records. + + +#### `groupBy` {#query-groupBy} + +Abstract +: A condition for grouping of (sorted) search results. + +Value +: Possible patterns: + + 1. A condition string to do grouping. (a column name or an expression) + 2. A hash to specify a condition for grouping with details. + +Default value +: Nothing. + +If a condition for grouping is given, then grouped result records will appear as the result, for following operations and the output. + +##### Basic condition of grouping {#query-groupBy-string} + +A condition of grouping is given as a string of a column name or an expression. + +Droonga groups (sorted) search result records, based on the value of the specified column. Then the result of the grouping will appear instead of search results from the `source`. Result records of a grouping will have following columns: + +`_key` +: A value of the grouped column. + +`_nsubrecs` +: An integer meaning the number of grouped records. + +For example, this condition means "group records by their `job` column's value, with the number of grouped records for each value": + + "job" + +##### Condition of grouping with details {#query-groupBy-hash} + +A condition of grouping can include more options, like: + + { + "key" : "<Basic condition for grouping>", + "maxNSubRecords" : <Number of sample records included into each grouped result> + } + +`key` +: A string meaning [a basic condition of grouping](#query-groupBy-string). + This parameter is always required. + +`maxNSubRecords` +: An integer, meaning maximum number of sample records included into each grouped result. Possible values are `0` or larger. `-1` is not acceptable. + + This parameter is optional, the default value is `0`. + +For example, this condition will return results grouped by their `job` column with one sample record per a grouped result: + + { + "key" : "job", + "maxNSubRecords" : 1 + } + +Grouped results will have all columns of [the result of the basic conditions for grouping](#query-groupBy-string), and following extra columns: + +`_subrecs` +: An array of sample records which have the value in its grouped column. + +*Note: On the version {{ site.droonga_version }}, too many records can be returned larger than the specified `maxNSubRecords`, if the dataset has multiple volumes. This is a known problem and to be fixed in a future version. + + +#### `output` {#query-output} + +Abstract +: A output definition for a search result + +Value +: A hash including information to control output format. + +Default value +: Nothing. + +If no `output` is given, then search results of the query won't be exported to the returned message. +You can reduce processing time and traffic via omitting of `output` for temporary tables which are used only for grouping and so on. + +An output definition is given as a hash like: + + { + "elements" : [<Names of elements to be exported>], + "format" : "<Format of each record>", + "offset" : <Offset of paging>, + "limit" : <Number of records to be exported>, + "attributes" : <Definition of columnst to be exported for each record> + } + +`elements` +: An array of strings, meaning the list of elements exported to the result of the search query in a [search response](#response). + Possible values are following, and you must specify it as an array even if you export just one element: + + * `"startTime"` *Note: This will be ignored because it is not implemented on the version {{ site.droonga_version }} yet. + * `"elapsedTime"` *Note: This will be ignored because it is not implemented on the version {{ site.droonga_version }} yet. + * `"count"` + * `"attributes"` + * `"records"` + + This parameter is optional, there is not default value. Nothing will be exported if no element is specified. + +`format` +: A string meaning the format of exported each record. + Possible values: + + * `"simple"` : Each record will be exported as an array of column values. + * `"complex"` : Each record will be exported as a hash. + + This parameter is optional, the default value is `"simple"`. + +`offset` +: An integer meaning the offset to the paging of exported records. Possible values are `0` or larger integers. + + This parameter is optional and the default value is `0`. + +`limit` +: An integer meaning the number of exported records. Possible values are `-1`, `0`, or larger integers. The value `-1` means "export all records". + + This parameter is optional and the default value is `0`. + +`attributes` +: Definition of columns to be exported for each record. + Possible patterns: + + 1. An array of column definitions. + 2. A hash of column definitions. + + Each column can be defined in one of following styles: + + * A name string of a column. + * `"name"` : Exports the value of the `name` column, as is. + * `"age"` : Exports the value of the `age` column, as is. + * A hash with details: + * This exports the value of the `name` column as a column with different name `realName`. + + { "label" : "realName", "source" : "name" } + + * This exports the snippet in HTML fragment as a column with the name `html`. + + { "label" : "html", "source": "snippet_html(name)" } + + * This exports a static value `"Japan"` for the `country` column of all records. + (This will be useful for debugging, or a use case to try modification of APIs.) + + { "label" : "country", "source" : "'Japan'" } + + * This exports a number of grouped records as the `"itemsCount"` column of each record (grouped result). + + { "label" : "itemsCount", "source" : "_nsubrecs", } + + * This exports samples of the source records of grouped records, as the `"items"` column of grouped records. + The format of the `"attributes"` is just same to this section. + + { "label" : "items", "source" : "_subrecs", + "attributes": ["name", "price"] } + + An array of column definitions can contain any type definition described above, like: + + [ + "name", + "age", + { "label" : "realName", "source" : "name" } + ] + + A hash of column definitions can contain any type definition described above except `label` of hashes, because keys of the hash means `label` of each column, like: + + { + "name" : "name", + "age" : "age", + "realName" : { "source" : "name" }, + "country" : { "source" : "'Japan'" } + } + + This parameter is optional, there is no default value. No column will be exported if no column is specified. + + +## Responses {#response} + +This command returns a hash as the result as the `body`, with `200` as the `statusCode`. + +Keys of the result hash is the name of each query (a result of a search query), values of the hash is the result of each [search query](#query-parameters), like: + + { + "<Name of the query 1>" : { + "startTime" : "<Time to start the operation>", + "elapsedTime" : <Elapsed time to process the query, in milliseconds), + "count" : <Number of records searched by the given conditions>, + "attributes" : <Array or hash of exported columns>, + "records" : [<Array of search result records>] + }, + "<Name of the query 2>" : { ... }, + ... + } + +A hash of a search query's result can have following elements, but only some elements specified in the `elements` of the [`output` parameter](#query-output) will appear in the response. + +### `startTime` {#response-query-startTime} + +A local time string meaning the search operation is started. + +It is formatted in the [W3C-DTF](http://www.w3.org/TR/NOTE-datetime "Date and Time Formats"), with the time zone like: + + 2013-11-29T08:15:30+09:00 + +### `elapsedTime` {#response-query-elapsedTime} + +An integer meaning the elapsed time of the search operation, in milliseconds. + +### `count` {#response-query-count} + +An integer meaning the total number of search result records. +Paging options `offset` and `limit` in [`sortBy`](#query-sortBy) or [`output`](#query-output) will not affect to this count. + +### `attributes` and `records` {#response-query-attributes-and-records} + + * `attributes` is an array or a hash including information of exported columns for each record. + * `records` is an array of search result records. + +There are two possible patterns of `attributes` and `records`, based on the [`output`](#query-output)'s `format` parameter. + +#### Simple format result {#response-query-simple-attributes-and-records} + +A search result with `"simple"` as the value of `output`'s `format` will be returned as a hash like: + + { + "startTime" : "<Time to start the operation>", + "elapsedTime" : <Elapsed time to process the query), + "count" : <Total number of search result records>, + "attributes" : [ + { "name" : "<Name of the column 1>", + "type" : "<Type of the column 1>", + "vector" : <It this column is a vector column?> }, + { "name" : "<Name of the column 2>", + "type" : "<Type of the column 2>", + "vector" : <It this column is a vector column?> }, + { "name" : "<Name of the column 3 (with subrecords)>" + "attributes" : [ + { "name" : "<Name of the column 3-1>", + "type" : "<Type of the column 3-1>", + "vector" : <It this column is a vector column?> }, + { "name" : "<Name of the the column 3-2>", + "type" : "<Type of the the column 3-2>", + "vector" : <It this column is a vector column?> }, + ], + ... + }, + ... + ], + "records" : [ + [<Value of the column 1 of the record 1>, + <Value of the column 2 of the record 1>, + [ + [<Value of the column of 3-1 of the subrecord 1 of the record 1>, + <Value of the column of 3-2 of the subrecord 2 of the record 1>, + ...], + [<Value of the column of 3-1 of the subrecord 1 of the record 1>, + <Value of the column of 3-2 of the subrecord 2 of the record 1>, + ...], + ...], + ...], + [<Value of the column 1 of the record 2>, + <Value of the column 2 of the record 2>, + [ + [<Value of the column of 3-1 of the subrecord 1 of the record 2>, + <Value of the column of 3-2 of the subrecord 2 of the record 2>, + ...], + [<Value of the column of 3-1 of the subrecord 1 of the record 2>, + <Value of the column of 3-2 of the subrecord 2 of the record 2>, + ...], + ...], + ...], + ... + ] + } + +This format is designed to reduce traffic with small responses, instead of useful rich data format. +Recommended for cases when the response can include too much records, or the service can accept too much requests. + +##### `attributes` {#response-query-simple-attributes} + +An array of column informations for each exported search result, ordered by [the `output` parameter](#query-output)'s `attributes`. + +Each column information is returned as a hash in the form of one of these three variations corresponding to the kind of values. The hash will have the following keys respectively: + +###### For ordinal columns + +`name` +: A string meaning the name (label) of the exported column. It is just same to labels defined in [the `output` parameter](#query-output)'s `attributes`. + +`type` +: A string meaning the value type of the column. + The type is indicated as one of [Groonga's primitive data formats](http://groonga.org/docs/reference/types.html), or a name of an existing table for referring columns. + +`vector` +: A boolean value meaning it is a [vector column](http://groonga.org/docs/tutorial/data.html#vector-types) or not. + Possible values: + + * `true` : It is a vector column. + * `false` : It is not a vector column, but a scalar column. + +###### For columns corresponding to subrecords + +`name` +: A string meaning the name (label) of the exported column. It is just same to labels defined in [the `output` parameter](#query-output)'s `attributes`. + +`attributes` +: An array including information about columns of subrecords. The form is the same as `attributes` for (main) records. This means `attributes` has recursive structure. + +###### For expressions + +`name` +: A string meaning the name (label) of the exported column. It is just same to labels defined in [the `output` parameter](#query-output)'s `attributes`. + +##### `records` {#response-query-simple-records} + +An array of exported search result records. + +Each record is exported as an array of column values, ordered by the [`output` parameter](#query-output)'s `attributes`. + +A value of [date time type](http://groonga.org/docs/tutorial/data.html#date-and-time-type) column will be returned as a string formatted in the [W3C-DTF](http://www.w3.org/TR/NOTE-datetime "Date and Time Formats"), with the time zone. + +#### Complex format result {#response-query-complex-attributes-and-records} + +A search result with `"complex"` as the value of `output`'s `format` will be returned as a hash like: + + { + "startTime" : "<Time to start the operation>", + "elapsedTime" : <Elapsed time to process the query), + "count" : <Total number of search result records>, + "attributes" : { + "<Name of the column 1>" : { "type" : "<Type of the column 1>", + "vector" : <It this column is a vector column?> }, + "<Name of the column 2>" : { "type" : "<Type of the column 2>", + "vector" : <It this column is a vector column?> }, + "<Name of the column 3 (with subrecords)>" : { + "attributes" : { + "<Name of the column 3-1>" : { "type" : "<Type of the column 3-1>", + "vector" : <It this column is a vector column?> }, + "<Name of the column 3-2>" : { "type" : "<Type of the column 3-2>", + "vector" : <It this column is a vector column?> }, + ... + } + }, + ... + ], + "records" : [ + { "<Name of the column 1>" : <Value of the column 1 of the record 1>, + "<Name of the column 2>" : <Value of the column 2 of the record 1>, + "<Name of the column 3 (with subrecords)>" : [ + { "<Name of the column 3-1>" : <Value of the column 3-1 of the subrecord 1 of record 1>, + "<Name of the column 3-2>" : <Value of the column 3-2 of the subrecord 1 of record 1>, + ... }, + { "<Name of the column 3-1>" : <Value of the column 3-1 of the subrecord 2 of record 1>, + "<Name of the column 3-2>" : <Value of the column 3-2 of the subrecord 2 of record 1>, + ... }, + ... + ], + ... }, + { "<Name of the column 1>" : <Value of the column 1 of the record 2>, + "<Name of the column 2>" : <Value of the column 2 of the record 2>, + "<Name of the column 3 (with subrecords)>" : [ + { "<Name of the column 3-1>" : <Value of the column 3-1 of the subrecord 1 of record 2>, + "<Name of the column 3-2>" : <Value of the column 3-2 of the subrecord 1 of record 2>, + ... }, + { "<Name of the column 3-1>" : <Value of the column 3-1 of the subrecord 2 of record 2>, + "<Name of the column 3-2>" : <Value of the column 3-2 of the subrecord 2 of record 2>, + ... }, + ... + ], + ... }, + ... + ] + } + +This format is designed to keep human readability, instead of less traffic. +Recommended for small traffic cases like development, debugging, features only for administrators, and so on. + +##### `attributes` {#response-query-complex-attributes} + +A hash of column informations for each exported search result. Keys of the hash are column names defined by [the `output` parameter](#query-output)'s `attributes`, values are informations of each column. + +Each column information is returned as a hash in the form of one of these three variations corresponding to the kind of values. The hash will have the following keys respectively: + +###### For ordinal columns + +`type` +: A string meaning the value type of the column. + The type is indicated as one of [Groonga's primitive data formats](http://groonga.org/docs/reference/types.html), or a name for an existing table for referring columns. + +`vector` +: A boolean value meaning it is a [vector column](http://groonga.org/docs/tutorial/data.html#vector-types) or not. + Possible values: + + * `true` : It is a vector column. + * `false` : It is not a vector column, but a scalar column. + +###### For columns corresponding to subrecords + +`attributes` +: An array including information about columns of subrecords. The form is the same as `attributes` for (main) records. This means `attributes` has recursive structure. + +###### For expressions + +Has no key. Just a empty hash `{}` will be returned. + +##### `records` {#response-query-complex-records} + + +An array of exported search result records. + +Each record is exported as a hash. Keys of the hash are column names defined by [`output` parameter](#query-output)'s `attributes`, values are column values. + +A value of [date time type](http://groonga.org/docs/tutorial/data.html#date-and-time-type) column will be returned as a string formatted in the [W3C-DTF](http://www.w3.org/TR/NOTE-datetime "Date and Time Formats"), with the time zone. + + +## Error types {#errors} + +This command reports errors not only [general errors](/reference/message/#error) but also followings. + +### `MissingSourceParameter` + +Means you've forgotten to specify the `source` parameter. The status code is `400`. + +### `UnknownSource` + +Means there is no existing table and no other query with the name, for a `source` of a query. The status code is `404`. + +### `CyclicSource` + +Means there is any circular reference of sources. The status code is `400`. + +### `SearchTimeout` + +Means the engine couldn't finish to process the request in the time specified as `timeout`. The status code is `500`. Added: reference/1.0.3/commands/select/index.md (+81 -0) 100644 =================================================================== --- /dev/null +++ reference/1.0.3/commands/select/index.md 2014-05-19 16:48:30 +0900 (a0bb319) @@ -0,0 +1,81 @@ +--- +title: select +layout: en +--- + +* TOC +{:toc} + +## Abstract {#abstract} + +The `select` command finds records from the specified table based on given conditions, and returns found records. + +This is compatible to [the `select` command of the Groonga](http://groonga.org/docs/reference/commands/select.html). + +Style +: Request-Response. One response message is always returned per one request. + +`type` of the request +: `select` + +`body` of the request +: A hash of parameters. + +`type` of the response +: `select.result` + +## Parameter syntax {#syntax} + + { + "table" : "<Name of the table>", + "match_columns" : "<List of matching columns, separated by '||'>", + "query" : "<Simple search conditions>", + "filter" : "<Complex search conditions>", + "scorer" : "<An expression to be applied to matched records>", + "sortby" : "<List of sorting columns, separated by ','>", + "output_columns" : "<List of returned columns, separated by ','>", + "offset" : <Offset of paging>, + "limit" : <Number of records to be returned>, + "drilldown" : "<Column name to be drilldown-ed>", + "drilldown_sortby" : "List of sorting columns for drilldown's result, separated by ','>", + "drilldown_output_columns" : + "List of returned columns for drilldown's result, separated by ','>", + "drilldown_offset" : <Offset of drilldown's paging>, + "drilldown_limit" : <Number of drilldown results to be returned>, + "cache" : "<Query cache option>", + "match_escalation_threshold": + <Threshold to escalate search methods>, + "query_flags" : "<Flags to customize query parameters>", + "query_expander" : "<Arguments to expanding queries>" + } + +## Parameter details {#parameters} + +All parameters except `table` are optional. + +On the version {{ site.droonga_version }}, only following parameters are available. Others are simply ignored because they are not implemented. + + * `table` + * `match_columns` + * `query` + * `filter` + * `output_columns` + * `offset` + * `limit` + * `drilldown` + * `drilldown_output_columns` + * `drilldown_sortby` + * `drilldown_offset` + * `drilldown_limit` + +All parameters are compatible to [parameters for `select` command of the Groonga](http://groonga.org/docs/reference/commands/select.html#parameters). See the linked document for more details. + + + +## Responses {#response} + +This returns an array including search results as the response's `body`. + +The structure of the returned array is compatible to [the returned value of the Groonga's `select` command](http://groonga.org/docs/reference/commands/select.html#id6). See the linked document for more details. + +This command always returns a response with `200` as its `statusCode`, because this is a Groonga compatible command and errors of this command must be handled in the way same to Groonga's one. Added: reference/1.0.3/commands/table-create/index.md (+77 -0) 100644 =================================================================== --- /dev/null +++ reference/1.0.3/commands/table-create/index.md 2014-05-19 16:48:30 +0900 (07a74cc) @@ -0,0 +1,77 @@ +--- +title: table_create +layout: en +--- + +* TOC +{:toc} + +## Abstract {#abstract} + +The `table_create` command creates a new table. + +This is compatible to [the `table_create` command of the Groonga](http://groonga.org/docs/reference/commands/table_create.html). + +Style +: Request-Response. One response message is always returned per one request. + +`type` of the request +: `table_create` + +`body` of the request +: A hash of parameters. + +`type` of the response +: `table_create.result` + +## Parameter syntax {#syntax} + + { + "name" : "<Name of the table>", + "flags" : "<Flags for the table>", + "key_type" : "<Type of the primary key>", + "value_type" : "<Type of the value>", + "default_tokenizer" : "<Default tokenizer>", + "normalizer" : "<Normalizer>" + } + +## Parameter details {#parameters} + +All parameters except `name` are optional. + +They are compatible to [the parameters of the `table_create` command of the Groonga](http://groonga.org/docs/reference/commands/table_create.html#parameters). See the linked document for more details. + +## Responses {#response} + +This returns an array meaning the result of the operation, as the `body`. + + [ + [ + <Groonga's status code>, + <Start time>, + <Elapsed time> + ], + <Table is successfully created or not> + ] + +This command always returns a response with `200` as its `statusCode`, because this is a Groonga compatible command and errors of this command must be handled in the way same to Groonga's one. + +Response body's details: + +Status code +: An integer which means the operation's result. Possible values are: + + * `0` (`Droonga::GroongaHandler::Status::SUCCESS`) : Successfully processed. + * `-22` (`Droonga::GroongaHandler::Status::INVALID_ARGUMENT`) : There is any invalid argument. + +Start time +: An UNIX time which the operation was started on. + +Elapsed time +: A decimal of seconds meaning the elapsed time for the operation. + +Table is successfully created or not +: A boolean value meaning the table was successfully created or not. Possible values are: + + * `true`:The table was successfully created. + * `false`:The table was not created. Added: reference/1.0.3/commands/table-remove/index.md (+72 -0) 100644 =================================================================== --- /dev/null +++ reference/1.0.3/commands/table-remove/index.md 2014-05-19 16:48:30 +0900 (dc0d865) @@ -0,0 +1,72 @@ +--- +title: table_remove +layout: en +--- + +* TOC +{:toc} + +## Abstract {#abstract} + +The `table_remove` command removes an existing table. + +This is compatible to [the `table_remove` command of the Groonga](http://groonga.org/docs/reference/commands/table_remove.html). + +Style +: Request-Response. One response message is always returned per one request. + +`type` of the request +: `table_remove` + +`body` of the request +: A hash of parameters. + +`type` of the response +: `table_remove.result` + +## Parameter syntax {#syntax} + + { + "name" : "<Name of the table>" + } + +## Parameter details {#parameters} + +The only one parameter `name` is required. + +They are compatible to [the parameters of the `table_remove` command of the Groonga](http://groonga.org/docs/reference/commands/table_remove.html#parameters). See the linked document for more details. + +## Responses {#response} + +This returns an array meaning the result of the operation, as the `body`. + + [ + [ + <Groonga's status code>, + <Start time>, + <Elapsed time> + ], + <Table is successfully removed or not> + ] + +This command always returns a response with `200` as its `statusCode`, because this is a Groonga compatible command and errors of this command must be handled in the way same to Groonga's one. + +Response body's details: + +Status code +: An integer which means the operation's result. Possible values are: + + * `0` (`Droonga::GroongaHandler::Status::SUCCESS`) : Successfully processed. + * `-22` (`Droonga::GroongaHandler::Status::INVALID_ARGUMENT`) : There is any invalid argument. + +Start time +: An UNIX time which the operation was started on. + +Elapsed time +: A decimal of seconds meaning the elapsed time for the operation. + +Table is successfully removed or not +: A boolean value meaning the table was successfully removed or not. Possible values are: + + * `true`:The table was successfully removed. + * `false`:The table was not removed. Added: reference/1.0.3/http-server/index.md (+156 -0) 100644 =================================================================== --- /dev/null +++ reference/1.0.3/http-server/index.md 2014-05-19 16:48:30 +0900 (986ee8f) @@ -0,0 +1,156 @@ +--- +title: HTTP Server +layout: en +--- + +* TOC +{:toc} + +## Abstract {#abstract} + +The [Droonga HTTP Server][droonga-http-server] is as an HTTP protocol adapter for the Droonga Engine. + +The Droonga Engine supports only the fluentd protocol, so you have to use `fluent-cat` or something, to communicate with the Drooga Engine. +This application provides ability to communicate with the Droonga Engine via HTTP. + +## Install {#install} + +It is released as the [droonga-http-server npm module][], a [Node.js][] module package. +You can install it via the `npm` command, like: + + # npm install -g droonga-http-server + +## Usage {#usage} + +### Command line options {#usage-command} + +It includes a command `droonga-http-server` to start an HTTP server. +You can start it with command line options, like: + + # droonga-http-server --port 3003 + +Available options and their default values are: + +`--port <13000>` +: The port number which the server receives HTTP requests at. + +`--receive-host-name <127.0.0.1>` +: The host name (or the IP address) of the computer itself which the server is running. + It is used by the Droonga Engine, to send response messages to the protocol adapter. + +`--droonga-engine-host-name <127.0.0.1>` +: The host name (or the IP address) of the computer which the Droonga Engine is running on. + +`--droonga-engine-port <24224>` +: The port number which the Droonga Engine receives messages at. + +`--default-dataset <Droonga>` +: The name of the default dataset. + It is used for requests triggered via built-in HTTP APIs. + +`--tag <droonga>` +: The tag used for fluentd messages sent to the Droonga Engine. + +`--enable-logging` +: If you specify this option, log messages are printed to the standard output. + +`--cache-size <100>` +: The maximum size of the LRU response cache. + Droonga HTTP server caches all responses for GET requests on the RAM, unthil this size. + +You have to specify appropriate values for your Droonga Engine. For example, if the HTTP server is running on the host 192.168.10.90 and the Droonga engine is running on the host 192.168.10.100 with following configurations: + +fluentd.conf: + + <source> + type forward + port 24324 + </source> + <match books.message> + name localhost:24224/books + type droonga + </match> + <match output.message> + type stdout + </match> + +catalog.json: + + { + "version": 2, + "effectiveDate": "2013-09-01T00:00:00Z", + "datasets": { + "Books": { + ... + } + } + } + +Then, you'll start the HTTP server on the host 192.168.10.90, with options like: + + # droonga-http-server --receive-host-name 192.168.10.90 \ + --droonga-engine-host-name 192.168.10.100 \ + --droonga-engine-port 24324 \ + --default-dataset Books \ + --tag books + +See also the [basic tutorial][]. + +## Built-in APIs {#usage-api} + +The Droonga HTTP Server includes following APIs: + +### REST API {#usage-rest} + +#### `GET /tables/<table name>` {#usage-rest-get-tables-table} + +This emits a simple [search request](../commands/search/). +The [`source`](../commands/search/#query-source) is filled by the table name in the path. +Available query parameters are: + +`attributes` +: Corresponds to [`output.attributes`](../commands/search/#query-output). + The value is a comma-separated list, like: `attributes=_key,name,age`. + +`query` +: Corresponds to [`condition.*.query`](../commands/search/#query-condition-query-syntax-hash). + The vlaue is a query string. + +`match_to` +: Corresponds to [`condition.*.matchTo`](../commands/search/#query-condition-query-syntax-hash). + The vlaue is an comma-separated list, like: `match_to=_key,name`. + +`match_escalation_threshold` +: Corresponds to [`condition.*.matchEscalationThreshold`](../commands/search/#query-condition-query-syntax-hash). + The vlaue is an integer. + +`script` +: Corresponds to [`condition`](../commands/search/#query-condition-query-syntax-hash) in the script syntax. + If you specity both `query` and `script`, then they work with an `and` logical condition. + +`adjusters` +: Corresponds to `adjusters`. + +`sort_by` +: Corresponds to [`sortBy`](../commands/search/#query-sortBy). + The value is a column name string. + +`limit` +: Corresponds to [`output.limit`](../commands/search/#query-output). + The value is an integer. + +`offset` +: Corresponds to [`output.offset`](../commands/search/#query-output). + The value is an integer. + +### Groonga HTTP server compatible API {#usage-groonga} + +#### `GET /d/<command name>` {#usage-groonga-d} + +(TBD) + + + [basic tutorial]: ../../tutorial/basic/ + [droonga-http-server]: https://github.com/droonga/droonga-http-server + [droonga-http-server npm module]: https://npmjs.org/package/droonga-http-server + [Node.js]: http://nodejs.org/ Added: reference/1.0.3/index.md (+19 -0) 100644 =================================================================== --- /dev/null +++ reference/1.0.3/index.md 2014-05-19 16:48:30 +0900 (0a37859) @@ -0,0 +1,19 @@ +--- +title: Reference manuals +layout: en +--- + +[Catalog](catalog/) +: Describes details of `catalog.json` which defines behavior of the Droonga Engine. + +[Message format](message/) +: Describes details of message format flowing in the Droonga Engines. + +[Commands](commands/) +: Describes details of built-in commands available on the Droonga Engines. + +[HTTP Server](http-server/) +: Describes usage of the [droonga-http-server](https://github.com/droonga/droonga-http-server). + +[Plugin development](plugin/) +: Describes details of public APIs to develop custom plugins for the Droonga Engine. Added: reference/1.0.3/message/index.md (+206 -0) 100644 =================================================================== --- /dev/null +++ reference/1.0.3/message/index.md 2014-05-19 16:48:30 +0900 (bce02ba) @@ -0,0 +1,206 @@ +--- +title: Message format +layout: en +--- + +* TOC +{:toc} + + +## Request {#request} + +The basic format of a request message is like following: + + { + "id" : "<ID of the message>", + "type" : "<Type of the message>", + "replyTo" : "<Route to the receiver>", + "dataset" : "<Name of the target dataset>", + "body" : <Body of the message> + } + +### `id` {#request-id} + +Abstract +: The unique identifier for the message. + +Value +: An identifier string. You can use any string with any format as you like, if only it is unique. The given id of a request message will be used for the ['inReplyTo`](#response-inReplyTo) information of its response. + +Default value +: Nothing. This is required information. + +### `type` {#request-type} + +Abstract +: The type of the message. + +Value +: A type string of [a command](/reference/commands/). + +Default value +: Nothing. This is required information. + +### `replyTo` {#request-replyTo} + +Abstract +: The route to the response receiver. + +Value +: An path string in the format: `<hostname>:<port>/<tag>`, for example: `localhost:24224/output`. + +Default value +: Nothing. This is optional. If you specify no `replyTo`, then the response message will be thrown away. + +### `dataset` {#request-dataset} + +Abstract +: The target dataset. + +Value +: A name string of a dataset. + +Default value +: Nothing. This is required information. + +### `body` {#request-body} + +Abstract +: The body of the message. + +Value +: Object, string, number, boolean, or `null`. + +Default value +: Nothing. This is optional. + +## Response {#response} + +The basic format of a response message is like following: + + { + "type" : "<Type of the message>", + "inReplyTo" : "<ID of the related request message>", + "statusCode" : <Status code>, + "body" : <Body of the message>, + "errors" : <Errors from nodes> + } + +### `type` {#response-type} + +Abstract +: The type of the message. + +Value +: A type string. Generally it is a suffixed version of the type string of the request message, with the suffix ".result". + +### `inReplyTo` {#response-inReplyTo} + +Abstract +: The identifier of the related request message. + +Value +: An identifier string of the related request message. + +### `statusCode` {#response-statusCode} + +Abstract +: The result status for the request message. + +Value +: A status code integer. + +Status codes of responses are similar to HTTP's one. Possible values: + +`200` and other `2xx` statuses +: The command is successfully processed. + +### `body` {#response-body} + +Abstract +: The result information for the request message. + +Value +: Object, string, number, boolean, or `null`. + +### `errors` {#response-errors} + +Abstract +: All errors from nodes. + +Value +: Object. + +This information will appear only when the command is distributed to multiple volumes and they returned errors. Otherwise, the response message will have no `errors` field. For more details, see [the "Error response" section](#error). + +## Error response {#error} + +Some commands can return an error response. + +An error response has the `type` same to a regular response, but it has different `statusCode` and `body`. General type of the error is indicated by the `statusCode`, and details are reported as the `body`. + +If a command is distributed to multiple volumes and they return errors, then the response message will have an `error` field. All errors from all nodes are stored to the field, like: + + { + "type" : "add.result", + "inReplyTo" : "...", + "statusCode" : 400, + "body" : { + "name": "UnknownTable", + "message": ... + }, + "errors" : { + "/path/to/the/node1" : { + "statusCode" : 400, + "body" : { + "name": "UnknownTable", + "message": ... + } + }, + "/path/to/the/node2" : { + "statusCode" : 400, + "body" : { + "name": "UnknownTable", + "message": ... + } + } + } + } + +In this case, one of all errors will be exported as the main message `body`, as a representative. + + +### Status codes of error responses {#error-status} + +Status codes of error responses are similar to HTTP's one. Possible values: + +`400` and other `4xx` statuses +: An error of the request message. + +`500` and other `5xx` statuses +: An internal error of the Droonga Engine. + +### Body of error responses {#error-body} + +The basic format of the body of an error response is like following: + + { + "name" : "<Type of the error>", + "message" : "<Human readable details of the error>", + "detail" : <Other extra information for the error, in various formats> + } + +If there is no detail, `detial` can be missing. + +#### Error types {#error-type} + +There are some general error types for any command. + +`MissingDatasetParameter` +: Means you've forgotten to specify the `dataset`. The status code is `400`. + +`UnknownDataset` +: Means you've specified a dataset which is not existing. The status code is `404`. + +`UnknownType` +: Means there is no handler for the command given as the `type`. The status code is `400`. Added: reference/1.0.3/plugin/adapter/index.md (+308 -0) 100644 =================================================================== --- /dev/null +++ reference/1.0.3/plugin/adapter/index.md 2014-05-19 16:48:30 +0900 (124ee7a) @@ -0,0 +1,308 @@ +--- +title: API set for plugins on the adaption phase +layout: en +--- + +* TOC +{:toc} + + +## Abstract {#abstract} + +Each Droonga Engine plugin can have its *adapter*. On the adaption phase, adapters can modify both incoming messages (from the Protocol Adapter to the Droonga Engine, in other words, they are "request"s) and outgoing messages (from the Droonga Engine to the Protocol Adapter, in other words, they are "response"s). + + +### How to define an adapter? {#howto-define} + +For example, here is a sample plugin named "foo" with an adapter: + +~~~ruby +require "droonga/plugin" + +module Droonga::Plugins::FooPlugin + extend Plugin + register("foo") + + class Adapter < Droonga::Adapter + # operations to configure this adapter + XXXXXX = XXXXXX + + def adapt_input(input_message) + # operations to modify incoming messages + input_message.XXXXXX = XXXXXX + end + + def adapt_output(output_message) + # operations to modify outgoing messages + output_message.XXXXXX = XXXXXX + end + end +end +~~~ + +Steps to define an adapter: + + 1. Define a module for your plugin (ex. `Droonga::Plugins::FooPlugin`) and register it as a plugin. (required) + 2. Define an adapter class (ex. `Droonga::Plugins::FooPlugin::Adapter`) inheriting [`Droonga::Adapter`](#classes-Droonga-Adapter). (required) + 3. [Configure conditions to apply the adapter](#howto-configure). (required) + 4. Define adaption logic for incoming messages as [`#adapt_input`](#classes-Droonga-Adapter-adapt_input). (optional) + 5. Define adaption logic for outgoing messages as [`#adapt_output`](#classes-Droonga-Adapter-adapt_output). (optional) + +See also the [plugin development tutorial](../../../tutorial/plugin-development/adapter/). + + +### How an adapter works? {#how-works} + +An adapter works like following: + + 1. The Droonga Engine starts. + * A global instance of the adapter class (ex. `Droonga::Plugins::FooPlugin::Adapter`) is created and it is registered. + * The input pattern and the output pattern are registered. + * The Droonga Engine starts to wait for incoming messages. + 2. An incoming message is transferred from the Protocol Adapter to the Droonga Engine. + Then, the adaption phase (for an incoming message) starts. + * The adapter's [`#adapt_input`](#classes-Droonga-Adapter-adapt_input) is called, if the message matches to the [input matching pattern](#config) of the adapter. + * The method can modify the given incoming message, via [its methods](#classes-Droonga-InputMessage). + 3. After all adapters are applied, the adaption phase for an incoming message ends, and the message is transferred to the next "planning" phase. + 4. An outgoing message returns from the previous "collection" phase. + Then, the adaption phase (for an outgoing message) starts. + * The adapter's [`#adapt_output`](#classes-Droonga-Adapter-adapt_output) is called, if the message meets following both requirements: + - It is originated from an incoming message which was processed by the adapter itself. + - It matches to the [output matching pattern](#config) of the adapter. + * The method can modify the given outgoing message, via [its methods](#classes-Droonga-OutputMessage). + 5. After all adapters are applied, the adaption phase for an outgoing message ends, and the outgoing message is transferred to the Protocol Adapter. + +As described above, the Droonga Engine creates only one global instance of the adapter class for each plugin. +You should not keep stateful information for a pair of incoming and outgoing messages as instance variables of the adapter itself. +Instead, you should give stateful information as a part of the incoming message body, and receive it from the body of the corresponding outgoing message. + +Any error raised from the adapter is handled by the Droonga Engine itself. See also [error handling][]. + + +## Configurations {#config} + +`input_message.pattern` ([matching pattern][], optional, default=`nil`) +: A [matching pattern][] for incoming messages. + If no pattern (`nil`) is given, any message is regarded as "matched". + +`output_message.pattern` ([matching pattern][], optional, default=`nil`) +: A [matching pattern][] for outgoing messages. + If no pattern (`nil`) is given, any message is regarded as "matched". + +## Classes and methods {#classes} + +### `Droonga::Adapter` {#classes-Droonga-Adapter} + +This is the common base class of any adapter. Your plugin's adapter class must inherit this. + +#### `#adapt_input(input_message)` {#classes-Droonga-Adapter-adapt_input} + +This method receives a [`Droonga::InputMessage`](#classes-Droonga-InputMessage) wrapped incoming message. +You can modify the incoming message via its methods. + +In this base class, this method is defined as just a placeholder and it does nothing. +To modify incoming messages, you have to override it by yours, like following: + +~~~ruby +module Droonga::Plugins::QueryFixer + class Adapter < Droonga::Adapter + def adapt_input(input_message) + input_message.body["query"] = "fixed query" + end + end +end +~~~ + +#### `#adapt_output(output_message)` {#classes-Droonga-Adapter-adapt_output} + +This method receives a [`Droonga::OutputMessage`](#classes-Droonga-OutputMessage) wrapped outgoing message. +You can modify the outgoing message via its methods. + +In this base class, this method is defined as just a placeholder and it does nothing. +To modify outgoing messages, you have to override it by yours, like following: + +~~~ruby +module Droonga::Plugins::ErrorConcealer + class Adapter < Droonga::Adapter + def adapt_output(output_message) + output_message.status_code = Droonga::StatusCode::OK + end + end +end +~~~ + +### `Droonga::InputMessage` {#classes-Droonga-InputMessage} + +#### `#type`, `#type=(type)` {#classes-Droonga-InputMessage-type} + +This returns the `"type"` of the incoming message. + +You can override it by assigning a new string value, like: + +~~~ruby +module Droonga::Plugins::MySearch + class Adapter < Droonga::Adapter + input_message.pattern = ["type", :equal, "my-search"] + + def adapt_input(input_message) + p input_message.type + # => "my-search" + # This message will be handled by a plugin + # for the custom "my-search" type. + + input_message.type = "search" + + p input_message.type + # => "search" + # The messge type (type) is changed. + # This message will be handled by the "search" plugin, + # as a regular search request. + end + end +end +~~~ + +#### `#body`, `#body=(body)` {#classes-Droonga-InputMessage-body} + +This returns the `"body"` of the incoming message. + +You can override it by assigning a new value, partially or fully. For example: + +~~~ruby +module Droonga::Plugins::MinimumLimit + class Adapter < Droonga::Adapter + input_message.pattern = ["type", :equal, "search"] + + MAXIMUM_LIMIT = 10 + + def adapt_input(input_message) + input_message.body["queries"].each do |name, query| + query["output"] ||= {} + query["output"]["limit"] ||= MAXIMUM_LIMIT + query["output"]["limit"] = [query["output"]["limit"], MAXIMUM_LIMIT].min + end + # Now, all queries have "output.limit=10". + end + end +end +~~~ + +Another case: + +~~~ruby +module Droonga::Plugins::MySearch + class Adapter < Droonga::Adapter + input_message.pattern = ["type", :equal, "my-search"] + + def adapt_input(input_message) + # Extract the query string from the custom type message. + query_string = input_message["body"]["query"] + + # Construct internal search request for the "search" type. + input_message.type = "search" + input_message.body = { + "queries" => { + "source" => "Store", + "condition" => { + "query" => query_string, + "matchTo" => ["name"], + }, + "output" => { + "elements" => ["records"], + "limit" => 10, + }, + }, + } + # Now, both "type" and "body" are completely replaced. + end + end +end +~~~ + +### `Droonga::OutputMessage` {#classes-Droonga-OutputMessage} + +#### `#status_code`, `#status_code=(status_code)` {#classes-Droonga-OutputMessage-status_code} + +This returns the `"statusCode"` of the outgoing message. + +You can override it by assigning a new status code. For example: + +~~~ruby +module Droonga::Plugins::ErrorConcealer + class Adapter < Droonga::Adapter + input_message.pattern = ["type", :equal, "search"] + + def adapt_output(output_message) + unless output_message.status_code == StatusCode::InternalServerError + output_message.status_code = Droonga::StatusCode::OK + output_message.body = {} + output_message.errors = nil + # Now any internal server error is ignored and clients + # receive regular responses. + end + end + end +end +~~~ + +#### `#errors`, `#errors=(errors)` {#classes-Droonga-OutputMessage-errors} + +This returns the `"errors"` of the outgoing message. + +You can override it by assigning new error information, partially or fully. For example: + +~~~ruby +module Droonga::Plugins::ErrorExporter + class Adapter < Droonga::Adapter + input_message.pattern = ["type", :equal, "search"] + + def adapt_output(output_message) + output_message.errors.delete(secret_database) + # Delete error information from secret database + + output_message.body["errors"] = { + "records" => output_message.errors.collect do |database, error| + { + "database" => database, + "error" => error + } + end, + } + # Convert error informations to a fake search result named "errors". + end + end +end +~~~ + +#### `#body`, `#body=(body)` {#classes-Droonga-OutputMessage-body} + +This returns the `"body"` of the outgoing message. + +You can override it by assigning a new value, partially or fully. For example: + +~~~ruby +module Droonga::Plugins::SponsoredSearch + class Adapter < Droonga::Adapter + input_message.pattern = ["type", :equal, "search"] + + def adapt_output(output_message) + output_message.body.each do |name, result| + next unless result["records"] + result["records"].unshift(sponsored_entry) + end + # Now all search results include sponsored entry. + end + + def sponsored_entry + { + "title"=> "SALE!", + "url"=> "http://..." + } + end + end +end +~~~ + + + [matching pattern]: ../matching-pattern/ + [error handling]: ../error/ Added: reference/1.0.3/plugin/collector/index.md (+51 -0) 100644 =================================================================== --- /dev/null +++ reference/1.0.3/plugin/collector/index.md 2014-05-19 16:48:30 +0900 (f065268) @@ -0,0 +1,51 @@ +--- +title: Collector +layout: en +--- + +* TOC +{:toc} + + +## Abstract {#abstract} + +A collector merges two input values to single value. +The Droonga Engine tries to collect three or more values by applying the specified collector for two of them again and again. + +## Built-in collector classes {#builtin-collectors} + +There are some pre-defined collector classes used by built-in plugins. +Of course they are available for your custom plugins. + +### `Droonga::Collectors::And` + +Returns a result from comparison of two values by the `and` logical operator. +If both values are logically equal to `true`, then one of them (it is indeterminate) becomes the result. + +Values `null` (`nil`) and `false` are treated as `false`. +Otherwise `true`. + +### `Droonga::Collectors::Or` + +Returns a result from comparison of two values by the `or` logical operator. +If only one of them is logically equal to `true`, then the value becomes the result. +Otherwise, if values are logically same, one of them (it is indeterminate) becomes the result. + +Values `null` (`nil`) and `false` are treated as `false`. +Otherwise `true`. + +### `Droonga::Collectors::Sum` + +Returns a summarized value of two input values. + +This collector works a little complicatedly. + + * If one of values is equal to `null` (`nil`), then the other value becomes the result. + * If both values are hash, then a merged hash becomes the result. + * The result hash has all keys of two hashes. + If both have same keys, then one of their values appears as the value of the key in the reuslt hash. + * It is indeterminate which value becomes the base. + * Otherwise the result of `a + b` becomes the result. + * If they are arrays or strings, a concatenated value becomes the result. + It is indeterminate which value becomes the lefthand. + Added: reference/1.0.3/plugin/error/index.md (+61 -0) 100644 =================================================================== --- /dev/null +++ reference/1.0.3/plugin/error/index.md 2014-05-19 16:48:30 +0900 (8e4bf9e) @@ -0,0 +1,61 @@ +--- +title: Error handling in plugins +layout: en +--- + +* TOC +{:toc} + + +## Abstract {#abstract} + +Any unhandled error raised from a plugin is returned as an [error response][] for the corresponding incoming message, with the status code `500` (means "internal error"). + +If you want formatted error information to be returned, then rescue errors and raise your custom errors inheriting `Droonga::ErrorMessage::BadRequest` or `Droonga::ErrorMessage::InternalServerError` instead of raw errors. +(By the way, they are already included to the base class of plugins so you can define your custom errors easily like: `class CustomError < BadRequest`) + + +## Built-in error classes {#builtin-errors} + +There are some pre-defined error classes used by built-in plugins and the Droonga Engine itself. + +### `Droonga::ErrorMessage::NotFound` + +Means an error which the specified resource is not found in the dataset or any source. For example: + + # the second argument means "details" of the error. (optional) + raise Droonga::NotFound.new("#{name} is not found!", :elapsed_time => elapsed_time) + +### `Droonga::ErrorMessage::BadRequest` + +Means any error originated from the incoming message itself, ex. syntax error, validation error, and so on. For example: + + # the second argument means "details" of the error. (optional) + raise Droonga::NotFound.new("Syntax error in #{query}!", :detail => detail) + +### `Droonga::ErrorMessage::InternalServerError` + +Means other unknown error, ex. timed out, file I/O error, and so on. For example: + + # the second argument means "details" of the error. (optional) + raise Droonga::MessageProcessingError.new("busy!", :elapsed_time => elapsed_time) + + +## Built-in status codes {#builtin-status-codes} + +You should use following or other status codes as [a matter of principle](../../message/#error-status). + +`Droonga::StatusCode::OK` +: Equals to `200`. + +`Droonga::StatusCode::NOT_FOUND` +: Equals to `404`. + +`Droonga::StatusCode::BAD_REQUEST` +: Equals to `400`. + +`Droonga::StatusCode::INTERNAL_ERROR` +: Equals to `500`. + + + [error response]: ../../message/#error Added: reference/1.0.3/plugin/handler/index.md (+227 -0) 100644 =================================================================== --- /dev/null +++ reference/1.0.3/plugin/handler/index.md 2014-05-19 16:48:30 +0900 (b5e0a49) @@ -0,0 +1,227 @@ +--- +title: API set for plugins on the handling phase +layout: en +--- + +* TOC +{:toc} + + +## Abstract {#abstract} + +Each Droonga Engine plugin can have its *handler*. +On the handling phase, handlers can process a request and return a result. + + +### How to define a handler? {#howto-define} + +For example, here is a sample plugin named "foo" with a handler: + +~~~ruby +require "droonga/plugin" + +module Droonga::Plugins::FooPlugin + extend Plugin + register("foo") + + define_single_step do |step| + step.name = "foo" + step.handler = :Handler + step.collector = Collectors::And + end + + class Handler < Droonga::Handler + def handle(message) + # operations to process a request + end + end +end +~~~ + +Steps to define a handler: + + 1. Define a module for your plugin (ex. `Droonga::Plugins::FooPlugin`) and register it as a plugin. (required) + 2. Define a "single step" corresponding to the handler you are going to implement, via [`Droonga::SingleStepDefinition`](#class-Droonga-SingleStepDefinition). (required) + 3. Define a handler class (ex. `Droonga::Plugins::FooPlugin::Handler`) inheriting [`Droonga::Handler`](#classes-Droonga-Handler). (required) + 4. Define handling logic for requests as [`#handle`](#classes-Droonga-Handler-handle). (optional) + +See also the [plugin development tutorial](../../../tutorial/plugin-development/handler/). + + +### How a handler works? {#how-works} + +A handler works like following: + + 1. The Droonga Engine starts. + * Your custom steps are registered. + Your custom handler classes also. + * Then the Droonga Engine starts to wait for request messages. + 2. A request message is transferred from the adaption phase. + Then, the processing phase starts. + * The Droonga Engine finds a step definition from the message type. + * The Droonga Engine builds a "single step" based on the registered definition. + * A "single step" creates an instance of the registered handler class. + Then the Droonga Engine enters to the handling phase. + * The handler's [`#handle`](#classes-Droonga-Handler-handle) is called with a task massage including the request. + * The method can process the given incoming message as you like. + * The method returns a result value, as the output. + * After the handler finishes, the handling phase for the task message (and the request) ends. + * If no "step" is found for the type, nothing happens. + * All "step"s finish their task, the processing phase for the request ends. + +As described above, the Droonga Engine creates an instance of the handler class for each request. + +Any error raised from the handler is handled by the Droonga Engine itself. See also [error handling][]. + + +## Configurations {#config} + +`action.synchronous` (boolean, optional, default=`false`) +: Indicates that the request must be processed synchronously. + For example, a request to define a new column in a table must be processed after a request to define the table itself, if the table does not exist yet. + Then handlers for these requests have the configuration `action.synchronous = true`. + + +## Classes and methods {#classes} + +### `Droonga::SingleStepDefinition` {#classes-Droonga-SingleStepDefinition} + +This provides methods to describe the "step" corresponding to the handler. + +#### `#name`, `#name=(name)` {#classes-Droonga-SingleStepDefinition-name} + +Describes the name of the step itself. +Possible value is a string. + +The Droonga Engine treats an incoming message as a request of a "command", if there is any step with the `name` which equals to the message's `type`. +In other words, this defines the name of the command corresponding to the step itself. + + +#### `#handler`, `#handler=(handler)` {#classes-Droonga-SingleStepDefinition-handler} + +Associates a specific handler class to the step itself. +You can specify the class as any one of following choices: + + * A reference to a handler class itself, like `Handler` or `Droonga::Plugins::FooPlugin::Handler`. + Of course, the class have to be already defined at the time. + * A symbol which refers the name of a handler class in the current namespace, like `:Handler`. + This is useful if you want to describe the step at first and define the actual class after that. + * A class path string of a handler class, like `"Droonga::Plugins::FooPlugin::Handler"`. + This is also useful to define the class itself after the description. + +You must define the referenced class by the time the Droonga Engine actually processes the step, if you specify the name of the handler class as a symbol or a string. +If the Droonga Engine fails to find out the actual handler class, or no handler is specified, then the Droonga Engine does nothing for the request. + +#### `#collector`, `#collector=(collector)` {#classes-Droonga-SingleStepDefinition-collector} + +Associates a specific collector class to the step itself. +You can specify the class as any one of following choices: + + * A reference to a collector class itself, like `Collectors::Something` or `Droonga::Plugins::FooPlugin::MyCollector`. + Of course, the class have to be already defined at the time. + * A symbol which refers the name of a collector class in the current namespace, like `:MyCollector`. + This is useful if you want to describe the step at first and define the actual class after that. + * A class path string of a collector class, like `"Droonga::Plugins::FooPlugin::MyCollector"`. + This is also useful to define the class itself after the description. + +You must define the referenced class by the time the Droonga Engine actually collects results, if you specify the name of the collector class as a symbol or a string. +If the Droonga Engine fails to find out the actual collector class, or no collector is specified, then the Droonga Engine doesn't collect results and returns multiple messages as results. + +See also [descriptions of collectors][collector]. + +#### `#write`, `#write=(write)` {#classes-Droonga-SingleStepDefinition-write} + +Describes whether the step modifies any data in the storage or don't. +If a request aims to modify some data in the storage, the request must be processed for all replicas. +Otherwise the Droonga Engine can optimize handling of the step. +For example, caching of results, reducing of CPU/memory usage, and so on. + +Possible values are: + + * `true`, means "this step can modify the storage." + * `false`, means "this step never modifies the storage." (default) + +#### `#inputs`, `#inputs=(inputs)` {#classes-Droonga-SingleStepDefinition-inputs} + +(TBD) + +#### `#output`, `#output=(output)` {#classes-Droonga-SingleStepDefinition-output} + +(TBD) + +### `Droonga::Handler` {#classes-Droonga-Handler} + +This is the common base class of any handler. +Your plugin's handler class must inherit this. + +#### `#handle(message)` {#classes-Droonga-Handler-handle} + +This method receives a [`Droonga::HandlerMessage`](#classes-Droonga-HandlerMessage) wrapped task message. +You can read the request information via its methods. + +In this base class, this method is defined as just a placeholder and it does nothing. +To process messages, you have to override it by yours, like following: + +~~~ruby +module Droonga::Plugins::MySearch + class Handler < Droonga::Handler + def handle(message) + search_query = message.request["body"]["query"] + ... + { ... } # the result + end + end +end +~~~ + +The Droonga Engine uses the returned value of this method as the result of the handling. +It will be used to build the body of the unified response, and delivered to the Protocol Adapter. + + +### `Droonga::HandlerMessage` {#classes-Droonga-HandlerMessage} + +This is a wrapper for a task message. + +The Droonga Engine analyzes a transferred request message, and build multiple task massages to process the request. +A task massage has some information: a request, a step, descendant tasks, and so on. + +#### `#request` {#classes-Droonga-HandlerMessage-request} + +This returns the request message. +You can read request body via this method. For example: + +~~~ruby +module Droonga::Plugins::MySearch + class Handler < Droonga::Handler + def handle(message) + request = message.request + search_query = request["body"]["query"] + ... + end + end +end +~~~ + +#### `@context` {#classes-Droonga-HandlerMessage-context} + +This is a reference to the `Groonga::Context` instance for the storage of the corresponding volume. +See the [class reference of Rroonga][Groonga::Context]. + +You can use any feature of Rroonga via `@context`. +For example, this code returns the number of records in the specified table: + +~~~ruby +module Droonga::Plugins::CountRecords + class Handler < Droonga::Handler + def handle(message) + request = message.request + table_name = request["body"]["table"] + count = @context[table_name].size + end + end +end +~~~ + + [error handling]: ../error/ + [collector]: ../collector/ + [Groonga::Context]: http://ranguba.org/rroonga/en/Groonga/Context.html Added: reference/1.0.3/plugin/index.md (+13 -0) 100644 =================================================================== --- /dev/null +++ reference/1.0.3/plugin/index.md 2014-05-19 16:48:30 +0900 (89e7398) @@ -0,0 +1,13 @@ +--- +title: Plugin development +layout: en +--- + +Droonga Engine has different API sets for plugins, on each phase. +See also the [plugin development tutorial](../../tutorial/plugin-development/). + + * [API set for the adaption phase](adapter/) + * [API set for the handling phase](handler/) + * [Matching pattern for messages](matching-pattern/) + * [Collector](collector/) + * [Error handling](error/) Added: reference/1.0.3/plugin/matching-pattern/index.md (+233 -0) 100644 =================================================================== --- /dev/null +++ reference/1.0.3/plugin/matching-pattern/index.md 2014-05-19 16:48:30 +0900 (0df1b64) @@ -0,0 +1,233 @@ +--- +title: Matching pattern for messages +layout: en +--- + +* TOC +{:toc} + + +## Abstract {#abstract} + +The Droonga Engine provides a tiny language to specify patterns of messages, called *matching pattern*. +It is used to specify target messages of various operations, ex. plugins. + + +## Examples {#examples} + +### Simple matching + + pattern = ["type", :equal, "search"] + +This matches to messages like: + + { + "type": "search", + ... + } + +### Matching for a deep target + + pattern = ["body.success", :equal, true] + +This matches to messages like: + + { + "type": "add.result", + "body": { + "success": true + } + } + +Doesn't match to: + + { + "type": "add.result", + "body": { + "success": false + } + } + +### Nested patterns + + pattern = [ + ["type", :equal, "table_create"], + :or, + ["body.success", :equal, true] + ] + +This matches to both: + + { + "type": "table_create", + ... + } + +and: + + { + "type": "column_create", + ... + "body": { + "success": true + } + } + + +## Syntax {#syntax} + +There are two typeos of matching patterns: "basic pattern" and "nested pattern". + +### Basic pattern {#syntax-basic} + +#### Structure {#syntax-basic-structure} + +A basic pattern is described as an array including 2 or more elements, like following: + + ["type", :equal, "search"] + + * The first element is a *target path*. It means the location of the information to be checked, in the [message][]. + * The second element is an *operator*. It means how the information specified by the target path should be checked. + * The third element is an *argument for the oeprator*. It is a primitive value (string, numeric, or boolean) or an array of values. Some operators require no argument. + +#### Target path {#syntax-basic-target-path} + +The target path is specified as a string, like: + + "body.success" + +The matching mechanism of the Droonga Engine interprets it as a dot-separated list of *path components*. +A path component represents the property in the message with same name. +So, the example above means the location: + + { + "body": { + "success": <target> + } + } + + + + +#### Avialable operators {#syntax-basic-operators} + +The operator is specified as a symbol. + +`:equal` +: Returns `true`, if the target value is equal to the given value. Otherwise `false`. + For example, + + ["type", :equal, "search"] + + The pattern above matches to a message like following: + + { + "type": "search", + ... + } + +`:in` +: Returns `true`, if the target value is in the given array of values. Otherwise `false`. + For example, + + ["type", :in, ["search", "select"]] + + The pattern above matches to a message like following: + + { + "type": "select", + ... + } + + But it doesn't match to: + + { + "type": "find", + ... + } + +`:include` +: Returns `true` if the target array of values includes the given value. Otherwise `false`. + In other words, this is the opposite of the `:in` operator. + For example, + + ["body.tags", :include, "News"] + + The pattern above matches to a message like following: + + { + "type": "my.notification", + "body": { + "tags": ["News", "Groonga", "Droonga", "Fluentd"] + } + } + +`:exist` +: Returns `true` if the target exists. Otherwise `false`. + For example, + + ["body.comments", :exist, "News"] + + The pattern above matches to a message like following: + + { + "type": "my.notification", + "body": { + "title": "Hello!", + "comments": [] + } + } + + But it doesn't match to: + + { + "type": "my.notification", + "body": { + "title": "Hello!" + } + } + +`:start_with` +: Returns `true` if the target string value starts with the given string. Otherwise `false`. + For example, + + ["body.path", :start_with, "/archive/"] + + The pattern above matches to a message like following: + + { + "type": "my.notification", + "body": { + "path": "/archive/2014/02/28.html" + } + } + + +### Nested pattern {#syntax-nested} + +#### Structure {#syntax-nested-structure} + +A nested pattern is described as an array including 3 elements, like following: + + [ + ["type", :equal, "table_create"], + :or, + ["type", :equal, "column_create"] + ] + + * The first and the third elements are patterns, basic or nested. (In other words, you can nest patterns recursively.) + * The second element is a *logical operator*. + +#### Avialable operators {#syntax-nested-operators} + +`:and` +: Returns `true` if both given patterns are evaluated as `true`. Otherwise `false`. + +`:or` +: Returns `true` if one of given patterns (the first or the third element) is evaluated as `true`. Otherwise `false`. + + + + + [message]:../../message/ + Added: tutorial/1.0.3/basic/index.md (+1501 -0) 100644 =================================================================== --- /dev/null +++ tutorial/1.0.3/basic/index.md 2014-05-19 16:48:30 +0900 (5659dda) @@ -0,0 +1,1501 @@ +--- +title: "Droonga tutorial: basic usage" +layout: en +--- + +* TOC +{:toc} + +## The goal of this tutorial + +Learning steps to setup a Droonga based search system by yourself. + +## Precondition + +* You must have basic knowledge and experiences to setup and operate an [Ubuntu][] Server. +* You must have basic knowledge and experiences to develop applications based on the [Ruby][] and the [Node.js][]. + +## Abstract + +### What is the Droonga? + +It is a data processing engine based on a distributed architecture, named after the terms "distributed-Groonga". + +The Droonga is built on some components which are made as separated packages. You can develop various data processing systems (for example, a fulltext search engine) with high scalability from a distributed architecture, with those packages. + +### Components of the Droonga + +#### Droonga Engine + +The component "Droonga Engine" is the main part to process data with a distributed architecture. It is triggered by requests and processes various data. + +This component is developed and released as the [droonga-engine][]. +The protocol is compatible to [Fluentd]. + +It internally uses [Groonga][] as its search engine. +Groonga is an open source, fulltext search engine, including a column-store feature. + +#### Protocol Adapter + +The component "Protocol Adapter" provides ability for clients to communicate with a Droonga engine, using various protocols. + +The only one available protocol of a Droonga engine is the fluentd protocol. +Instead, protocol adapters translate it to other common protocols (like HTTP, Socket.OP, etc.) between the Droonga Engine and clients. + +Currently, there is an implementation for the HTTP: [droonga-http-server][], a [Node.js][] module package. +In other words, the droonga-http-server is one of Droonga Progocol Adapters, and it's a "Droonga HTTP Protocol Adapter". + +## Abstract of the system described in this tutorial + +This tutorial describes steps to build a system like following: + + +-------------+ +------------------+ +----------------+ + | Web Browser | <--------> | Protocol Adapter | <-------> | Droonga Engine | + +-------------+ HTTP +------------------+ Fluent +----------------+ + w/droonga-http protocol w/droonga-engine + -server + + + \--------------------------------------------------/ + This tutorial describes about this part. + +User agents (ex. a Web browser) send search requests to a protocol adapter. The adapter receives them, and sends internal (translated) search requests to a Droonga engine. The engine processes them actually. Search results are sent from the engine to the protocol adapter, and finally delivered to the user agents. + +For example, let's try to build a database system to find [Starbucks stores in New York](http://geocommons.com/overlays/430038). + + +## Prepare an environment for experiments + +Prepare a computer at first. This tutorial describes steps to develop a search service based on the Droonga, on an existing computer. +Following instructions are basically written for a successfully prepared virtual machine of the `Ubuntu 13.10 x64` on the service [DigitalOcean](https://www.digitalocean.com/), with an available console. + +NOTE: Make sure to use instances with >= 2GB memory equipped, at least during installation of required packages for Droonga. Otherwise, you may experience a strange build error. + +Assume that the host is `192.168.0.10`. + +## Install packages required for the setup process + +Install packages required to setup a Droonga engine. + + # apt-get update + # apt-get -y upgrade + # apt-get install -y ruby ruby-dev build-essential nodejs npm + +## Build a Droonga engine + +The part "Droonga engine" stores the database and provides the search feature actually. +In this section we install a droonga-engine and load searchable data to the database. + +### Install a droonga-engine and droonga-client + + # gem install droonga-engine droonga-client + +Required packages are prepared by the command above. Let's continue to the configuration step. + +### Prepare configuration files to start a Droonga engine + +Create a directory for a Droonga engine: + + # mkdir engine + # cd engine + +Next, put a configuration file `catalog.json` like following, into the directory: + +catalog.json: + + { + "version": 2, + "effectiveDate": "2013-09-01T00:00:00Z", + "datasets": { + "Starbucks": { + "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" + } + } + ] + } + ] + } + } + } + +This `catalog.json` defines a dataset `Starbucks` as: + + * At the top level, there is one volume based on two sub volumes, called "replicas". + * At the next lower level, one replica volume is based on three sub volumes, called "slices". + They are minimum elements constructing a Droonga's dataset. + +These six atomic volumes having `"address"` information are internally called as *single volume*s. +The `"address"` indicates the location of the corresponding physical storage which is a database for Groonga, they are managed by `droonga-engine` instances automatically. + +For more details of the configuration file `catalog.json`, see [the reference manual of catalog.json](/reference/catalog). + +### Start an instance of droonga-engine + +Start a Droonga engine, you can start it with the command `droonga-engine`, like: + + # droonga-engine --host 192.168.0.10 --log-file=$PWD/droonga-engine.log --daemon --pid-file $PWD/droonga-engine.pid + +### Stop an instance of droonga-engine + +First, you need to know how to stop droonga-engine. + +Send SIGTERM to droonga-engine: + + # kill $(cat droonga-engine.pid) + +This is the way to stop droonga-engine. + +Start droonga-engine again: + + # droonga-engine --host 192.168.0.10 --log-file=$PWD/droonga-engine.log --daemon --pid-file $PWD/droonga-engine.pid + +### Create a database + +After a Droonga engine is started, let's load data. +Prepare `stores.jsons` including location data of stores. + +stores.jsons: + +~~~ +{ + "dataset": "Starbucks", + "type": "add", + "body": { + "table": "Store", + "key": "1st Avenue & 75th St. - New York NY (W)", + "values": { + "location": "40.770262,-73.954798" + } + } +} +{ + "dataset": "Starbucks", + "type": "add", + "body": { + "table": "Store", + "key": "76th & Second - New York NY (W)", + "values": { + "location": "40.771056,-73.956757" + } + } +} +{ + "dataset": "Starbucks", + "type": "add", + "body": { + "table": "Store", + "key": "2nd Ave. & 9th Street - New York NY", + "values": { + "location": "40.729445,-73.987471" + } + } +} +{ + "dataset": "Starbucks", + "type": "add", + "body": { + "table": "Store", + "key": "15th & Third - New York NY (W)", + "values": { + "location": "40.733946,-73.9867" + } + } +} +{ + "dataset": "Starbucks", + "type": "add", + "body": { + "table": "Store", + "key": "41st and Broadway - New York NY (W)", + "values": { + "location": "40.755111,-73.986225" + } + } +} +{ + "dataset": "Starbucks", + "type": "add", + "body": { + "table": "Store", + "key": "84th & Third Ave - New York NY (W)", + "values": { + "location": "40.777485,-73.954979" + } + } +} +{ + "dataset": "Starbucks", + "type": "add", + "body": { + "table": "Store", + "key": "150 E. 42nd Street - New York NY (W)", + "values": { + "location": "40.750784,-73.975582" + } + } +} +{ + "dataset": "Starbucks", + "type": "add", + "body": { + "table": "Store", + "key": "West 43rd and Broadway - New York NY (W)", + "values": { + "location": "40.756197,-73.985624" + } + } +} +{ + "dataset": "Starbucks", + "type": "add", + "body": { + "table": "Store", + "key": "Macy's 35th Street Balcony - New York NY", + "values": { + "location": "40.750703,-73.989787" + } + } +} +{ + "dataset": "Starbucks", + "type": "add", + "body": { + "table": "Store", + "key": "Macy's 6th Floor - Herald Square - New York NY (W)", + "values": { + "location": "40.750703,-73.989787" + } + } +} +{ + "dataset": "Starbucks", + "type": "add", + "body": { + "table": "Store", + "key": "Herald Square- Macy's - New York NY", + "values": { + "location": "40.750703,-73.989787" + } + } +} +{ + "dataset": "Starbucks", + "type": "add", + "body": { + "table": "Store", + "key": "Macy's 5th Floor - Herald Square - New York NY (W)", + "values": { + "location": "40.750703,-73.989787" + } + } +} +{ + "dataset": "Starbucks", + "type": "add", + "body": { + "table": "Store", + "key": "80th & York - New York NY (W)", + "values": { + "location": "40.772204,-73.949862" + } + } +} +{ + "dataset": "Starbucks", + "type": "add", + "body": { + "table": "Store", + "key": "Columbus @ 67th - New York NY (W)", + "values": { + "location": "40.774009,-73.981472" + } + } +} +{ + "dataset": "Starbucks", + "type": "add", + "body": { + "table": "Store", + "key": "45th & Broadway - New York NY (W)", + "values": { + "location": "40.75766,-73.985719" + } + } +} +{ + "dataset": "Starbucks", + "type": "add", + "body": { + "table": "Store", + "key": "Marriott Marquis - Lobby - New York NY", + "values": { + "location": "40.759123,-73.984927" + } + } +} +{ + "dataset": "Starbucks", + "type": "add", + "body": { + "table": "Store", + "key": "Second @ 81st - New York NY (W)", + "values": { + "location": "40.77466,-73.954447" + } + } +} +{ + "dataset": "Starbucks", + "type": "add", + "body": { + "table": "Store", + "key": "52nd & Seventh - New York NY (W)", + "values": { + "location": "40.761829,-73.981141" + } + } +} +{ + "dataset": "Starbucks", + "type": "add", + "body": { + "table": "Store", + "key": "1585 Broadway (47th) - New York NY (W)", + "values": { + "location": "40.759806,-73.985066" + } + } +} +{ + "dataset": "Starbucks", + "type": "add", + "body": { + "table": "Store", + "key": "85th & First - New York NY (W)", + "values": { + "location": "40.776101,-73.949971" + } + } +} +{ + "dataset": "Starbucks", + "type": "add", + "body": { + "table": "Store", + "key": "92nd & 3rd - New York NY (W)", + "values": { + "location": "40.782606,-73.951235" + } + } +} +{ + "dataset": "Starbucks", + "type": "add", + "body": { + "table": "Store", + "key": "165 Broadway - 1 Liberty - New York NY (W)", + "values": { + "location": "40.709727,-74.011395" + } + } +} +{ + "dataset": "Starbucks", + "type": "add", + "body": { + "table": "Store", + "key": "1656 Broadway - New York NY (W)", + "values": { + "location": "40.762434,-73.983364" + } + } +} +{ + "dataset": "Starbucks", + "type": "add", + "body": { + "table": "Store", + "key": "54th & Broadway - New York NY (W)", + "values": { + "location": "40.764275,-73.982361" + } + } +} +{ + "dataset": "Starbucks", + "type": "add", + "body": { + "table": "Store", + "key": "Limited Brands-NYC - New York NY", + "values": { + "location": "40.765219,-73.982025" + } + } +} +{ + "dataset": "Starbucks", + "type": "add", + "body": { + "table": "Store", + "key": "19th & 8th - New York NY (W)", + "values": { + "location": "40.743218,-74.000605" + } + } +} +{ + "dataset": "Starbucks", + "type": "add", + "body": { + "table": "Store", + "key": "60th & Broadway-II - New York NY (W)", + "values": { + "location": "40.769196,-73.982576" + } + } +} +{ + "dataset": "Starbucks", + "type": "add", + "body": { + "table": "Store", + "key": "63rd & Broadway - New York NY (W)", + "values": { + "location": "40.771376,-73.982709" + } + } +} +{ + "dataset": "Starbucks", + "type": "add", + "body": { + "table": "Store", + "key": "195 Broadway - New York NY (W)", + "values": { + "location": "40.710703,-74.009485" + } + } +} +{ + "dataset": "Starbucks", + "type": "add", + "body": { + "table": "Store", + "key": "2 Broadway - New York NY (W)", + "values": { + "location": "40.704538,-74.01324" + } + } +} +{ + "dataset": "Starbucks", + "type": "add", + "body": { + "table": "Store", + "key": "2 Columbus Ave. - New York NY (W)", + "values": { + "location": "40.769262,-73.984764" + } + } +} +{ + "dataset": "Starbucks", + "type": "add", + "body": { + "table": "Store", + "key": "NY Plaza - New York NY (W)", + "values": { + "location": "40.702802,-74.012784" + } + } +} +{ + "dataset": "Starbucks", + "type": "add", + "body": { + "table": "Store", + "key": "36th and Madison - New York NY (W)", + "values": { + "location": "40.748917,-73.982683" + } + } +} +{ + "dataset": "Starbucks", + "type": "add", + "body": { + "table": "Store", + "key": "125th St. btwn Adam Clayton & FDB - New York NY", + "values": { + "location": "40.808952,-73.948229" + } + } +} +{ + "dataset": "Starbucks", + "type": "add", + "body": { + "table": "Store", + "key": "70th & Broadway - New York NY (W)", + "values": { + "location": "40.777463,-73.982237" + } + } +} +{ + "dataset": "Starbucks", + "type": "add", + "body": { + "table": "Store", + "key": "2138 Broadway - New York NY (W)", + "values": { + "location": "40.781078,-73.981167" + } + } +} +{ + "dataset": "Starbucks", + "type": "add", + "body": { + "table": "Store", + "key": "118th & Frederick Douglas Blvd. - New York NY (W)", + "values": { + "location": "40.806176,-73.954109" + } + } +} +{ + "dataset": "Starbucks", + "type": "add", + "body": { + "table": "Store", + "key": "42nd & Second - New York NY (W)", + "values": { + "location": "40.750069,-73.973393" + } + } +} +{ + "dataset": "Starbucks", + "type": "add", + "body": { + "table": "Store", + "key": "Broadway @ 81st - New York NY (W)", + "values": { + "location": "40.784972,-73.978987" + } + } +} +{ + "dataset": "Starbucks", + "type": "add", + "body": { + "table": "Store", + "key": "Fashion Inst of Technology - New York NY", + "values": { + "location": "40.746948,-73.994557" + } + } +} +~~~ + +Open another terminal and send the json to the Droonga engine. + +Send `stores.jsons` as follows: + +~~~ +# droonga-request --tag starbucks 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 + } +] +~~~ + +Now a Droonga engine for searching Starbucks stores database is ready. + +### Send request with droonga-request + +Check if it is working. Create a query as a JSON file as follows. + +search-all-stores.json: + +~~~ +{ + "dataset": "Starbucks", + "type": "search", + "body": { + "queries": { + "stores": { + "source": "Store", + "output": { + "elements": [ + "startTime", + "elapsedTime", + "count", + "attributes", + "records" + ], + "attributes": ["_key"], + "limit": -1 + } + } + } + } +} +~~~ + +Send the request to the 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)" + ] + ] + } + } + } +] +~~~ + +Now the store names are retrieved. The engine looks working correctly. +Next, setup a protocol adapter for clients to accept search requests via HTTP. + +## Setup an HTTP Protocol Adapter + +Let's use the `droonga-http-server` as an HTTP protocol adapter. It is an npm package for the Node.js. + +### Install the droonga-http-server + + # npm install -g droonga-http-server + +Then, run it. + + # droonga-http-server --port 3000 \ + --receive-host-name=192.168.0.10 \ + --droonga-engine-host-name=192.168.0.10 \ + --default-dataset=Starbucks \ + --daemon \ + --pid-file $PWD/droonga-http-server.pid + + +### Search request via HTTP + +We're all set. Let's send a search request to the protocol adapter via HTTP. At first, try to get all records of the `Stores` table by a request like following. (Note: The `attributes=_key` parameter means "export the value of the column `_key` to the search result". If you don't set the parameter, each record returned in the `records` will become just a blank array. You can specify multiple column names by the delimiter `,`. For example `attributes=_key,location` will return both the primary key and the location for each record.) + + # curl "http://192.168.0.10:3000/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)" + ] + ] + } + } + +Because the `count` says `40`, you know there are all 40 records in the table. Search result records are returned as an array `records`. + +Next step, let's try more meaningful query. To search stores which contain "Columbus" in their name, give `Columbus` as the parameter `query`, and give `_key` as the parameter `match_to` which means the column to be searched. Then: + + # curl "http://192.168.0.10:3000/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)" + ] + ] + } + } + +As the result, two stores are found by the search condition. + +For more details of the Droonga HTTP Server, see the [reference manual][http-server]. + + +## Conclusion + +In this tutorial, you did setup both packages [droonga-engine][] and [droonga-http-server][] which construct [Droonga][] service on a [Ubuntu Linux][Ubuntu]. +Moreover, you built a search system based on an HTTP protocol adapter with a Droonga engine, and successfully searched. + + + [http-server]: ../../reference/http-server/ + [Ubuntu]: http://www.ubuntu.com/ + [Droonga]: https://droonga.org/ + [droonga-engine]: https://github.com/droonga/droonga-engine + [droonga-http-server]: https://github.com/droonga/droonga-http-server + [Groonga]: http://groonga.org/ + [Ruby]: http://www.ruby-lang.org/ + [nvm]: https://github.com/creationix/nvm + [Socket.IO]: http://socket.io/ + [Fluentd]: http://fluentd.org/ + [Node.js]: http://nodejs.org/ Added: tutorial/1.0.3/groonga/index.md (+297 -0) 100644 =================================================================== --- /dev/null +++ tutorial/1.0.3/groonga/index.md 2014-05-19 16:48:30 +0900 (4f85425) @@ -0,0 +1,297 @@ +--- +title: "Droonga tutorial: How to migrate from Groonga?" +layout: en +--- + +* TOC +{:toc} + +## The goal of this tutorial + +Learning steps to run a Droonga cluster by your hand, and use it as a [Groonga][groonga] compatible server. + +## Precondition + +* You must have basic knowledge and experiences to set up and operate an [Ubuntu][] Server. +* You must have basic knowledge and experiences to use the [Groonga][groonga] via HTTP. + +## What's Droonga? + +It is a data processing engine based on a distributed architecture, named after the terms "distributed-Groonga". +As its name suggests, it can work as a Groonga compatible server with some improvements - replication and sharding. + +In a certain sense, the Droonga is quite different from Groonga, about its architecture, design, API etc. +However, you don't have to understand the whole architecture of the Droonga, if you simply use it just as a Groonga compatible server. + +For example, let's try to build a database system to find [Starbucks stores in New York](http://geocommons.com/overlays/430038). + +## Set up a Droonga cluster + +### Prepare an environment for experiments + +Prepare a computer at first. +This tutorial describes steps to set up a Droonga cluster based on existing computers. +Following instructions are basically written for a successfully prepared virtual machine of the `Ubuntu 13.10 x64` on the service [DigitalOcean](https://www.digitalocean.com/), with an available console. + +NOTE: Make sure to use instances with >= 2GB memory equipped, at least during installation of required packages for Droonga. +Otherwise, you may experience a strange build error. + +You need to prepare two or more computers for effective replication. + +### Steps to install Droonga components + +Groonga provides binary packages and you can install Groonga easily, for some environments. +(See: [how to install Groonga](http://groonga.org/docs/install.html)) + +However, currently there is no such an easy way to set up a database system based on Droonga. +We are planning to provide a better way (like a chef cookbook), but for now, you have to set up it by your hand. + +A database system based on the Droonga is called *Droonga cluster*. +A Droonga cluster is constructed from multiple computers, called *Droonga node*. +So you have to set up multiple Droonga nodes for your Droonga cluster. + +Assume that you have two computers: `192.168.0.10` and `192.168.0.11`. + + 1. Install required platform packages, *on each computer*. + + # apt-get update + # apt-get -y upgrade + # apt-get install -y ruby ruby-dev build-essential nodejs npm + + 2. Install a gem package `droonga-engine`, *on each computer*. + It is the core component provides most features of Droonga system. + + # gem install droonga-engine + + 3. Install an npm package `droonga-http-server`, *on each computer*. + It is the frontend component required to translate HTTP requests to Droonga's native one. + + # npm install -g droonga-http-server + + 4. Install [Serf][] command, *on each computer*. + It is required to do alive monitoring of nodes in the cluster. + + # wget https://dl.bintray.com/mitchellh/serf/0.5.0_linux_amd64.zip + # unzip 0.5.0_linux_amd64.zip + # sudo mv serf /usr/local/bin/ + + 5. Prepare a configuration directory for a Droonga node, *on each computer*. + All physical databases are placed under this directory. + + # mkdir ~/droonga + # cd ~/droonga + + 6. Create a `catalog.json`, *on one of Droonga nodes*. + The file defines the structure of your Droonga cluster. + You'll specify the name of the dataset via the `--dataset` option and the list of your Droonga node's IP addresses via the `--hosts` option, like: + + # droonga-catalog-generate --dataset=Starbucks \ + --hosts=192.168.0.10,192.168.0.11 \ + --output=./catalog.json + + If you have only one computer and trying to set up it just for testing, then you'll do: + + # droonga-catalog-generate --dataset=Starbucks \ + --hosts=127.0.0.1 \ + --output=./catalog.json + + 7. Share the generated `catalog.json` *to your all Droonga nodes*. + + # scp ~/droonga/catalog.json 192.168.0.11:~/droonga/ + + (Or, of course, you can generate same `catalog.json` on each computer, instead of copying.) + +All Droonga nodes for your Droonga cluster are prepared by steps described above. +Let's continue to the next step. + +## Use the Droonga cluster, via HTTP + +### Start and stop services on each Droonga node + +You can run Groonga as an HTTP server with the option `-d`, like: + + # groonga -p 10041 -d --protocol http /tmp/databases/db + +On the other hand, you have to run multiple servers for each Droonga node to use your Droonga cluster via HTTP. + +To start them, run commands like following on each Droonga node: + + # cd ~/droonga + # host=192.168.0.10 + # droonga-engine --host=$host \ + --daemon \ + --pid-file=$PWD/droonga-engine.pid + # droonga-http-server --port=10041 \ + --receive-host-name=$host \ + --droonga-engine-host-name=$host \ + --default-dataset=Starbucks \ + --daemon \ + --pid-file=$PWD/droonga-http-server.pid + # serf agent -node="${host}:10031" -bind=$host \ + -event-handler="droonga-handle-serf-event --base-dir $PWD" & + +Note that you have to specify the host name of the Droonga node itself via some options. +It will be used to communicate with other Droonga nodes in the cluster. +So you have to specify different host name on another Droonga node, like: + + # cd ~/droonga + # host=192.168.0.11 + # droonga-engine --host=$host \ + ... + +After that, run following command to start alive monitoring, on the node "192.168.0.10": + + # serf join 192.168.0.11 + +By the command two nodes construct a cluster and they monitor each other. +If one of nodes dies and there is any still alive node, survivor(s) will work as the Droonga cluster. +Then you can recover the dead node and re-join it to the cluster secretly. + +To stop services, run commands like following on each Droonga node: + + # kill $(cat ~/droonga/droonga-engine.pid) + # kill $(cat ~/droonga/droonga-http-server.pid) + # serf leave + +### Create a table + +Now your Droonga cluster actually works as a Groonga's HTTP server. + +Requests are completely same to ones for a Groonga server. +To create a new table `Store`, you just have to send a GET request for the `table_create` command, like: + + # endpoint="http://192.168.0.10:10041/d" + # curl "${endpoint}/table_create?name=Store&type=Hash&key_type=ShortText" + [[0,1398662266.3853862,0.08530688285827637],true] + +Note that you have to specify the host, one of Droonga nodes with active droonga-http-server, in your Droonga cluster. +In other words, you can use any favorite node in the cluster as an endpoint. +All requests will be distributed to suitable nodes in the cluster. + +OK, now the table has been created successfully. +Let's see it by the `table_list` command: + + # curl "${endpoint}/table_list" + [[0,1398662423.509928,0.003869295120239258],[[["id","UInt32"],["name","ShortText"],["path","ShortText"],["flags","ShortText"],["domain","ShortText"],["range","ShortText"],["default_tokenizer","ShortText"],["normalizer","ShortText"]],[256,"Store","/home/username/groonga/droonga-engine/000/db.0000100","TABLE_HASH_KEY|PERSISTENT","ShortText",null,null,null]]] + +Because it is a cluster, another endpoint returns same result. + + # curl "http://192.168.0.11:10041/d/table_list" + [[0,1398662423.509928,0.003869295120239258],[[["id","UInt32"],["name","ShortText"],["path","ShortText"],["flags","ShortText"],["domain","ShortText"],["range","ShortText"],["default_tokenizer","ShortText"],["normalizer","ShortText"]],[256,"Store","/home/username/groonga/droonga-engine/000/db.0000100","TABLE_HASH_KEY|PERSISTENT","ShortText",null,null,null]]] + +### Create a column + +Next, create a new column `location` to the `Store` table by the `column_create` command, like: + + # curl "${endpoint}/column_create?table=Store&name=location&flags=COLUMN_SCALAR&type=WGS84GeoPoint" + [[0,1398664305.8856306,0.00026226043701171875],true] + +Then verify that the column is correctly created, by the `column_list` command: + + # curl "${endpoint}/column_list?table=Store" + [[0,1398664345.9680889,0.0011739730834960938],[[["id","UInt32"],["name","ShortText"],["path","ShortText"],["type","ShortText"],["flags","ShortText"],["domain","ShortText"],["range","ShortText"],["source","ShortText"]],[257,"location","/home/username/groonga/droonga-engine/000/db.0000101","fix","COLUMN_SCALAR","Store","WGS84GeoPoint",[]]]] + +### Create indexes + +Create indexes also. + + # curl "${endpoint}/table_create?name=Location&type=PatriciaTrie&key_type=WGS84GeoPoint" + [[0,1398664401.4927232,0.12011909484863281],true] + # curl "${endpoint}/column_create?table=Location&name=store&flags=COLUMN_INDEX&type=Store&source=location" + [[0,1398664429.5348525,0.13435077667236328],true] + # curl "${endpoint}/table_create?name=Term&type=PatriciaTrie&key_type=ShortText&default_tokenizer=TokenBigram&normalizer=NormalizerAuto" + [[0,1398664454.446939,0.14734888076782227],true] + # curl "${endpoint}/column_create?table=Term&name=store__key&flags=COLUMN_INDEX|WITH_POSITION&type=Store&source=_key" + [[0,1398664474.7112074,0.12619781494140625],true] + + +### Load data to a table + +Let's load data to the `Store` table. +First. prepare the data as a JSON file `stores.json`. + +stores.json: + +~~~ +[ +["_key","location"], +["1st Avenue & 75th St. - New York NY (W)","40.770262,-73.954798"], +["76th & Second - New York NY (W)","40.771056,-73.956757"], +["2nd Ave. & 9th Street - New York NY","40.729445,-73.987471"], +["15th & Third - New York NY (W)","40.733946,-73.9867"], +["41st and Broadway - New York NY (W)","40.755111,-73.986225"], +["84th & Third Ave - New York NY (W)","40.777485,-73.954979"], +["150 E. 42nd Street - New York NY (W)","40.750784,-73.975582"], +["West 43rd and Broadway - New York NY (W)","40.756197,-73.985624"], +["Macy's 35th Street Balcony - New York NY","40.750703,-73.989787"], +["Macy's 6th Floor - Herald Square - New York NY (W)","40.750703,-73.989787"], +["Herald Square- Macy's - New York NY","40.750703,-73.989787"], +["Macy's 5th Floor - Herald Square - New York NY (W)","40.750703,-73.989787"], +["80th & York - New York NY (W)","40.772204,-73.949862"], +["Columbus @ 67th - New York NY (W)","40.774009,-73.981472"], +["45th & Broadway - New York NY (W)","40.75766,-73.985719"], +["Marriott Marquis - Lobby - New York NY","40.759123,-73.984927"], +["Second @ 81st - New York NY (W)","40.77466,-73.954447"], +["52nd & Seventh - New York NY (W)","40.761829,-73.981141"], +["1585 Broadway (47th) - New York NY (W)","40.759806,-73.985066"], +["85th & First - New York NY (W)","40.776101,-73.949971"], +["92nd & 3rd - New York NY (W)","40.782606,-73.951235"], +["165 Broadway - 1 Liberty - New York NY (W)","40.709727,-74.011395"], +["1656 Broadway - New York NY (W)","40.762434,-73.983364"], +["54th & Broadway - New York NY (W)","40.764275,-73.982361"], +["Limited Brands-NYC - New York NY","40.765219,-73.982025"], +["19th & 8th - New York NY (W)","40.743218,-74.000605"], +["60th & Broadway-II - New York NY (W)","40.769196,-73.982576"], +["63rd & Broadway - New York NY (W)","40.771376,-73.982709"], +["195 Broadway - New York NY (W)","40.710703,-74.009485"], +["2 Broadway - New York NY (W)","40.704538,-74.01324"], +["2 Columbus Ave. - New York NY (W)","40.769262,-73.984764"], +["NY Plaza - New York NY (W)","40.702802,-74.012784"], +["36th and Madison - New York NY (W)","40.748917,-73.982683"], +["125th St. btwn Adam Clayton & FDB - New York NY","40.808952,-73.948229"], +["70th & Broadway - New York NY (W)","40.777463,-73.982237"], +["2138 Broadway - New York NY (W)","40.781078,-73.981167"], +["118th & Frederick Douglas Blvd. - New York NY (W)","40.806176,-73.954109"], +["42nd & Second - New York NY (W)","40.750069,-73.973393"], +["Broadway @ 81st - New York NY (W)","40.784972,-73.978987"], +["Fashion Inst of Technology - New York NY","40.746948,-73.994557"] +] +~~~ + +Then, send it as a POST request of the `load` command, like: + + # curl --data "@stores.json" "${endpoint}/load?table=Store" + [[0,1398666180.023,0.069],[40]] + +Now all data in the JSON file are successfully loaded. + +### Select data from a table + +OK, all data is now ready. + +As the starter, let's select initial ten records with the `select` command: + + # curl "${endpoint}/select?table=Store&output_columns=_key&limit=10" + [[0,1398666260.887927,0.000017404556274414062],[[[40],[["_key","ShortText"]],[["1st Avenue & 75th St. - New York NY (W)"],["2nd Ave. & 9th Street - New York NY"],["76th & Second - New York NY (W)"],["15th & Third - New York NY (W)"],["41st and Broadway - New York NY (W)"],["West 43rd and Broadway - New York NY (W)"],["84th & Third Ave - New York NY (W)"],["150 E. 42nd Street - New York NY (W)"],["Macy's 35th Street Balcony - New York NY"],["Herald Square- Macy's - New York NY"]]]]] + +Of course you can specify conditions via the `query` option: + + # curl "${endpoint}/select?table=Store&query=Columbus&match_columns=_key&output_columns=_key&limit=10" + [[0,1398670157.661574,0.0012705326080322266],[[[2],[["_key","ShortText"]],[["Columbus @ 67th - New York NY (W)"],["2 Columbus Ave. - New York NY (W)"]]]]] + # curl "${endpoint}/select?table=Store&filter=_key@'Ave'&output_columns=_key&limit=10" + [[0,1398670586.193325,0.0003848075866699219],[[[3],[["_key","ShortText"]],[["2nd Ave. & 9th Street - New York NY"],["84th & Third Ave - New York NY (W)"],["2 Columbus Ave. - New York NY (W)"]]]]] + + +## Conclusion + +In this tutorial, you did set up a [Droonga][] cluster on [Ubuntu Linux][Ubuntu] computers. +Moreover, you load data to it and select data from it successfully, as a [Groonga][] compatible server. + +Currently, Droonga supports only some limited features of Groonga compatible commands. +See the [command reference][] for more details. + + [Ubuntu]: http://www.ubuntu.com/ + [Droonga]: https://droonga.org/ + [Groonga]: http://groonga.org/ + [Serf]: http://www.serfdom.io/ + [command reference]: ../../reference/commands/ Added: tutorial/1.0.3/index.md (+18 -0) 100644 =================================================================== --- /dev/null +++ tutorial/1.0.3/index.md 2014-05-19 16:48:30 +0900 (dcd8223) @@ -0,0 +1,18 @@ +--- +title: Droonga tutorial +layout: en +--- + +## For Groonga users + + * [How to migrate from Groonga?](groonga/) + +## For application developers + + * [Basic usage tutorial](basic/) + +## For plugin developers + + * [Plugin development tutorial](plugin-development/) + + Added: tutorial/1.0.3/plugin-development/adapter/index.md (+694 -0) 100644 =================================================================== --- /dev/null +++ tutorial/1.0.3/plugin-development/adapter/index.md 2014-05-19 16:48:30 +0900 (0991288) @@ -0,0 +1,694 @@ +--- +title: "Plugin: Adapt requests and responses, to add a new command based on other existing commands" +layout: en +--- + +* TOC +{:toc} + +## The goal of this tutorial + +Learning steps to develop a Droonga plugin by yourself. + +This page focuses on the "adaption" by Droonga plugins. +At the last, we create a new command `storeSearch` based on the existing `search` command, with a small practical plugin. + +## Precondition + +* You must complete the [basic tutorial][]. + + +## Adaption for incoming messages + +First, let's study basics with a simple logger plugin named `sample-logger` affects at the adaption phase. + +We sometime need to modify incoming requests from outside to Droonga Engine. +We can use a plugin for this purpose. +Let's see how to create a plugin for the adaption phase, in this section. + +### Directory Structure + +Assume that we are going to add a new plugin to the system built in the [basic tutorial][]. +In that tutorial, Droonga engine was placed under `engine` directory. + +Plugins need to be placed in an appropriate directory. Let's create the directory: + +~~~ +# cd engine +# mkdir -p lib/droonga/plugins +~~~ + +After creating the directory, the directory structure should be like this: + +~~~ +engine +├── catalog.json +├── fluentd.conf +└── lib + └── droonga + └── plugins +~~~ + + +### Create a plugin + +You must put codes for a plugin into a file which has the name *same to the plugin itself*. +Because the plugin now you creating is `sample-logger`, put codes into a file `sample-logger.rb` in the `droonga/plugins` directory. + +lib/droonga/plugins/sample-logger.rb: + +~~~ruby +require "droonga/plugin" + +module Droonga + module Plugins + module SampleLoggerPlugin + extend Plugin + register("sample-logger") + + class Adapter < Droonga::Adapter + # You'll put codes to modify messages here. + end + end + end +end +~~~ + +This plugin does nothing except registering itself to the Droonga Engine. + + * The `sample-logger` is the name of the plugin itself. You'll use it in your `catalog.json`, to activate the plugin. + * As the example above, you must define your plugin as a module. + * Behaviors at the adaption phase is defined a class called *adapter*. + An adapter class must be defined as a subclass of the `Droonga::Adapter`, under the namespace of the plugin module. + + +### Activate the plugin with `catalog.json` + +You need to update `catalog.json` to activate your plugin. +Insert the name of the plugin `"sample-logger"` to the `"plugins"` list under the dataset, like: + +catalog.json: + +~~~ +(snip) + "datasets": { + "Starbucks": { + (snip) + "plugins": ["sample-logger", "groonga", "crud", "search"], +(snip) +~~~ + +Note: you must place `"sample-logger"` before `"search"`, because the `sample-logger` plugin depends on the `search`. Droonga Engine applies plugins at the adaption phase in the order defined in the `catalog.json`, so you must resolve plugin dependencies by your hand (for now). + +### Run and test + +Let's get Droonga started. +Note that you need to specify `./lib` directory in `RUBYLIB` environment variable in order to make ruby possible to find your plugin. + +~~~ +# kill $(cat fluentd.pid) +# RUBYLIB=./lib fluentd --config fluentd.conf --log fluentd.log --daemon fluentd.pid +~~~ + +Then, verify that the engine is correctly working. +First, create a request as a JSON. + +search-columbus.json: + +~~~json +{ + "dataset" : "Starbucks", + "type" : "search", + "body" : { + "queries" : { + "stores" : { + "source" : "Store", + "condition" : { + "query" : "Columbus", + "matchTo" : "_key" + }, + "output" : { + "elements" : [ + "startTime", + "elapsedTime", + "count", + "attributes", + "records" + ], + "attributes" : ["_key"], + "limit" : -1 + } + } + } + } +} +~~~ + +This is corresponding to the example to search "Columbus" in the [basic tutorial][]. +Note that the request for the Protocol Adapter is encapsulated in `"body"` element. + +Send the request to engine with `droonga-request`: + +~~~ +# droonga-request --tag starbucks search-columbus.json +Elapsed time: 0.021544 +[ + "droonga.message", + 1392617533, + { + "inReplyTo": "1392617533.9644868", + "statusCode": 200, + "type": "search.result", + "body": { + "stores": { + "count": 2, + "records": [ + [ + "Columbus @ 67th - New York NY (W)" + ], + [ + "2 Columbus Ave. - New York NY (W)" + ] + ] + } + } + } +] +~~~ + +This is the search result. + + +### Do something in the plugin: take logs + +The plugin we have created do nothing so far. Let's get the plugin to do some interesting. + +First of all, trap `search` request and log it. Update the plugin like below: + +lib/droonga/plugins/sample-logger.rb: + +~~~ruby +(snip) + module SampleLoggerPlugin + extend Plugin + register("sample-logger") + + class Adapter < Droonga::Adapter + input_message.pattern = ["type", :equal, "search"] + + def adapt_input(input_message) + logger.info("SampleLoggerPlugin::Adapter", :message => input_message) + end + end + end +(snip) +~~~ + +The line beginning with `input_message.pattern` is a configuration. +This example defines a plugin for any incoming message with `"type":"search"`. +See the [reference manual's configuration section](../../../reference/plugin/adapter/#config) + +The method `adapt_input` is called for every incoming message matching to the pattern. +The argument `input_message` is a wrapped version of the incoming message. + +Restart fluentd: + +~~~ +# kill $(cat fluentd.pid) +# RUBYLIB=./lib fluentd --config fluentd.conf --log fluentd.log --daemon fluentd.pid +~~~ + +Send the request same as the previous section: + +~~~ +# droonga-request --tag starbucks search-columbus.json +Elapsed time: 0.014714 +[ + "droonga.message", + 1392618037, + { + "inReplyTo": "1392618037.935901", + "statusCode": 200, + "type": "search.result", + "body": { + "stores": { + "count": 2, + "records": [ + [ + "Columbus @ 67th - New York NY (W)" + ], + [ + "2 Columbus Ave. - New York NY (W)" + ] + ] + } + } + } +] +~~~ + +You will see something like below fluentd's log in `fluentd.log`: + +~~~ +2014-02-17 15:20:37 +0900 [info]: SampleLoggerPlugin::Adapter message=#<Droonga::InputMessage:0x007f8ae3e1dd98 @raw_message={"dataset"=>"Starbucks", "type"=>"search", "body"=>{"queries"=>{"stores"=>{"source"=>"Store", "condition"=>{"query"=>"Columbus", "matchTo"=>"_key"}, "output"=>{"elements"=>["startTime", "elapsedTime", "count", "attributes", "records"], "attributes"=>["_key"], "limit"=>-1}}}}, "replyTo"=>{"type"=>"search.result", "to"=>"127.0.0.1:64591/droonga"}, "id"=>"1392618037.935901", "date"=>"2014-02-17 15:20:37 +0900", "appliedAdapters"=>[]}> +~~~ + +This shows the message is received by our `SampleLoggerPlugin::Adapter` and then passed to Droonga. Here we can modify the message before the actual data processing. + +### Modify messages with the plugin + +Suppose that we want to restrict the number of records returned in the response, say `1`. +What we need to do is set `limit` to be `1` for every request. +Update plugin like below: + +lib/droonga/plugins/sample-logger.rb: + +~~~ruby +(snip) + def adapt_input(input_message) + logger.info("SampleLoggerPlugin::Adapter", :message => input_message) + input_message.body["queries"]["stores"]["output"]["limit"] = 1 + end +(snip) +~~~ + +Like above, you can modify the incoming message via methods of the argument `input_message`. +See the [reference manual for the message class](../../../reference/plugin/adapter/#classes-Droonga-InputMessage). + +Restart fluentd: + +~~~ +# kill $(cat fluentd.pid) +# RUBYLIB=./lib fluentd --config fluentd.conf --log fluentd.log --daemon fluentd.pid +~~~ + +After restart, the response always includes only one record in `records` section. + +Send the request same as the previous: + +~~~ +# droonga-request --tag starbucks search-columbus.json +Elapsed time: 0.017343 +[ + "droonga.message", + 1392618279, + { + "inReplyTo": "1392618279.0578449", + "statusCode": 200, + "type": "search.result", + "body": { + "stores": { + "count": 2, + "records": [ + [ + "Columbus @ 67th - New York NY (W)" + ] + ] + } + } + } +] +~~~ + +Note that `count` is still `2` because `limit` does not affect to `count`. See [search][] for details of the `search` command. + +You will see something like below fluentd's log in `fluentd.log`: + +~~~ +2014-02-17 15:24:39 +0900 [info]: SampleLoggerPlugin::Adapter message=#<Droonga::InputMessage:0x007f956685c908 @raw_message={"dataset"=>"Starbucks", "type"=>"search", "body"=>{"queries"=>{"stores"=>{"source"=>"Store", "condition"=>{"query"=>"Columbus", "matchTo"=>"_key"}, "output"=>{"elements"=>["startTime", "elapsedTime", "count", "attributes", "records"], "attributes"=>["_key"], "limit"=>-1}}}}, "replyTo"=>{"type"=>"search.result", "to"=>"127.0.0.1:64616/droonga"}, "id"=>"1392618279.0578449", "date"=>"2014-02-17 15:24:39 +0900", "appliedAdapters"=>[]}> +~~~ + + +## Adaption for outgoing messages + +In case we need to modify outgoing messages from Droonga Engine, for example, search results, then we can do it simply by another method. +In this section, we are going to define a method to adapt outgoing messages. + + +### Add a method to adapt outgoing messages + +Let's take logs of results of `search` command. +Define the `adapt_output` method to process outgoing messages. +Remove `adapt_input` at this moment for the simplicity. + +lib/droonga/plugins/sample-logger.rb: + +~~~ruby +(snip) + module SampleLoggerPlugin + extend Plugin + register("sample-logger") + + class Adapter < Droonga::Adapter + input_message.pattern = ["type", :equal, "search"] + + def adapt_output(output_message) + logger.info("SampleLoggerPlugin::Adapter", :message => output_message) + end + end + end +(snip) +~~~ + +The method `adapt_output` is called only for outgoing messages triggered by incoming messages trapped by the plugin itself, even if there is only the matching pattern and the `adapt_input` method is not defined. +See the [reference manual for plugin developers](../../../reference/plugin/adapter/) for more details. + +### Run + +Let's restart fluentd: + +~~~ +# kill $(cat fluentd.pid) +# RUBYLIB=./lib fluentd --config fluentd.conf --log fluentd.log --daemon fluentd.pid +~~~ + +And send search request (Use the same JSON for request as in the previous section): + +~~~ +# droonga-request --tag starbucks search-columbus.json +Elapsed time: 0.015491 +[ + "droonga.message", + 1392619269, + { + "inReplyTo": "1392619269.184789", + "statusCode": 200, + "type": "search.result", + "body": { + "stores": { + "count": 2, + "records": [ + [ + "Columbus @ 67th - New York NY (W)" + ], + [ + "2 Columbus Ave. - New York NY (W)" + ] + ] + } + } + } +] +~~~ + +The fluentd's log should be like as follows: + +~~~ +2014-02-17 15:41:09 +0900 [info]: SampleLoggerPlugin::Adapter message=#<Droonga::OutputMessage:0x007fddcad4d5a0 @raw_message={"dataset"=>"Starbucks", "type"=>"dispatcher", "body"=>{"stores"=>{"count"=>2, "records"=>[["Columbus @ 67th - New York NY (W)"], ["2 Columbus Ave. - New York NY (W)"]]}}, "replyTo"=>{"type"=>"search.result", "to"=>"127.0.0.1:64724/droonga"}, "id"=>"1392619269.184789", "date"=>"2014-02-17 15:41:09 +0900", "appliedAdapters"=>["Droonga::Plugins::SampleLoggerPlugin::Adapter", "Droonga::Plugins::Error::Adapter"]}> +~~~ + +This shows that the result of `search` is passed to the `adapt_output` method (and logged), then outputted. + + +### Modify results in the adaption phase + +Let's modify the result. +For example, add `completedAt` attribute that shows the time completed the request. +Update your plugin as follows: + +lib/droonga/plugins/sample-logger.rb: + +~~~ruby +(snip) + def adapt_output(output_message) + logger.info("SampleLoggerPlugin::Adapter", :message => output_message) + output_message.body["stores"]["completedAt"] = Time.now + end +(snip) +~~~ + +Like above, you can modify the outgoing message via methods of the argument `output_message`. +See the [reference manual for the message class](../../../reference/plugin/adapter/#classes-Droonga-OutputMessage). + +Restart fluentd: + +~~~ +# kill $(cat fluentd.pid) +# RUBYLIB=./lib fluentd --config fluentd.conf --log fluentd.log --daemon fluentd.pid +~~~ + +Send the same search request: + +~~~ +# droonga-request --tag starbucks search-columbus.json +Elapsed time: 0.013983 +[ + "droonga.message", + 1392619528, + { + "inReplyTo": "1392619528.235121", + "statusCode": 200, + "type": "search.result", + "body": { + "stores": { + "count": 2, + "records": [ + [ + "Columbus @ 67th - New York NY (W)" + ], + [ + "2 Columbus Ave. - New York NY (W)" + ] + ], + "completedAt": "2014-02-17T06:45:28.247669Z" + } + } + } +] +~~~ + +Now you can see `completedAt` attribute containing the time completed the request. +The results in `fluentd.log` will be like this: + +~~~ +2014-02-17 15:45:28 +0900 [info]: SampleLoggerPlugin::Adapter message=#<Droonga::OutputMessage:0x007fd384f3ab60 @raw_message={"dataset"=>"Starbucks", "type"=>"dispatcher", "body"=>{"stores"=>{"count"=>2, "records"=>[["Columbus @ 67th - New York NY (W)"], ["2 Columbus Ave. - New York NY (W)"]]}}, "replyTo"=>{"type"=>"search.result", "to"=>"127.0.0.1:64849/droonga"}, "id"=>"1392619528.235121", "date"=>"2014-02-17 15:45:28 +0900", "appliedAdapters"=>["Droonga::Plugins::SampleLoggerPlugin::Adapter", "Droonga::Plugins::Error::Adapter"]}> +~~~ + + +## Adaption for both incoming and outgoing messages + +We have learned the basics of plugins for the adaption phase so far. +Let's try to build more practical plugin. + +You may feel the Droonga's `search` command is too flexible for your purpose. +Here, we're going to add our own `storeSearch` command to wrap the `search` command in order to provide an application-specific and simple interface, with a new plugin named `store-search`. + +### Accepting of simple requests + +First, create the `store-search` plugin. +Remember, you must put codes into a file which has the name same to the plugin now you are creating. +So, the file is `store-search.rb` in the `droonga/plugins` directory. Then define your `StoreSearchPlugin` as follows: + +lib/droonga/plugins/store-search.rb: + +~~~ruby +require "droonga/plugin" + +module Droonga + module Plugins + module StoreSearchPlugin + extend Plugin + register("store-search") + + class Adapter < Droonga::Adapter + input_message.pattern = ["type", :equal, "storeSearch"] + + def adapt_input(input_message) + logger.info("StoreSearchPlugin::Adapter", :message => input_message) + + query = input_message.body["query"] + logger.info("storeSearch", :query => query) + + body = { + "queries" => { + "stores" => { + "source" => "Store", + "condition" => { + "query" => query, + "matchTo" => "_key", + }, + "output" => { + "elements" => [ + "startTime", + "elapsedTime", + "count", + "attributes", + "records", + ], + "attributes" => [ + "_key", + ], + "limit" => -1, + } + } + } + } + + input_message.type = "search" + input_message.body = body + end + end + end + end +end +~~~ + +Then update your `catalog.json` to activate the plugin. +Remove the `sample-logger` plugin previously created. + +catalog.json: + +~~~ +(snip) + "datasets": { + "Starbucks": { + (snip) + "plugins": ["store-search", "groonga", "crud", "search"], +(snip) +~~~ + +Remember, you must place your plugin `"store-search"` before the `"search"` because yours depends on it. + +Restart fluentd: + +~~~ +# kill $(cat fluentd.pid) +# RUBYLIB=./lib fluentd --config fluentd.conf --log fluentd.log --daemon fluentd.pid +~~~ + +Now you can use this new command by the following request: + +store-search-columbus.json: + +~~~json +{ + "dataset" : "Starbucks", + "type" : "storeSearch", + "body" : { + "query" : "Columbus" + } +} +~~~ + +In order to issue this request, you need to run: + +~~~ +# droonga-request --tag starbucks store-search-columbus.json +Elapsed time: 0.01494 +[ + "droonga.message", + 1392621168, + { + "inReplyTo": "1392621168.0119512", + "statusCode": 200, + "type": "storeSearch.result", + "body": { + "stores": { + "count": 2, + "records": [ + [ + "Columbus @ 67th - New York NY (W)" + ], + [ + "2 Columbus Ave. - New York NY (W)" + ] + ] + } + } + } +] +~~~ + +And you will see the result on fluentd's log in `fluentd.log`: + +~~~ +2014-02-17 16:12:48 +0900 [info]: StoreSearchPlugin::Adapter message=#<Droonga::InputMessage:0x007fe4791d3958 @raw_message={"dataset"=>"Starbucks", "type"=>"storeSearch", "body"=>{"query"=>"Columbus"}, "replyTo"=>{"type"=>"storeSearch.result", "to"=>"127.0.0.1:49934/droonga"}, "id"=>"1392621168.0119512", "date"=>"2014-02-17 16:12:48 +0900", "appliedAdapters"=>[]}> +2014-02-17 16:12:48 +0900 [info]: storeSearch query="Columbus" +~~~ + +Now we can perform store search with simple requests. + +Note: look at the `"type"` of the response message. Now it became `"storeSearch.result"`, from `"search.result"`. Because it is triggered from the incoming message with the type `"storeSearch"`, the outgoing message has the type `"(incoming command).result"` automatically. In other words, you don't have to change the type of the outgoing messages, like `input_message.type = "search"` in the method `adapt_input`. + +### Returning of simple responses + +Second, let's return results in more simple way: just an array of the names of stores. + +Define the `adapt_output` method as follows. + +lib/droonga/plugins/store-search.rb: + +~~~ruby +(snip) + module StoreSearchPlugin + extend Plugin + register("store-search") + + class Adapter < Droonga::Adapter + (snip) + + def adapt_output(output_message) + logger.info("StoreSearchPlugin::Adapter", :message => output_message) + + records = output_message.body["stores"]["records"] + simplified_results = records.flatten + + output_message.body = simplified_results + end + end + end +(snip) +~~~ + +The `adapt_output` method receives outgoing messages only corresponding to the incoming messages trapped by the plugin. + +Restart fluentd: + +~~~ +# kill $(cat fluentd.pid) +# RUBYLIB=./lib fluentd --config fluentd.conf --log fluentd.log --daemon fluentd.pid +~~~ + +Send the request: + +~~~ +# droonga-request --tag starbucks store-search-columbus.json +Elapsed time: 0.014859 +[ + "droonga.message", + 1392621288, + { + "inReplyTo": "1392621288.158763", + "statusCode": 200, + "type": "storeSearch.result", + "body": [ + "Columbus @ 67th - New York NY (W)", + "2 Columbus Ave. - New York NY (W)" + ] + } +] +~~~ + +The log in `fluentd.log` will be like this: + +~~~ +2014-02-17 16:14:48 +0900 [info]: StoreSearchPlugin::Adapter message=#<Droonga::InputMessage:0x007ffb8ada9d68 @raw_message={"dataset"=>"Starbucks", "type"=>"storeSearch", "body"=>{"query"=>"Columbus"}, "replyTo"=>{"type"=>"storeSearch.result", "to"=>"127.0.0.1:49960/droonga"}, "id"=>"1392621288.158763", "date"=>"2014-02-17 16:14:48 +0900", "appliedAdapters"=>[]}> +2014-02-17 16:14:48 +0900 [info]: storeSearch query="Columbus" +2014-02-17 16:14:48 +0900 [info]: StoreSearchPlugin::Adapter message=#<Droonga::OutputMessage:0x007ffb8ad78e48 @raw_message={"dataset"=>"Starbucks", "type"=>"dispatcher", "body"=>{"stores"=>{"count"=>2, "records"=>[["Columbus @ 67th - New York NY (W)"], ["2 Columbus Ave. - New York NY (W)"]]}}, "replyTo"=>{"type"=>"storeSearch.result", "to"=>"127.0.0.1:49960/droonga"}, "id"=>"1392621288.158763", "date"=>"2014-02-17 16:14:48 +0900", "appliedAdapters"=>["Droonga::Plugins::StoreSearchPlugin::Adapter", "Droonga::Plugins::Error::Adapter"], "originalTypes"=>["storeSearch"]}> +~~~ + +Now you've got the simplified response. + +In the way just described, we can use adapter to implement the application specific search logic. + +## Conclusion + +We have learned how to add a new command based only on a custom adapter and an existing command. +In the process, we also have learned how to receive and modify messages, both of incoming and outgoing. + +See also the [reference manual](../../../reference/plugin/adapter/) for more details. + + + [basic tutorial]: ../../basic/ + [overview]: ../../../overview/ + [search]: ../../../reference/commands/select/ Added: tutorial/1.0.3/plugin-development/handler/index.md (+533 -0) 100644 =================================================================== --- /dev/null +++ tutorial/1.0.3/plugin-development/handler/index.md 2014-05-19 16:48:30 +0900 (22f4986) @@ -0,0 +1,533 @@ +--- +title: "Plugin: Handle requests on all volumes, to add a new command working around the storage" +layout: en +--- + +* TOC +{:toc} + +## The goal of this tutorial + +This tutorial aims to help you to learn how to develop plugins which do something dispersively for/in each volume, around the handling phase. +In other words, this tutorial describes *how to add a new simple command to the Droonga Engine*. + +## Precondition + +* You must complete the [tutorial for the adaption phase][adapter]. + +## Handling of requests + +When a request is transferred from the adaption phase, the Droonga Engine enters into the *processing phase*. + +In the processing phase, the Droonga Engine processes the request step by step. +One *step* is constructed from some sub phases: *planning phase*, *distribution phase*, *handling phase*, and *collection phase*. + + * At the *planning phase*, the Droonga Engine generates multiple sub steps to process the request. + In simple cases, you don't have to write codes for this phase, then there is just one sub step to handle the request. + * At the *distribution phase*, the Droonga Engine distributes task messages for the request, to multiple volumes. + (It is completely done by the Droonga Engine itself, so this phase is not pluggable.) + * At the *handling phase*, *each single volume simply processes only one distributed task message as its input, and returns a result.* + This is the time that actual storage accesses happen. + Actually, some commands (`search`, `add`, `create_table` and so on) access to the storage at the time. + * At the *collection phase*, the Droonga Engine collects results from volumes to one unified result. + There are some useful generic collectors, so you don't have to write codes for this phase in most cases. + +After all steps are finished, the Droonga Engine transfers the result to the post adaption phase. + +A class to define operations at the handling phase is called *handler*. +Put simply, adding of a new handler means adding a new command. + + + + + + +## Design a read-only command `countRecords` + +Here, in this tutorial, we are going to add a new custom `countRecords` command. +At first, let's design it. + +The command reports the number of records about a specified table, for each single volume. +So it will help you to know how records are distributed in the cluster. +Nothing is changed by the command, so it is a *read-only command*. + +The request must have the name of one table, like: + +~~~json +{ + "dataset" : "Starbucks", + "type" : "countRecords", + "body" : { + "table": "Store" + } +} +~~~ + +Create a JSON file `count-records.json` with the content above. +We'll use it for testing. + +The response must have number of records in the table, for each single volume. +They can be appear in an array, like: + +~~~json +{ + "inReplyTo": "(message id)", + "statusCode": 200, + "type": "countRecords.result", + "body": [10, 10] +} +~~~ + +If there are 2 volumes and 20 records are stored evenly, the array will have two elements like above. +It means that a volume has 10 records and another one also has 10 records. + +We're going to create a plugin to accept such requests and return such responses. + + +### Directory structure + +The directory structure for plugins are in same rule as explained in the [tutorial for the adaption phase][adapter]. +Now let's create the `count-records` plugin, as the file `count-records.rb`. The directory tree will be: + +~~~ +lib +└── droonga + └── plugins + └── count-records.rb +~~~ + +Then, create a skeleton of a plugin as follows: + +lib/droonga/plugins/count-records.rb: + +~~~ruby +require "droonga/plugin" + +module Droonga + module Plugins + module CountRecordsPlugin + extend Plugin + register("count-records") + end + end +end +~~~ + +### Define a "step" for the command + +Define a "step" for the new `countRecords` command, in your plugin. Like: + +lib/droonga/plugins/count-records.rb: + +~~~ruby +require "droonga/plugin" + +module Droonga + module Plugins + module CountRecordsPlugin + extend Plugin + register("count-records") + + define_single_step do |step| + step.name = "countRecords" + end + end + end +end +~~~ + +The `step.name` equals to the name of the command itself. +Currently we just define the name of the command. +That's all. + +### Define the handling logic + +The command has no handler, so it does nothing yet. +Let's define the behavior. + +lib/droonga/plugins/count-records.rb: + +~~~ruby +require "droonga/plugin" + +module Droonga + module Plugins + module CountRecordsPlugin + extend Plugin + register("count-records") + + define_single_step do |step| + step.name = "countRecords" + step.handler = :Handler + end + + class Handler < Droonga::Handler + def handle(message) + [0] + end + end + end + end +end +~~~ + +The class `Handler` is a handler class for our new command. + + * It must inherit a builtin-class `Droonga::Handler`. + * It implements the logic to handle requests. + Its instance method `#handle` actually handles requests. + +Currently the handler does nothing and returns an result including an array of a number. +The returned value is used to construct the response body. + +The handler is bound to the step with the configuration `step.handler`. +Because we define the class `Handler` after `define_single_step`, we specify the handler class with a symbol `:Handler`. +If you define the handler class before `define_single_step`, then you can write as `step.handler = Handler` simply. +Moreover, a class path string like `"OtherPlugin::Handler"` is also available. + +Then, we also have to bind a collector to the step, with the configuration `step.collector`. + +lib/droonga/plugins/count-records.rb: + +~~~ruby +# (snip) + define_single_step do |step| + step.name = "countRecords" + step.handler = :Handler + step.collector = Collectors::Sum + end +# (snip) +~~~ + +The `Collectors::Sum` is one of built-in collectors. +It merges results returned from handler instances for each volume to one result. + + +### Activate the plugin with `catalog.json` + +Update catalog.json to activate this plugin. +Add `"count-records"` to `"plugins"`. + +~~~ +(snip) + "datasets": { + "Starbucks": { + (snip) + "plugins": ["count-records", "groonga", "crud", "search"], +(snip) +~~~ + +### Run and test + +Let's get Droonga started. +Note that you need to specify ./lib directory in RUBYLIB environment variable in order to make ruby possible to find your plugin. + + # kill $(cat fluentd.pid) + # RUBYLIB=./lib fluentd --config fluentd.conf --log fluentd.log --daemon fluentd.pid + +Then, send a request message for the `countRecords` command to the Droonga Engine. + +~~~ +# droonga-request --tag starbucks count-records.json +Elapsed time: 0.01494 +[ + "droonga.message", + 1392621168, + { + "inReplyTo": "1392621168.0119512", + "statusCode": 200, + "type": "countRecords.result", + "body": [ + 0, + 0, + 0 + ] + } +] +~~~ + +You'll get a response message like above. +Look at these points: + + * The `type` of the response becomes `countRecords.result`. + It is automatically named by the Droonga Engine. + * The format of the `body` is same to the returned value of the handler's `handle` method. + +There are three elements in the array. Why? + + * Remember that the `Starbucks` dataset was configured with two replicas and three sub volumes for each replica, in the `catalog.json` of [the basic tutorial][basic]. + * Because it is a read-only command, a request is delivered to only one replica (and it is chosen at random). + Then only three single volumes receive the command, so only three results appear, not six. + (TODO: I have to add a figure to indicate active nodes: [000, 001, 002, 010, 011, 012] => [000, 001, 002]) + * The `Collectors::Sum` collects them. + Those three results are joined to just one array by the collector. + +As the result, just one array with three elements appears in the final response. + +### Read-only access to the storage + +Now, each instance of the handler class always returns `0` as its result. +Let's implement codes to count up the number of records from the actual storage. + +lib/droonga/plugins/count-records.rb: + +~~~ruby +# (snip) + class Handler < Droonga::Handler + def handle(message) + request = message.request + table_name = request["table"] + table = @context[table_name] + count = table.size + [count] + end + end +# (snip) +~~~ + +Look at the argument of the `handle` method. +It is different from the one an adapter receives. +A handler receives a message meaning a distributed task. +So you have to extract the request message from the distributed task by the code `request = message.request`. + +The instance variable `@context` is an instance of `Groonga::Context` for the storage of the corresponding single volume. +See the [class reference of Rroonga][Groonga::Context]. +You can use any feature of Rroonga via `@context`. +For now, we simply access to the table itself by its name and read the value of its `size` method - it returns the number of records. + +Then, test it. +Restart the Droonga Engine and send the request again. + +~~~ +# kill $(cat fluentd.pid) +# RUBYLIB=./lib fluentd --config fluentd.conf --log fluentd.log --daemon fluentd.pid +# droonga-request --tag starbucks count-records.json +Elapsed time: 0.01494 +[ + "droonga.message", + 1392621168, + { + "inReplyTo": "1392621168.0119512", + "statusCode": 200, + "type": "countRecords.result", + "body": [ + 14, + 15, + 11 + ] + } +] +~~~ + +Because there are totally 40 records, they are stored evenly like above. + +## Design a read-write command `deleteStores` + +Next, let's add another new custom command `deleteStores`. + +The command deletes records of the `Store` table, from the storage. +Because it modifies something in existing storage, it is a *read-write command*. + +The request must have the condition to select records to be deleted, like: + +~~~json +{ + "dataset" : "Starbucks", + "type" : "deleteStores", + "body" : { + "keyword": "Broadway" + } +} +~~~ + +Any record including the given keyword `"Broadway"` in its `"key"` is deleted from the storage of all volumes. + +Create a JSON file `delete-stores-broadway.json` with the content above. +We'll use it for testing. + +The response must have a boolean value to indicate "success" or "fail", like: + +~~~json +{ + "inReplyTo": "(message id)", + "statusCode": 200, + "type": "deleteStores.result", + "body": true +} +~~~ + +If the request is successfully processed, the `body` becomes `true`. Otherwise `false`. +The `body` is just one boolean value, because we don't have to receive multiple results from volumes. + + +### Directory Structure + +Now let's create the `delete-stores` plugin, as the file `delete-stores.rb`. The directory tree will be: + +~~~ +lib +└── droonga + └── plugins + └── delete-stores.rb +~~~ + +Then, create a skeleton of a plugin as follows: + +lib/droonga/plugins/delete-stores.rb: + +~~~ruby +require "droonga/plugin" + +module Droonga + module Plugins + module DeleteStoresPlugin + extend Plugin + register("delete-stores") + end + end +end +~~~ + + +### Define a "step" for the command + +Define a "step" for the new `deleteStores` command, in your plugin. Like: + +lib/droonga/plugins/delete-stores.rb: + +~~~ruby +require "droonga/plugin" + +module Droonga + module Plugins + module DeleteStoresPlugin + extend Plugin + register("delete-stores") + + define_single_step do |step| + step.name = "deleteStores" + step.write = true + end + end + end +end +~~~ + +Look at a new configuration `step.write`. +Because this command modifies the storage, we must indicate it clearly. + +### Define the handling logic + +Let's define the handler. + +lib/droonga/plugins/delete-stores.rb: + +~~~ruby +require "droonga/plugin" + +module Droonga + module Plugins + module DeleteStoresPlugin + extend Plugin + register("delete-stores") + + define_single_step do |step| + step.name = "deleteStores" + step.write = true + step.handler = :Handler + step.collector = Collectors::And + end + + class Handler < Droonga::Handler + def handle(message) + request = message.request + keyword = request["keyword"] + table = @context["Store"] + table.delete do |record| + record.key =~ keyword + end + true + end + end + end + end +end +~~~ + +Remember, you have to extract the request message from the received task message. + +The handler finds and deletes existing records which have the given keyword in its "key", by the [API of Rroonga][Groonga::Table_delete]. + +And, the `Collectors::And` is bound to the step by the configuration `step.collector`. +It is is also one of built-in collectors, and merges boolean values returned from handler instances for each volume, to one boolean value. + +### Activate the plugin with `catalog.json` + +Update catalog.json to activate this plugin. +Add `"delete-stores"` to `"plugins"`. + +~~~ +(snip) + "datasets": { + "Starbucks": { + (snip) + "plugins": ["delete-stores", "count-records", "groonga", "crud", "search"], +(snip) +~~~ + +### Run and test + +Restart the Droonga Engine and send the request. + +~~~ +# kill $(cat fluentd.pid) +# RUBYLIB=./lib fluentd --config fluentd.conf --log fluentd.log --daemon fluentd.pid +# droonga-request --tag starbucks count-records.json +Elapsed time: 0.01494 +[ + "droonga.message", + 1392621168, + { + "inReplyTo": "1392621168.0119512", + "statusCode": 200, + "type": "deleteStores.result", + "body": true + } +] +~~~ + +Because results from volumes are unified to just one boolean value, the response's `body` is a `true`. +As the verification, send the request of `countRecords` command. + +~~~ +# droonga-request --tag starbucks count-records.json +Elapsed time: 0.01494 +[ + "droonga.message", + 1392621168, + { + "inReplyTo": "1392621168.0119512", + "statusCode": 200, + "type": "countRecords.result", + "body": [ + 7, + 13, + 6 + ] + } +] +~~~ + +Note, the number of records are smaller than the previous result. +This means that four or some records are deleted from each volume. + +## Conclusion + +We have learned how to add a new simple command working around the data. +In the process, we also have learned how to create plugins working in the handling phrase. + + + [adapter]: ../adapter + [basic]: ../basic + [Groonga::Context]: http://ranguba.org/rroonga/en/Groonga/Context.html + [Groonga::Table_delete]: http://ranguba.org/rroonga/en/Groonga/Table.html#delete-instance_method Added: tutorial/1.0.3/plugin-development/index.md (+87 -0) 100644 =================================================================== --- /dev/null +++ tutorial/1.0.3/plugin-development/index.md 2014-05-19 16:48:30 +0900 (6a9b0bf) @@ -0,0 +1,87 @@ +--- +title: Droonga plugin development tutorial +layout: en +--- + +* TOC +{:toc} + +## The goal of this tutorial + +Learning steps to develop a Droonga plugin by yourself. +You must complete the [basic tutorial][] before this. + + +## What's "plugin"? + +Plugin is one of the most important concept of Droonga. +This makes Droonga flexible. + +Generally, data processing tasks in the real world need custom treatments of the data, in various stages of the data stream. +This is not easy to be done in one-size-fits-all approach. + + * One may want to modify incoming requests to work well with other systems, one may want to modify outgoing responses to help other systems understand the result. + * One may want to do more complex data processing than that provided by Droonga as built-in, to have direct storage access for efficiency. + * One may need to control data distribution and collection logic of Droonga to profit from the distributed nature of Droonga. + +You can use plugins in those situations. + +## Pluggable operations in Droonga Engine + +In Droonga Engine, there are 2 large pluggable phases and 3 sub phases for plugins. +In other words, from the point of view of plugins, each plugin can do from 1 to 4 operations. +See the [overview][] to grasp the big picture. + +Adaption phase +: At this phase, a plugin can modify incoming requests and outgoing responses. + +Processing phase +: At this phase, a plugin can process incoming requests on each volume, step by step. + +The processing phase includes 3 sub pluggable phases: + +Handling phase +: At this phase, a plugin can do low-level data handling, for example, database operations and so on. + +Planning phase +: At this phase, a plugin can split an incoming request to multiple steps. + +Collection phase +: At this phase, a plugin can merge results from steps to a unified result. + +However, the point of view of these descriptions is based on the design of the system itself, so you're maybe confused. +Then, let's shift our perspective on pluggable operations - what you want to do by a plugin. + +Adding a new command based on another existing command. +: For example, you possibly want to define a shorthand command wrapping the complex `search` command. + *Adaption* of request and response messages makes it come true. + +Adding a new command working around the storage. +: For example, you possibly want to modify data stored in the storage as you like. + *Handling* of requests makes it come true. + +Adding a new command for a complex task +: For example, you possibly want to implement a powerful command like the built-in `search` command. + *Planning and collection* of requests make it come true. + +In this tutorial, we focus on the adaption at first. +This is the most "basic" usecase of plugins, so it will help you to understand the overview of Droonga plugin development. +Then, we focus on other cases in this order. +Following this tutorial, you will learn how to write plugins. +This will be the first step to create plugins fit with your own requirements. + +## How to develop plugins? + +For more details, let's read these sub tutorials: + + 1. [Adapt requests and responses, to add a new command based on other existing commands][adapter]. + 2. [Handle requests on all volumes, to add a new command working around the storage][handler]. + 3. Handle requests only on a specific volume, to add a new command around the storage more smartly. (under construction) + 4. Distribute requests and collect responses, to add a new complex command based on sub tasks. (under construction) + + + [basic tutorial]: ../basic/ + [overview]: ../../overview/ + [adapter]: ./adapter/ + [handler]: ./handler/ + [distribute-collect]: ./distribute-collect/ Added: tutorial/1.0.3/watch.md (+208 -0) 100644 =================================================================== --- /dev/null +++ tutorial/1.0.3/watch.md 2014-05-19 16:48:30 +0900 (5e6347f) @@ -0,0 +1,208 @@ +--- +title: Droonga tutorial +layout: en +--- + +* TOC +{:toc} + +## Real-time search + +Droonga supports streaming-style real-time search. + +### Update configurations of the Droonga engine + +Update your fluentd.conf and catalog.jsons, like: + +fluentd.conf: + + <source> + type forward + port 24224 + </source> + <match starbucks.message> + name localhost:24224/starbucks + type droonga + </match> + + <match droonga.message> + + name localhost:24224/droonga + + type droonga + + </match> + <match output.message> + type stdout + </match> + +catalog.json: + + { + "effective_date": "2013-09-01T00:00:00Z", + "zones": [ + + "localhost:24224/droonga", + "localhost:24224/starbucks" + ], + "farms": { + + "localhost:24224/droonga": { + + "device": ".", + + "capacity": 10 + + }, + "localhost:24224/starbucks": { + "device": ".", + "capacity": 10 + } + }, + "datasets": { + + "Watch": { + + "workers": 2, + + "plugins": ["search", "groonga", "add", "watch"], + + "number_of_replicas": 1, + + "number_of_partitions": 1, + + "partition_key": "_key", + + "date_range": "infinity", + + "ring": { + + "localhost:23041": { + + "weight": 50, + + "partitions": { + + "2013-09-01": [ + + "localhost:24224/droonga.watch" + + ] + + } + + } + + } + + }, + "Starbucks": { + "workers": 0, + "plugins": ["search", "groonga", "add"], + "number_of_replicas": 2, + "number_of_partitions": 2, + "partition_key": "_key", + "date_range": "infinity", + "ring": { + "localhost:23041": { + "weight": 50, + "partitions": { + "2013-09-01": [ + "localhost:24224/starbucks.000", + "localhost:24224/starbucks.001" + ] + } + }, + "localhost:23042": { + "weight": 50, + "partitions": { + "2013-09-01": [ + "localhost:24224/starbucks.002", + "localhost:24224/starbucks.003" + ] + } + } + } + } + }, + "options": { + "plugins": [] + } + } + +### Add a streaming API to the protocol adapter + + +Add a streaming API to the protocol adapter, like; + +application.js: + + var express = require('express'), + droonga = require('express-droonga'); + + var application = express(); + var server = require('http').createServer(application); + server.listen(3000); // the port to communicate with clients + + //============== INSERTED ============== + var streaming = { + 'streaming': new droonga.command.HTTPStreaming({ + dataset: 'Watch', + path: '/watch', + method: 'GET', + subscription: 'watch.subscribe', + unsubscription: 'watch.unsubscribe', + notification: 'watch.notification', + createSubscription: function(request) { + return { + condition: request.query.query + }; + } + }) + }; + //============= /INSERTED ============== + + application.droonga({ + prefix: '/droonga', + tag: 'starbucks', + defaultDataset: 'Starbucks', + server: server, // this is required to initialize Socket.IO API! + plugins: [ + droonga.API_REST, + droonga.API_SOCKET_IO, + droonga.API_GROONGA, + droonga.API_DROONGA + //============== INSERTED ============== + ,streaming + //============= /INSERTED ============== + ] + }); + + application.get('/', function(req, res) { + res.sendfile(__dirname + '/index.html'); + }); + +### Prepare feeds + +Prepare "feed"s like: + +feeds.jsons: + + {"id":"feed:0","dataset":"Watch","type":"watch.feed","body":{"targets":{"key":"old place 0"}}} + {"id":"feed:1","dataset":"Watch","type":"watch.feed","body":{"targets":{"key":"new place 0"}}} + {"id":"feed:2","dataset":"Watch","type":"watch.feed","body":{"targets":{"key":"old place 1"}}} + {"id":"feed:3","dataset":"Watch","type":"watch.feed","body":{"targets":{"key":"new place 1"}}} + {"id":"feed:4","dataset":"Watch","type":"watch.feed","body":{"targets":{"key":"old place 2"}}} + {"id":"feed:5","dataset":"Watch","type":"watch.feed","body":{"targets":{"key":"new place 2"}}} + +### Try it! + +At first, restart servers in each console. + +The engine: + + # fluentd --config fluentd.conf + +The protocol adapter: + + # nodejs application.js + +Next, connect to the streaming API via curl: + + # curl "http://localhost:3000/droonga/watch?query=new" + +Then the client starts to receive streamed results. + +Next, open a new console and send "feed"s to the engine like: + + # fluent-cat droonga.message < feeds.jsons + +Then the client receives three results "new place 0", "new place 1", and "new place 2" like: + + {"targets":{"key":"new place 0"}} + {"targets":{"key":"new place 1"}} + {"targets":{"key":"new place 2"}} + +They are search results for the query "new", given as a query parameter of the streaming API. + +Results can be appear in different order, like: + + {"targets":{"key":"new place 1"}} + {"targets":{"key":"new place 0"}} + {"targets":{"key":"new place 2"}} + +because "feed"s are processed in multiple workers asynchronously. +