人工知能技術 セマンティックウェブ技術 オントロジー技術 検索技術 データベース技術 デジタルトランスフォーメーション技術 Visualization & UX ワークフロー&サービス. プログラミング Clojure
前回述べた機械学習の結果を利用するにはデータベースもしくは検索エンジンにデータを投入して活用するのが最も手早くできる方法となる。クライアントのUIは、nodeやreactあるいはD3.js等を利用して見える化し、サーバー側でデータベースあるいは検索エンジンとREST等を介してつなげる構成だ。
今回はサーバー側のシステム構築について述べてみたい。NodeとEXPRESSを用いて構築する方法もあるが、少し複雑なビジネスロジックの構築を念頭に、Clojureを使ったものを紹介する。
Clojureでサーバー(ウェブ)アプリケーションを構築する手段も多々あるが、比較的ポピュラーなものとして”Ring“と”compojure“そして”clj-http“を利用してみる。
まずRingについて、RingはWeb サーバーと Web アプリケーションやフレームワーク間の標準的なインターフェイスを定めたもので、Ruby でいう Rack 、 Python でいう WSGI にあたるものとなる。Ringには4つのコンポーネント(ハンドラー、ミドルウェア、リクエストマップ、レスポンスマップ)があり、役割としてはハンドラーがクライアントからのリクエストマップを受け取り、レスポンスマップを返し、ミドルウェアはシンプルなハンドラーの機能を補うものとなる。一番シンプルなハンドラー以下のようになる。
(defn handler [req]
{:status 200
:headers {"Content-Type" "text/plain"}
:body (:remote-addr req)})
Handlerという関数が定義されて(defn)、reqという引数(入力)を受けて、送信するレスポンスデータが定義されている。
そもそも、インターネットでの通信はTCP(Transmission Control Protocol)やIP(Internet Protocol)で規定された手順で通信パケットの送受信を行い。そのプロトコルの上でウェブブラウザ(クライアント)とサーバーがHTTP(Hypertext Transfer Protocol)あるいはHTTPS(Hypertext Transfer Protocol Secure)を使って通信する形となる。TCP/IPがデータの塊を誤りなく送信する手段であるのに対して、HTTPはクライアントがサーバにリクエストメッセージとして「何を」「どうして」欲しいのかを伝え、サーバはこれにレスポンスメッセージを返すものとなる。この時、URLが「何を」、メソッドが「どうして」に当たる。
Ringのリクエストマップ、レスポンスマップは上記のコード例のように、これらをClojureのデータ構造であるedn((extensible data notation)で表すものとなる。
実際にRingのリクエストマップに現れるキーは以下のようなものとなり、
:server-port リクエストをハンドルしたポート番号
:server-name 解決されたサーバー名もしくは IP アドレス
:remote-addr クライアントか最後にリクエストを投げたプロキシの IP アドレス
:uri リクエスト URI (ドメイン名以下のフルパス)
:query-string もしあればクエリ文字列
:scheme トランスポートプロトコル :http または :https
:request-method HTTP リクエストメソッド :get, :head, :options, :put, :post, :delete のいずれか
:headers ヘッダーの文字列を小文字化したキーを持つマップ
:body もしあればリクエストボディのための InputStream
ハンドラーが作成するレスポンスマップは以下の 3 つのキーを持つ
:status HTTP ステータス
:headers クライアントへと返す HTTP ヘッダー
:body レスポンスボディ
レスポンスマップのキーであるステータスは HTTP RFC で定義されているものと同じで、 200 や 404等のウェブブラウザ上でよく見かけるものとなる。
当初の目的であるデータベースとの連携のケースでは、リクエストマップでデータベース側の設定を反映したものに、リスポンスマップでAPIに規定された情報に合わせた構成にするイメージとなる。
ここで具体的なサーバーの立ち上げを行う。まずproject.cljファイルにringのライブラリを追加する。
:dependencies [[org.clojure/clojure "1.10.1"]
[ring "1.8.2"]]
次にsrcのcore.cljを以下のようにする。
(ns my-app.core
(:require [ring.adapter.jetty :as server]))
(defonce server (atom nil)) ;; (1)
(defn handler [req] ;;(2)
{:status 200
:headers {"Content-Type" "text/plain"}
:body "Hello, world"})
(defn start-server [] ;;(3)
(when-not @server
(reset! server (server/run-jetty handler {:port 3000 :join? false}))))
(defn stop-server [] ::(4)
(when @server
(.stop @server)
(reset! server nil)))
(defn restart-server [] ;;(5)
(when @server
(stop-server)
(start-server)))
(1)はサーバーのインスタンスの生成。(2)でハンドラー関数を設定して、(3)でサーバーをスタート、(4)でサーバー停止と(5)はリスタートになる。上記のファイルをspacemacs上で開き、「SPC」「m」「s」「i」を順に押してreplサーバーを起動し、それぞれの関数の後ろで「CTRL」「c」「e」を同時に押すと評価ができる。start-serverまで評価が終わった時点でブラウザ上で「http://localhost:3000/」を入力すると”Hello world”が見える。また、ターミナル上で「curl -i localhost:3000/」と入力しても、レスポンスが確認できる。
今回はClojureのringを使ったサーバーの立ち上げまでを述べた。次回はcompojureとclj-httpを使ったルーティングまで述べられればと思う。
コメント
[…] 機械学習等の結果をデータベースに入れて活用することを目的として、前回はまずサーバーの立ち上げまで行った。次のステップとしてルーティングを述べたい。 […]
[…] 具体的な実装例はwebサーバーとDBの連携にて述べる。 […]
[…] WebサーバーとDBの連携(1) Clojureでのサーバーの立ち上げ […]
[…] WebサーバーとDBの連携(1) Clojureでのサーバーの立ち上げ […]
[…] 「PHPフレームワークLaravel Webアプリケーション開発」より。前回はLaravelを使ったアプリケーションの構築の概略について述べた。今回はLaravelアプリケーションの起動から終了までの流れを追ってみる。今回の記事は以前述べたClojureでのウェブアプリケーションの流れと比較するとより理解が深まると思う。 […]