do postgres-dream-of-graph-database

Post on 15-Jan-2017

832 Views

Category:

Technology

4 Downloads

Preview:

Click to see full reader

TRANSCRIPT

Do Postgres dream of Graph-Database?

ぬこ@横浜 (@nuko_yokohama)

2

自己紹介「 PostgreSQL ラーメン」

でググってください。

3

日本 PostgreSQL ユーザ会のゆる枠担当 ( 自称 ) やってるPostgreSQL おじさんです。

4

今日話すこと

5

今日はこの本に書いてあるような話はしません。

この本

6

PostgreSQL からグラフデータを扱ってみよう

7

グラフデータベース?

8

グラフデータベース

データを「ノード」と「関連」で管理するの NoSQL の一種。

ノード間を関連で接続することでノード間の関係性を表現する。

ノードのトラバースが容易に可能。

9

例えば Neo4j

ノード

関連

https://neo4j.com/Community Edition と Enterprise Edition があります。

例えば Neo4j

10

PostgreSQL の更新を

Neo4j へ反映

11

Neo4j Server

Logideco4neo4j

PostgreSQL

Relational Model

Cypher Query

WAL(wal_level=logical) Logical

Replication Slot

Execute Cypher Query on REST

Convert Cypher Query

PostgreSQL WAL to Neo4j

Graph Model

olumn1 column2 column3

・・・ ・・・ ・・・

・・・・ ・・・・ ・・・

Get Replication Slot Data

Decoding FunctionConvert JSON

スロット定義

12

Neo4j Server

Logideco4neo4j

PostgreSQL

Relational Model

Cypher Query

WAL(wal_level=logical) Logical

Replication Slot

Execute Cypher Query on REST

Convert Cypher Query

PostgreSQL WAL to Neo4j

Graph Model

olumn1 column2 column3

・・・ ・・・ ・・・

・・・・ ・・・・ ・・・

Get Replication Slot Data

Decoding FunctionConvert JSON

スロット定義

13

Data Model

Neo4j にマッピングするためのPostgreSQL 上のデータモデル

非常にざっくり言うと、ノードテーブルと関連テーブルの

2 種のテーブルで構成する。

14

Data Modelノードテーブル

ノード ID(pk)ノードプロパティ ( 任意 )

関連テーブル関連 ID(pk)

起点ノードラベル(種類)起点ノード ID

関連タイプ (text)終点ノードラベル(種類)

終点ノード ID

ノード種類をテーブル名に

マッピングするのが良さげ

今回は全ての関連タイプを

1 テーブルで管理

15

Neo4j Server

Logideco4neo4j

PostgreSQL

Relational Model

Cypher Query

WAL(wal_level=logical) Logical

Replication Slot

Execute Cypher Query on REST

Convert Cypher Query

PostgreSQL WAL to Neo4j

Graph Model

olumn1 column2 column3

・・・ ・・・ ・・・

・・・・ ・・・・ ・・・

Get Replication Slot Data

Decoding FunctionConvert JSON

スロット定義

16

ロジカルデコーディング

17

ロジカルデコーディングPostgreSQL 9.4 から導入された基盤

WAL を任意形式にデコーディングする基盤デコーディング方法や、

デコードされた更新情報の反映は利用者が好きに開発できる。

夢が広がりんぐ機能

18

Decoding Function

ざっくり言うと PostgreSQL の更新ログ (WAL) を

任意の形式の論理ログに変換する関数。

どういった形式に変換するのかは、Decoding Function 実装者まかせ。

19

Decoding Function

幸い PostgreSQL のソース内にはLogical Decoding の

サンプルが入っている。

contrib/test_decoding

20

Decoding Function

実際に動作させてみる。デコードされた更新ログが、

pg_logical_replication_slot に格納されている。

SQL 関数を使って、このスロット内のデコードされた内容を読み取る。

21

Decoding Function例えば以下のような DML を発行するBEGIN;DROP TABLE IF EXISTS node;CREATE TABLE node(id int primary key, name text, age int, gender text, location text);COMMIT;

INSERT INTO node VALUES(1, 'Akagi',17,'Famale','Tokyo'),(2, 'Yamato',28,'Male','Tokyo'),(3, 'Musashi',27,'Male','Yokohama'),(4, 'Nagato',22,'Male','Kawasaki');

BEGIN;UPDATE node SET age = age + 1 WHERE id IN (1,2);DELETE FROM node WHERE id IN (3,4);SELECT * FROM node;COMMIT;

22

Decoding Function以下のような更新ログが出力される

logideco=# SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL); BEGIN 1959 COMMIT 1959 BEGIN 1960 table public.node: INSERT: id[integer]:1 name[text]:'Akagi' age[integer]:17 gender[text]:'Famale' location[text]:'Tokyo' table public.node: INSERT: id[integer]:2 name[text]:'Yamato' age[integer]:28 gender[text]:'Male' location[text]:'Tokyo' table public.node: INSERT: id[integer]:3 name[text]:'Musashi' age[integer]:27 gender[text]:'Male' location[text]:'Yokohama' table public.node: INSERT: id[integer]:4 name[text]:'Nagato' age[integer]:22 gender[text]:'Male' location[text]:'Kawasaki' COMMIT 1960 BEGIN 1961 table public.node: UPDATE: id[integer]:1 name[text]:'Akagi' age[integer]:18 gender[text]:'Famale' location[text]:'Tokyo' table public.node: UPDATE: id[integer]:2 name[text]:'Yamato' age[integer]:29 gender[text]:'Male' location[text]:'Tokyo' table public.node: DELETE: id[integer]:3 table public.node: DELETE: id[integer]:4 COMMIT 1961

