제가 2019년 1월 30일에 Pivotal 의 Data Science Webinar 에서 발표했었던 "오픈소스 그림플럼 DB와 아파치 MADlib을 활용한 그래프 분석, 네트워크 분석 (Graph analytics with Greenplum and Apache MADlib)" 자료를 공유합니다. 


[ Agenda ]

1. Why Graph Analytics?

2. What is Graph Analytics?

3. Graph Analytics with Apache MADlib on Greenplum in parallel


presented by Hongdon Lee, Pivotal Senior Data Scientist


[ 파일 첨부: Graph Analytics with Greenplum and Apache MADlib ]

Pivotal_Graph_Analytics_w_MADlib_GPDB_20190130.pdf




개별 단위별 객체, 대상만을 놓고 나누어 분석하는 환원주의(Reductionism: Divide and conquer) 대비 전체를 하나로 놓고 관계와 연결에 주목해서 분석하면 새로운 인사이트를 얻을 수 있다는 전체론 관점(Holism: Everything has to be understood in relation to the whole)의 분석 기법으로 그래프 이론(graph theory)네트워크 분석(network analysis)을 소개하는 자료입니다. 


그래프 분석 시 도전 사항으로 복잡도가 매우 높아 연산 부하가 크고 분석이 불가능하거나 시간이 오래 걸린다는 점입니다. 이를 해결할 수 있는 대안으로 MPP(Massively Parallel Processing) 아키텍처 기반의 오픈소스 Greenplum DBApache MADlib을 이용한 그래프, 네트워크 분석의 In-Database 병렬 처리 분석을 소개하였습니다. 


Webinar 발표할 때 재미를 더하기 위해서 슬라이드 중간 중간에 제 사진도 좀 넣어보았는데요, 이렇게 파일 공유하려니 좀 쑥스럽기도 하네요. ^^;  Webinar 발표할 때는 우리나라말로 했었는데요, 글로벌 데이터 팀 구성원들한테도 공유할 생각으로 슬라이드는 영어로 만들었습니다. 중간에 수식도 많은데 영어라서 눈에 잘 안들어온다는 피드백이 있었는데요, 양해 바랍니다. ^^;;; 


알고리즘 세부 소개하는 부분은 위키피디아를 많이 참고하였습니다. 


저는 실제 프로젝트 하면서 그래프 / 네트워크 분석이 제공할 수 있는 인사이트의 유용함을 경험하기도 했구요, Greenplum DB 에서 MADlib으로 분석하면서 In-DB parallel processing의 강력함을 경험했던 지라 기회되면 꼭 한번 소개를 하고 싶었던 주제였습니다. R이나 Python으로 노트북에서 network 분석 공부할 땐 아무 문제 없다가도, 실제 기업이나 공공기관의 수 terabyte, petabyte 급 데이터를 마주하게 되면 당황하기 마련인데요, 이럴 때 사용할 수 있는 방법, 툴입니다. 


주요 장표 몇 장만 아래에 화면 캡쳐한거 소개하자면요, 



  • Everything is connected!




  • Network: Everywhere with Everything, All the time



  • What is Graph Theory?



  • Graph algorithms and measures


  • Tools for Graph Analytics



  • Apache MADlib: Scaleable, In-Database Machine Learning in SQL



  • Apache MADlib: Graph Analytics Functions




그래프/ 네트워크 분석 주제 중에서 Page Rank 에 대한 간단한 예제 SQL 코드와 Graphviz, PyGraphviz를 활용한 네트워크 시각화 코드도 공유합니다. 



[ 그래프 분석 MADlib SQL codes ]

graph_pagerank_madlib.sql


----------------------------------------------

-- Graph Analytics with Greenplum and MADlib

----------------------------------------------


-- CREATE VERTEX TABLE

DROP TABLE IF EXISTS vertex;

CREATE TABLE vertex(

id INTEGER

) DISTRIBUTED RANDOMLY;


INSERT INTO vertex 

VALUES

(0), 

(1), 

(2), 

(3), 

(4),

(5),

(6);


select * from vertex


-- CREATE EDGE TABLE

DROP TABLE IF EXISTS edge;

CREATE TABLE edge(

src INTEGER,

dest INTEGER,

user_id INTEGER

)

DISTRIBUTED BY (user_id);


INSERT INTO edge 

VALUES 

(0, 1, 1), (0, 2, 1), -- user id 1

(0, 4, 1), (1, 2, 1),

(1, 3, 1), (2, 3, 1),

(2, 5, 1), (2, 6, 1),

(3, 0, 1), (4, 0, 1),

(5, 6, 1), (6, 3, 1),

(0, 1, 2), (0, 2, 2), -- user id 2

(0, 4, 2), (1, 2, 2),

(1, 3, 2), (2, 3, 2),

(3, 0, 2), (4, 0, 2),

(5, 6, 2), (6, 3, 2);


select * from edge;



-- (1) Compute the PageRank with All IDs

DROP TABLE IF EXISTS pagerank_out, pagerank_out_summary;

