本記事では、家庭でデバイス管理を行うグラフネットワークを、実際にデータモデリングしていきましょう。Neo4j Aura 及び Cypher を利用します。
デジタル化の推進により、家庭でも一人複数台のデバイスを持つことが当たり前になってきました。
一人一台以上のスマホを持ち、作業用のパソコンと自宅用には携帯タブレット。右手にはウェアラブルデバイスを装着し、居間にはテレビ用にパソコンも備え、他にもホームデバイスやゲーム機など、家庭に置かれるデバイス機器は増えていく一方でしょう。
一家庭が所有する個人デバイスを管理できるアプリケーションを作成し、OS の更新作業やメンテナンス、アカウントの利用状況などを可視化したいというニーズが出てきたと仮定します。
そこで、解決策として、簡単なモバイルデバイス管理システム (Mobile Device Managemnt System, MDM) を表現するグラフネットワークを作成してみましょう。
Alice は、iPhone 13 と Macbook Pro 16 inch を所有しているとします。まずはユーザーを表す User
ノードと、デバイスを表す Device
ノードを、所有するという意味での [:OWNS]
リレーションを用いて作成してみましょう。
CREATE (u:User {name: 'alice'}),
(u)-[:OWNS]->(d1:Device:Asset:Mobile {id: 1, name: 'iPhone 13'}),
(u)-[:OWNS]->(d2:Device:Asset:Computer {id: 2, name: 'Macbook Pro 16 inch'});
この時、デバイスのモデリングについて一つポイントが有ります。Device
という汎用的なラベルだけを持つ形にして、プロパティで Device {type: 'iPhone'}
のようにデバイスの種類を表現することも可能です。
しかし、ユースケースの一つとして、「家庭で所有する全ての iPhone をリストしたい」といったクエリを発行したいことは容易に想像できます。その場合、プロパティでデバイスの種類を表現するより、複数のラベルでデバイスの種類を表現しておくほうが、効率的なクエリを実行できます。
また、全てのデバイスに Device
というラベルをもれなく付与しておくことで、「家庭で所有する全てのデバイスをリストしたい」という要求にも答えることができます。
Bob も同様に以下のデバイスを所有しているようです。すでに作成したグラフネットワークにデータセットを追加してみましょう。
CREATE (u:User {name: 'bob'}),
(u)-[:OWNS]->(d1:Device:Asset:Mobile {id: 3, name: 'iPhone 10'}),
(u)-[:OWNS]->(d2:Device:Asset:Computer {id: 4, name: 'Macbook Air 13 inch'}),
(u)-[:OWNS]->(d3:Device:Asset:Computer {id: 5, name: 'Macbook Pro 16 inch'}),
(u)-[:OWNS]->(d4:Device:Asset:Smartwatch {id: 6, name: 'Apple Watch Series 7'});
ところで、Alice と Bob の関係性についても定義してみましょう。二人は親子のようです。ユーザー間のリレーションも以下のように定義しておきましょう。
MATCH (a:User), (b:User)
WHERE a.name = 'alice' AND b.name = 'bob'
CREATE (a)-[PARENTS_OF]->(b), (b)-[:CHILD_OF]->(a)
この段階で、グラフネットワークは以下の様になっているはずです。
例えば、家庭で所有する全ての Mobile を取得したい場合、以下の Cypher クエリを実行します。
MATCH (m:Mobile) RETURN m.id, m.name
また、例えば Bob が所有する全ての Computer を取得したい場合、以下の Cypher クエリを実行します。
MATCH (u:User)-[:OWNS]->(c:Computer)
WHERE u.name = 'bob'
RETURN u.name, c.id, c.name
ここで、製品ごとにデバイスを管理したい要件が出てきました。例えば、iPhone であれば現在どのモデルを誰が持っているのか、を知りたいケースです。
今回は、後から Product
ノードを製品ごとに作成し、既存の Device
ノードと紐づけてみましょう。
CREATE (p:Product {name: 'Macbook'});
MATCH (p:Product), (d:Device)
WHERE p.name = 'Macbook' AND d.name IN ['Macbook Air 13 inch', 'Macbook Pro 16 inch']
CREATE (d)-[:PRODUCTS_OF]->(p);
CREATE (p:Product {name: 'iPhone'});
MATCH (p:Product), (d:Device)
WHERE p.name = 'iPhone' AND d.name IN ['iPhone 13', 'iPhone 10']
CREATE (d)-[:PRODUCTS_OF]->(p);
CREATE (p:Product {name: 'Apple Watch'});
MATCH (p:Product), (d:Device)
WHERE p.name = 'Apple Watch' AND d.name IN ['Apple Watch Series 7']
CREATE (d)-[:PRODUCTS_OF]->(p);
この時点で、グラフネットワークは以下の様になっているはずです。
例えば、「Alice が持っている iPhone 製品全て」をグラフで知りたい場合、以下の Cypher クエリが利用できます。
MATCH (u:User)-[:OWNS]->(d:Device)-[:PRODUCTS_OF]->(p:Product)
WHERE p.name = 'iPhone' AND u.name = 'alice'
RETURN d, p, u
ここで、Apple という会社が出しているデバイス一覧についてデータをクエリしたいケースが出てきたと考えてみましょう。
その場合、新しく Company
ノードを作成し、Product
ノードに :PRODUCES
リレーションを追加することで表現できます。
CREATE (c:Company {name: 'Apple Inc.'});
MATCH (p:Product), (c:Company)
WHERE c.name = 'Apple Inc.' AND p.name in ['Macbook', 'iPhone', 'Apple Watch']
CREATE (c)-[:PRODUCES]->(p);
例えば、「Apple Inc. が生産している全てのデバイス一覧をユーザー名と共に表示させる」クエリは、以下のように表現できます。
MATCH (u:User)-[:OWNS]->(d:Device)-[:PRODUCTS_OF]->(p:Product)<-[:PRODUCES]-(c:Company)
WHERE c.name = 'Apple Inc.'
RETURN u.name, d.name, p.name
最終的に、グラフネットワークは以下の様になっていることでしょう。
以上、家庭でデバイス管理を行う MDM を具体例に、データモデリングの手法と Cypher について簡単に紹介しました。
色々なパターンのデータモデリングを経験することは、グラフデータベースならではのモデリング手法を学んでいく優れた手法の一つでしょう。
Neo4j グラフデータベースはスキーマレスであり、後から要件を追加していく場合でも、既存の関連に破壊的変更を加えることなくデータセットを容易に追加していけます。
今回紹介したグラフネットワークに、自分なりの要件を追加してデータモデリングの試行錯誤をしてみてはいかがでしょうか。