기타/프로그래밍

[그래프 데이터베이스][무작정해보기] [13/30] 쿼리 패턴 익히기

코드아키택트 2021. 2. 13. 09:00
반응형

이 모듈이 끝나면 다음과 같은 것을 할 수 있어야 한다

- 여러 MATCH 패턴 사용

- 여러 MATCH 절 사용

- OPTIONAL 사용

- subgraph return

- 변화하는 paths 길이 사용

 

 

 

MATCH절 순회

 The Replacements라는 영화를 리뷰한 사람들을 팔로우하는 사람들을 찾고 싶다면

 

MATCH (follower:Person)-[:FOLLOWS]->(reviewer:Person)-[:REVIEWED]->(m:Movie)
WHERE m.title = 'The Replacements'
RETURN follower.name, reviewer.name

데이터를 구성하는 그래프

 다음과 같은 순서로 그래프 엔진이 작동한다. 우선 영화를 찾는다. 그 후 영화를 리뷰한 사람들을 찾는다. 그런 후 다시 리뷰얼르 팔로우 하는 사람들을 찾는다. 위의 그래프에서 Jessica Thompson은 아무도 팔로우하고 있지 않기 때문에 테이블에 나오지 않는다.

 

 

 

여러개의 패턴을 MATCH에 사용하기

 지금까진 WHERE를 사용해서 원하는 데이터를 쿼리했지만 MATCH안에 여러 패턴을 써서 데이터를 쿼리할 수 있다. 콤마를 사용하면 된다.

위는 2000년에 개봉한 영화와 이 영화에 참여한 사람들의 그래프이다.

 

MATCH (a:Person)-[:ACTED_IN]->(m:Movie),
      (m)<-[:DIRECTED]-(d:Person)
WHERE m.released = 2000
RETURN a.name, m.title, d.name

Cast Away, The Replacements, Jerry Maguire 세 영화가 2000년에 개봉한 것을 볼 수 있다.

 

 

 

하나의 패턴으로 쓰기

MATCH (a:Person)-[:ACTED_IN]->(m:Movie)<-[:DIRECTED]-(d:Person)
WHERE m.released = 2000
RETURN a.name, m.title, d.name

위의 콤마를 이용한 문장을 한줄로 옮길 수 있다. 여러개의 패턴을 사용하는 방식은 기존의 노드와 새로운 노드를 이을때 유용하다고 한다. 이건 해당하는 챕터에 갔을떄 해봐야 겠다.

 

 

 

예제: 두 패턴을 하나의 MATCH안에 사용하기. 

 만약 우리가 휴고 위빙을 만나기 위해 키아누 리브스와 일했던 배우를 알고 싶다면 어떻게 해야할까? Cypher 사고 방식으로 하면 다음과 같다. 쉽게 말하면 키아누리브스와 작업해봤지만, 휴고위빙과는 작업해보지 않은 배우들을 찾아내면 된다. 그래프는 다음과 같다.

 

 

만약 위의 그래프를 얻고 싶다면 다음의 Cypher문장을 쓰면 된다

 

MATCH path=(keanu:Person)-[:ACTED_IN]->(movie:Movie)<-[:ACTED_IN]-(n:Person),
     (hugo:Person)
WHERE keanu.name='Keanu Reeves' AND
      hugo.name='Hugo Weaving'
AND NOT (hugo)-[:ACTED_IN]->(movie)
RETURN path

잘 읽어보면 답을 알 수 있다. 키아누 리브스가 연기한 한 영화를 구하고 그 영화 중 휴고위빙이 연기하지 않은 영화를 걸러내는 것이다.

 

이름만 얻고 싶다면 아래의 Cypher문을 쓰면 된다.

 

MATCH (keanu:Person)-[:ACTED_IN]->(movie:Movie)<-[:ACTED_IN]-(n:Person),
     (hugo:Person)
WHERE keanu.name='Keanu Reeves' AND
      hugo.name='Hugo Weaving'
AND NOT (hugo)-[:ACTED_IN]->(movie)
RETURN n.name

 

이름만 가져온 결과

 

