まだプログラマーですが何か?

プログラマーネタ中心。たまに作成したウェブサービス関連の話も https://twitter.com/dotnsf

IBM Bluemix からも提供されている NoSQL 型 DBaaS の1つが Cloudant です:
2016071301


ベースとなる製品はオープンソースの Apache CouchDB です。私自身も以前は疑問に思っていたのですが、たまに聞かれる質問の1つに「Cloudant と Apache CouchDB は何が違うのか?」があります。

Cloudant は(ソフトウェア単体版も存在していますが) DBaaS としてクラウドで提供されているとか、 IBM の管理下で利用できる(サーバーインフラを自分が管理しなくてよい)とか、運用面での違いは比較的わかりやすいのですが、機能面での決定的な違いについてあまり目にする機会がありませんでした。

その違いの1つが今回紹介する「全文検索」機能です。一般的に NoSQL DB はスケーラビリティにすぐれた大容量データの保存に向くストレージシステムですが、SQL のようなクエリー言語が使えないこともあり、柔軟な検索はあまり得意ではありません。全文検索に関しては SQL DB であれば、
> select * from xxx where name like '%テスト%'

のような指定で「name にテストという文字を含むもの」が検索できます。パフォーマンス対策とか色々考慮すべき点はありますが、処理そのものは単純だし簡単・便利に実現できてしまいます。

一方で、一般的な NoSQL DB には全文検索を実現するためのこのような便利な機能がありません。Apache CouchDB でもインデックスを作成することで「完全一致検索」は実現できますが、「全文検索」はそうはいきません。Apache Lucene や ElasticSearch などの全文検索エンジンを使って NoSQL DB とは別に全文検索機能を実装し、併用して運用していくことになります。この方法はデータの一元管理が難しく、また DB と検索エンジンの整合性も併せて管理する必要が生じるため、比較的運用負荷の高い実現方法になってしまいます。

実はこの点で Cloudant は Apache CouchDB とは違います。Cloudant の検索機能には Apache Lucene が初めから含まれており、特に Lucene の存在を意識することなく全文検索インデックスが使えるようになっています。その使い方を紹介します。


まずは Cloudant のインスタンスを用意します。IBM Bluemix アカウントをお持ちであれば、サービスとして Cloudant を1インスタンス用意いただくのが一番簡単だと思います。IBM Bluemix アカウントがない場合は http://cloudant.com/ に直接サインアップしていただいても構いません。以下は前者の前提で紹介します。

作成した Cloudant の環境変数を参照して、Cloudant サービスを利用するための接続情報を確認します:
2016071301


サービス接続情報の JSON を確認し、credentials.url の値をメモしておきます(後で使います)。ここでは credentials.url の値が以下のようになっていると仮定して続きを紹介します:
{
  "credentials": {
    "username": "USERNAME",
    "password": "PASSWORD",
    "host": "USERNAME.cloudant.com",
    "port": 443,
    "url": "https://USERNAME:PASSWORD@USERNAME.cloudant.com"
  }
}


まずは Cloudant のダッシュボード画面にアクセスしてみます。まだ何も作業していなければ特にデータベースも作られてなく、データベース一覧は空の状態のはずです。ここでは今回の作業用に1つデータベースを追加することにします。画面右上の "Create Database" をクリックします:
2016071302


新規に作成するデータベースの名称を入力するよう求められるので適当に(以下の例では "mydb" と)入力して "Create" をクリックします:
2016071303


mydb データベースが新規に作成されました。が、(当たり前ですが)まだこのデータベースには何のドキュメントも登録されていません:
2016071304


検索作業用にいくつかのドキュメントを追加してみましょう。+印から "New Doc" を選択します:
2016071305


以下の様なドキュメント編集画面が表示されるはずです。ここに登録するドキュメントの内容を JSON 形式で入力していきます:
2016071306


今回は以下の様に "name" と "desc" という2つのフィールドを持つドキュメントを生成することにします("_id" は初めから入っている値をそのまま使います):
{
 "_id": "XXXXXXXX....XXX",
 "name": "Natural Language Classifier",
 "desc": "自然言語テキストを学習してカテゴリを分類する"
}

