Node.js
Cloudant

Cloudant で日本語検索は使えるか? 検証メモ

More than 1 year has passed since last update.

CSV形式のオープンデータを Bluemix の Cloudant へロードするメモ の続編で、読み込んだ郵便番号データに対して、Cloudantの日本語検索が、どの程度動作するか確認したメモです。

Cloudantの日本語対応

Cloundat には、各言語特有のアナライザー(1)が提供され、その中に japanese も含まれているので、日本語検索も期待しても良いと思わる。 この日本語対応アナライザーには、kuromoji (2), cjk (4) が利用できる。 しかし、Cloudantのドキュメントは英語がほとんどで、日本語処理への対応が心配なので、検証することにした。

インデックス無しでの検索

文字列一致で検索

インデックスを設定していない福岡県の郵便番号データベースの中から、町域で、港町と魚町に一致する市町村を探してみる。

スニペット・クエリー
    query = {
        'selector': {
            '$or': [
                {'cyoiki': '港町'},
                {'cyoiki': '魚町'},
            ]
        },
        "fields": ["cyoiki", "jusho_CD", "todoufuken", "sicyoson"]
    };
    cdb.find(query,function(err, result) {
        console.log("err = ", err);
        console.log("size = ", result.docs.length);
        console.log("result = ", result);
    });

実行結果では、港町と魚町が表示された。 インデックスを設定しなくても、日本語文字列の一致を取得できる。

実行結果
err =  null
size =  6
result =  { warning: 'no matching index found, create an index to optimize query time',
  docs: 
   [ { cyoiki: '港町',
       jusho_CD: '800031500',
       todoufuken: '福岡県',
       sicyoson: '京都郡苅田町' },
     { cyoiki: '港町',
       jusho_CD: '801085200',
       todoufuken: '福岡県',
       sicyoson: '北九州市門司区' },
     { cyoiki: '港町',
       jusho_CD: '801850300',
       todoufuken: '福岡県',
       sicyoson: '北九州市門司区' },
     { cyoiki: '魚町',
       jusho_CD: '802000600',
       todoufuken: '福岡県',
       sicyoson: '北九州市小倉北区' },
     { cyoiki: '魚町',
       jusho_CD: '825001400',
       todoufuken: '福岡県',
       sicyoson: '田川市' },
     { cyoiki: '港町',
       jusho_CD: '836002200',
       todoufuken: '福岡県',
       sicyoson: '大牟田市' } ] }

確認のために、grep コマンドで、答え合わせをしておくが、結果は同じであった。

grep結果
imac:test maho$ grep -e ',魚町' -e ',港町' 40fukuok.csv.utf-8  
801085200,40,40101,401010100,801-0852,0,0,福岡県,フクオカケン,北九州市門司区,キタキュウシュウシモジク,港町,ミナトマチ,,,,,,,,,
801850300,40,40101,401010100,801-8503,1,0,福岡県,フクオカケン,北九州市門司区,キタキュウシュウシモジク,港町,ミナトマチ,,,,,,株式会社 門司港ホテル,カブシキカイシヤ モジコウホテル,港町9番11号,
802000600,40,40106,401060015,802-0006,0,0,福岡県,フクオカケン,北九州市小倉北区,キタキュウシュウシコクラキタク,魚町,ウオマチ,,,,,,,,,
836002200,40,40202,402020144,836-0022,0,0,福岡県,フクオカケン,大牟田市,オオムタシ,港町,ミナトマチ,,,,,,,,,
825001400,40,40206,402060006,825-0014,0,0,福岡県,フクオカケン,田川市,タガワシ,魚町,ウオマチ,,,,,,,,,
800031500,40,40621,406210036,800-0315,0,0,福岡県,フクオカケン,京都郡苅田町,ミヤコグンカンダマチ,港町,ミナトマチ,,,,,,,,,

文字列先頭一致で検索(失敗例)

次の様に先頭一文字だけで検索すると、一致したものだけが、返される

