do postgres-dream-of-graph-database

55
Do Postgres dream of Graph-Database? ぬこ@横浜 (@nuko_yokohama)

Upload: toshi-harada

Post on 15-Jan-2017

832 views

Category:

Technology


4 download

TRANSCRIPT

Page 1: Do postgres-dream-of-graph-database

Do Postgres dream of Graph-Database?

ぬこ@横浜 (@nuko_yokohama)

Page 2: Do postgres-dream-of-graph-database

2

自己紹介「 PostgreSQL ラーメン」

でググってください。

Page 3: Do postgres-dream-of-graph-database

3

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

Page 4: Do postgres-dream-of-graph-database

4

今日話すこと

Page 5: Do postgres-dream-of-graph-database

5

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

この本

Page 6: Do postgres-dream-of-graph-database

6

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

Page 7: Do postgres-dream-of-graph-database

7

グラフデータベース?

Page 8: Do postgres-dream-of-graph-database

8

グラフデータベース

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

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

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

Page 9: Do postgres-dream-of-graph-database

9

例えば Neo4j

ノード

関連

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

例えば Neo4j

Page 10: Do postgres-dream-of-graph-database

10

PostgreSQL の更新を

Neo4j へ反映

Page 11: Do postgres-dream-of-graph-database

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

スロット定義

Page 12: Do postgres-dream-of-graph-database

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

スロット定義

Page 13: Do postgres-dream-of-graph-database

13

Data Model

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

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

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

Page 14: Do postgres-dream-of-graph-database

14

Data Modelノードテーブル

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

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

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

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

終点ノード ID

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

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

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

1 テーブルで管理

Page 15: Do postgres-dream-of-graph-database

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

スロット定義

Page 16: Do postgres-dream-of-graph-database

16

ロジカルデコーディング

Page 17: Do postgres-dream-of-graph-database

17

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

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

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

夢が広がりんぐ機能

Page 18: Do postgres-dream-of-graph-database

18

Decoding Function

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

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

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

Page 19: Do postgres-dream-of-graph-database

19

Decoding Function

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

サンプルが入っている。

contrib/test_decoding

Page 20: Do postgres-dream-of-graph-database

20

Decoding Function

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

pg_logical_replication_slot に格納されている。

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

Page 21: Do postgres-dream-of-graph-database

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;

Page 22: Do postgres-dream-of-graph-database

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 は未対応です。

Page 23: Do postgres-dream-of-graph-database

23

Decoding Function

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

(サンプルだし)

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

Page 24: Do postgres-dream-of-graph-database

24

Decoding Function

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

↓表現能力は十分

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

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

Page 25: Do postgres-dream-of-graph-database

25

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

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

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

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

INSERT ○ ○ ○ - -

UPDATE ○ ○ - ○ ○

DELETE ○ ○ - - ○

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

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

Page 26: Do postgres-dream-of-graph-database

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 形式にデコードしてくれる。せっかくなので、今回はこれを使ってみる。

Page 27: Do postgres-dream-of-graph-database

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

Page 28: Do postgres-dream-of-graph-database

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 によるログ情報

Page 29: Do postgres-dream-of-graph-database

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

スロット定義

Page 30: Do postgres-dream-of-graph-database

30

Logideco4neo4j必要なパーツ

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

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

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

Page 31: Do postgres-dream-of-graph-database

31

Logideco4neo4j

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

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

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

Page 32: Do postgres-dream-of-graph-database

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[])

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

Page 33: Do postgres-dream-of-graph-database

33

Logideco4neo4j

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

Neo4j Cypher クエリを生成する

Page 34: Do postgres-dream-of-graph-database

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 に変換

Page 35: Do postgres-dream-of-graph-database

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 に変換

Page 36: Do postgres-dream-of-graph-database

36

Logideco4neo4j

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

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

よしなにやってくれる。

Page 37: Do postgres-dream-of-graph-database

37

デモ

Page 38: Do postgres-dream-of-graph-database

38

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

やったね♪

Page 39: Do postgres-dream-of-graph-database

39

PostgreSQL からSQL で

Neo4j を検索

Page 40: Do postgres-dream-of-graph-database

40

ForeignData Wrapper

Page 41: Do postgres-dream-of-graph-database

41

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

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

Page 42: Do postgres-dream-of-graph-database

42

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

Foreign Data Wrapper を開発する。

Page 43: Do postgres-dream-of-graph-database

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

スロット定義

Page 44: Do postgres-dream-of-graph-database

44

というか、以前 Neo4j に

接続する FDW を作っていた

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

Page 45: Do postgres-dream-of-graph-database

45

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

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

Page 46: Do postgres-dream-of-graph-database

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!

Page 47: Do postgres-dream-of-graph-database

47

デモ

Page 48: Do postgres-dream-of-graph-database

48

PostgreSQL からSQL を使って

Neo4j の検索ができた。

やったね♪

Page 49: Do postgres-dream-of-graph-database

49

と、いうことで

Page 50: Do postgres-dream-of-graph-database

50

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

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

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

わりとどうでもいい

Page 51: Do postgres-dream-of-graph-database

51

おしまい

Page 52: Do postgres-dream-of-graph-database

52

補足(というか蛇足)

Page 53: Do postgres-dream-of-graph-database

53

FDW を良く知っている人

からのツッコミ

Page 54: Do postgres-dream-of-graph-database

54

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

(PostgreSQL 9.3 以降 )

Page 55: Do postgres-dream-of-graph-database

55

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

いけないのが面倒…

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