SELECT madlib.pagerank(

'vertex' -- Vertex table

, 'id' -- Vertex id column

, 'edge' -- Edge table

, 'src=src, dest=dest' -- Comma delimited string of edge arguments

, 'pagerank_out' -- Output table of RageRank

, NULL -- Default damping factor (0.85)

); 


SELECT * FROM pagerank_out ORDER BY pagerank DESC;



-- (2) Compute the PageRank of vertices associated with each user using the grouping feature

DROP TABLE IF EXISTS pagerank_gr_out, pagerank_gr_out_summary;

SELECT madlib.pagerank(

'vertex' -- Vertex table

, 'id' -- Vertex id column

, 'edge' -- Edge table

, 'src=src, dest=dest' -- Comma delimited string of edge arguments

, 'pagerank_gr_out' -- Output table of PageRank

, NULL -- Default damping factor (0.85)

, NULL -- Default max iterations (100)

, 0.00000001 -- Threshold

, 'user_id'); -- Grouping column name


SELECT * FROM pagerank_gr_out ORDER BY user_id, pagerank DESC;



-- (3) Personalized PageRank of vertices {2, 4}

DROP TABLE IF EXISTS pagerank_pers_out, pagerank_pers_out_summary;

SELECT madlib.pagerank(

'vertex' -- Vertex table

, 'id' -- Vertex id column

, 'edge' -- Edge table

, 'src=src, dest=dest' -- Comma delimited string of edge arguments

, 'pagerank_pers_out' -- Output table of PageRank

, NULL -- Default damping factor (0.85)

, NULL


-- Default max iterations (100)

, NULL -- Default Threshold (1/number of vertices*1000)

, NULL -- No Grouping

, '{2, 4}' -- Personalization vertices

);


SELECT * FROM pagerank_pers_out ORDER BY pagerank DESC;


SELECT * FROM pagerank_pers_out_summary;


 




[ Graphviz 활용한 네트워크 시각화 Python codes ]

NW_visualization.py





#!/usr/bin/env python2

# -*- coding: utf-8 -*-

"""

Created on Tuesday Jau 29 2019

@author: Hongdon Lee

"""

#%% network visualization using Graphviz

import numpy as np

import pandas as pd

import pygraphviz as pgv


def run_query(query):

     import pandas as pd

     import psycopg2 as pg


    # DB Connection

     conn = pg.connect(host='localhost',

                       port='5432', 

                       dbname='gpadmin', 

                       user='gpadmin', 

                       password='pivotal')


     # Get a DataFrame

     query_result = pd.read_sql(query, conn)

     conn.close()

     return query_result



#%% Network Edge Table

query = """

select a.*, b.pagerank 

    from edge a

    left outer join pagerank_out b on a.src = b.id

;

"""


edge_pagerank = run_query(query)


#%% PageRank Values

query = """

select * from pagerank_out;

"""


pagerank_out  = run_query(query)



#%% NW Visualization using Graphviz with different size proportional to PageRank


import pygraphviz as pgv


# Generating the output flow_graph with PyGraphviz

flow_graph = pgv.AGraph(strict=False, directed=True) # directed graph


# Flow Direction(Left to Right, or Top to Bottom)

flow_graph.graph_attr['rankdir'] = 'LR' # from Left to Right


# Node Shape

flow_graph.node_attr['shape'] = 'circle'


# Making node with different size proportional to PageRank

for i in range(len(pagerank_out)):

    label_text = str(pagerank_out.id[i]) + '\n(' + str(pagerank_out.pagerank[i].round(decimals=2)) + ')'

    node_width = pagerank_out.pagerank[i]*10

    node_height = pagerank_out.pagerank[i]*10

    

    flow_graph.add_node(str(pagerank_out.id[i]), 

                        label=label_text, 

                        **{'width': str(node_width), 

                           'height': str(node_height)})


# Adding edge with different color by user_id

colors = ['blue', 'red']

 

for i in range(len(edge_pagerank)):

    if edge_pagerank.user_id[i] == 1:

        color_text = colors[0]

    else:

        color_text = colors[1]

    

    flow_graph.add_edge(str(edge_pagerank.src[i])

                        , str(edge_pagerank.dest[i])

                        , color = color_text)


#----- Finally, Draw the Network Diagram using dot program :-)

flow_graph.draw("/Users/ihongdon/Documents/nw_diagram.png", prog='dot')

 



[ Docker image를 이용해서 Greenplum, MADlib, PL/R, PL/Python 분석 환경 구성하는 방법 (싱글 노드의 로컬 기능 테스트, 공부 용도로)]

https://rfriend.tistory.com/379 

https://hub.docker.com/r/hdlee2u/gpdb-analytics



많은 도움이 되었기를 바랍니다. 


ps. 앤 해서웨이(ANNE HATHAWAY)와 연결해주실 분 계신가요? 6 degrees of separation 의 기적이 저에게도 일어날 수 있으려나요? ^^" 



Posted by R Friend R_Friend

댓글을 달아 주세요