이 작업을 수행할때 노란색으로 느낌표가 뜬다. 공식 사이트에 설명에선 Catesian Product를 수행하기 때문이라고 한다. 컴퓨터 리소스를 많이 잡아먹기 때문에 자신이 무엇을 하려고한는지 명확히 알때만 쓰라고 쓰여있다.

경고메세지
Cartesian Product이미지

Catesian Product는 잠시 찾아봤는데, 모든 경우의 수를 구하는 방법인 듯 하다. 그럼 당연히 엄청나게 리소스가 많이 소비될 것이다.

 

 

 

 패턴 순회하기 : 여러줄의 MATCH 사용

 여러줄의 MATCH를 사용해서 쿼리가 가능하다

MATCH (valKilmer:Person)-[:ACTED_IN]->(m:Movie)
MATCH (actor:Person)-[:ACTED_IN]->(m)
WHERE valKilmer.name = 'Val Kilmer'
RETURN m.title as movie , actor.name

 위의 방식을 사용하면 위와 같이 두번 MATCH가 이루어진다. 첫번째는 Val Kilmer노드를 찾아내고, Val Kilmer가 ACTED_IN한 노드를 찾아내는 것이다. 여기에선 Top Gun이다

이 사람이 Val Kilmer...

 두번째는 탑건을 중심으로 탑건을 연기한 배우들을 찾아내는 것이다. 위에서 주목할 사항은 Val Kilmer에 대한 relationship은 두번 계산되는 것이다.

결과는 다음과 같다

 

 

 

하나의 MATCH절에 여러 패턴 쓰기

MATCH (valKilmer:Person)-[:ACTED_IN]->(m:Movie),
      (actor:Person)-[:ACTED_IN]->(m)
WHERE valKilmer.name = 'Val Kilmer'
RETURN m.title as movie , actor.name

 위는 해석해보면 다음과 같다. Val Kilmer가 출연한 영화를 찾고, 그 영화에서 연기한 배우들을 찾아라가 된다. 위의 예제와 다른것은 Val Kilmer는 제외한다는 것이다. 왜냐하면 이미 Val Kilmer가 출연했다는 것을 알고 시작했기 때문이다. 

 MATCH를 두번 사용한 방법과 비교해서 장점은 노드 사이를 순회하는 숫자가 줄었다는 것이다. 공식사이트에 의하면 Best practice는 위와 같이 최소한의 노드 순회를 만들어 내는 것이라고 한다.

 

 

 

다양한 paths length에 대해 해보기

 

 path length는 노드와 노드사이의 hop이라고 생각하면 되겠다. 2촌이라면 length =2 이고 나머지는 각자 대응되는 숫자가 되겠다. 위의 그림에서 Paul Blthe의 팔로잉의 팔로잉을 구하려면 어떻게 해야할까? 전에 다른 예제를 하면서 나왔지만 또 써본다. 우선 생각해 볼 것은 위의 그림을 보면 'Jessica Thopson'이 나온다는것이다.

 

MATCH (follower:Person)-[:FOLLOWS*2]->(p:Person)
WHERE follower.name = 'Paul Blythe'
RETURN p.name

 

 

 

모든 path length에 대한 Cypher질의문

기본적인 문법은 다음과 같다. 노드 A 에서 B까지 방향으로 특정 관계에대해 모두다 찾아내고 싶으면 다음과 같이 하면 된다. 

(nodeA)-[:RELTYPE*]->(nodeB)

 Follow에 대해서 한번 해보았다. Cypher문은 다음과 같다

MATCH path = ()-[:FOLLOWS]->()
RETURN path

Follow 관계가 생각처럼 많진 않았다.

노드 A 에서 B까지 방향에 상관없이 특정 관계에대해 모두다 찾아내고 싶으면 다음과 같이 하면 된다.

(nodeA)-[:RELTYPE*]->(nodeB)

 역시나 Follow에 대해서 해봤는데 결과가 동일해 적지 않겠다.

 

 

특정 Path길이에 대해서 하고싶을떄

위는 길이에 상관없이 수행했지만 길이를 정할 수 있다.

(node1)-[:RELTYPE*3]->(node2)

1번 노드로 부터 2번 노드까지 3번의 hop을 통해 특정관계로 도달할수 있는 관계를 나타낸다. 위의 Follow 관계를 으용해 보겠다.

