Articles

Microsoft SQL Serverのグラフ-短い試み(今のところ)

Posted by admin
トラン-ンゴック-タック
TRAN Ngoc Thach

フォローしている

2020年6月29日•9分読み取り

免責事項:この記事の意見は、SQL Serverのグラフへの私の限られた露出に基づいて、私のものです。 私は決してSQL Serverの専門家ではありません。 私はNeo4Jに偏っているかもしれません。

グラフデータベースの使用が増加し、このニッチ市場でのNeo4Jの優位性、および高度に接続されたデータのクエリにおけるパフォーマンスの大幅な向上に

SQL Server2017以降、SQL Serverはグラフ機能を提供しており、MATCHキーワードが導入されています。 2019年のバージョンでは、エッジ制約とMATCHクエリでの派生テーブルの使用という2つの新しい注目すべき機能が追加されました。 十分な長さのこの技術でダイビング、私は今のように、という印象を持っています:

  • SQL Serverでのグラフサポートは、neo4Jなどの本格的なグラフデータベースからはまだ遠いです。
  • 機能の追加は徐々に増加しています。
  • グラフ機能は、リレーショナルデータベースの考え方に不本意ながら適合しています。

詳細に入りましょう!

長所&短所

MATCHキーワードは、私の意見では、単なる構文糖です。 というよりも、:

SELECT *
FROM NodeTable1 nt1 JOIN EdgeTable et ON nt1.$node_id = et.$from_id JOIN NodeTable2 nt2 ON nt2.$node_id = et.$to_id

… ユーザーは、次のようにクエリを大幅に短縮できます:

SELECT *
FROM NodeTable1 nt1, EdgeTable et, NodeTable2 nt2
WHERE MATCH(nt1-(et)->nt2)

短縮されたクエリは間違いなく目に楽しいです。 ただし、.NETの世界では、Entity Frameworkはデータ指向のソフトウェアアプリケーションに適している可能性があります。 開発者は、高レベルの抽象化に焦点を当てている間に、フレームワークに最適なクエリを生成させるだけです。 この論理によって、MATCHの喜ばしい効果は突然無関係です。 さらに悪いことに、現時点では、Entity Framework(Core)でこれらのグラフ機能をサポートするロードマップはありません。

Neo4Jと比較すると、上記のクエリをもう一度見ると、ユーザーがグラフの考え方を関係データベースの世界に曲げることは避けられません。 一致を実行するには、FROM句でどのテーブルを事前に宣言する必要があります(むしろグラフを「横断可能な全体」とみなし、詳細なデータ編成を気にする必). MATCHの矢印方向を知る必要があるとき、ユーザーはソースノードとターゲットノードを区別しなければならないという意味で、MATCH句と元のJOIN句の間の1-1マッピングを実現するようになります。 対照的に、Neo4JのCypher構文はこの区別を無視することができます。 これらはすべて必ずしもゲームチェンジャーではありませんが、単に利便性と開発の喜びの問題です。 (後に、第1回の研究事例では、このためにUNION ALLを実行する必要があることがわかります。)

接続されたデータをトラバースする際のネイティブグラフデータベースの高性能の鍵の一つは、インデックスフリーの隣接です。 残念ながら、SQL Serverのグラフ機能にはそのようなものはありません:

すべてのノードで隣接リストを維持するのではなく、エッジデータをテーブルに格納しています。 リレーショナルデータベースであるため、データをテーブルの形で保存することは、私たちにとってより自然な選択でした

もう一つの厄介な問題は、スキーマとデータの両方のために、グラフに合わせた可視化ツールがないことです。 回避策として、ユーザーはSSMSでスキーマ図を作成できますが、これらのノードテーブルとエッジテーブルは、エッジ制約がある場合でも、個別の切断されたテーブルと とりわけ、グラフ技術はまた、正しいクエリを構築するために、ユーザーを容易に、視覚的な魅力をもた このようなツールを欠いていると、開発者の生産性にイライラし、有害です。

グラフテーブルの図

では、グラフスキーマを取得するにはどうすればよいですか? 各エッジテーブルを開いて制約を手動で確認し、紙の助けを借りてそれらを推論して、グラフスキーマ全体を把握すると思います。

グラフのエッジ制約

