AttsuBlog

ATTSU INC. Official Blog
IMGP3649_Fotor
0 comments

ArangoDBとClojure その2

タグ:,

こんにちは、萬屋です。

今年の4月は春雨ばかりで洗濯物に困ってしまいましたね……(´・ω・`)本来は「春小雨」と書いて「はるさめ」と読むらしいですよ。
「春雨じゃ、濡れて参ろう」という有名な一節がありますし、村下孝蔵さんの「春雨」という美しい曲がありますので、風情があるものではありますが(^_^;)

5月に入って良い天気が続いています。外を歩くと気持ちが良いですね(・∀・)
「五月晴」という言葉がありますが、「さつきばれ」「ごがつばれ」の読み方で意味が変わるそうです。
「さつきばれ」は旧暦5月(新暦の6月)の梅雨時に見られる晴れ間のことで、「ごがつばれ」と読むと新暦5月の晴れの日を指す、とのこと。
なので今回の場合は「ごがつばれ」が正しいですね。

さて、天気ネタはこの辺りにして、前回に引き続きClojureとArangoDBを少し掘り下げていきます。前回の記事はこちら

ArangoDBの特徴として独自のクエリ言語、AQLがあるという説明を前回書いたと思いますが、こちらの説明を少ししてみたいと思います。

AQLはJavascriptを触ったことがある人なら直感ですぐに使えると思います。
ClojureでAQLを使うサンプルを上げてみます。


(ns arango-test.core
  (:gen-class)
  (:require [travesedo.collection :as col]
            [travesedo.database :as db]
            [travesedo.query :as q]))

;; 作成するデータベース名
(def db-name "clojure_test")
;; ArangoDBのホスト名
(def arango-host "http://127.0.0.1:8529/")
;; DBユーザ名
(def db-user "user")
;; DBパスワード
(def db-password "password")

;; データベースの作成
(defn create-database
  []
  (db/create {:conn {:type :simple
                     :url arango-host}
              :payload {:name db-name
                        :users [{:username db-user
                                 :password db-password}]
                        }}))

;; ArangoDB接続設定)
(def CTX {:conn {:type :simple
                 :url arango-host
                 :uname db-user
                 :password db-password
                 }
          :db db-name})

;; ArangoDB操作時のパラメータを作成
(defn create-context
  "Create Context"
  [ctx]
  (conj ctx CTX))

;; コレクションの作成
(defn create-collection
  []
  (col/create (create-context {:payload {:name "users"}})))

;; 値の追加
(defn add-user
  [name mail age]
  (-> {:payload {:query (str "INSERT { name: '" name "', mail: '" mail "', age: " age " } IN users")}} create-context q/aql-query))

;; 名前から値の取得
(defn get-user-from-name
  [name]
  (-> {:payload {:query (str "FOR u IN users FILTER u.name == '" name "' RETURN u")}} create-context q/aql-query))

;; 名前を更新
(defn update-user-name
  [old-name new-name]
  (-> {:payload {:query (str "FOR u IN users FILTER u.name == '" old-name "' UPDATE u WITH {name: '" new-name "'} IN users")}} create-context q/aql-query))

(defn -main
  "I don't do a whole lot ... yet."
  [& args]
  (create-database)
  (create-collection)
  (add-user "宮川" "miyagawa@attsu.co.jp" 100)
  (add-user "萬屋" "yorozuya@attsu.co.jp" 28)
  (println (get-user-from-name "宮川"))
  (update-user-name "宮川" "ミヤガワ")
  (println (get-user-from-name "宮川"))
  (println (get-user-from-name "ミヤガワ")))

こちらを実行してみます。


$ lein run
# 「name == '宮川'」の結果
{:has-more false, :code 201, :error false, :extra {:stats {:writesExecuted 0, :writesIgnored 0, :scannedFull 2, :scannedIndex 0, :filtered 1}, :warnings []}, :result [{:_id users/138358560469, :_key 138358560469, :_rev 138358560469, :age 100, :name 宮川, :mail miyagawa@attsu.co.jp}]}
# nameを「ミヤガワ」に変更したあとの結果
{:has-more false, :code 201, :error false, :extra {:stats {:writesExecuted 0, :writesIgnored 0, :scannedFull 2, :scannedIndex 0, :filtered 2}, :warnings []}, :result []}
{:has-more false, :code 201, :error false, :extra {:stats {:writesExecuted 0, :writesIgnored 0, :scannedFull 2, :scannedIndex 0, :filtered 1}, :warnings []}, :result [{:_id users/138358560469, :_key 138358560469, :_rev 138359346901, :age 100, :name ミヤガワ, :mail miyagawa@attsu.co.jp}]}

ちゃんとAQLによる作成、取得、更新などができていますね!(・∀・)

AQLを投げるときはtravesedo.queryのaql-query関数を使用します。
パラメータを作成する関数などを作ったりと前回と違うところがいくつかありますが、難しいコードではないので読み解いて下さい^^;

しかしこちらの例だとわざわざAQLを作らずともtravesedo.documentのcreate関数やtravesedo.queryのby-example関数で事が済んでしまいます。
実際AQLより速いです。可能であればAQLを使わずに実装していき、必要であればAQLを使うという手法を取ったほうが良いかもしれません。
この辺りの速度比較は改めて記事にしたいところです。

さて、RDBMSでSQLをバンバン書いていた人は「結合どうすんねん、ゴラァ(#゚Д゚)」ってなりますよね?
ClojureでAQLを使用する方法は上に書いたのでAQLのサンプルだけ上げていきます。

新たにroleコレクション(キーはAutoincrementにします、方法は前回の最後の方に記載しています)を追加してそのキーをusersコレクションのフィールドに持つ状態を考えてみます。


// ユーザ作成
INSERT { name: '宮川', mail: 'miyagawa@attsu.co.jp', age: 100, role_id: 1 } IN users
// 役職追加
INSERT { name: '社長'} IN role
// 取得
FOR u IN users
  RETURN {
    name: u.name, 
    mail: u.mail, 
    age: u.age, 
    role: (
      FOR r IN role
        FILTER TO_NUMBER(r._key) == u.role_id
        RETURN r.name
    )
  }

という感じになります。
TO_NUMBERという関数が登場していますが、これはInt型にキャストする関数です。この他にも文字列にキャストする関数などいろいろ準備されています。
_keyの値が文字列になるのでusersでrole_idをInt型で保存していた場合キャストが必要なのであえてそのように書いてみました。

更に詳しく、ということであればArangoDBのAQL部分のドキュメントを見ることをおすすめします。
英語ですが読みやすくよく出来ていると思います。読んでいるとこんなこともできるんだといろんな感動がありました〜

今回も長くなってしまいました(-_-;)
書いているとあれもこれもってなってしまいますね……きちんと綺麗にまとめて書けるように精進します。

暑くなっているので熱中症などには気を付けてくださいね(;´∀`)


Leave A Comment