AttsuBlog

ATTSU INC. Official Blog
IMGP4236_Fotor
0 comments

ArangoDBとClojure その5

タグ:, , , ,

こんにちは、萬屋です(・∀・)

夏本番になってきましたね!熱中症や脱水症状などに注意してくださいね(*_*;

さて、先日弊社より初のiOSアプリ「my-mo」がリリースされました!
アプリはSwiftで、サーバサイドはClojure、データベースはArangoDBという、まさにこのシリーズ化している技術でガシガシ作りました(^^)

ちなみにアプリに登場しているお化け君のLINEスタンプもありますよ〜デザイナのphmoさんが描きました( ゚∀゚)
かわいいです、しかもこれだけで結構会話が成り立ちますw

チームは3人体制で、自分の他にデザイナ1名、ディレクタ1名という少人数でほぼ二ヶ月での開発となりました。
よくこの期間で、しかも初めてのアプリを完成出来たなぁと……更にはLINEスタンプまで……
phmoさん、ディレクタのKaz君、本当にお疲れ様でした( ;∀;)アプデとか頑張っていきましょう!

今後とも「my-mo」をよろしくお願い致します!

さてはて、久々のClojureとArangoDBですが、今回はグラフについてご紹介したいと思います(^^ゞ

グラフデータベースってご存知でしょうか?あまり耳馴染みのないものかもしれませんが、おそらく有名なのは Neo4j というデータベースです。グラフデータベースをググるとだいたいこれが出てきます。

どういうものか自分なりの解釈で伝えると、データとデータのつながりを持つ事ができるデータベース、という感じですかね(^_^;)

例えばデータベースにユーザテーブルがあったとして、A/B/Cというユーザが登録されています。
AはBをフォローしている、BとCはお互いをフォローしている、という状態をテーブルで持たせる事ができるのです。

graph1

この図にある矢印がデータとしてテーブルに持たせることが出来て、このデータのことをArangoDBではEdgeと呼びます。

ではユーザ情報を持つusers、ユーザ同士のつながりを持つEdgeコレクションのconnection、を作成しこの2つを結びつけるグラフusers_connection_graphを作成し、つながりを作成・AQLで取得までやってみます。


(ns arango-test.core
  (:gen-class)
  (:require [travesedo.collection :as col]
            [travesedo.database :as db]
            [travesedo.document :as doc]
            [travesedo.query :as q]
            [travesedo.graph :as graph])
  (:import (java.util Date)
           (java.text SimpleDateFormat)))

;; 作成するデータベース名
(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
  [name]
  (col/create (create-context {:payload {:name name}})))

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

;; グラフの作成
(defn create-graph
  [name edge from to]
  (graph/create-graph! (create-context {:payload {:name name
                                                  :edge-definitions [{:collection edge
                                                                      :from [from]
                                                                      :to [to]}]}})))

;; ユーザ登録
(defn add-user
  [name]
  (let [params (create-context {:in-collection "users"
                                :payload {:name name}})
        result (doc/create params)]
    (result :_key)))

;; つながり作成
(defn create-connection
  [graph edge from to]
  (graph/create-edge! (create-context {:graph graph
                                       :collection edge
                                       :payload {:from from
                                                 :to to
                                                 :follow true
                                                 :created (.format (doto (SimpleDateFormat. "yyyy-MM-dd HH:mm:ss")) (Date.))}})))

;; つながり取得
(defn get-connection-user
  [user]
  (let [aql (str "FOR c IN GRAPH_EDGES('users_connection_graph', {}, {edgeExamples: [{_to: 'users/" user "'}], includeData: true})
                   RETURN c")
        result (q/aql-query (create-context {:payload {:query aql}}))]
    (println result)))

(defn -main
  [& args]
  ; データベース作成
  (create-database)
  ; コレクションの作成
  (create-collection "users")
  ; エッジコレクションの作成
  (create-edge-collection "connection")
  ; グラフの作成
  (create-graph "users_connection_graph" "connection" "users" "users")
  ; ユーザの作成
  (let [a (add-user "A")
        b (add-user "B")
        c (add-user "C")]
    ; つながりの作成
    (create-connection "users_connection_graph" "connection" (str "users/" a) (str "users/" b))
    (create-connection "users_connection_graph" "connection" (str "users/" b) (str "users/" c))
    (create-connection "users_connection_graph" "connection" (str "users/" c) (str "users/" b))
    ; それぞれのユーザに対してつながっているユーザを取得
    (get-connection-user a)
    (get-connection-user b)
    (get-connection-user c)))

少し長いソースになってしまいましたが(-_-;)
実行結果はこちら。


$ lein run
/_db/clojure_test/_api/gharial
{:has-more false, :code 201, :error false, :extra {:stats {:writesExecuted 0, :writesIgnored 0, :scannedFull 0, :scannedIndex 0, :filtered 0}, :warnings []}, :result []}
{:has-more false, :code 201, :error false, :extra {:stats {:writesExecuted 0, :writesIgnored 0, :scannedFull 0, :scannedIndex 0, :filtered 0}, :warnings []}, :result [{:_id connection/1333405975419, :_key 1333405975419, :_rev 1333405975419, :_from users/1333405123451, :_to users/1333405320059, :follow true, :created 2015-07-22 11:49:35} {:_id connection/1333406499707, :_key 1333406499707, :_rev 1333406499707, :_from users/1333405516667, :_to users/1333405320059, :follow true, :created 2015-07-22 11:49:35}]}
{:has-more false, :code 201, :error false, :extra {:stats {:writesExecuted 0, :writesIgnored 0, :scannedFull 0, :scannedIndex 0, :filtered 0}, :warnings []}, :result [{:_id connection/1333406237563, :_key 1333406237563, :_rev 1333406237563, :_from users/1333405320059, :_to users/1333405516667, :follow true, :created 2015-07-22 11:49:35}]}

:result の中を見るとちゃんと取得できていますね(^o^)
AQLでusersコレクションと結合すればユーザの名前なんかも取得できますね〜AQLを書くとこんな感じです(`・ω・´)


FOR c IN GRAPH_EDGES('users_connection_graph', {}, {edgeExamples: [{_to: 'users/1333405320059'}], includeData: true})
    RETURN {
        _key: c._key, 
        _from: c._from, 
        _to: c._to, 
        follow: c.follow, 
        created: c.created, 
        userName: FIRST(
            FOR u IN users
                FILTER u._id == c._to
                RETURN u.name
        )
    }

ここで注意です!Σ(゚Д゚)
ArangoDB2.6からエッジコレクションからデータを取得する際、_keyや_fromなど全ての値を取得するには includeData: true のオプションをつけないと取得できなくなりました……(´・ω・`)
ArangoDBのバージョン上げてテスト回したら通らなくて焦った……

Edgeも作成したところでArangoDBのWeb画面でグラフの画面をみてみましょう!

graph2

こんな風に出てきます。ヌルヌル動いて面白いですw
これだと視覚的にもわかりやすいですね!

グラフDBいかがでしょうか?なかなか使いどころなどが難しいですが、色んな使い方が出来そうです!
こちらの方の記事(日本語の情報です、レアですねw)でも紹介はされていますのでご参考までにm(_ _)m

ではではこの辺で(^_^)/~


Leave A Comment