この状態でドキュメントを保存します。"Create Document" と書かれたボタンをクリックします:
2016071307


ドキュメントが保存されました。mydb データベースのドキュメント一覧からも参照できますが、指定した "name" や "desc" の値はこの画面からは確認できません。ドキュメントの内容を確認するには該当ドキュメントの右上の鉛筆マークをクリックします:
2016071308


"name" や "desc" 、そして追加された "_rev" の値なども確認することができます。正しく格納されているようです。一度 "<" 印をクリックして元の画面に戻ります:
2016071309


同様にしていくつかのドキュメントを追加していきましょう。上記の作業を繰り返して、とりあえず以下の3つのドキュメントが登録された状態にしておきます:
#name の値desc の値
1Natural Language Classifier自然言語テキストを学習してカテゴリを分類する
2Personality Insights入力されたテキストから性格を分析する
3Tradeoff Analytics優先順位を意識したトレードオフ判断を視覚化する


ではこのデータベースに全文検索の索引を追加して全文検索ができるようにします。mydb のメニュー画面から Design Documents 横の+印をクリックし、サブメニューから "New Search Index" を選択します:
2016071301


索引に関する情報を入力する画面に切り替わります。ここではデザイン ID ("_design/" と書かれた右)に "mydbdoc" と、インデックス名("Index name" と書かれた下)に "mydbsearch" とそれぞれ入力します:
2016071302


続けて下にスクロールし、Search Index function の中身を以下のように書き換えます:
function(doc){
 if ('name' in doc) {
  var search_this = [doc.name, doc.desc];
  index('default', search_this.join(' '));
  index('name', doc.name, {store: 'yes'});
  index('desc', doc.desc, {store: 'yes'});
 }
}
  ↑ "name" というフィールドを持つドキュメントに対して、
   "name" と "desc" の2フィールドを対象に検索インデックスを作成するようにしています。


最後に Type には "Japanese" を選択して、一番下の "Create Document and Build Index" をクリックします。これで検索索引が作成され、かつ索引付けが実行されて検索が可能になります:
2016071303


元の画面に戻ると "Build Indexes" 欄が追加されており、その中に作成したインデックス名称(mydbsearch)が表示されているはずです。これを選択すると検索のプレビューを確認することができるので、本当にこれだけで全文検索が可能になったのか試してみましょう:
2016071304


画面右の検索ボックスに「テキスト」と入力してみます(上記3ドキュメントと同じデータを登録していれば、3つのうちの2つのドキュメントが「テキスト」という文字列を含んでいるので、正しく検索できれば結果は2ドキュメントになることが予想されます):
2016071305


全文検索が実行され、画面のように2ドキュメントが検索結果にリストされました。正しく全文検索が実行されたことが確認できました:
2016071306


ちなみに、この検索処理を API で実行する場合は以下の URL に対して GET リクエストを実行することになります:
https://USERNAME:PASSWORD@USERNAME.cloudant.com/mydb/_design/mydbdoc/_search/mydbsearch?q=テキスト

指定する URL は以下の形になっています:
(上述の環境変数で取得した青字部分)/(DB名)/_design/(デザインID)/_search/(インデックス名)?q=(検索文字列)

試しにこの文字列をブラウザのアドレスバーに入力して実行すると、同じ2件の検索結果が得られるはずです:
2016071307


というわけで、Cloudant サービスには標準で Lucene ベースの全文検索エンジンが搭載されており、Apache CouchDB 同様に簡単に使うことができる上、NoSQL DB に苦手な全文検索が簡単に実現・実装することができる、という特徴を持っていることが確認できました。

(参考)
https://cloudant.com/product/cloudant-features/cloudant-search/

IBM BluemixAPI Connect サービスを利用して、データベースのテーブルスキーマから CRUD の API を生成する、という手順を試してみました:
2017071001


以下にその作業内容を紹介します。なお、以下の内容は基本的にはこのドキュメントに書かれている内容を補足しながら実行したものです:
https://new-console.ng.bluemix.net/apis/apiconnect/start