スニペット・クエリー
    query = {
        'selector': {
            'cyoiki': '港'
        },
        "fields": ["cyoiki", "jusho_CD", "todoufuken", "sicyoson"]
    };
    cdb.find(query,function(err, result) {
実行結果
result =  { warning: 'no matching index found, create an index to optimize query time',
  docs: 
   [ { cyoiki: '港',
       jusho_CD: '810007500',
       todoufuken: '福岡県',
       sicyoson: '福岡市中央区' },
     { cyoiki: '港',
       jusho_CD: '810864800',
       todoufuken: '福岡県',
       sicyoson: '福岡市中央区' } ] }

grepの結果と上記実行結果は同じであった。

grepでの照合結果
$ grep -e ',港,' 40fukuok.csv.utf-8 
810007500,40,40133,401330047,810-0075,0,0,福岡県,フクオカケン,福岡市中央区,フクオカシチュウオウク,港,ミナト,,,,,,,,,
810864800,40,40133,401330047,810-8648,1,0,福岡県,フクオカケン,福岡市中央区,フクオカシチュウオウク,港,ミナト,,,,,,株式会社 トクスイコーポレーション,カブシキガイシヤ トクスイコ−ポレ−シヨン,港2丁目2−21,

文字列先頭一致で検索(成功例)

$regex で正規表現が利用できるので、試してみると、先頭に"港"がつくデータがリストされた。

スニペット・クエリー
    query = {
        "selector": {
            "cyoiki": {
                "$regex": "^港"
            }
        },
        "fields": ["cyoiki", "jusho_CD", "todoufuken", "sicyoson"]
    };
    cdb.find(query,function(err, result) {
実行結果
result =  { warning: 'no matching index found, create an index to optimize query time',
  docs: 
   [ { cyoiki: '港町',
       jusho_CD: '800031500',
       todoufuken: '福岡県',
       sicyoson: '京都郡苅田町' },
     { cyoiki: '港町',
       jusho_CD: '801085200',
       todoufuken: '福岡県',
       sicyoson: '北九州市門司区' },
     { cyoiki: '港町',
       jusho_CD: '801850300',
       todoufuken: '福岡県',
       sicyoson: '北九州市門司区' },
     { cyoiki: '港',
       jusho_CD: '810007500',
       todoufuken: '福岡県',
       sicyoson: '福岡市中央区' },
     { cyoiki: '港',
       jusho_CD: '810864800',
       todoufuken: '福岡県',
       sicyoson: '福岡市中央区' },
     { cyoiki: '港町',
       jusho_CD: '836002200',
       todoufuken: '福岡県',
       sicyoson: '大牟田市' } ] }

インデックス ワーニング対策

以下のワーニングを解消するためには、インデックスを設定する必要がある。

result =  { warning: 'no matching index found, create an index to optimize query time',
  docs: 
   [ { cyoiki: '港町',

JSON形式のインデックスを設定した場合

次の様な、JSON形式のインデックスを生成した場合、

JSON形式インデックスのデザインドキュメント
// JSON インデックス                                                                              
var ddoc_name =  "index1";
var key = "_design/" + ddoc_name;
var index = {
    type: "json",
    name: "index-1",
    ddoc: ddoc_name,
    index: {
        fields: ["jusho_CD:string","cyoiki:string"]
    }
}

下記のクエリーで得られる結果で、確認します。

    query = {
        "selector": {
            "cyoiki": "港町"
        },
        "fields": ["cyoiki", "jusho_CD", "todoufuken", "sicyoson"],
        "sort": [{"jusho_CD:string": "desc"}]
    };
    cdb.find(query,function(err, result) {

次の様に、warningは出るが、意図した結果が得られる。

JSON形式インデックスでの検索結果
size =  4
result =  { warning: 'no matching index found, create an index to optimize query time',
  docs: 
   [ { cyoiki: '港町',
       jusho_CD: '836002200',
       todoufuken: '福岡県',
       sicyoson: '大牟田市' },
     { cyoiki: '港町',
       jusho_CD: '801850300',
       todoufuken: '福岡県',
       sicyoson: '北九州市門司区' },
     { cyoiki: '港町',
       jusho_CD: '801085200',
       todoufuken: '福岡県',
       sicyoson: '北九州市門司区' },
     { cyoiki: '港町',
       jusho_CD: '800031500',
       todoufuken: '福岡県',
       sicyoson: '京都郡苅田町' } ] }

ここで、インデックス作成時に、項目の順番を入れ替えた場合、言い換えると、クエリーの "sort" の項目の順番が一致していない場合は、エラーになる。 Index と Query の項目の順番を注意しておく必要がある。

正常に処理されるケース
fields: ["jusho_CD:string","cyoiki:string"]
異常終了するケース
fields: ["cyoiki:string","jusho_CD:string"]

JSON形式のインデックスでは、warningが解消しないことが判った。

TEXT形式のインデックスを利用した場合

次が、TEXT形式のインデックス作成のJSONデータです。 違いは、type の項目が text になること、fields の書式が異なる点です。内部的な違いは、Apache CouchDB のソースを参照してください。

テキスト形式インデックスのデザインドキュメント
var ddoc_name =  "index1";
var key = "_design/" + ddoc_name;
var index = {
    "type": "text",
    "name": "index-1",
    "ddoc": ddoc_name,
    "index": {
        "fields": [
            { "name": "cyoiki", "type": "string" },
            { "name": "jusho_CD", "type": "string" }
        ],
    }
}

このインデックスを設定して、前述と同じ条件で検索を実施した結果が、以下です。 JSON形式で表示されていた Warning は解消して、新たに bookmark が表示されています。このbookmarkは、クエリーの結果のページ送りするために、利用することができます。(3)

TEXTインデックスに対して検索した結果
result =  { docs: 
   [ { cyoiki: '港町',
       jusho_CD: '836002200',
       todoufuken: '福岡県',
       sicyoson: '大牟田市' },
     { cyoiki: '港町',
       jusho_CD: '801850300',
       todoufuken: '福岡県',
       sicyoson: '北九州市門司区' },
     { cyoiki: '港町',
       jusho_CD: '801085200',
       todoufuken: '福岡県',
       sicyoson: '北九州市門司区' },
     { cyoiki: '港町',
       jusho_CD: '800031500',
       todoufuken: '福岡県',
       sicyoson: '京都郡苅田町' } ],
  bookmark: 'g1AAAAFJeJzLYWBgYMlgTmFQTUlKzi9KdUhJMjTQS8rVTU7WTUnM0TUw1kvOyS9NScwr0ctLLckBKmdKUgCSSfr____PAvNzgQSnhYGBgbGhqYFB4sssNPOMCJkXADIvHt08QwtTA2OgeaJg81Tg5pkRMq4AZFw9hnEGFqZGQOO4SXVeHguQZJgApIBGzkc209jMwMAIZGZHVhYAzIVcSw' }

インデックスの作成と明示的なインデックスの指定

インデックスは、JSON形式とTEXT形式で作ることができ、クラウドのコンソール画面だけでなく、次の様なnodeのスクリプトでも作成することができます。

JSONインデックスを作成するスニペット
var ddoc_name =  "index-json";                                                                        
var key = "_design/" + ddoc_name;                                                                 
var index = {                                                                                     
    type: "json",                                                                                 
    name: "index-json",                                                                              
    ddoc: ddoc_name,                                                                              
    index: {                                                                                      
        fields: ["jusho_CD:string","cyoiki:string"]                                               
    }                                                                                             
}  
cdb.index(index, function(err, response) {
    if (err) throw err;
    console.log('Index creation result: %s', response.result);
    callback(err, response);
});
TEXTインデックスを作成するスニペット
var ddoc_name =  "index-text";
var key = "_design/" + ddoc_name;
var index = {
    "type": "text",
    "name": "index-text",
    "ddoc": ddoc_name,
    "index": {
        "fields": [
            { "name": "cyoiki", "type": "string" },
            { "name": "jusho_CD", "type": "string" }
        ],
    }
}
cdb.index(index, function(err, response) {
    if (err) throw err;
    console.log('Index creation result: %s', response.result);
    callback(err, response);
});

Cloudantは、必要に応じて、DDOC (Design Document) として書き込むことで、インデックスを設定していくことが出ます。しかし、この2系統のインデックスの使い分けがわからないですね。 名前からすると、JSONがTEXTに置き換わるのではないかと思われますが、特に書かれていないので、本家のApache CouchDBのプロジェクトのドキュメントやコードを探してみたいといけないですが、warning以外に違いがあったので、メモがわりに書いておきます。

次の様に、JSONインデックスとTEXTインデックスを作成しておき、クエリーで明示的にインデックスをDDOC名で指定する機能が働くか試してみます。

スクリーンショット 2017-07-16 17.43.57.png

JSONインデックスの場合

次の様なQueryを書いて、"use_index" で、index-jsonを指定すると、エラーが発生して実行できませんでした。

    query = {
        "selector": {
            "cyoiki": "港町"
        },
        "fields": ["cyoiki", "jusho_CD", "todoufuken", "sicyoson"],
        "use_index": "_design/index-json",
        "sort": [{"jusho_CD:string": "desc"}]
    };
    cdb.find(query,function(err, result) {
        console.log("err = ", err);
        console.log("size = ", result.docs.length);
        console.log("result = ", result);
    });

上記のクエリーで発生したエラーメッセージの抜粋です。

  name: 'Error',
  error: 'no_usable_index',
  reason: 'There is no index available for this selector.',
  scope: 'couch',
  statusCode: 400,

TEXTインデックスの場合

これに対して、_design/index-text を指定した場合は、次の様に期待通りの動作になります。 どうもJSONインデックスは、発展途上なのか、特別な目的のために用意された様です。

err =  null
size =  4
result =  { docs: 
   [ { cyoiki: '港町',
       jusho_CD: '836002200',
       todoufuken: '福岡県',
       sicyoson: '大牟田市' },
     { cyoiki: '港町',
       jusho_CD: '801850300',
       todoufuken: '福岡県',
       sicyoson: '北九州市門司区' },
     { cyoiki: '港町',
       jusho_CD: '801085200',
       todoufuken: '福岡県',
       sicyoson: '北九州市門司区' },
     { cyoiki: '港町',
       jusho_CD: '800031500',
       todoufuken: '福岡県',
       sicyoson: '京都郡苅田町' } ],
  bookmark: 'g1AAAAFIeJzLYWBgYMlgTmFQSUlKzi9KdUhJstRLytVNTtZNSczRNTDWS87JL01JzCvRy0styQGqZkpSAJJJ-v___88C83OBBKeFgYGBsaGpgUHiyyyQcapw4wwNCZkXADIvHt08QwtTA2OgeaJZqM4zI2RcAci4egzjDCxMjYDGcZPqvDwWIMkwAUgBjZyPbKaxmYGBEcjMjqwsAJTIXCA' }

日本語の全文検索を試してみる

まずは、インデックスの設定です。 TEXTインデックスで、フィールド名 cyoikiとjusho_CDをインデックスにセットします。これで、全文検索は、この二つのフィールドに対して適用されます。

var ddoc_name =  "index-text2";
var key = "_design/" + ddoc_name;
var index = {
    "type": "text",
    "name": "index-fulltext",
    "ddoc": ddoc_name,
    "index": {
        "fields": [
            { "name": "jusho_CD", "type": "string" },
            { "name": "cyoiki", "type": "string" }
        ],
    }
}

次のクエリーとして、「門司」で全文検索してみたいと思います。

    query = {
        "selector": {
            "$text": '門司'
        },
        "fields": ["cyoiki", "sicyoson"],
        "use_index": "_design/index-text2",
        "sort": [{"jusho_CD:string": "asc"}]
    };

結果は、「門司」以外のものが沢山出てきています。良くみると、「門」と「司」が含まれる文字列が全てヒットしていることが、解ります。 困りましたね。 やりたいと事は、門司を含む町域をリストしたいのに、これでは使えませんね。

err =  null
size =  42
result =  { docs: 
   [ { cyoiki: '新門司北', sicyoson: '北九州市門司区' },
     { cyoiki: '新門司', sicyoson: '北九州市門司区' },
     { cyoiki: '旧門司', sicyoson: '北九州市門司区' },
     { cyoiki: '門司', sicyoson: '北九州市門司区' },
     { cyoiki: '庄司町', sicyoson: '北九州市門司区' },
     { cyoiki: '東門司', sicyoson: '北九州市門司区' },
     { cyoiki: '山門町', sicyoson: '北九州市小倉北区' },
     { cyoiki: '大門', sicyoson: '北九州市小倉北区' },
     { cyoiki: '正門町', sicyoson: '遠賀郡芦屋町' },
     { cyoiki: '古門', sicyoson: '鞍手郡鞍手町' },
     { cyoiki: '黒門', sicyoson: '福岡市中央区' },
     { cyoiki: '大手門', sicyoson: '福岡市中央区' },
     { cyoiki: '大手門', sicyoson: '福岡市中央区' },
     { cyoiki: '大手門', sicyoson: '福岡市中央区' },
     { cyoiki: '大手門', sicyoson: '福岡市中央区' },
     { cyoiki: '黒門', sicyoson: '福岡市中央区' },
     { cyoiki: '大手門', sicyoson: '福岡市中央区' },
     { cyoiki: '大手門', sicyoson: '福岡市中央区' },
     { cyoiki: '大手門', sicyoson: '福岡市中央区' },
     { cyoiki: '老司', sicyoson: '福岡市南区' },
     { cyoiki: '宮司', sicyoson: '福津市' },
     { cyoiki: '宮司元町', sicyoson: '福津市' },
     { cyoiki: '宮司浜', sicyoson: '福津市' },
     { cyoiki: '宮司ヶ丘', sicyoson: '福津市' },
     { cyoiki: '島門', sicyoson: '遠賀郡遠賀町' },
     { cyoiki: '古門戸町', sicyoson: '福岡市博多区' },
     { cyoiki: '古門戸町', sicyoson: '福岡市博多区' },
     { cyoiki: '古門戸町', sicyoson: '福岡市博多区' },
     { cyoiki: '下山門団地', sicyoson: '福岡市西区' },
     { cyoiki: '下山門', sicyoson: '福岡市西区' },
     { cyoiki: '上山門', sicyoson: '福岡市西区' },
     { cyoiki: '大門', sicyoson: '糸島市' },
     { cyoiki: '庄司', sicyoson: '飯塚市' },
     { cyoiki: '大門', sicyoson: '飯塚市' },
     { cyoiki: '門樋町', sicyoson: '行橋市' },
     { cyoiki: '門樋町', sicyoson: '行橋市' },
     { cyoiki: '三毛門', sicyoson: '豊前市' },
     { cyoiki: '長門石町', sicyoson: '久留米市' },
     { cyoiki: '長門石', sicyoson: '久留米市' },
     { cyoiki: '六ツ門町', sicyoson: '久留米市' },
     { cyoiki: '北野町赤司', sicyoson: '久留米市' },
     { cyoiki: '瀬高町山門', sicyoson: 'みやま市' } ],
  bookmark: 'g1AAAAUXeJyd0z9OwzAUBnALWGChN4ABxoTnOP-6QCUmprIzgJ1UQlaaIFTECBdAcAM6sMMBkOAGcAM4AAJuEN6rESLuEDmLo0jWT8_fZxeMsd7xYs42cpVVp6NBrkJfjb0s83JZeCD8rKjOcllO_HI0KXD3gmRqta5rPfsZ47KciggAQgD5qcna_LN40IKpHq5qzfICAM7JO9fN2fpt3DpxWxbH0Qv6yHkWl7RxQNyOzUEaAXHb2i05NSBuaIeH2QmO3IFzePvkHc6dNo15it6ea3hHxFV2F9gDxMhNLS5u406Iu7Cn46EQeGT54RheuYQru8QPitd2H5wCzFwDNOaNMW9tM0jQHDqGaMipIe-tSw0RjXnleAsN-WDIpwaZ_l6du05hPhvypdmPEPRe5GO3MF-N-fbfBEwzoc5XOoX5bsgvq58Y6wG52ynMb0POvcNZ5ZXWP51UcoE' }

アナライザー指定

テキストの中の単語をどの様に認識するかを設定するのが、アナライザー(1)です。これを設定して、動作を確認します。最初は、次のコードの通り、japanese (kuromoji)です。

var ddoc_name =  "index-text2";
var key = "_design/" + ddoc_name;
var index = {
    "type": "text",
    "name": "index-fulltext",
    "ddoc": ddoc_name,
    "index": {
        "fields": [
            { "name": "jusho_CD", "type": "string" },
            { "name": "cyoiki", "type": "string" }
        ],
        "default_field": {
            'enabled': true,
            'analyzer': 'japanese'  //<<--- ココ
        }
    }
}

実行結果は、期待ハズレですね。 kuromojiは、Javaで書かれているオープンソースの日本語形態素解析エンジンなのですが、地名を品詞に分解するのは、逆に難しい様ですね。

err =  null
size =  2
result =  { docs: 
   [ { cyoiki: '旧門司', sicyoson: '北九州市門司区' },
     { cyoiki: '門司', sicyoson: '北九州市門司区' } ],

次に keyword を試してみます。 まったくトークン化しない、形態素解析しない指定です。

        "default_field": {
            'enabled': true,
            'analyzer': 'keyword'  // <<--- ココ
        }

実行結果は、以下の通りです。 「門司」にぴったり一致したものだけが、ヒットしていますね。これも使えません。

err =  null
size =  1
result =  { docs: [ { cyoiki: '門司', sicyoson: '北九州市門司区' } ],

次は、cjk (Chinese, Japanese, Korean)を試してみます。 cjkアナライザー(4)は、基本は bi-gram のトークナイザーですが、どうでしょうか? うまくいくでしょうか

        "default_field": {
            'enabled': true,
            'analyzer': 'cjk'
        }

結果は次の通りです。 もっとも期待する通りの結果が出た様に思います。 地名を処理するなら、cjkが良さそうですね。

err =  null
size =  5
result =  { docs: 
   [ { cyoiki: '新門司北', sicyoson: '北九州市門司区' },
     { cyoiki: '新門司', sicyoson: '北九州市門司区' },
     { cyoiki: '旧門司', sicyoson: '北九州市門司区' },
     { cyoiki: '門司', sicyoson: '北九州市門司区' },
     { cyoiki: '東門司', sicyoson: '北九州市門司区' } ],

日本語のソート

検索結果の日本語文字列のソートについて、確認してみます。最初にソートなしの結果を確認します。

    query = {
        "selector": {
            '$or': [
                {'cyoiki': '港町'},
                {'cyoiki': '魚町'},
            ]
        },
        "fields": ["cyoiki", "sicyoson"],
        "use_index": "_design/index-text2"
    };

次の様に、港町、魚町が入り乱れる感じで結果が返ってきています。

err =  null
size =  6
result =  { docs: 
   [ { cyoiki: '港町', sicyoson: '北九州市門司区' },
     { cyoiki: '魚町', sicyoson: '田川市' },
     { cyoiki: '港町', sicyoson: '北九州市門司区' },
     { cyoiki: '港町', sicyoson: '大牟田市' },
     { cyoiki: '港町', sicyoson: '京都郡苅田町' },
     { cyoiki: '魚町', sicyoson: '北九州市小倉北区' } ],

それでは、次のクエリーで町域にソート条件を設定してみます。

    query = {
        "selector": {
            '$or': [
                {'cyoiki': '港町'},
                {'cyoiki': '魚町'},
            ]
        },
        "fields": ["cyoiki", "sicyoson"],
        "use_index": "_design/index-text2",
        "sort": [{"cyoiki:string": "asc"}]
    };

結果は、期待どおり、魚町と港町が順番になっています。

err =  null
size =  6
result =  { docs: 
   [ { cyoiki: '港町', sicyoson: '北九州市門司区' },
     { cyoiki: '港町', sicyoson: '北九州市門司区' },
     { cyoiki: '港町', sicyoson: '大牟田市' },
     { cyoiki: '港町', sicyoson: '京都郡苅田町' },
     { cyoiki: '魚町', sicyoson: '北九州市小倉北区' },
     { cyoiki: '魚町', sicyoson: '田川市' } ],

まとめ

Cloundant の日本語処理の対応について確認した結果、十分使えると言えるが、設定を正しく理解しないと、判断を間違えるので注意が必要ですね。

  • JSONインデックスとTEXTインデックスがあるが、確実に動作するのは、TEXTインデックス
  • 日本語処理では、TEXTインデックスのアナライザーの設定が重要
  • 日本語アナライザーは、kuromoji と cjk の2つが選択できる。地名などは、cjk が期待値を返してくれた。

参考資料

(1) Cloudant NoSQL DB API Reference Search Analyzers https://console.bluemix.net/docs/services/Cloudant/api/search.html#analyzers
(2) Lucene 4.2.1 analyzers-kuromoji API http://lucene.apache.org/core/4_2_1/analyzers-kuromoji/overview-summary.html
(3) Cloudant NoSQL DB API Reference Request body https://console.bluemix.net/docs/services/Cloudant/api/cloudant_query.html#finding-documents-by-using-an-index
(4) Package org.apache.lucene.analysis.cjk https://lucene.apache.org/core/4_0_0/analyzers-common/org/apache/lucene/analysis/cjk/package-summary.html
(5) Luene/SolrのCJKAnalyzerをカスタマイズして遊んでみる http://www.mwsoft.jp/programming/lucene/lucene_custom_cjk.html
(6) Cloudant NoSQL DB Query https://console.bluemix.net/docs/services/Cloudant/api/cloudant_query.html#query
(7) Cloudant NoSQL DB Design Documents https://console.bluemix.net/docs/services/Cloudant/api/design_documents.html#design-documents