Skip to content

2주차 기술공유 graphdb

sang-eun edited this page May 18, 2020 · 5 revisions

2주차 기술공유

주제 : graphdb


what is graphDB

정의

질의어 : Cypher

  • declarative graph query language(선언적 그래프 질의 언어)

구성요소

  • node , relationship, label, properties

  • node : 그래프 DB에서 1개의 개체

  • label : node의 그룹조건 노드의 역할을 명시하고, 노드를 그룹화 하기 위한 타입

    • 하나의 노드는 여러 라벨링이 가능
  • propreties : node,relation이 가질 수 있는 값들 ex) user node의 name, phone, id..

  • relationship : node의 관계 entity 연결, 구조를 설정, properties

노드는 graphDB에서 하나의 개체이고 노드의 관계를 표시하는 게 relationship입니다. 노드와 relation은 label과 property를 가질 수 있다. 라벨은 명시되는 타입입니다. 회사 타입, employee 타입등을 명시해서 쿼리 셀렉트를 쉽게할 수 있습니다. 프로퍼티는 node,relation이 가질 수 있는 값들


Node:Label

()
(variable)
(:Label)
(variable:Label)
(:Label1:Label2)
(variable:Label1:Label2)

여러개의 라벨을 한 노드에 사용가능하다.

(신기하게도)neo4j는 하나의 노드에 여러 라벨을 부여 할 수 있습니다.


HOW TO USE : CRUD

DB는 Curd!! 기초 crud 를 알아봅시다


CREATE

CREATE (john:Person {name: 'John'})
CREATE (joe:Person {name: 'Joe'})
CREATE (steve:Person {name: 'Steve'})
CREATE (sara:Person {name: 'Sara'})
CREATE (maria:Person {name: 'Maria'})
// 관계설정해서 만들기(뒤에 나옴)
CREATE (john)-[:FRIEND]->(joe)-[:FRIEND]->(steve)
CREATE (john)-[:FRIEND]->(sara)-[:FRIEND]->(maria)

먼저 노드를 만들어야겠져?


Relation - MATCH/MERGE

// name A인 Person label 노드와 name B인 노드를 연결한다 
MATCH (a:Person),(b:Person)
WHERE a.name = 'John' AND b.name = 'Joe'
CREATE (a)-[r:Friend { description : a.name + '<->' + b.name }]->(b)
RETURN type(r), r.description

그다음은 관계를 만들어야겠져? joe 와 john은 친구다


SELECT - MATCH/RETURN

MATCH (user)-[:friend]->(follower)
WHERE user.name IN ['Joe', 'John', 'Sara', 'Maria', 'Steve'] AND follower.name =~ 'S.*'
RETURN user.name, follower.name

(tip) =~ 정규표현식으로 검색
  • 모든 노드 반환
MATCH (variable)
RETURN variable
  • Label에 해당하는 노드 반환
MATCH (variable:Label)
RETURN variable

만든 노드들을 조회해봅시다


UPDATE - MATCH/SET

MATCH (n:Person {name:"kkyu"}) SET n.age=35

만든 노드의 프로퍼티를 수정해봅시다. SET을 이용하면 됨


DELETE - MATCH/REMOVE

MATCH (n:Person {name:"kkyu"}) REMOVE n.age=35

// 관계 삭지
MATCH (a:Persion{name:'yeon'})-[r]-(b) DELETE r
  • 관계가 설정된 노드는 관계부터 삭제해야 한다. ref

만든 노드를 삭제해봅시다. 하지만 관계가 있다면 관계부터 삭제해야 합니다


MATCH 
  (person:Person)-[:KNOWS]-(friend:Person)-[:KNOWS]-(foaf:Person)
WHERE 
  person.name = "Joe"
  AND NOT (person)-[:KNOWS]-(foaf)
RETURN
  foaf    

우리의 상황은 항상 쉽지 않죠. 조금 더 복잡한 쿼리를 알아보겠습니다. 목적 : 친구의 친구들 중 나와 친구가 아닌 친구들을 찾아봅시다 예상되야되는 결과 : bob은 뜨면안되고 sally, anna 만 결과로 확인되어야 합니다. person의 이름이 Joe이고 person과 KNOW의 관계가 2depth가 아닌 1depth인 경우를 나타내는 cypher입니다.

MATCH 
  (person:Person)-[:KNOWS]-(friend)-[:KNOWS]-(foaf:Person)