何はともあれ API Connect サービスインスタンスを1つ作成します。なお 2016/07/10 時点では(クラシックエクスペリエンスではなく)新しいUI 画面でないと正しく動かなかったので、以下は新 UI でのスクリーションショットで紹介します。

まず API Connect サービスインスタンスを作成します。新 UI 画面のダッシュボードから「コンソール」を選択し、「API」を選択します:
2016071001


API に関連するサービスの画面が表示されたら「API Connect」を選択:
2016071002


API Connect の画面に移動しますが、まだインスタンスが作成されていないので、「作成」ボタンをクリックします:
2016071003


API Connect サービスの紹介画面が表示されたら、下にスクロールします:
2016071004


利用プランを選択して「作成」ボタンをクリックします。下図では無料の "Essential" プランを選択しました。共有サーバーで利用できるリソースもあまり多くありませんが、まずはこれで作ってみます:
2016071005


作成された API Connect サービスインスタンスの画面に移動します。"Sandbox" と表示されていれば成功です。また後でこの画面を使うことになりますが、まずはここまでの作業で API Connect サーバーが1つ用意できました。Bluemix のダッシュボードに戻るには左上の "IBM Bluemix" 部分をクリックします:
2016071006


さて、API が用意できたら再度この API Connect サービスを使って公開のための設定を行うことになります。既に公開してもよい API があればしばらく読み飛ばしてください。以下はこれから1つのデータベーステーブルを作り、その中身を読み書きするための API を API Connect Developer Toolkit を使って新たに生成するための作業手順を紹介します。

API Connect Developer Toolkit を導入するにはまず Node.js と npm を作業マシンに導入する必要があります。Windows 環境であればこちらからインストーラーをダウンロードして導入します。Linux などの UNIX 環境であればこちらの記事(の nodejs と npm のインストールまで)を参考に Node.js と npm を導入しておいてください:
http://dotnsf.blog.jp/archives/1036420834.html

Node.js および npm が導入できたら、npm を使って API Connect Developer Toolkit を導入します:
# npm install -g apiconnect

なお、この作業マシン上でも API Connect サーバーを起動することになり、一部の作業をウェブブラウザから実行することになります。つまりこの作業マシンには GUI のデスクトップ環境やウェブブラウザが導入されている必要があります。環境に合わせて導入しておいてください。CentOS であれば以下のコマンドで X Window のデスクトップおよび FireFox ウェブブラウザを導入できます:
# yum groupinstall "Desktop"
# yum install firefox

そして、API Connect Developer Toolkit を使って StrongLoop LoopBack アプリケーションを作成します。以下の例ではホームディレクトリ以下に src サブディレクトリを作り、更にその下に apic コマンドで loopback アプリケーションを作成しています。この通りに実行していただいても構いませんし、別途適宜ディレクトリを変更して実行することもできます:
# mkdir ~/src
# cd ~/src
# apic loopback

最初の1回目だけはライセンスに同意していただく手続きが必要です。内容を確認の上、"Yes" を選択してください:

2017071001


ライセンス同意後、ここからは StrongLoop LoopBack とほぼ同じ手順を実行することになります。まずは API アプリケーションとしての名前を指定します。ここでは "myapp" という名前にしました:
2017071002


次にアプリケーションを作成するディレクトリ名を指定します。デフォルトではアプリケーション名と同じ名前のディレクトリが指定されます。このままでも構いませんし、変更していただいても構いません:
2017071003


アプリケーションの種類を聞かれます。今回はサーバー上で動く API をテンプレートなしで作るので、"empty-server" を選択します:
2017071004


すると入力された内容にそってアプリケーションが作られます・・・・が、私の場合は何故かここでエラーになってしまいました:
2017071005


エラーになった場合はアプリケーションディレクトリ(この例では myapp)に移動し、"npm install" を実行して手動でインストールします:
2017071006


ではこの API アプリケーションを具体的に作成していきます。ここからはブラウザでの作業になるので、まずはデスクトップ画面を開き、その中でターミナルウィンドウを開きます。

