a2 Tech blog

試したこと・調べたこと・感じたことを発信するITエンジニアの日記です。仕事とは直接関係ないけど興味あることを模索していきます。

Graph DatabaseをSQL Server on Linuxで試してみる

SQL Server 2017では、Graphオブジェクトを扱えるようになりました。SQL Server on LinuxをAzure Virtual Machine上に構築したので、Graphオブジェクトで遊んでみたいと思います。ちなみに、私は「ぐらふおぶじぇくと、なにそれ、おいしいの?」状態の初心者です。業務ではRDBMSを扱ってますが、Graph Databaseについては、Data Ampで初めて知り、今回、初めて触ります。

参考にしたサイトは、下記です。

SQL Graph overview | Microsoft Docs

書かれている通りになぞりながら感覚をつかんでいきたいと思います。習うより慣れろの精神でとりあえず触ってみることをモットーにやっていますので、理論的な話はあまり触れません。あしからず。

余談…VSCode Extensions “mssql” が正式版に!!

Visual Studio Code(VSCode)のExtensionsでSQL Serverに接続できるmssqlですが、2017-5-2にver1.0になっていました。

まず、GA(General Availability)版になってます。0.3まではPreviewだったのですが、正式版になったようですね。localizedされたようで言語の選択ができるようになったようです。実行時のメッセージが確かに日本語になっていました。全部ではないので、何となく中途半端な感じです。機能追加としてはSELECTの結果をEXCELに保存することができるようになりました。0.3ではCSVJSON形式で保存できましたが、それにEXCEL形式が追加されたようです。あとは、バグフィックスですね。

f:id:ninna2:20170504193619j:plain

より使いやすくなってます。0.3のプレビュー版の時ですが使い方簡単に書いてますので、参考にしてみてください。

ninna2.hatenablog.com

余談でした。

Graph Databaseって…

本題です。

Graphと聞くと、円グラフみたいな算数や数学で用いるような表示形式のものを思い浮かべてしまいますが、ここで言っているGraph Databaseとは、関係性を表現するデータモデルを扱えるデータベースらしいです。分類はNoSQLになるそうですが、NoSQLといっても、Key-Value-Store(KVS)などとは少しジャンルが違うのでひとくくりにはしない方が良い感じですかね。分類するならってことです。

関係性を表すために、"Node"という概念と、"Edge"という概念が出てきます。ちゃんと私も理解しきれていないのですが、Nodeが点でEdgeが線のようなイメージなんですかね。Nodeを繋いで関係性を表現するモデルと理解しました。

Graph Databaseについてやってみようと思ってから読んだ記事を紹介しておきます。

qiita.com

www.atmarkit.co.jp

www.slideshare.net

SQL ServerにGraphオブジェクトを作る

前置き長くなりましたが、始めていきたいと思います。まず、SQL Server 2017を手元に用意していることが前提です。SQL Server 2017の構築がまだって方は、下記参考に構築してみてください。SQL Server on LinuxをAzure VM上に構築した記事になります。

ninna2.hatenablog.com

SQL実行を行っていくためにSQL Clientを用意してください。SQL Server Management Studio(SSMS)でもいいですし、ほかの気に入っているもので構いません。最新のSSMSだとGraphオブジェクトが表示されるようです。私は、先にも紹介しましたがVisual Studio Code + mssql Extensionを使っているので本記事では、VSCodeで実行した内容になります。

さっそくやっていきましょう。

まずデータベースを作成します。データベースが作成できたら、NodeEdgeをそれぞれ作成していきます。Microsoftのサンプルでは、Person(人)の関係性を題材にしているので、PersonがNodeで、friendsがEdgeとなっています。どの人とどの人が友達かっていう関係性を表すモデルですね。

Graphオブジェクトの作成は、通常のCREATE構文に、AS NODEもしくはAS EDGEを付けてあげるだけです。

USE master
GO

CREATE DATABASE GraphSample
GO

USE GraphSample
GO

CREATE TABLE Person (
    ID INTEGER PRIMARY KEY,
    name VARCHAR(100),
    Age INTEGER
    ) AS NODE;
GO

CREATE TABLE friends (
    ID INTEGER PRIMARY KEY,
    StartDate date
    ) AS EDGE;
GO

SELECt
    name,is_node,is_edge
FROM
    SYS.TABLES
WHERE
    name = N'Person' or name = N'friends';
GO

Person(Node)とfriends(Edge)ができました。SYS.TABLESにis_nodeとかis_edgeが追加されています。テーブルがNodeなのかEdgeなのか確認するために使えますね。