データの可視化に関しては、Microsoft Power BIをForce-Directed Graph addonで試しました。 ただし、このツールは無料ではなく、SQL Serverのグラフ機能をすぐにサポートしていないため、ノードテーブルとエッジテーブルは通常のデータベーステーブルと見なされ 列リストをよく調べると、奇妙に見える列名があります。graph_id_...from_obj_id...。 これらは内部列で、ノード/エッジテーブルの作成時に自動的に生成され、外部からアクセスできません。 これらの列にアクセスすると、Power BIのGet Data関数によって以下のようにエラーが発生します。

Power BI-SQL Serverのグラフテーブルから「データの取得」

この問題を回避するには、関連する/到達可能な列のみを含むデータベースビューを作成する必要があります。 エッジテーブルにはfrom_idto_id、ノードテーブルにはnode_idがあります。 次に、Power BIで、そのビューを使用してデータを抽出します。 うまくいけば、私は間違っていない、Power BIの力有向グラフは、列で構成される1つのテーブルを必要とするようですSource, Target, Weight, Source Type, Target Type, Link Type. サンプルスキーマは単純なので、この単一のテーブルを作成するのは簡単です。 スキーマに+20個のノードテーブルと+10個のエッジテーブルが含まれている場合、Power BIでグラフ全体を視覚化する単一のテーブルになる可能性がありますか?

#更新日04.07.2020: 考え直して、これはまだ面倒であっても確かに可能です。 それぞれの$from_id$to_idは、関連するノードテーブルに対して結合され、すべてのノードの共有プロパティに変換されます。NameまたはId。 次に、power BIで必要とされる最後の単一テーブルに結合するために、すべてのUNION ALLを実行します。

ノードとエッジのクエリは、グラフ技術の可能性の一つです。 グラフデータベースを目立たせることができるのは、PageRankやLouvain Community Detection(別名)などのグラフアルゴリズムの組み込みでありながら拡張可能なサポートです。 ルーヴァン)。 悲しいことに、前述のように、SQL ServerのGraphではそのような分析機能は利用できません:

グラフデータベースの中には、”最短経路”や”ページランク”などの専用のグラフ分析機能を提供するものがあります。「SQL Graphは、このリリースではそのような機能を提供していません。 ここでも、T-SQLループと一時テーブルを使用して、これらのシナリオの回避策を記述することができます。

Neo4Jでは、Graph Data Science Libraryのおかげで、これらのアルゴリズムは生産グレードで容易に利用できます。 さらに、それはオープンソースです。 一般的に、ドキュメントは有用ですが、十分ではない場合があります。 オープンソースを使用すると、開発者は特定のアルゴリズムがどのように実装されているかをダウンロードして調べることができます。 SqlでPageRankを実装することは可能ですが、Louvain modularityのようなより複雑なアルゴリズムは困難な場合があります。 それにもかかわらず、多くのソフトウェアエンジニアは、低レベルの技術的な詳細に行き詰まっているのではなく、ビジネスロジックに最後に、私の見解では、共通テーブル式は派生テーブルの一種です。 SQL Server2019以降、この手法は正式にGraphで実行可能であると想定されています:

グラフテーブルとMATCH句を持つ共通テーブル式(CTE)

しかし、ビューの作成後に実行できる場合は、次のようになります:

グラフテーブルとMATCH句を使用したビューの作成

これは矛盾の兆候だと思います。 2番目のアプローチでは、SQL Serverで一時ビューを作成することはできないため、永続的に作成されたビューが必要です。 通常、ユーザーはCTEでこれを克服しますが、上記のように、CTEはGraphでは機能しません。

研究事例

サンプルシナリオ:学生と教師。

Neo4J’S Cypher:

CREATE (S1:NStudents {name: "S1"}), (S2:NStudents {name: "S2"}), (T1:NTeachers {name: "T1"}), (S3:NStudents {name: "S3"}), (T2:NTeachers {name: "T2"}), (S4:NStudents {name: "S4"}), (S1)-->(S2), (S2)-->(T1), (T1)-->(T2), (T2)-->(S4), (S3)-->(T1)

SQL Server2019のグラフ:

CREATE TABLE NStudents ( NVARCHAR(MAX) NOT NULL, INT NOT NULL) AS NODE;CREATE TABLE NTeachers ( NVARCHAR(MAX) NOT NULL, FLOAT NOT NULL) AS NODE;CREATE TABLE Talks (CONSTRAINT EC_Talk CONNECTION (NStudents TO NStudents, NStudents TO NTeachers, NTeachers TO NStudents, NTeachers TO NTeachers) ON DELETE CASCADE) AS EDGE;INSERT INTO NStudents VALUES ('S1',1),('S2',2),('S3',3),('S4',4);
INSERT INTO NTeachers VALUES ('T1',123), ('T2',456);
INSERT INTO Talks VALUES (
(SELECT $node_id FROM NStudents WHERE = 'S1'),
(SELECT $node_id FROM NStudents WHERE = 'S2'));
INSERT INTO Talks VALUES (
(SELECT $node_id FROM NStudents WHERE = 'S2'),
(SELECT $node_id FROM NTeachers WHERE = 'T1'));
INSERT INTO Talks VALUES (
(SELECT $node_id FROM NTeachers WHERE = 'T1'),
(SELECT $node_id FROM NTeachers WHERE = 'T2'));
INSERT INTO Talks VALUES (
(SELECT $node_id FROM NTeachers WHERE = 'T2'),
(SELECT $node_id FROM NStudents WHERE = 'S4'));
INSERT INTO Talks VALUES (
(SELECT $node_id FROM NStudents WHERE = 'S3'),
(SELECT $node_id FROM NTeachers WHERE = 'T1'));

ケース1:ノードのすべての着信接続と発信接続

動機:各ノードのこれらの接続を数えることは、最も重要なものを見つけるための一つの方法です。

Neo4J’scypher:

MATCH (n)--()
RETURN n.name, COUNT(r) AS allCons
ORDER BY allCons DESC

SQL Server2019のグラフ:

--Create a View first, for convenience purpose.
CREATE VIEW view_AllPeople
AS
SELECT $node_id AS ,
FROM NStudents
UNION ALL
SELECT $node_id AS ,
FROM NTeachers;--Query using the View.
WITH CTE()
AS
(
SELECT ap1.
FROM view_AllPeople ap1, Talks t, view_AllPeople ap2
WHERE MATCH(ap1-(t)->ap2)
UNION ALL
SELECT ap1.
FROM view_AllPeople ap1, Talks t, view_AllPeople ap2
WHERE MATCH(ap1<-(t)-ap2)
)
SELECT , COUNT(*) AS allConns
FROM CTE
GROUP BY
ORDER BY allConns DESC

備考: SQLのバージョンは長くなるだけでなく、MATCHの矢印の方向を常に考慮する必要があるため、より不便です。

ケース2:トップ最長パス

動機:長い依存関係チェーンは壊れやすい傾向があります。 たとえば、ライブラリの依存関係。

Neo4J’scypher:

// The WHERE is to filter out duplicate paths, e.g. A->B = B->A.
MATCH p=(n)--(m)
WHERE ID(n) < ID(m)
RETURN n.name, m.name, length(p) AS len, AS node_list
ORDER BY len DESC

SQL Server2019のグラフ:

WITH CTE(from_id, to_id, , )
AS
(
SELECT $from_id, $to_id, 1 AS , CONVERT(NVARCHAR(MAX), $to_id) AS
FROM Talks
UNION ALL
SELECT t.$from_id, t.$to_id, +1, CONVERT(NVARCHAR(MAX), CTE. + ',' + CONVERT(NVARCHAR(MAX), $to_id))
FROM Talks t JOIN CTE ON t.$to_id = CTE.
)
SELECT vap., ,
FROM CTE JOIN (SELECT MAX(c.) AS maxLevel FROM CTE c GROUP BY c.) myMax ON CTE. = myMax.maxLevel JOIN
view_AllPeople vap ON CTE. = vap.
ORDER BY DESC

備考: SQL Serverバージョンでは、再帰的な共通テーブル式技術に頼る必要があります。 それはかなりグラフの問題を解決するために、リレーショナルデータベースの考え方を包含しています。

結論

グラフドメインでは、グラフの問題に取り組むために使用されるグラフ機能を使用するかどうかにかかわらず、SQL ServerのSQLコマンドは、Neo4JのCypherと比較して、一般的にははるかに長く、より複雑です。 これは、コードの開発に時間がかかり、後で維持したり拡張したりすることが困難になるという意味につながります。 別のエンジニアや元のエンジニアでさえ、一ヶ月後に同じコードスニペットを見て、そのすべての側面を把握することはイライラするでしょう。 この状況を説明するためのよく知られた用語は、技術的負債です。

コード面から機能サポート、ツール/ライブラリのエコシステムまで、前述のすべての点を組み合わせると、現在のSQL Serverのグラフ機能は、奨励されていますが、期待には満たないものとなっています。

SQL Serverはリレーショナルデータベースに関して非常に成熟していますが、明らかにグラフデータベースの初心者です。 このグラフのサポートは、おそらくリレーショナルデータベースの考え方に含まれていると考えられています。

Related Post