アプリケーションディレクトリ(この例では myapp)に移動し、"apic edit" と入力します。すると "Express server listening on http://127.0.0.1:9000" と表示され、デスクトップ内にデフォルトブラウザが開いて、この URL が開きます。まず最初に Bluemix にログインする必要があるため、「Bluemix にサインイン」を選択します:
2017071007


IBM Bluemix のアカウントとパスワードでログインします:
2017071008


ログインが成功すると「ドラフト API」の画面に移動します。「OK」をクリックします:
2017071001


IBM API Connect のトップ画面に移動します。以下の様な画面が表示されることを確認してください:
2017071002


ここからテーブルモデルのスキーマを定義して、そのモデルの CRUD 操作 API を生成するのですが、その前にその情報を格納するデータソース(データベース)を作成する必要があります。「データソース」タブに移動して、まだデータソースが1つも定義されていないことを確認してから「追加」をクリックします:
2016071001


最初にデータソースの名称を入力します。ここでは "db" とだけ指定して「新規作成」します:
2016071002


次にこのデータソースのコネクターと localStorage を指定します。前者はデフォルトでもあるインメモリDB(In-memory db)を指定し、localStorage には window.localStrage と入力して、画面右上の保存ボタンで保存します。これでデータソースの定義は決まりました:
2016071003


続けてモデルを定義します。「モデル」タブに移動して「追加」ボタンをクリックします:
2016071001


新しく作成するモデルの名称を入力します。この例では "item" という名前のモデルにしました:
2016071002


続けて新規作成した item モデルに追加設定を加えるため、一覧から選択します:
2016071003


(モデルの)複数形には "items" 、基本モデルには "PersistedModel" 、そしてデータソースには先程作成した "db" を指定します:
2016071202


続けてプロパティを追加するために右下の+印をクリックして、以下のようにプロパティを設定します。追加するプロパティは2つで、1つ目は必須の name(string)、2つ目は必須ではない price(number)とします。item(商品)のname(名前)とprice(値段)を設定するためのプロパティだと思ってください。なお、特に指定しなくても id というインデックスプロパティがこれらに加えて追加されます:
2016071000


プロパティの追加が完了したら、右上の保存ボタンでモデル定義を保存します。またこの状態で CRUD API を有効にするため、画面下の "Stopped" と書かれた左にある三角をクリックして、API アプリケーションを実行します:
2016071201