f:id:ninna2:20170504222456j:plain

データを入れる

テーブルができたので、データを格納していきます。NodeへのINSERTは通常のINSERTと何ら変わりません。

--Insert Person Data
USE graphSample
GO

INSERT INTO Person VALUES 
(1,'John',30),
(2,'Mary',28),
(3,'Alice',25);
GO

SELECT * FROM Person;
GO

f:id:ninna2:20170504224459j:plain

$node_id_xxxというCloumnが追加されています。これがNodeオブジェクトには自動的に付与されます。

Edgeへのデータの格納は、Nodeほど単純にはいかないようです。関係性を表現しないといけないので、どのNodeとどのNodeを繋げるのかをデータで定義していくことになります。今回のモデルの場合、友達関係は下記を定義していきます。

  • ID1(John) は ID2(Mary)を友達と思っている
  • ID2(Mary) は ID2(Alice)を友達と思っている
  • ID3(Alice) は ID1(Mary)を友達と思っている

すごい三角関係ですねw。これをデータとして入れていきます。

--Insert friends Data
INSERT INTO friends VALUES(
    (SELECT $node_id FROM Person WHERE ID=1),
    (SELECT $node_id FROM Person WHERE ID=2),
    1,
    '2013/01/31');
INSERT INTO friends VALUES(
    (SELECT $node_id FROM Person WHERE ID=2),
    (SELECT $node_id FROM Person WHERE ID=3),
    2,
    '2010/05/05');
INSERT INTO friends VALUES(
    (SELECT $node_id FROM Person WHERE ID=3),
    (SELECT $node_id FROM Person WHERE ID=1),
    3,
    '2016/09/09');
GO

f:id:ninna2:20170504225902j:plain

データは準備できました。思っていたよりも簡単にここまでやって来れましたね。

検索してみる

データが登録できたので、Graphオブジェクトを検索してみましょう。検索を行うのもやはりSELECT文を使います。通常とSELECT文にMATCH構文を使います。Johnの友達(友達だと思っている)は誰かを問い合わせるSQLです。すごく直感的に書けるので、少し好きになりました。

SELECT
    Person2.Name
FROM 
    Person Person1,
    Friends, 
    Person Person2
WHERE 
    MATCH(Person1 - (Friends) -> Person2)
AND Person1.Name = 'John'

f:id:ninna2:20170504230605j:plain

もう少し複雑なサンプル

先ほどのサンプルだとあまり面白くないので、もう1つのモデルを試してみたいと思います。これもMicrosoftでサンプル提供されているものです。

docs.microsoft.com

“Sample schema with restaurant, city, person nodes and LivesIn, LocatedIn, Likes edges."です。人と町とレストランの関係性を表すモデルですね。誰がどこに住んでいるのか、どのレストランが好きなのかを表しています。サンプルスクリプトは提供されているので、データ投入までやってみてください。1点注意点。Microsoftの記載のスクリプトだとデータが足りません。friendsOfのEdgeのデータが足りないので追加しないといけません。

INSERT INTO friendOf VALUES ((SELECT $node_id FROM Person WHERE id =1),(SELECT $node_id FROM Person WHERE id = 2));
INSERT INTO friendOf VALUES ((SELECT $node_id FROM Person WHERE id =2),(SELECT $node_id FROM Person WHERE id = 3));
INSERT INTO friendOf VALUES ((SELECT $node_id FROM Person WHERE id =3),(SELECT $node_id FROM Person WHERE id = 1));

サンプルでは、"Joneの友達(friendof)が好きな(likes)、レストランの名前"を検索してます。MATCH構文がわかりやすいですね。

SELECT
      Restaurant.name
FROM 
      Person person1,
      Person person2,
      likes,
      friendOf,
      Restaurant
WHERE 
      MATCH(person1 - (friendOf) -> person2 - (likes) -> Restaurant)
      AND person1.name='John';

f:id:ninna2:20170504235728j:plain

感想…

SQL Server 2017で扱えるようになったGraphオブジェクトを簡単に触ってみました。これをどのような場面で使えばよいのか、普通のリレーショナルモデルではだめなのか、まだまだ勉強すべきことは多いですが、導入として感触はつかめたような気がします。MATCH構文が直感的で素敵です。NoSQLにしろ今回のGraph Databaseにしろ、RDBMS一辺倒でデータベースを理解してきたものとして、少し視野を広げて色々なモデルのデータベースに触れる必要があるのではないかと思います。

最後に…このSQL ServerLinuxで動いているんだよね…まだ信じられない。