test_decoding はDDL は未対応です。

23

Decoding Function

contrib/test_decoding は、見やすさを重視した形式で出力。

(サンプルだし)

でも、更新ログを他の DBMS に反映するには、不向きかも・・・?

24

Decoding Function

JSON のような汎用形式にしておけば、デコード結果を処理するのも楽になる。

↓表現能力は十分

可読性もある程度はある既存の JSON パーサが使える

既存のパーサが使えるのは仕様検討も実装も楽!

25

Decoding Function以下のような情報を含む

JSON データを生成すれば良さげ。コマンド タグ 更新対象の

スキーマと表挿入列と値 更新列と

更新後の値検索キー列とキー値

INSERT ○ ○ ○ - -

UPDATE ○ ○ - ○ ○

DELETE ○ ○ - - ○

トランザクションを意識するなら、BEGIN や COMMIT も考慮する必要がある。

もう作っている人はいそうだが・・・

26

Decoding Function探したら、やっぱりありましたw

「 PostgreSQL の Logical Decoding 機能についての紹介」http://qiita.com/bwtakacy/items/d8461518a1770524e0d6

まとめを書いたのは@bwtakacy さん

pg_rman や pg_bulkload のメンテナやってる人です。

Deconding Function Plug-in wal2jsonhttps://github.com/eulerto/wal2json

名前のとおり WAL を JSON 形式にデコードしてくれる。せっかくなので、今回はこれを使ってみる。

27

Decoding Functionjson2wal の使用例

例えば以下のような DML を発行するneo4j=# BEGIN;BEGINneo4j=# INSERT INTO node_person VALUES ('2005','Shinano','Famale','Kawasaki','22');INSERT 0 1neo4j=# INSERT INTO rel_person_person VALUES ('10028','2005','love','1001');INSERT 0 1neo4j=# UPDATE node_person SET location = 'Yokohama' WHERE uid = '2005';UPDATE 1neo4j=# DELETE FROM rel_person_person WHERE rid = '10028';DELETE 1neo4j=# DELETE FROM node_person WHERE uid = '2005';DELETE 1neo4j=# COMMIT;COMMIT

28

Decoding Functionjson2wal の使用例

レプリケーションスロットから、取得したデコード結果トランザクション全体で 1 つの JSON 文書になっている

neo4j=# SELECT data FROM pg_logical_slot_get_changes('neo4j', NULL, NULL); {"xid":1976,"change":[ {"kind":"insert","schema":"public","table":"node_person","columnnames":["uid","name","gender","location","age"],"columntypes":["text","text","text","text","text"],"columnvalues":["2005","Shinano","Famale","Kawasaki","22"]} ,{"kind":"insert","schema":"public","table":"rel_person_person","columnnames":["rid","f_uid","type","t_uid"],"columntypes":["text","text","text","text"],"columnvalues":["10028","2005","love","1001"]} ,{"kind":"update","schema":"public","table":"node_person","columnnames":["uid","name","gender","location","age"],"columntypes":["text","text","text","text","text"],"columnvalues":["2005","Shinano","Famale","Yokohama","22"],"oldkeys":{"keynames":["uid"],"keytypes":["text"],"keyvalues":["2005"]}} ,{"kind":"delete","schema":"public","table":"rel_person_person","oldkeys":{"keynames":["rid"],"keytypes":["text"],"keyvalues":["10028"]}} ,{"kind":"delete","schema":"public","table":"node_person","oldkeys":{"keynames":["uid"],"keytypes":["text"],"keyvalues":["2005"]}} ]}

赤字が 1 つの DML によるログ情報

29

Neo4j Server

Logideco4neo4j

PostgreSQL

Relational Model

Cypher Query

WAL(wal_level=logical) Logical

Replication Slot

Execute Cypher Query on REST

Convert Cypher Query

PostgreSQL WAL to Neo4j

Graph Model

olumn1 column2 column3

・・・ ・・・ ・・・

・・・・ ・・・・ ・・・

Get Replication Slot Data

Decoding FunctionConvert JSON

スロット定義

30

Logideco4neo4j必要なパーツ

PostgreSQL クライアントライブラリJSON パーサ

http クライアントライブラリ

これが揃えば、どんな言語で組んでも OK今回は C 言語で組んでみたよ!

31

Logideco4neo4j

Logical Decoding 内容からNeo4j への反映に必要な処理

レプリケーションスロットへの検索検索結果から Cypher Query を生成

Cypher Query を REST API で Neo4j へこれを繰り返す

32

Logideco4neo4j

レプリケーションスロットからデコードされた WAL を