しばらくすると HTTP サーバーが起動し、ステータスが "Running" に変わります。同時に API アプリケーションの URL(http://127.0.0.1:4001/)が表示されます:
2016071203


この状態になると、作成した myapp の API アプリケーションが起動している状態になり、item モデルの読み書きが可能になります。試しにいくつかの API を curl で実行してみましょう(以下青字が入力コマンド、黒字が出力結果)。

まずは item の一覧を取得(GET /api/items)します。まだ何も追加していないので、結果は空配列になっています:
# curl -XGET http://localhost:4001/api/items
[]

1つの item を追加(POST /api/items)してみます。まずは必須の "name" プロパティをわざと指定せずにデータを POST してエラーになることを確認します:
# curl -H 'Content-Type: application/json' -XPOST http://localhost:4001/api/items -d '{"price":100}'
{
 "error":{
  "name":"ValidationError",
  "status":422,
  "message":"The `item` instance is not valid. Details: `name` can't be blank (value: undefined).",
  "statusCode":422,
  "details":{
   "context":"item",
   "codes":{
    "name":["presence"]
   },
   "messages":{
    "name":["can't be blank"]
   }
  },
  "stack":"ValidationError: The `item` instance is not valid. Details: `name` can't be blank (value: undefined).\n ....
    :

↑"name" がブランクではダメ、と怒られています。というわけで、改めて正しいデータを指定して追加してみましょう:
# curl -H 'Content-Type: application/json' -XPOST http://localhost:4001/api/items -d '{"name":"あいうえお","price":100}'
{"name":"あいうえお","price":100,"id":1}

↑追加処理が成功したようです。入力データに指定しなかった id 要素が追加され、その値が1になっているようです。


この状態で再度 item の一覧取得を実行すると、追加したデータが含まれた配列で返ってくることを確認します:
# curl -XGET http://localhost:4001/api/items
[{"name":"あいうえお","price":100,"id":1}]

また id を指定して要素を取り出す(GET /api/items/{id})こともできます:
# curl -XGET http://localhost:4001/api/items/1
{"name":"あいうえお","price":100,"id":1}

↑こちらは結果が1つしか存在しない API なので、結果は配列ではなく、該当する JSON オブジェクトそのものになります。

データを更新(PUT /api/items)することもできます:
# curl -H 'Content-Type: application/json' -XPUT http://localhost:4001/api/items -d '{"id":1,"name":"かきくけこ","price":200}'
{"name":"かきくけこ","price":200,"id":1}

# curl -XGET http://localhost:4001/api/items
[{"name":"かきくけこ","price":200,"id":1}]

そして削除(DELETE /api/items/{id})する API も用意されています:
# curl -XDELETE http://localhost:4001/api/items/1
{"count":1}

# curl -XGET http://localhost:4001/api/items
[]

というわけで、item モデルを定義しただけで、その item モデルを読み書き更新削除する API が自動生成できていることが確認できました。


API Connect 本体の機能をほとんど紹介できてないのですが、長くなったのでとりあえずここまで。


(注 今回のエントリは以下の内容が古くなってしまったため、新たに書き直したものです)



全文検索エンジン ElasticSearch に日本語形態素解析ソフトウェア Kuromoji のプラグインを導入して日本語全文検索エンジンを作ります。なおプラットフォームは CentOS 6 を前提とします。


まず ElasticSearch の動作に必要な Java 環境を用意します。Oracle Java を導入しても構いませんが、Open Java であれば以下のコマンドで導入可能です(Java 7 の場合):
# yum install java-1.7.0-openjdk

次に検索エンジンである ElasticSearch 本体を導入します。公式サイトから最新版(2016/07/11時点では 2.3.4)のインストールモジュールをダウンロードします。インストールモジュールにはいくつかの種類はありますが、今回は rpm パッケージ版(elasticsearch-2.3.4.rpm)をダウンロードします:
https://www.elastic.co/downloads/elasticsearch

2016071101


ダウンロードできたら rpm コマンドでインストールして起動、および自動起動設定までを行います。ちなみにこの rpm 版をインストールした場合、ElasticSearch 本体は /usr/share/elasticsearch/ 以下に導入されます :
# rpm -ivh elasticsearch-2.3.4.rpm
# /etc/init.d/elasticsearch start
# chkconfig elasticsearch on

これで ElasticSearch 本体の導入は完了しました。続けて Kuromoji (とウェブ GUI である head)を導入します。いったん ElasticSearch を止めた上で本体のディレクトリに移動し、それぞれのプラグインを導入します:
# /etc/init.d/elasticsearch stop
# cd /usr/share/elasticsearch
# bin/plugin install analysis-kuromoji
# bin/plugin install mobz/elasticsearch-head

設定ファイル(/etc/elasticsearch/elasticsearch.yml)を編集します。まずデフォルトの状態だとウェブ GUI にはローカルホストからでないとアクセスできません。何かと不便なので外部からもアクセスできるように変更します(以下の例では全てのホストからのアクセスを許可しています)。また解析エンジンのデフォルトとして Kuromoji を利用するよう変更します:
(/etc/elasticsearch/elasticsearch.yml)

# allow http connection from every hosts
network.host: 0.0.0.0

# set kuromoji as default Tokenizer
index.analysis.analyzer.default.type: custom
index.analysis.analyzer.default.tokenizer: kuromoji_tokenizer

この状態で ElasticSearch を起動すれば日本語全文検索エンジンとしての ElasticSearch が、ウェブ GUI 付きで稼働します:
# /etc/init.d/elasticsearch start

ウェブ GUI にアクセスするにはウェブブラウザから http://(ElasticSearch のホスト):9200/_plugin/head/ にアクセスします:

2016071102


では実際に日本語データを挿入して検索してみましょう。以下の内容のテキストを manho.json という名前で保存します:
(manho.json)

{"create":{"_id":"4442072443477838363"}}
{"id": 4442072443477838363,"username": "michelle_yama","created": "2016/07/11 12:49:25","updated": "2016/07/11 12:49:25","tag": "","filename": "","type": "image/jpeg","address": "","text": "","lat": 35.6565093994141,"lng": 139.752868652344,"nice": 0,"niceby": "","width": 480,"height": 360,"imgkey": "","misc": "東京都港区芝大門2丁目1"}

{"create":{"_id":"5545583388040541151"}}
{"id": 5545583388040541151,"username": "42ER03","created": "2016/07/11 05:59:20","updated": "2016/07/11 05:59:20","tag": "市章と市の花「ツツジ」","filename": "20051119兵庫県加古川市山手2丁目29-12地先_ .jpg","type": "image/jpeg","address": "","text": "平成17年11月撮影","lat": 34.78293426048821,"lng": 134.88915952863033,"nice": 0,"niceby": "","width": 480,"height": 480,"imgkey": "","misc": "兵庫県加古川市山手2丁目27"}

{"create":{"_id":"1831807387175567807"}}
{"id": 1831807387175567807,"username": "ippei0605","created": "2016/07/10 23:07:24","updated": "2016/07/11 16:01:52","tag": "居合の稽古","filename": "image.jpeg","type": "image/jpeg","address": "","text": "","lat": 35.76108611111111,"lng": 139.5356611111111,"nice": 1,"niceby": "dotnsf","width": 480,"height": 360,"imgkey": "","misc": "東京都東久留米市新川町1丁目10 都道125号線"}

{"create":{"_id":"3546975096233083798"}}
{"id": 3546975096233083798,"username": "dotnsf","created": "2016/07/10 22:28:51","updated": "2016/07/10 22:28:51","tag": "hiroshima shobara","filename": "hilside.jpg","type": "image/jpeg","address": "","text": "国営備北丘陵公園内のヒルサイドパークマンホール","lat": 34.83977596170017,"lng": 132.99681892575074,"nice": 0,"niceby": "","width": 269,"height": 480,"imgkey": "","misc": "広島県庄原市上原町1300"}

{"create":{"_id":"4946513086810703103"}}
{"id": 4946513086810703103,"username": "minamu4545","created": "2016/07/10 21:06:11","updated": "2016/07/10 21:08:31","tag": "","filename": "image.jpeg","type": "image/jpeg","address": "","text": "某水泳アニメの聖地となった岩美町の色蓋(おすい)。<br/>浦富海岸が描かれて美しい蓋。此の蓋もかなり美しいですが、實際の海岸はもっと美しかったです。<br/>色蓋は浦富海岸沿いの縣道155號線にたくさん設置されてますが、路上なので状態は惡いものが多いです。<br/>此の蓋もガムが付いて無ければ完璧だったのですが殘念です。蓋にガム捨てるのほんとやめて欲しい。<br/>","lat": 35.59056896685199,"lng": 134.32106172622503,"nice": 0,"niceby": "","width": 480,"height": 480,"imgkey": "","misc": "鳥取県岩美郡岩美町大字浦富 県道155号線"}

{"create":{"_id":"7542390449304551253"}}
{"id": 7542390449304551253,"username": "42ER03","created": "2016/07/10 07:50:19","updated": "2016/07/10 07:50:19","tag": "ビルバオ市の市章","filename": "20140731③ビルバオ03_.jpg","type": "image/jpeg","address": "","text": "2014年07月撮影/グッゲンハイム美術館付近","lat": 43.26813637672919,"lng": -2.9336467575902736,"nice": 0,"niceby": "","width": 480,"height": 480,"imgkey": "","misc": "スペイン"}

{"create":{"_id":"8484297972018100687"}}
{"id": 8484297972018100687,"username": "42ER03","created": "2016/07/09 08:17:30","updated": "2016/07/09 08:17:30","tag": "高崎まつり","filename": "20160610,1156,03群馬県高崎市高崎駅東口_.jpg","type": "image/jpeg","address": "","text": "平成28年06月撮影","lat": 36.32132769063828,"lng": 139.01428243101884,"nice": 0,"niceby": "","width": 480,"height": 480,"imgkey": "","misc": "群馬県高崎市栄町16"}

{"create":{"_id":"4255462064362665608"}}
{"id": 4255462064362665608,"username": "minamu4545","created": "2016/07/08 19:42:02","updated": "2016/07/08 19:43:49","tag": "","filename": "image.jpeg","type": "image/jpeg","address": "","text": "にかほ市(旧象潟町)小滝地區の農業集落排水の色蓋。<br/>描かれているのは奈曽の白滝。<br/>奈曽の白滝の駐車場前の歩道に設置されていますが劣化が激しいです。<br/>ちなみに、駐車場の横には農業集落排水の処理場があります。","lat": 39.18138258105665,"lng": 139.94690930427362,"nice": 0,"niceby": "","width": 480,"height": 480,"imgkey": "","misc": "秋田県にかほ市象潟町小滝"}

{"create":{"_id":"5394969523646972723"}}
{"id": 5394969523646972723,"username": "ujiteaa","created": "2016/07/08 06:08:46","updated": "2016/07/08 06:08:46","tag": "埼玉県川越市旭町","filename": "_20160708_053352.JPG","type": "image/jpeg","address": "","text": "","lat": 35.690625,"lng": 139.699788,"nice": 0,"niceby": "","width": 473,"height": 480,"imgkey": "","misc": "東京都新宿区西新宿1丁目1"}

{"create":{"_id":"3662100910616235567"}}
{"id": 3662100910616235567,"username": "ujiteaa","created": "2016/07/08 06:07:30","updated": "2016/07/08 06:07:30","tag": "埼玉県川越市","filename": "_20160708_053352.JPG","type": "image/jpeg","address": "","text": "","lat": 35.690625,"lng": 139.699788,"nice": 0,"niceby": "","width": 473,"height": 480,"imgkey": "","misc": "東京都新宿区西新宿1丁目1"}

この内容をバルク API でまとめて挿入します。以下の例ではインデックスに manholes、タイプに geo を指定しています:
# curl -XPOST http://localhost:9200/manholes/geo/_bulk --data-binary @manho.json

ではこの状態で「美しさ」というキーワードで検索してみましょう:
# curl -X GET http://localhost:9200/manholes/geo/_search -d '{"query":{"match":{"text":"美しさ"}}}'

{
  :
 "hits":{
  "total":2,
  "max_score":0.045926645,
  "hits":[
   {
    "_index":"manholes",
    "_type":"geo",
    "_id":"4946513086810703103",
    "_score":0.045926645,
    "_source":{
     "id": 4946513086810703103,
       :
     "text": "某水泳アニメの聖地となった岩美町の色蓋(おすい)。&lt;br/&gt;浦 富海岸が描かれて美しい蓋。此の蓋もかなり美しいですが、實際の海岸はもっと美しかったです。&lt;br/&gt;色蓋は浦富海岸沿いの縣道155號線にたくさん設置されてますが、路上なので状態は惡いものが多いです。&lt;br/&gt;此の蓋もガムが付いて無ければ完璧だ ったのですが殘念です。蓋にガム捨てるのほんとやめて欲しい。&lt;br/&gt;",
       :
   },
   {
    "_index":"manholes",
    "_type":"geo",
    "_id":"4255462064362665608",
    "_score":0.0049227546,
    "_source":{
     "id": 4255462064362665608,
       :
     "text": "にかほ市(旧象潟町)小滝地區の農業集落排水の色蓋。&lt;br/&gt;描かれているのは奈曽の白滝。&lt;br/&gt;奈曽の白滝の駐車場前の歩道に設置されていますが劣化が激しいです。&lt;br/&gt;ちなみに、駐 車場の横には農業集落排水の処理場があります。",
       :
   }
  ]
 }
}

「美しさ」で完全一致するデータは存在しませんが、「美しい」でヒットしたようです。正しく日本語が形態素解析されて判断されていることがわかります。

というわけで、日本語全文検索エンジンの出来上がり!


このページのトップヘ