MATCH path = (n:Person{name:'Paul Blythe'})-[:FOLLOWS*1]->()
RETURN path

위의 Cypher문을 쓰면 Paul Blythe라는 사람으로 시작해 Follow Hop이 1번인 관계를 뽑아낸다.

 

MATCH path = (n:Person{name:'Paul Blythe'})-[:FOLLOWS*2]->()
RETURN path

 

Hop을 2로 늘리면 Follow의 Follow를 찾아낸다.

 

Hop을 3으로 늘리면 그런 관계는 존재하지 않기때문에 아무것도 나오지 않는다.

 

 

Path Length가 1,2 또는 3인 경우 찾아내기

위의 예제들은 정확히 path length가 n인 경우만 찾아내는 경우였다. 다시 follow예제를 통해서 해보겠다

MATCH path = (:Person{name:'Paul Blythe'})-[:FOLLOWS*1..3]->()
RETURN path

 위의 문장은 Paul Blythe를 시작으로 Paul Blythe의 Follow, Follow*2, Follow*3의 관계를 가져오는 것이다. 실행 결과는 다음과 같다.

OR로 처리되기 때문에 Follow Hop이 1인경우 2인 경우가 나왔다. 3인 경우가 나오지 않은 것은 3Hop의 Follow 관계가 존재하지 않기 때문이다.

 

 

 

최소거리찾기

 어떠한 두 노드에 대해서 최소의 Hop을 찾는 방법이다. shortestPath()라는 기능을 통해 찾을 수 있다. 여기서는 Matrix와 A Few Good Men 사이의 최소거리를 찾는다.

MATCH p = shortestPath((m1:Movie)-[*]-(m2:Movie))
WHERE m1.title = 'A Few Good Men' AND
      m2.title = 'The Matrix'
RETURN  p

 위를 보면 m1과 m2사이에는 어떤 관계도 허용하도록 한것을 볼 수 있다.

오랜 시간이 걸릴것이라는 메세지

 위의 메세지에선 최대 바운드를 정하라고 되어있는데, 아직까지 진도에선 다루고 있지 않아 추후에 나온다면 써봐야 겠다. 여튼 상식적으로 생각해도 오래걸릴수밖에 없다.

 

 

 

서브 그래프 쿼리하기

 서브그래프라는 말이 나와서 뭔가 했는데, 노드와 연결된노드의 모습을 띄는것은 모두다 서브그래프라고 하는 듯 하다. 영어 표현으론 Set of paths 라고 한다.

그냥 이렇게 노드와 노드가 연결된건 모두다 subgraph

텍스트 뷰로 보면 영화 - ACTED_IN정보- 배우 또는 영화 - REVIEWED- 리뷰어 의 관계로 이루어진 데이터가 나온다. 

 

 

 

OPTIONAL MATCH 사용하기

MATCH와 기본적으로 비슷하지만, 질의문에 대한 답이 없으면 Null로 처리하는 것이다. SQL의 LEFT JOIN과 비슷하다고 보면 된다. 예시 데이터는 James라는 이름을 가진 사람들의 subgraph이다


사이퍼문은 아래와 같다.

MATCH (p:Person)
WHERE p.name STARTS WITH 'James'
OPTIONAL MATCH (p)-[r:REVIEWED]->(m:Movie)
RETURN p.name, type(r), m.title

해석해보면 이름은 'Jame'로 시작하고, Optional Match로 그 중 영화를 리뷰한 사람을 찾아내는 것이다.

결과는 다음과 같다.

기본적으로 James라는 이름을 가지는 사람들은 모두다 찾은 것을 볼 수 있다. 리뷰에 관한 사항은 Optional Match였기 때문에 James로 시작한 사람중 리뷰를 한적이 없는 사람은 해당란이 null로 나왔다. 

 

 

 

끝맺으며

 코드를 직접 사용해보는 것이 이해하는데 훨씬 도움이 된다. 기존의 RDBMS에서는 테이블과 테이블 사이의 join을 통해서 원하는 데이터를 얻어내야 했다. 그런 과정속에 제대로 하고있는게 맞나 헷갈리는 경우가 많았는데, 그래프데이터베이스의 경우엔 눈으로 시각화 해주니 이해하기 훨씬 쉬웠다. 

반응형