WHERE 
  user.name = "Joe" AND foaf.name = "Sally"
RETURN 
  friend.name

MATCH 
  path = shortestPath(
    (p1:Person)-[:KNOWS*..6]-(p2:Person)
  )
WHERE 
  p1.name = "Joe" AND p2.name = "Billy"
RETURN
  path

고민 : 어려웠던 점

친구의 친구 찾기가 엄청 편하네!를 알게 되었어요 그럼 우리가 도입할 수 있을지를 생각해봅시다


Mysql vs Neo4j

  • 일반적인 RDB에서 너비 우선 탐색을 구현하려면 대규모의 JOINGROUP BY 가 불가피함 -> 따라서 수많은 관계를 나타내기 위해서는 그에 특화된 그래프 DB를 이용하는 것이 성능이 빠르다.

이하의 공식 문서 결과를 보면 graphDB가 얼마나 관계에 최적화되어있는지 볼 수 있다.

이 공식 문서에 대해 정확한 확인을 해보기 위해서 직접 테스트를 작성해서 이하에서 테스트해보았다.


비교해보자

공통 테스트 환경
  • 유저 1,000,000명

  • depth : 1,2 depth

  • Graph db: 한 유저에 대한 friends 관계인 User들 143명 가져오는 쿼리

    • MATCH (a:Person {name : 'User33'}) -[:FRIENDS] -> (m:Person) RETURN m;
  • Mysql db: 한 유저에 대해 tb_friend_relation 테이블 inner join을 통해 143명 가져옴

    • select * from tb_user as user
        left join tb_friend_relation friend
          on user.id = friend.user_id
        left join tb_user as user1
          on friend.user_id2 = user1.id
       where user.id = 'id1200';

Case graphDB Mysql
Depth1 8ms 0.1ms
Depth2 26ms 10.1ms
  • neo4j에 대한 orm이 존재하지 않음. ( 개발 속도가 더딜 수 있음. )
  • mysql에 비해 neo4j에 대한 reference가 많이는 존재하지 않음.
결론

보았을 때 mysql쪽이 성능이 더 좋은 것으로 판단되었다. 하지만

  • 공식 홈페이지와 성능 차이가 커서 올바르게 측정을 하였는지 정확하지 않음
  • 팀원의 의사를 존중
  • 확장성을 고려 하여 그래프 db를 사용하는 것으로 결정하였다.


주의사항

  1. 스키마 제약이 없어도 기본 스키마는 만들자. 스키마의 크기를 고려해야 한다
  2. Neo4j limits the number of relationship types to 65K to keep the database fast
  3. file은 blob으로 저장하지 말기
  4. Indexing : legacy indexing -> schema indexing
  5. never use explain profile
  6. MERGE 는 유일성을 보장하지 않는다. use the UNIQUE constrain

HOW TO MODELING

naming

  • LABEL은 대문자로 시작하는 명사로 정의 User
  • RelationShips : 목적어를 가질 수 있는 동사로 정의, 대문자 권장 SENT
  • property : 명사형 {name:""}

그럼 우리 디비에서 어떻게 모델링을 해야할까요? 각 요소들의 네이밍 규칙을 먼저 알아봅시다


Modeling Example

=> * John is friends with Sally * Sally is friends with John * John has read Graph Databases * Sally has read Graph Databases

  • 동사와 명사로 구분해서 모델링

그럼 네이밍 규칙을 적용해서 문장을 모델링하는 것을 살펴봅시다 이런 방식으로 우리도 데이터 모델링을 함

겟챠 우리도 모델링을 해보자

(Node)-[relation]->(Node) User authored Feed Feed authored by User Feed has comments User authored Comment Comment authored by User Comment liked by User User likes comments User friend User User tagged at Feed Feed tagged User

프로젝트 수행 중 팀에서 어떻게 기술을 공유했는지

  • 오전 회의 때 공부한 내용 공유
    • 왜 모두가 공유했는지. : 디비설계 및 설정은 모두가알아야 하는 내용이므로 서로 이해했는지 명확해 해야 했음.
    • 공부한 내용을 발표하고 그 내용을 이해했는지 다시 말해봄.
  • 테스트 데이터, 환경을 위키로 공유
    • 기록으로 남겨야 하는부분은 위키로 공유

팀에 어떤 기여를 했는지

  • 팀원모두 기술 공유에 대한 여러 아이디어를 냄
Clone this wiki locally