読み込む SQL 関数を発行する

http://www.postgresql.jp/document/9.5/html/functions-admin.html#functions-replication

関数名 説明

pg_create_logical_replication_slot(slot_name name, plugin name)

論理レプリケーションスロットを生成

pg_logical_slot_get_changes(slot_name name, upto_lsn pg_lsn, upto_nchanges int, VARIADIC options text[])

論理レプリケーションスロットから変更内容を読み取る。

33

Logideco4neo4j

デコード結果( JSON )を json-c 等のJSON パーサで解析して挿入・更新・削除用の

Neo4j Cypher クエリを生成する

34

Logideco4neo4jノード挿入の Cypher Query への変換例

INSERT INTO public.person (nid, name, gender, location, age) VALUES ('10001','ぬこ','Male','Yokohama','48')

{"kind":"insert","schema":"public","table":"person","columnnames":["nid","name","gender","location","age"],"columntypes":["text","text","text","text","text"],"columnvalues":["10001","ぬこ","Male","Yokohama","48"]}

CREATE (n:person { nid:"10001",name:"ぬこ",gender:"Male",location:"Yokohama",age:"48" })

{"query":"CREATE (n:person { nid:\"10001\",name:\"ぬこ\",gender:\"Male\",location:\"Yokohama\",age:\"48\" }) "}

SQL

論理ログ

Cypher

REST API

更新も削除も同様に REST API に変換

35

Logideco4neo4j関連挿入の Cypher Query への変換例

INSERT INTO relationship VALUES ('100001', 'employ', 'company', '1001', 'person', '10001');

{"kind":"insert","schema":"public","table":"relationship","columnnames":["rid","type","f_label","f_uid","t_label","t_uid"],"columntypes":["text","text","text","text","text","text"],"columnvalues":["100001","employ","company","1001","person","10001"]}

MATCH (f:company {nid:"1001"}),(t:person {nid:"10001"}) MERGE (f)-[e:employ {rid:"100001"}]->(t)

query={"query":"MATCH (f:company {nid:\"1001\"}),(t:person {nid:\"10001\"}) MERGE (f)-[e:employ {rid:\"100001\"}]->(t)"}

SQL

論理ログ

Cypher

REST API

更新も削除も同様に REST API に変換

36

Logideco4neo4j

Neo4j Cypher クエリを含むREST API パラメータを

libcurl などの HTTP ライブラリ経由で発行すると、後は Neo4j サーバが

よしなにやってくれる。

37

デモ

38

PostgreSQL の更新ログをNeo4j に適用できた。

やったね♪

39

PostgreSQL からSQL で

Neo4j を検索

40

ForeignData Wrapper

41

PostgreSQL の外部にあるデータに対して

標準的な SQL クエリでアクセスするための夢が広がりんぐ基盤

42

Neo4j のデータをSQL で検索するための

Foreign Data Wrapper を開発する。

43

Neo4j Server

Logideco4neo4j

PostgreSQL

Cypher Query

WAL(wal_level=logical) Logical

Replication Slot

Execute Cypher Query on REST

Convert Cypher Query

olumn1 column2 column3

・・・ ・・・ ・・・

・・・・ ・・・・ ・・・

Get Replication Slot Data

Decoding FunctionConvert JSON

Neo4j Foriegn Data Wrapper

Defined Cypher Query

Execute Cypher Query on REST

Generate PostgreSQL Record

PostgreSQLRecord

JSONResult

Provide Cypher Result View

SQL

CypherQuery

スロット定義

44

というか、以前 Neo4j に

接続する FDW を作っていた

https://github.com/nuko-yokohama/neo4j_fdw

45

何故か PostgreSQL Wiki に載ってる・・・

メンテナンスをサボっているので、 PostgreSQL 9.5 以降に対応してません・・・

46

neo4j_fdw外部データラッパを登録

外部サーバと外部テーブルを定義CREATE EXTENSION neo4j_fdw;

CREATE SERVER foo FOREIGN DATA WRAPPER neo4j_fdw OPTIONS (url 'http://localhost:7474/db/data/cypher');

CREATE FOREIGN TABLE persons ( uid text, name text, gender text, age text, company text ) SERVER foo OPTIONS (query '{"query":"MATCH (c:company)-[e:employ]->(p:person) RETURN p.nid, p.name, p.gender, p.age, c.name"}');

あとは persons テーブルに SELECT 文を発行すれば OK!

47

デモ

48

PostgreSQL からSQL を使って

Neo4j の検索ができた。

やったね♪

49

と、いうことで

50

ロジカルデコーディングとneo4j_fdw を組み合わせて

PostgreSQL からグラフデータベースNeo4j を扱えた!

それに意味があるのかどうかは

わりとどうでもいい

51

おしまい

52

補足(というか蛇足)

53

FDW を良く知っている人

からのツッコミ

54

あれ? FDW にも更新 I/F あるじゃん

(PostgreSQL 9.3 以降 )

55

汎用的に SQL DML からNeo4j の Cypher Query へ変換する仕組みを考えないと

いけないのが面倒…

面倒なので放置中…(だからロジデコ使った)

top related