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

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

2016/07

少し遅れてしまいましたが、2016/Jul/02 に Ruby の Web アプリケーションフレームワークである Rails の最新バージョン 5.0 のリリースが発表されました:
This Week In Rails: Rails 5 is out with new guides and more!


早速インストールしてみたので、その手順を紹介します。対象は CentOS 6.x とします。また導入手順としては rbenv を使って Ruby 本体を導入し、続けて gem で Rails 5.0 を導入します。

まずは Ruby の導入です。CentOS の場合、Ruby は "yum install ruby" で導入することも可能ですが、デフォルトで導入される Ruby のバージョンが少し低い(1.8.x)ので、rbenv を使って 2.x を導入することにします。なお Rail 5.0 のサポート Ruby バージョンは 2.2 以上とのことです。

というわけで、最初に rbenv を導入します。rbenv の導入前提として git が、そして rbenv を使って Ruby 2.x を導入する際の前提としていくつかの開発用ライブラリ必要になります。先に導入しておきましょう:
# yum install git gcc make openssl-devel libffi-devel readline-devel

では改めて rbenv を導入します:
# cd /opt
# git clone git://github.com/sstephenson/rbenv.git
# mkdir /opt/rbenv/plugins
# cd /opt/rbenv/plugins
# git clone git://github.com/sstephenson/ruby-build.git

最後に /etc/profile に次の3行を追加します:
export RBENV_ROOT="/opt/rbenv"
export PATH="${RBENV_ROOT}/bin:${PATH}"
eval "$(rbenv init -)"

そして一旦ログアウトして再ログインします(編集した /etc/profile を読み込んで rbenv を有効にします)。

更に ruby-build を導入して、rbenv で install コマンドを実行できるようにしておきます:
# cd /usr/local/src
# git clone git://github.com/sstephenson/ruby-build.git
# cd ruby-build
# ./install.sh

ここまでの準備が長かったのですが、これで rbenv が導入できました。rbenv を使って、今回は Ruby 2.2.5 を導入します:
# rbenv install 2.2.5
   :
# rbenv global 2.2.5
# ruby -v
ruby 2.2.5p319 (2016-04-26 revision 54774) [x86_64-linux] <- 確認

Ruby が導入できたことを確認し、最後に gem を使って Rails 5.0 を導入します:
# gem update --system
# gem install rails -v 5.0.0
# gem install bundler
# rbenv rehash
# rails -v
Rails 5.0.0 <- 確認

導入できましたー!


Windows 環境向けの Raspberry Pi エミュレータ(Raspbian エミュレータと呼ぶべき?)を使ってみました。

準備は簡単。パッケージが用意されているので、最新ファイルをダウンロードして展開するだけです:
https://sourceforge.net/projects/rpiqemuwindows/


最新ファイル(2016/Jul/18 時点では qemu.zip)をダウンロード&展開できたら、実行は run.bat ファイルを実行するだけです(QEMU上で動く、ってことだと思う):
2016071801


これだけでラズパイの起動が開始します。CPU は1つだけなんですね。ちなみにこの画面をアクティブにするとマウスコントロールが奪われてしまうので、他のウィンドウを操作する場合は Ctrl+ALT でマウス制御を戻してください:
2016071802


そしてしばらく待つと(ラズパイを触ったことがある人ならお馴染みの)初期設定画面が起動します:
2016071803


上記メニューの update を選んでシステムのアップデートを行うと自動的にテキスト端末画面に戻ります。ここで普通にコマンドを実行しての利用もできますが、ここで "startx" と入力すると X Window のデスクトップを起動することができます:
2016071801


こんな感じ。Scratch も使えそうです:
2016071802



ラズパイに興味あるけど、まだ持ってなくて、試しに操作を体験してみたい、という人向け・・・かな? OS イメージを SD カードに書き込んで・・・とか、余計な意識なしにとりあえず動く環境が使えるので、気分は味わえると思います。

アプリケーションの国際化を意識する場合に多言語対応は避けて通れなくなります。要するに画面に表示される文字列を変数化して、実際の表示に使われる中身をブラウザの言語設定などから動的に変更して表示する、という考え方です。したがって各変数に対応する文字列を各言語ごとに用意する必要があります。特に Java などでは .properties リソースファイルとして用意します。

このリソースファイル、日本語と英語程度であれば普通に用意できるかもしれませんが、多言語対応のメリットを考えると、フランス語やドイツ語、中国語など、リソースファイルを用意するだけでその言語向けの画面を用意できます(そのための多言語対応です)。しかしこれらの言語にリソースファイルを翻訳するのは言うほど簡単ではないはずです。事実、自分も日本語と英語以外では翻訳サービスを併用しないと無理だし、その結果作成されたリソースファイルがどの程度正しいのか(おかしくないのか)は正直よくわかりません。ましてやアラビア語のような表記方向すら異なるような文字だと、リソースファイルの編集方法すらよくわかってなかったりします。

そんなリソースファイルの翻訳に便利なサービスの1つが IBM Bluemix から提供されている Globalization Pipeline です。以前からベータリリースはされていましたが、2016年7月に正式リリースを迎え、REST API による操作もサポートされました:
2016071501


使い方は基本言語となる英語のリソースファイルを用意すれば、日本語を含む9言語(元の英語まで含めると10言語)のリソースファイルを自動生成してくれます。使い方も簡単です:
2016071502


このサービスの使い方について、以前に(ベータだった頃に)ブログで紹介しています。ちとUIが変更になっているようなので、参考程度ですが:


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 本体の機能をほとんど紹介できてないのですが、長くなったのでとりあえずここまで。


このページのトップヘ